1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.Loops,debug.ExprInspection -verify -analyzer-config eagerly-assume=false %s |
2 | |
3 | void clang_analyzer_eval(int); |
4 | void clang_analyzer_warnIfReached(); |
5 | |
6 | #define nil ((id)0) |
7 | |
8 | typedef unsigned long NSUInteger; |
9 | @protocol NSFastEnumeration |
10 | - (int)countByEnumeratingWithState:(void *)state objects:(id *)objects count:(unsigned)count; |
11 | - (void)protocolMethod; |
12 | @end |
13 | |
14 | @interface NSObject |
15 | + (instancetype)testObject; |
16 | @end |
17 | |
18 | @interface NSEnumerator <NSFastEnumeration> |
19 | @end |
20 | |
21 | @interface NSArray : NSObject <NSFastEnumeration> |
22 | - (NSUInteger)count; |
23 | - (NSEnumerator *)objectEnumerator; |
24 | + (NSArray *)arrayWithObjects:(const id [])objects count:(NSUInteger)count; |
25 | @end |
26 | |
27 | @interface NSDictionary : NSObject <NSFastEnumeration> |
28 | - (NSUInteger)count; |
29 | - (id)objectForKey:(id)key; |
30 | + (id)dictionaryWithObjects:(const id [])objects forKeys:(const id /* <NSCopying> */ [])keys count:(NSUInteger)count; |
31 | @end |
32 | |
33 | @interface NSDictionary (SomeCategory) |
34 | - (void)categoryMethodOnNSDictionary; |
35 | - (id) allKeys; |
36 | @end |
37 | |
38 | @interface NSMutableDictionary : NSDictionary |
39 | - (void)setObject:(id)obj forKey:(id)key; |
40 | @end |
41 | |
42 | @interface NSMutableArray : NSArray |
43 | - (void)addObject:(id)obj; |
44 | @end |
45 | |
46 | @interface NSSet : NSObject <NSFastEnumeration> |
47 | - (NSUInteger)count; |
48 | @end |
49 | |
50 | @interface NSPointerArray : NSObject <NSFastEnumeration> |
51 | @end |
52 | |
53 | @interface NSString : NSObject |
54 | @end |
55 | |
56 | void test() { |
57 | id x; |
58 | for (x in [NSArray testObject]) |
59 | clang_analyzer_eval(x != nil); // expected-warning{{TRUE}} |
60 | |
61 | for (x in [NSMutableDictionary testObject]) |
62 | clang_analyzer_eval(x != nil); // expected-warning{{TRUE}} |
63 | |
64 | for (x in [NSSet testObject]) |
65 | clang_analyzer_eval(x != nil); // expected-warning{{TRUE}} |
66 | |
67 | for (x in [[NSArray testObject] objectEnumerator]) |
68 | clang_analyzer_eval(x != nil); // expected-warning{{TRUE}} |
69 | |
70 | for (x in [NSPointerArray testObject]) |
71 | clang_analyzer_eval(x != nil); // expected-warning{{UNKNOWN}} |
72 | } |
73 | |
74 | void testWithVarInFor() { |
75 | for (id x in [NSArray testObject]) |
76 | clang_analyzer_eval(x != nil); // expected-warning{{TRUE}} |
77 | for (id x in [NSPointerArray testObject]) |
78 | clang_analyzer_eval(x != nil); // expected-warning{{UNKNOWN}} |
79 | } |
80 | |
81 | void testNonNil(id a, id b) { |
82 | clang_analyzer_eval(a != nil); // expected-warning{{UNKNOWN}} |
83 | for (id x in a) |
84 | clang_analyzer_eval(a != nil); // expected-warning{{TRUE}} |
85 | |
86 | if (b != nil) |
87 | return; |
88 | for (id x in b) |
89 | *(volatile int *)0 = 1; // no-warning |
90 | clang_analyzer_eval(b != nil); // expected-warning{{FALSE}} |
91 | } |
92 | |
93 | void collectionIsEmpty(NSMutableDictionary *D){ |
94 | if ([D count] == 0) { // Count is zero. |
95 | NSString *s = 0; |
96 | for (NSString *key in D) { |
97 | s = key; // Loop is never entered. |
98 | } |
99 | clang_analyzer_eval(s == 0); //expected-warning{{TRUE}} |
100 | } |
101 | } |
102 | |
103 | void processCollection(NSMutableDictionary *D); |
104 | void collectionIsEmptyCollectionIsModified(NSMutableDictionary *D){ |
105 | if ([D count] == 0) { // Count is zero. |
106 | NSString *s = 0; |
107 | processCollection(D); // However, the collection has changed. |
108 | for (NSString *key in D) { |
109 | s = key; // Loop might be entered. |
110 | } |
111 | clang_analyzer_eval(s == 0); //expected-warning{{FALSE}} //expected-warning{{TRUE}} |
112 | } |
113 | } |
114 | |
115 | int collectionIsEmptyNSSet(NSSet *S){ |
116 | if ([S count] == 2) { // Count is non-zero. |
117 | int tapCounts[2]; |
118 | int i = 0; |
119 | for (NSString *elem in S) { |
120 | tapCounts[i]= 1; // Loop is entered. |
121 | i++; |
122 | } |
123 | return (tapCounts[0]); //no warning |
124 | } |
125 | return 0; |
126 | } |
127 | |
128 | int collectionIsNotEmptyNSArray(NSArray *A) { |
129 | int count = [A count]; |
130 | if (count > 0) { |
131 | int i; |
132 | int j = 0; |
133 | for (NSString *a in A) { |
134 | i = 1; |
135 | j++; |
136 | } |
137 | clang_analyzer_eval(i == 1); // expected-warning {{TRUE}} |
138 | } |
139 | return 0; |
140 | } |
141 | |
142 | void onlySuppressExitAfterZeroIterations(NSMutableDictionary *D) { |
143 | if (D.count > 0) { |
144 | int *x; |
145 | int i = 0; |
146 | for (NSString *key in D) { |
147 | x = 0; |
148 | i++; |
149 | } |
150 | // Test that this is reachable. |
151 | int y = *x; // expected-warning {{Dereference of null pointer}} |
152 | y++; |
153 | } |
154 | } |
155 | |
156 | void onlySuppressLoopExitAfterZeroIterations_WithContinue(NSMutableDictionary *D) { |
157 | if (D.count > 0) { |
158 | int *x; |
159 | int i = 0; |
160 | for (NSString *key in D) { |
161 | x = 0; |
162 | i++; |
163 | continue; |
164 | } |
165 | // Test that this is reachable. |
166 | int y = *x; // expected-warning {{Dereference of null pointer}} |
167 | y++; |
168 | } |
169 | } |
170 | |
171 | int* getPtr(); |
172 | void onlySuppressLoopExitAfterZeroIterations_WithBreak(NSMutableDictionary *D) { |
173 | if (D.count > 0) { |
174 | int *x; |
175 | int i; |
176 | for (NSString *key in D) { |
177 | x = 0; |
178 | break; |
179 | x = getPtr(); |
180 | i++; |
181 | } |
182 | int y = *x; // expected-warning {{Dereference of null pointer}} |
183 | y++; |
184 | } |
185 | } |
186 | |
187 | int consistencyBetweenLoopsWhenCountIsUnconstrained(NSMutableDictionary *D, |
188 | int shouldUseCount) { |
189 | // Test with or without an initial count. |
190 | int count; |
191 | if (shouldUseCount) |
192 | count = [D count]; |
193 | |
194 | int i; |
195 | int j = 0; |
196 | for (NSString *key in D) { |
197 | i = 5; |
198 | j++; |
199 | } |
200 | for (NSString *key in D) { |
201 | return i; // no-warning |
202 | } |
203 | return 0; |
204 | } |
205 | |
206 | int consistencyBetweenLoopsWhenCountIsUnconstrained_dual(NSMutableDictionary *D, |
207 | int shouldUseCount) { |
208 | int count; |
209 | if (shouldUseCount) |
210 | count = [D count]; |
211 | |
212 | int i = 8; |
213 | int j = 1; |
214 | for (NSString *key in D) { |
215 | i = 0; |
216 | j++; |
217 | } |
218 | for (NSString *key in D) { |
219 | i = 5; |
220 | j++; |
221 | } |
222 | return 5/i; |
223 | } |
224 | |
225 | int consistencyCountThenLoop(NSArray *array) { |
226 | if ([array count] == 0) |
227 | return 0; |
228 | |
229 | int x; |
230 | for (id y in array) |
231 | x = 0; |
232 | return x; // no-warning |
233 | } |
234 | |
235 | int consistencyLoopThenCount(NSArray *array) { |
236 | int x; |
237 | for (id y in array) |
238 | x = 0; |
239 | |
240 | if ([array count] == 0) |
241 | return 0; |
242 | |
243 | return x; // no-warning |
244 | } |
245 | |
246 | void nonMutatingMethodsDoNotInvalidateCountDictionary(NSMutableDictionary *dict, |
247 | NSMutableArray *other) { |
248 | if ([dict count]) |
249 | return; |
250 | |
251 | for (id key in dict) |
252 | clang_analyzer_eval(0); // no-warning |
253 | |
254 | (void)[dict objectForKey:@""]; |
255 | |
256 | for (id key in dict) |
257 | clang_analyzer_eval(0); // no-warning |
258 | |
259 | [dict categoryMethodOnNSDictionary]; |
260 | |
261 | for (id key in dict) |
262 | clang_analyzer_eval(0); // no-warning |
263 | |
264 | [dict setObject:@"" forKey:@""]; |
265 | |
266 | for (id key in dict) |
267 | clang_analyzer_eval(0); // expected-warning{{FALSE}} |
268 | |
269 | // Reset. |
270 | if ([dict count]) |
271 | return; |
272 | |
273 | for (id key in dict) |
274 | clang_analyzer_eval(0); // no-warning |
275 | |
276 | [other addObject:dict]; |
277 | |
278 | for (id key in dict) |
279 | clang_analyzer_eval(0); // expected-warning{{FALSE}} |
280 | } |
281 | |
282 | void nonMutatingMethodsDoNotInvalidateCountArray(NSMutableArray *array, |
283 | NSMutableArray *other) { |
284 | if ([array count]) |
285 | return; |
286 | |
287 | for (id key in array) |
288 | clang_analyzer_eval(0); // no-warning |
289 | |
290 | (void)[array objectEnumerator]; |
291 | |
292 | for (id key in array) |
293 | clang_analyzer_eval(0); // no-warning |
294 | |
295 | [array addObject:@""]; |
296 | |
297 | for (id key in array) |
298 | clang_analyzer_eval(0); // expected-warning{{FALSE}} |
299 | |
300 | // Reset. |
301 | if ([array count]) |
302 | return; |
303 | |
304 | for (id key in array) |
305 | clang_analyzer_eval(0); // no-warning |
306 | |
307 | [other addObject:array]; |
308 | |
309 | for (id key in array) |
310 | clang_analyzer_eval(0); // expected-warning{{FALSE}} |
311 | } |
312 | |
313 | void protocolMethods(NSMutableArray *array) { |
314 | if ([array count]) |
315 | return; |
316 | |
317 | for (id key in array) |
318 | clang_analyzer_eval(0); // no-warning |
319 | |
320 | NSArray *immutableArray = array; |
321 | [immutableArray protocolMethod]; |
322 | |
323 | for (id key in array) |
324 | clang_analyzer_eval(0); // no-warning |
325 | |
326 | [array protocolMethod]; |
327 | |
328 | for (id key in array) |
329 | clang_analyzer_eval(0); // expected-warning{{FALSE}} |
330 | } |
331 | |
332 | NSArray *globalArray; |
333 | NSDictionary *globalDictionary; |
334 | void boxedArrayEscape(NSMutableArray *array) { |
335 | if ([array count]) |
336 | return; |
337 | globalArray = @[array]; |
338 | for (id key in array) |
339 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
340 | |
341 | if ([array count]) |
342 | return; |
343 | globalDictionary = @{ @"array" : array }; |
344 | for (id key in array) |
345 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
346 | } |
347 | |
348 | int not_reachable_on_iteration_through_nil() { |
349 | NSDictionary* d = nil; |
350 | for (NSString* s in [d allKeys]) |
351 | clang_analyzer_warnIfReached(); // no-warning |
352 | return 0; |
353 | } |
354 | |