| 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 | |