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