InlineObjCInstanceMethod.m
3.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// RUN: %clang_analyze_cc1 -analyzer-checker=core.DivideZero,core.DynamicTypePropagation,osx.cocoa.IncompatibleMethodTypes -w -verify %s
#include "InlineObjCInstanceMethod.h"
typedef const struct __CFString * CFStringRef;
typedef const void * CFTypeRef;
extern CFTypeRef CFRetain(CFTypeRef cf);
extern void CFRelease(CFTypeRef cf);
extern CFStringRef getString(void);
// Method is defined in the parent; called through self.
@interface MyParent : NSObject
- (int)getInt;
- (const struct __CFString *) testCovariantReturnType __attribute__((cf_returns_retained));
@end
@implementation MyParent
- (int)getInt {
return 0;
}
- (CFStringRef) testCovariantReturnType __attribute__((cf_returns_retained)) {
CFStringRef Str = ((void*)0);
Str = getString();
if (Str) {
CFRetain(Str);
}
return Str;
}
@end
@interface MyClass : MyParent
@end
@implementation MyClass
- (int)testDynDispatchSelf {
int y = [self getInt];
return 5/y; // expected-warning {{Division by zero}}
}
// Get the dynamic type info from a cast (from id to MyClass*).
+ (int)testAllocInit {
MyClass *a = [[self alloc] init];
return 5/[a getInt]; // expected-warning {{Division by zero}}
}
// Method is called on inited object.
+ (int)testAllocInit2 {
MyClass *a = [[MyClass alloc] init];
return 5/[a getInt]; // expected-warning {{Division by zero}}
}
// Method is called on a parameter.
+ (int)testParam: (MyClass*) a {
return 5/[a getInt]; // expected-warning {{Division by zero}}
}
// Method is called on a parameter of unnown type.
+ (int)testParamUnknownType: (id) a {
return 5/[a getInt]; // no warning
}
@end
// TODO: When method is inlined, the attribute reset should be visible.
@interface TestSettingAnAttributeInCallee : NSObject {
int _attribute;
}
- (void) method2;
@end
@implementation TestSettingAnAttributeInCallee
- (int) method1 {
[self method2];
return 5/_attribute; // expected-warning {{Division by zero}}
}
- (void) method2 {
_attribute = 0;
}
@end
@interface TestSettingAnAttributeInCaller : NSObject {
int _attribute;
}
- (int) method2;
@end
@implementation TestSettingAnAttributeInCaller
- (void) method1 {
_attribute = 0;
[self method2];
}
- (int) method2 {
return 5/_attribute; // expected-warning {{Division by zero}}
}
@end
// Don't crash if we don't know the receiver's region.
void randomlyMessageAnObject(MyClass *arr[], int i) {
(void)[arr[i] getInt];
}
@interface EvilChild : MyParent
- (id)getInt;
- (const struct __CFString *) testCovariantReturnType __attribute__((cf_returns_retained));
@end
@implementation EvilChild
- (id)getInt { // expected-warning {{types are incompatible}}
return self;
}
- (CFStringRef) testCovariantReturnType __attribute__((cf_returns_retained)) {
CFStringRef Str = ((void*)0);
Str = getString();
if (Str) {
CFRetain(Str);
}
return Str;
}
@end
int testNonCovariantReturnType() {
MyParent *obj = [[EvilChild alloc] init];
// Devirtualization allows us to directly call -[EvilChild getInt], but
// that returns an id, not an int. There is an off-by-default warning for
// this, -Woverriding-method-mismatch, and an on-by-default analyzer warning,
// osx.cocoa.IncompatibleMethodTypes. This code would probably crash at
// runtime, but at least the analyzer shouldn't crash.
int x = 1 + [obj getInt];
[obj release];
return 5/(x-1); // no-warning
}
int testCovariantReturnTypeNoErrorSinceTypesMatch() {
MyParent *obj = [[EvilChild alloc] init];
CFStringRef S = ((void*)0);
S = [obj testCovariantReturnType];
if (S)
CFRelease(S);
CFRelease(obj);
}