1 | // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,deadcode.DeadStores,osx.cocoa.RetainCount,unix.Malloc,unix.MismatchedDeallocator -analyzer-output=plist -o %t -w %s |
2 | // RUN: cat %t | %diff_plist %S/Inputs/expected-plists/edges-new.mm.plist - |
3 | |
4 | //===----------------------------------------------------------------------===// |
5 | // Forward declarations (from headers). |
6 | //===----------------------------------------------------------------------===// |
7 | |
8 | typedef const struct __CFNumber * CFNumberRef; |
9 | typedef const struct __CFAllocator * CFAllocatorRef; |
10 | extern const CFAllocatorRef kCFAllocatorDefault; |
11 | typedef signed long CFIndex; |
12 | enum { |
13 | kCFNumberSInt8Type = 1, |
14 | kCFNumberSInt16Type = 2, |
15 | kCFNumberSInt32Type = 3, |
16 | kCFNumberSInt64Type = 4, |
17 | kCFNumberFloat32Type = 5, |
18 | kCFNumberFloat64Type = 6, |
19 | kCFNumberCharType = 7, |
20 | kCFNumberShortType = 8, |
21 | kCFNumberIntType = 9, |
22 | kCFNumberLongType = 10, |
23 | kCFNumberLongLongType = 11, |
24 | kCFNumberFloatType = 12, |
25 | kCFNumberDoubleType = 13, |
26 | kCFNumberCFIndexType = 14, |
27 | kCFNumberNSIntegerType = 15, |
28 | kCFNumberCGFloatType = 16, |
29 | kCFNumberMaxType = 16 |
30 | }; |
31 | typedef CFIndex CFNumberType; |
32 | CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr); |
33 | |
34 | #define nil ((id)0) |
35 | |
36 | __attribute__((objc_root_class)) |
37 | @interface NSObject |
38 | + (instancetype) alloc; |
39 | - (instancetype) init; |
40 | - (instancetype)retain; |
41 | - (void)release; |
42 | @end |
43 | |
44 | @interface NSArray : NSObject |
45 | @end |
46 | |
47 | //===----------------------------------------------------------------------===// |
48 | // Basic tracking of null and tests for null. |
49 | //===----------------------------------------------------------------------===// |
50 | |
51 | void test_null_init(void) { |
52 | int *p = 0; |
53 | *p = 0xDEADBEEF; |
54 | } |
55 | |
56 | void test_null_assign(void) { |
57 | int *p; |
58 | p = 0; |
59 | *p = 0xDEADBEEF; |
60 | } |
61 | |
62 | void test_null_assign_transitive(void) { |
63 | int *p; |
64 | p = 0; |
65 | int *q = p; |
66 | *q = 0xDEADBEEF; |
67 | } |
68 | |
69 | void test_null_cond(int *p) { |
70 | if (!p) { |
71 | *p = 0xDEADBEEF; |
72 | } |
73 | } |
74 | |
75 | void test_null_cond_transitive(int *q) { |
76 | if (!q) { |
77 | int *p = q; |
78 | *p = 0xDEADBEEF; |
79 | } |
80 | } |
81 | |
82 | void test_null_field(void) { |
83 | struct s { int *p; } x; |
84 | x.p = 0; |
85 | *(x.p) = 0xDEADBEEF; |
86 | } |
87 | |
88 | void test_assumptions(int a, int b) |
89 | { |
90 | if (a == 0) { |
91 | return; |
92 | } |
93 | if (b != 0) { |
94 | return; |
95 | } |
96 | int *p = 0; |
97 | *p = 0xDEADBEEF; |
98 | } |
99 | |
100 | int *bar_cond_assign(); |
101 | int test_cond_assign() { |
102 | int *p; |
103 | if ((p = bar_cond_assign())) |
104 | return 1; |
105 | return *p; |
106 | } |
107 | |
108 | //===----------------------------------------------------------------------===// |
109 | // Diagnostics for leaks and "noreturn" paths. |
110 | //===----------------------------------------------------------------------===// |
111 | |
112 | |
113 | // <rdar://problem/8331641> leak reports should not show paths that end with exit() (but ones that don't end with exit()) |
114 | |
115 | void stop() __attribute__((noreturn)); |
116 | |
117 | void rdar8331641(int x) { |
118 | signed z = 1; |
119 | CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}} |
120 | if (x) |
121 | stop(); |
122 | (void) value; |
123 | } |
124 | |
125 | //===----------------------------------------------------------------------===// |
126 | // Test loops and control-flow. |
127 | //===----------------------------------------------------------------------===// |
128 | |
129 | void test_objc_fast_enumeration(NSArray *x) { |
130 | id obj; |
131 | for (obj in x) |
132 | *(volatile int *)0 = 0; |
133 | } |
134 | |
135 | void test_objc_fast_enumeration_2(id arr) { |
136 | int x; |
137 | for (id obj in arr) { |
138 | x = 1; |
139 | } |
140 | x += 1; |
141 | } |
142 | |
143 | // Test that loops are documented in the path. |
144 | void rdar12280665() { |
145 | for (unsigned i = 0; i < 2; ++i) { |
146 | if (i == 1) { |
147 | int *p = 0; |
148 | *p = 0xDEADBEEF; // expected-warning {{dereference}} |
149 | } |
150 | } |
151 | } |
152 | |
153 | // Test for a "loop executed 0 times" diagnostic. |
154 | int *radar12322528_bar(); |
155 | |
156 | void radar12322528_for(int x) { |
157 | int z; |
158 | int *p = 0; |
159 | for (unsigned i = 0; i < x; ++i) { |
160 | p = radar12322528_bar(); |
161 | } |
162 | *p = 0xDEADBEEF; |
163 | } |
164 | |
165 | void radar12322528_while(int x) { |
166 | int *p = 0; |
167 | unsigned i = 0; |
168 | for ( ; i < x ; ) { |
169 | ++i; |
170 | p = radar12322528_bar(); |
171 | } |
172 | *p = 0xDEADBEEF; |
173 | } |
174 | |
175 | void radar12322528_foo_2() { |
176 | int *p = 0; |
177 | for (unsigned i = 0; i < 2; ++i) { |
178 | if (i == 0) |
179 | continue; |
180 | |
181 | if (i == 1) { |
182 | |
183 | break; |
184 | } |
185 | } |
186 | *p = 0xDEADBEEF; |
187 | } |
188 | |
189 | void test_loop_diagnostics() { |
190 | int *p = 0; |
191 | for (int i = 0; i < 2; ++i) { p = 0; } |
192 | *p = 1; |
193 | } |
194 | |
195 | void test_loop_diagnostics_2() { |
196 | int *p = 0; |
197 | |
198 | for (int i = 0; i < 2; ) { |
199 | |
200 | ++i; |
201 | |
202 | p = 0; |
203 | |
204 | } |
205 | |
206 | *p = 1; |
207 | } |
208 | |
209 | void test_loop_diagnostics_3() { |
210 | int z; |
211 | int y; |
212 | int k; |
213 | int *p = 0; |
214 | int i = 0; |
215 | while (i < 2) { |
216 | ++i; |
217 | p = 0; |
218 | } |
219 | * p = 1; |
220 | } |
221 | |
222 | void test_do_while() { |
223 | unsigned i = 0; |
224 | |
225 | int *p; |
226 | |
227 | do { |
228 | |
229 | ++i; |
230 | p = 0; |
231 | |
232 | } while (i< 2); |
233 | |
234 | *p = 0xDEADBEEF; |
235 | } |
236 | |
237 | |
238 | void test_logical_and() { |
239 | int *p = 0; |
240 | if (1 && 2) { |
241 | *p = 0xDEADBEEF; |
242 | } |
243 | } |
244 | |
245 | void test_logical_or() { |
246 | int *p = 0; |
247 | if (0 || 2) { |
248 | *p = 0xDEADBEEF; |
249 | } |
250 | } |
251 | |
252 | void test_logical_or_call() { |
253 | extern int call(int); |
254 | int *p = 0; |
255 | if (call(0 || 2)) { |
256 | *p = 0xDEADBEEF; |
257 | } |
258 | } |
259 | |
260 | void test_nested_logicals(int coin) { |
261 | int *p = 0; |
262 | |
263 | if ((0 || 0) || coin) { |
264 | *p = 0xDEADBEEF; |
265 | } |
266 | |
267 | if (0 || (0 || !coin)) { |
268 | *p = 0xDEADBEEF; |
269 | } |
270 | } |
271 | |
272 | void test_deeply_nested_logicals() { |
273 | extern int call(int); |
274 | int *p = 0; |
275 | |
276 | if ((0 || (5 && 0)) ? 0 : ((0 || 4) ? call(1 && 5) : 0)) { |
277 | |
278 | *p = 0xDEADBEEF; |
279 | } |
280 | } |
281 | |
282 | void test_ternary(int x, int *y) { |
283 | int z = x ? 0 : 1; |
284 | |
285 | int *p = z ? y : 0; |
286 | |
287 | *p = 0xDEADBEEF; |
288 | } |
289 | |
290 | void testUseless(int *y) { |
291 | if (y) { |
292 | |
293 | } |
294 | if (y) { |
295 | |
296 | } |
297 | int *p = 0; |
298 | *p = 0xDEADBEEF; |
299 | } |
300 | |
301 | //===----------------------------------------------------------------------===// |
302 | // Interprocedural tests. |
303 | //===----------------------------------------------------------------------===// |
304 | |
305 | @interface IPA_Foo |
306 | - (int *) returnsPointer; |
307 | @end |
308 | |
309 | int testFoo(IPA_Foo *x) { |
310 | if (x) |
311 | return 1; |
312 | return *[x returnsPointer]; |
313 | } |
314 | |
315 | @interface IPA_X : NSObject |
316 | - (int *)getPointer; |
317 | @end |
318 | |
319 | void test1_IPA_X() { |
320 | IPA_X *x = nil; |
321 | *[x getPointer] = 1; // here |
322 | } |
323 | |
324 | |
325 | @interface IPA_Y : NSObject |
326 | - (IPA_Y *)opaque; |
327 | - (IPA_X *)getX; |
328 | @end |
329 | |
330 | @implementation IPA_Y |
331 | - (IPA_X *)getX { |
332 | return nil; |
333 | } |
334 | @end |
335 | |
336 | void test_IPA_Y(IPA_Y *y) { |
337 | if (y) |
338 | return; |
339 | |
340 | IPA_X *x = [[y opaque] getX]; // here |
341 | *[x getPointer] = 1; |
342 | } |
343 | |
344 | // From diagnostics/report-issues-within-main-file.cpp: |
345 | void causeDivByZeroInMain(int in) { |
346 | int m = 0; |
347 | m = in/m; |
348 | m++; |
349 | } |
350 | |
351 | void mainPlusMain() { |
352 | int i = 0; |
353 | i++; |
354 | causeDivByZeroInMain(i); |
355 | i++; |
356 | } |
357 | |
358 | // From inlining/path-notes.c: |
359 | int *getZero() { |
360 | int *p = 0; |
361 | return p; |
362 | } |
363 | |
364 | void usePointer(int *p) { |
365 | *p = 1; |
366 | } |
367 | |
368 | void testUseOfNullPointer() { |
369 | // Test the case where an argument expression is itself a call. |
370 | usePointer(getZero()); |
371 | } |
372 | |
373 | |
374 | //===----------------------------------------------------------------------===// |
375 | // Misc. tests. |
376 | //===----------------------------------------------------------------------===// |
377 | |
378 | // Test for tracking null state of ivars. |
379 | @interface RDar12114812 : NSObject { char *p; } |
380 | @end |
381 | @implementation RDar12114812 |
382 | - (void)test { |
383 | p = 0; |
384 | *p = 1; |
385 | } |
386 | @end |
387 | |
388 | // Test diagnostics for initialization of structs. |
389 | void RDar13295437_f(void *i) __attribute__((__nonnull__)); |
390 | struct RDar13295437_S { int *i; }; |
391 | int RDar13295437() { |
392 | struct RDar13295437_S s = {0}; |
393 | struct RDar13295437_S *sp = &s; |
394 | RDar13295437_f(sp->i); |
395 | return 0; |
396 | } |
397 | |
398 | |
399 | void testCast(int coin) { |
400 | if (coin) { |
401 | (void)(1+2); |
402 | (void)(2+3); |
403 | (void)(3+4); |
404 | *(volatile int *)0 = 1; |
405 | } |
406 | } |
407 | |
408 | // The following previously crashed when generating extensive diagnostics. |
409 | // <rdar://problem/10797980> |
410 | @interface RDar10797980_help |
411 | @property (readonly) int x; |
412 | @end |
413 | @interface RDar10797980 : NSObject { |
414 | RDar10797980_help *y; |
415 | } |
416 | - (void) test; |
417 | @end |
418 | @implementation RDar10797980 |
419 | - (void) test { |
420 | if (y.x == 1) { |
421 | int *p = 0; |
422 | *p = 0xDEADBEEF; // expected-warning {{deference}} |
423 | } |
424 | } |
425 | |
426 | // The original source for the above Radar contains another problem: |
427 | // if the end-of-path node is an implicit statement, it may not have a valid |
428 | // source location. <rdar://problem/12446776> |
429 | - (void)test2 { |
430 | if (bar_cond_assign()) { |
431 | id foo = [[RDar10797980 alloc] init]; // leak |
432 | } |
433 | (void)y; // first statement after the 'if' is an implicit 'self' DeclRefExpr |
434 | } |
435 | |
436 | @end |
437 | |
438 | void variousLoops(id input) { |
439 | extern int a(); |
440 | extern int b(); |
441 | extern int c(); |
442 | |
443 | extern int work(); |
444 | |
445 | while (a()) { |
446 | work(); |
447 | work(); |
448 | work(); |
449 | *(volatile int *)0 = 1; |
450 | } |
451 | |
452 | int first = 1; |
453 | do { |
454 | work(); |
455 | work(); |
456 | work(); |
457 | if (!first) |
458 | *(volatile int *)0 = 1; |
459 | first = 0; |
460 | } while (a()); |
461 | |
462 | for (int i = 0; i != b(); ++i) { |
463 | work(); |
464 | *(volatile int *)0 = 1; |
465 | } |
466 | |
467 | for (id x in input) { |
468 | work(); |
469 | work(); |
470 | work(); |
471 | (void)x; |
472 | *(volatile int *)0 = 1; |
473 | } |
474 | |
475 | int z[] = {1,2}; |
476 | for (int y : z) { |
477 | work(); |
478 | work(); |
479 | work(); |
480 | (void)y; |
481 | } |
482 | |
483 | int empty[] = {}; |
484 | for (int y : empty) { |
485 | work(); |
486 | work(); |
487 | work(); |
488 | (void)y; |
489 | } |
490 | |
491 | for (int i = 0; ; ++i) { |
492 | work(); |
493 | if (i == b()) |
494 | break; |
495 | } |
496 | |
497 | int i; |
498 | for (i = 0; i != b(); ++i) { |
499 | work(); |
500 | *(volatile int *)0 = 1; |
501 | } |
502 | |
503 | for (; i != b(); ++i) { |
504 | work(); |
505 | *(volatile int *)0 = 1; |
506 | } |
507 | |
508 | for (; i != b(); ) { |
509 | work(); |
510 | if (i == b()) |
511 | break; |
512 | *(volatile int *)0 = 1; |
513 | } |
514 | |
515 | for (;;) { |
516 | work(); |
517 | if (i == b()) |
518 | break; |
519 | } |
520 | |
521 | *(volatile int *)0 = 1; |
522 | } |
523 | |
524 | void *malloc(unsigned long); |
525 | void *realloc(void *, unsigned long); |
526 | void free(void *); |
527 | |
528 | void reallocDiagnostics() { |
529 | char * buf = (char*)malloc(100); |
530 | char * tmp; |
531 | tmp = (char*)realloc(buf, 0x1000000); |
532 | if (!tmp) { |
533 | return;// expected-warning {{leak}} |
534 | } |
535 | buf = tmp; |
536 | free(buf); |
537 | } |
538 | |
539 | template <typename T> |
540 | class unique_ptr { |
541 | T *ptr; |
542 | public: |
543 | explicit unique_ptr(T *p) : ptr(p) {} |
544 | ~unique_ptr() { delete ptr; } |
545 | }; |
546 | |
547 | void test() { |
548 | int i = 0; |
549 | ++i; |
550 | |
551 | unique_ptr<int> p(new int[4]); |
552 | { |
553 | ++i; |
554 | } |
555 | } |
556 | |
557 | void longLines() { |
558 | id foo = [[NSObject alloc] init]; // leak |
559 | id bar = |
560 | [foo retain]; |
561 | [bar release]; |
562 | id baz = [foo |
563 | retain]; |
564 | [baz release]; |
565 | // This next line is intentionally longer than 80 characters. |
566 | id garply = [foo retain]; |
567 | [garply release]; |
568 | } |
569 | |
570 | #define POINTER(T) T* |
571 | POINTER(void) testMacroInFunctionDecl(void *q) { |
572 | int *p = 0; |
573 | *p = 1; |
574 | return q; |
575 | } |
576 | |
577 | namespace rdar14960554 { |
578 | class Foo { |
579 | int a = 1; |
580 | int b = 2; |
581 | int c = 3; |
582 | |
583 | Foo() : |
584 | a(0), |
585 | c(3) { |
586 | // Check that we don't have an edge to the in-class initializer for 'b'. |
587 | if (b == 2) |
588 | *(volatile int *)0 = 1; |
589 | } |
590 | }; |
591 | } |
592 | |
593 | |