1 // RUN: %clang_analyze_cc1 \ 2 // RUN: -analyzer-checker=core,debug.ExprInspection \ 3 // RUN: -verify %s \ 4 // RUN: -Wno-undefined-bool-conversion 5 // RUN: %clang_analyze_cc1 \ 6 // RUN: -analyzer-checker=core,debug.ExprInspection,unix.Malloc \ 7 // RUN: -verify %s \ 8 // RUN: -Wno-undefined-bool-conversion 9 // unix.Malloc is necessary to model __builtin_alloca, 10 // which could trigger an "unexpected region" bug in StackAddrEscapeChecker. 11 12 typedef __INTPTR_TYPE__ intptr_t; 13 14 template <typename T> 15 void clang_analyzer_dump(T x); 16 17 using size_t = decltype(sizeof(int)); 18 void * malloc(size_t size); 19 void free(void*); 20 21 const int& g() { 22 int s; 23 return s; // expected-warning{{Address of stack memory associated with local variable 's' returned}} expected-warning{{reference to stack memory associated with local variable 's' returned}} 24 } 25 26 const int& g2() { 27 int s1; 28 int &s2 = s1; // expected-note {{binding reference variable 's2' here}} 29 return s2; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{reference to stack memory associated with local variable 's1' returned}} 30 } 31 32 const int& g3() { 33 int s1; 34 int &s2 = s1; // expected-note {{binding reference variable 's2' here}} 35 int &s3 = s2; // expected-note {{binding reference variable 's3' here}} 36 return s3; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{reference to stack memory associated with local variable 's1' returned}} 37 } 38 39 void g4() { 40 static const int &x = 3; // no warning 41 } 42 43 int get_value(); 44 45 const int &get_reference1() { return get_value(); } // expected-warning{{Address of stack memory associated with temporary object of type 'int' returned}} expected-warning {{returning reference to local temporary}} 46 47 const int &get_reference2() { 48 const int &x = get_value(); // expected-note {{binding reference variable 'x' here}} 49 return x; // expected-warning{{Address of stack memory associated with temporary object of type 'int' lifetime extended by local variable 'x' returned to caller}} expected-warning {{returning reference to local temporary}} 50 } 51 52 const int &get_reference3() { 53 const int &x1 = get_value(); // expected-note {{binding reference variable 'x1' here}} 54 const int &x2 = x1; // expected-note {{binding reference variable 'x2' here}} 55 return x2; // expected-warning{{Address of stack memory associated with temporary object of type 'int' lifetime extended by local variable 'x1' returned to caller}} expected-warning {{returning reference to local temporary}} 56 } 57 58 int global_var; 59 int *f1() { 60 int &y = global_var; 61 return &y; 62 } 63 64 int *f2() { 65 int x1; 66 int &x2 = x1; // expected-note {{binding reference variable 'x2' here}} 67 return &x2; // expected-warning{{Address of stack memory associated with local variable 'x1' returned}} expected-warning {{address of stack memory associated with local variable 'x1' returned}} 68 } 69 70 int *f3() { 71 int x1; 72 int *const &x2 = &x1; // expected-note {{binding reference variable 'x2' here}} 73 return x2; // expected-warning {{address of stack memory associated with local variable 'x1' returned}} expected-warning {{Address of stack memory associated with local variable 'x1' returned to caller}} 74 } 75 76 const int *f4() { 77 const int &x1 = get_value(); // expected-note {{binding reference variable 'x1' here}} 78 const int &x2 = x1; // expected-note {{binding reference variable 'x2' here}} 79 return &x2; // expected-warning{{Address of stack memory associated with temporary object of type 'int' lifetime extended by local variable 'x1' returned to caller}} expected-warning {{returning address of local temporary}} 80 } 81 82 struct S { 83 int x; 84 }; 85 86 int *mf() { 87 S s1; 88 S &s2 = s1; // expected-note {{binding reference variable 's2' here}} 89 int &x = s2.x; // expected-note {{binding reference variable 'x' here}} 90 return &x; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{address of stack memory associated with local variable 's1' returned}} 91 } 92 93 void *lf() { 94 label: 95 void *const &x = &&label; // expected-note {{binding reference variable 'x' here}} 96 return x; // expected-warning {{returning address of label, which is local}} 97 } 98 99 template <typename T> 100 struct TS { 101 int *get(); 102 int *m() { 103 int *&x = get(); 104 return x; 105 } 106 }; 107 108 int* f5() { 109 int& i = i; // expected-warning {{Assigned value is garbage or undefined}} expected-warning{{reference 'i' is not yet bound to a value when used within its own initialization}} 110 return &i; 111 } 112 113 void *radar13226577() { 114 void *p = &p; 115 return p; // expected-warning {{stack memory associated with local variable 'p' returned to caller}} 116 } 117 118 namespace rdar13296133 { 119 class ConvertsToBool { 120 public: 121 operator bool() const { return this; } 122 }; 123 124 class ConvertsToIntptr { 125 public: 126 operator intptr_t() const { return reinterpret_cast<intptr_t>(this); } 127 }; 128 129 class ConvertsToPointer { 130 public: 131 operator const void *() const { return this; } 132 }; 133 134 intptr_t returnAsNonLoc() { 135 ConvertsToIntptr obj; 136 return obj; // expected-warning{{Address of stack memory associated with local variable 'obj' returned to caller}} 137 } 138 139 bool returnAsBool() { 140 ConvertsToBool obj; 141 return obj; // no-warning 142 } 143 144 intptr_t returnAsNonLocViaPointer() { 145 ConvertsToPointer obj; 146 return reinterpret_cast<intptr_t>(static_cast<const void *>(obj)); // expected-warning{{Address of stack memory associated with local variable 'obj' returned to caller}} 147 } 148 149 bool returnAsBoolViaPointer() { 150 ConvertsToPointer obj; 151 return obj; // no-warning 152 } 153 } // namespace rdar13296133 154 155 void write_stack_address_to(char **q) { 156 char local; 157 *q = &local; 158 // expected-warning@-1 {{Address of stack memory associated with local \ 159 variable 'local' is still referred to by the caller variable 'p' upon \ 160 returning to the caller}} 161 } 162 163 void test_stack() { 164 char *p; 165 write_stack_address_to(&p); 166 } 167 168 struct C { 169 ~C() {} // non-trivial class 170 }; 171 172 C make1() { 173 C c; 174 return c; // no-warning 175 } 176 177 void test_copy_elision() { 178 C c1 = make1(); 179 } 180 181 namespace leaking_via_direct_pointer { 182 void* returned_direct_pointer_top() { 183 int local = 42; 184 int* p = &local; 185 return p; // expected-warning{{associated with local variable 'local' returned}} 186 } 187 188 int* returned_direct_pointer_callee() { 189 int local = 42; 190 int* p = &local; 191 return p; // expected-warning{{associated with local variable 'local' returned}} 192 } 193 194 void returned_direct_pointer_caller() { 195 int* loc_ptr = nullptr; 196 loc_ptr = returned_direct_pointer_callee(); 197 (void)loc_ptr; 198 } 199 200 void* global_ptr; 201 202 void global_direct_pointer() { 203 int local = 42; 204 global_ptr = &local; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_ptr'}} 205 } 206 207 void static_direct_pointer_top() { 208 int local = 42; 209 static int* p = &local; 210 (void)p; // expected-warning{{local variable 'local' is still referred to by the static variable 'p'}} 211 } 212 213 void static_direct_pointer_callee() { 214 int local = 42; 215 static int* p = &local; 216 (void)p; // expected-warning{{local variable 'local' is still referred to by the static variable 'p'}} 217 } 218 219 void static_direct_pointer_caller() { 220 static_direct_pointer_callee(); 221 } 222 223 void lambda_to_global_direct_pointer() { 224 auto lambda = [&] { 225 int local = 42; 226 global_ptr = &local; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_ptr'}} 227 }; 228 lambda(); 229 } 230 231 void lambda_to_context_direct_pointer() { 232 int *p = nullptr; 233 auto lambda = [&] { 234 int local = 42; 235 p = &local; // expected-warning{{local variable 'local' is still referred to by the caller variable 'p'}} 236 }; 237 lambda(); 238 (void)p; 239 } 240 241 template<typename Callable> 242 class MyFunction { 243 Callable* fptr; 244 public: 245 MyFunction(Callable* callable) :fptr(callable) {} 246 }; 247 248 void* lambda_to_context_direct_pointer_uncalled() { 249 int *p = nullptr; 250 auto lambda = [&] { 251 int local = 42; 252 p = &local; // no-warning: analyzed only as top-level, ignored explicitly by the checker 253 }; 254 return new MyFunction(&lambda); 255 } 256 257 void lambda_to_context_direct_pointer_lifetime_extended() { 258 int *p = nullptr; 259 auto lambda = [&] { 260 int&& local = 42; 261 p = &local; // expected-warning{{'int' lifetime extended by local variable 'local' is still referred to by the caller variable 'p'}} 262 }; 263 lambda(); 264 (void)p; 265 } 266 267 template<typename Callback> 268 void lambda_param_capture_direct_pointer_callee(Callback& callee) { 269 int local = 42; 270 callee(local); // expected-warning{{'local' is still referred to by the caller variable 'p'}} 271 } 272 273 void lambda_param_capture_direct_pointer_caller() { 274 int* p = nullptr; 275 auto capt = [&p](int& param) { 276 p = ¶m; 277 }; 278 lambda_param_capture_direct_pointer_callee(capt); 279 } 280 } // namespace leaking_via_direct_pointer 281 282 namespace leaking_via_ptr_to_ptr { 283 void** returned_ptr_to_ptr_top() { 284 int local = 42; 285 int* p = &local; 286 void** pp = (void**)&p; 287 return pp; // expected-warning{{associated with local variable 'p' returned}} 288 } 289 290 void** global_pp; 291 292 void global_ptr_local_to_ptr() { 293 int local = 42; 294 int* p = &local; 295 global_pp = (void**)&p; // expected-warning{{local variable 'p' is still referred to by the global variable 'global_pp'}} 296 } 297 298 void global_ptr_to_ptr() { 299 int local = 42; 300 *global_pp = &local; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_pp'}} 301 } 302 303 void *** global_ppp; 304 305 void global_ptr_to_ptr_to_ptr() { 306 int local = 42; 307 **global_ppp = &local; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_ppp'}} 308 } 309 310 void** get_some_pp(); 311 312 void static_ptr_to_ptr() { 313 int local = 42; 314 static void** pp = get_some_pp(); 315 *pp = &local; 316 } // no-warning False Negative, requires relating multiple bindings to cross the invented pointer. 317 318 void param_ptr_to_ptr_top(void** pp) { 319 int local = 42; 320 *pp = &local; // expected-warning{{local variable 'local' is still referred to by the caller variable 'pp'}} 321 } 322 323 void param_ptr_to_ptr_callee(void** pp) { 324 int local = 42; 325 *pp = &local; // expected-warning{{local variable 'local' is still referred to by the caller variable 'p'}} 326 } 327 328 void param_ptr_to_ptr_caller() { 329 void* p = nullptr; 330 param_ptr_to_ptr_callee((void**)&p); 331 } 332 333 void param_ptr_to_ptr_to_ptr_top(void*** ppp) { 334 int local = 42; 335 **ppp = &local; // expected-warning {{local variable 'local' is still referred to by the caller variable 'ppp'}} 336 } 337 338 void param_ptr_to_ptr_to_ptr_callee(void*** ppp) { 339 int local = 42; 340 **ppp = &local; // expected-warning{{local variable 'local' is still referred to by the caller variable 'pp'}} 341 } 342 343 void param_ptr_to_ptr_to_ptr_caller(void** pp) { 344 param_ptr_to_ptr_to_ptr_callee(&pp); 345 } 346 347 void lambda_to_context_ptr_to_ptr(int **pp) { 348 auto lambda = [&] { 349 int local = 42; 350 *pp = &local; // expected-warning{{local variable 'local' is still referred to by the caller variable 'pp'}} 351 }; 352 lambda(); 353 (void)*pp; 354 } 355 356 void param_ptr_to_ptr_fptr(int **pp) { 357 int local = 42; 358 *pp = &local; // expected-warning{{local variable 'local' is still referred to by the caller variable 'p'}} 359 } 360 361 void param_ptr_to_ptr_fptr_caller(void (*fptr)(int**)) { 362 int* p = nullptr; 363 fptr(&p); 364 } 365 366 void param_ptr_to_ptr_caller_caller() { 367 void (*fptr)(int**) = param_ptr_to_ptr_fptr; 368 param_ptr_to_ptr_fptr_caller(fptr); 369 } 370 } // namespace leaking_via_ptr_to_ptr 371 372 namespace leaking_via_ref_to_ptr { 373 void** make_ptr_to_ptr(); 374 void*& global_rtp = *make_ptr_to_ptr(); 375 376 void global_ref_to_ptr() { 377 int local = 42; 378 int* p = &local; 379 global_rtp = p; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_rtp'}} 380 } 381 382 void static_ref_to_ptr() { 383 int local = 42; 384 static void*& p = *make_ptr_to_ptr(); 385 p = &local; 386 (void)p; 387 } // no-warning False Negative, requires relating multiple bindings to cross the invented pointer. 388 389 void param_ref_to_ptr_top(void*& rp) { 390 int local = 42; 391 int* p = &local; 392 rp = p; // expected-warning{{local variable 'local' is still referred to by the caller variable 'rp'}} 393 } 394 395 void param_ref_to_ptr_callee(void*& rp) { 396 int local = 42; 397 int* p = &local; 398 rp = p; // expected-warning{{local variable 'local' is still referred to by the caller variable 'p'}} 399 } 400 401 void param_ref_to_ptr_caller() { 402 void* p = nullptr; 403 param_ref_to_ptr_callee(p); 404 } 405 } // namespace leaking_via_ref_to_ptr 406 407 namespace leaking_via_arr_of_ptr_static_idx { 408 void** returned_arr_of_ptr_top() { 409 int local = 42; 410 int* p = &local; 411 void** arr = new void*[2]; 412 arr[1] = p; 413 return arr; 414 } // no-warning False Negative 415 416 void** returned_arr_of_ptr_callee() { 417 int local = 42; 418 int* p = &local; 419 void** arr = new void*[2]; 420 arr[1] = p; 421 return arr; 422 } // no-warning False Negative 423 424 void returned_arr_of_ptr_caller() { 425 void** arr = returned_arr_of_ptr_callee(); 426 (void)arr[1]; 427 } 428 429 void* global_aop[2]; 430 431 void global_arr_of_ptr() { 432 int local = 42; 433 int* p = &local; 434 global_aop[1] = p; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_aop'}} 435 } 436 437 void static_arr_of_ptr() { 438 int local = 42; 439 static void* arr[2]; 440 arr[1] = &local; 441 (void)arr[1]; // expected-warning{{local variable 'local' is still referred to by the static variable 'arr'}} 442 } 443 444 void param_arr_of_ptr_top(void* arr[2]) { 445 int local = 42; 446 int* p = &local; 447 arr[1] = p; // expected-warning{{local variable 'local' is still referred to by the caller variable 'arr'}} 448 } 449 450 void param_arr_of_ptr_callee(void* arr[2]) { 451 int local = 42; 452 int* p = &local; 453 arr[1] = p; // expected-warning{{local variable 'local' is still referred to by the caller variable 'arrStack'}} 454 } 455 456 void param_arr_of_ptr_caller() { 457 void* arrStack[2]; 458 param_arr_of_ptr_callee(arrStack); 459 (void)arrStack[1]; 460 } 461 } // namespace leaking_via_arr_of_ptr_static_idx 462 463 namespace leaking_via_arr_of_ptr_dynamic_idx { 464 void** returned_arr_of_ptr_top(int idx) { 465 int local = 42; 466 int* p = &local; 467 void** arr = new void*[2]; 468 arr[idx] = p; 469 return arr; 470 } // no-warning False Negative 471 472 void** returned_arr_of_ptr_callee(int idx) { 473 int local = 42; 474 int* p = &local; 475 void** arr = new void*[2]; 476 arr[idx] = p; 477 return arr; 478 } // no-warning False Negative 479 480 void returned_arr_of_ptr_caller(int idx) { 481 void** arr = returned_arr_of_ptr_callee(idx); 482 (void)arr[idx]; 483 } 484 485 void* global_aop[2]; 486 487 void global_arr_of_ptr(int idx) { 488 int local = 42; 489 int* p = &local; 490 global_aop[idx] = p; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_aop'}} 491 } 492 493 void static_arr_of_ptr(int idx) { 494 int local = 42; 495 static void* arr[2]; 496 arr[idx] = &local; 497 (void)arr[idx]; // expected-warning{{local variable 'local' is still referred to by the static variable 'arr'}} 498 } 499 500 void param_arr_of_ptr_top(void* arr[2], int idx) { 501 int local = 42; 502 int* p = &local; 503 arr[idx] = p; // expected-warning{{local variable 'local' is still referred to by the caller variable 'arr'}} 504 } 505 506 void param_arr_of_ptr_callee(void* arr[2], int idx) { 507 int local = 42; 508 int* p = &local; 509 arr[idx] = p; // expected-warning{{local variable 'local' is still referred to by the caller variable 'arrStack'}} 510 } 511 512 void param_arr_of_ptr_caller(int idx) { 513 void* arrStack[2]; 514 param_arr_of_ptr_callee(arrStack, idx); 515 (void)arrStack[idx]; 516 } 517 } // namespace leaking_via_arr_of_ptr_dynamic_idx 518 519 namespace leaking_via_struct_with_ptr { 520 struct S { 521 int* p; 522 }; 523 524 S returned_struct_with_ptr_top() { 525 int local = 42; 526 S s; 527 s.p = &local; 528 return s; 529 } // no-warning False Negative, requires traversing returned LazyCompoundVals 530 531 S returned_struct_with_ptr_callee() { 532 int local = 42; 533 S s; 534 s.p = &local; 535 return s; // expected-warning{{'local' is still referred to by the caller variable 's'}} 536 } 537 538 void returned_struct_with_ptr_caller() { 539 S s = returned_struct_with_ptr_callee(); 540 (void)s.p; 541 } 542 543 S global_s; 544 545 void global_struct_with_ptr() { 546 int local = 42; 547 global_s.p = &local; // expected-warning{{'local' is still referred to by the global variable 'global_s'}} 548 } 549 550 void static_struct_with_ptr() { 551 int local = 42; 552 static S s; 553 s.p = &local; 554 (void)s.p; // expected-warning{{'local' is still referred to by the static variable 's'}} 555 } 556 } // namespace leaking_via_struct_with_ptr 557 558 namespace leaking_via_ref_to_struct_with_ptr { 559 struct S { 560 int* p; 561 }; 562 563 S &global_s = *(new S); 564 565 void global_ref_to_struct_with_ptr() { 566 int local = 42; 567 global_s.p = &local; // expected-warning{{'local' is still referred to by the global variable 'global_s'}} 568 } 569 570 void static_ref_to_struct_with_ptr() { 571 int local = 42; 572 static S &s = *(new S); 573 s.p = &local; 574 (void)s.p; 575 } // no-warning False Negative, requires relating multiple bindings to cross a heap region. 576 577 void param_ref_to_struct_with_ptr_top(S &s) { 578 int local = 42; 579 s.p = &local; // expected-warning{{'local' is still referred to by the caller variable 's'}} 580 } 581 582 void param_ref_to_struct_with_ptr_callee(S &s) { 583 int local = 42; 584 s.p = &local; // expected-warning{{'local' is still referred to by the caller variable 'sStack'}} 585 } 586 587 void param_ref_to_struct_with_ptr_caller() { 588 S sStack; 589 param_ref_to_struct_with_ptr_callee(sStack); 590 } 591 592 template<typename Callable> 593 void lambda_param_capture_callee(Callable& callee) { 594 int local = 42; 595 callee(local); // expected-warning{{'local' is still referred to by the caller variable 'p'}} 596 } 597 598 void lambda_param_capture_caller() { 599 int* p = nullptr; 600 auto capt = [&p](int& param) { 601 p = ¶m; 602 }; 603 lambda_param_capture_callee(capt); 604 } 605 } // namespace leaking_via_ref_to_struct_with_ptr 606 607 namespace leaking_via_ptr_to_struct_with_ptr { 608 struct S { 609 int* p; 610 }; 611 612 S* returned_ptr_to_struct_with_ptr_top() { 613 int local = 42; 614 S* s = new S; 615 s->p = &local; 616 return s; 617 } // no-warning False Negative 618 619 S* returned_ptr_to_struct_with_ptr_callee() { 620 int local = 42; 621 S* s = new S; 622 s->p = &local; 623 return s; 624 } // no-warning False Negative 625 626 void returned_ptr_to_struct_with_ptr_caller() { 627 S* s = returned_ptr_to_struct_with_ptr_callee(); 628 (void)s->p; 629 } 630 631 S* global_s; 632 633 void global_ptr_to_struct_with_ptr() { 634 int local = 42; 635 global_s->p = &local; // expected-warning{{'local' is still referred to by the global variable 'global_s'}} 636 } 637 638 void static_ptr_to_struct_with_ptr_new() { 639 int local = 42; 640 static S* s = new S; 641 s->p = &local; 642 (void)s->p; 643 } // no-warning False Negative, requires relating multiple bindings to cross a heap region. 644 645 S* get_some_s(); 646 647 void static_ptr_to_struct_with_ptr_generated() { 648 int local = 42; 649 static S* s = get_some_s(); 650 s->p = &local; 651 } // no-warning False Negative, requires relating multiple bindings to cross the invented pointer. 652 653 void param_ptr_to_struct_with_ptr_top(S* s) { 654 int local = 42; 655 s->p = &local; // expected-warning{{'local' is still referred to by the caller variable 's'}} 656 } 657 658 void param_ptr_to_struct_with_ptr_callee(S* s) { 659 int local = 42; 660 s->p = &local; // expected-warning{{'local' is still referred to by the caller variable 's'}} 661 } 662 663 void param_ptr_to_struct_with_ptr_caller() { 664 S s; 665 param_ptr_to_struct_with_ptr_callee(&s); 666 (void)s.p; 667 } 668 } // namespace leaking_via_ptr_to_struct_with_ptr 669 670 namespace leaking_via_arr_of_struct_with_ptr { 671 struct S { 672 int* p; 673 }; 674 675 S* returned_ptr_to_struct_with_ptr_top() { 676 int local = 42; 677 S* s = new S[2]; 678 s[1].p = &local; 679 return s; 680 } // no-warning False Negative 681 682 S* returned_ptr_to_struct_with_ptr_callee() { 683 int local = 42; 684 S* s = new S[2]; 685 s[1].p = &local; 686 return s; 687 } // no-warning False Negative 688 689 void returned_ptr_to_struct_with_ptr_caller() { 690 S* s = returned_ptr_to_struct_with_ptr_callee(); 691 (void)s[1].p; 692 } 693 694 S global_s[2]; 695 696 void global_ptr_to_struct_with_ptr() { 697 int local = 42; 698 global_s[1].p = &local; // expected-warning{{'local' is still referred to by the global variable 'global_s'}} 699 } 700 701 void static_ptr_to_struct_with_ptr_new() { 702 int local = 42; 703 static S* s = new S[2]; 704 s[1].p = &local; 705 (void)s[1].p; 706 } 707 708 S* get_some_s(); 709 710 void static_ptr_to_struct_with_ptr_generated() { 711 int local = 42; 712 static S* s = get_some_s(); 713 s[1].p = &local; 714 } // no-warning False Negative, requires relating multiple bindings to cross the invented pointer. 715 716 void param_ptr_to_struct_with_ptr_top(S s[2]) { 717 int local = 42; 718 s[1].p = &local; // expected-warning{{'local' is still referred to by the caller variable 's'}} 719 } 720 721 void param_ptr_to_struct_with_ptr_callee(S s[2]) { 722 int local = 42; 723 s[1].p = &local; // expected-warning{{'local' is still referred to by the caller variable 's'}} 724 } 725 726 void param_ptr_to_struct_with_ptr_caller() { 727 S s[2]; 728 param_ptr_to_struct_with_ptr_callee(s); 729 (void)s[1].p; 730 } 731 } // namespace leaking_via_arr_of_struct_with_ptr 732 733 namespace leaking_via_nested_and_indirect { 734 struct NestedAndTransitive { 735 int** p; 736 NestedAndTransitive* next[3]; 737 }; 738 739 NestedAndTransitive global_nat; 740 741 void global_nested_and_transitive() { 742 int local = 42; 743 *global_nat.next[2]->next[1]->p = &local; // expected-warning{{'local' is still referred to by the global variable 'global_nat'}} 744 } 745 746 void param_nested_and_transitive_top(NestedAndTransitive* nat) { 747 int local = 42; 748 *nat->next[2]->next[1]->p = &local; // expected-warning{{'local' is still referred to by the caller variable 'nat'}} 749 } 750 751 void param_nested_and_transitive_callee(NestedAndTransitive* nat) { 752 int local = 42; 753 *nat->next[2]->next[1]->p = &local; // expected-warning{{'local' is still referred to by the caller variable 'natCaller'}} 754 } 755 756 void param_nested_and_transitive_caller(NestedAndTransitive natCaller) { 757 param_nested_and_transitive_callee(&natCaller); 758 } 759 760 } // namespace leaking_via_nested_and_indirect 761 762 namespace leaking_as_member { 763 class CRef { 764 int& ref; // expected-note{{reference member declared here}} 765 CRef(int x) : ref(x) {} 766 // expected-warning@-1 {{binding reference member 'ref' to stack allocated parameter 'x'}} 767 }; 768 769 class CPtr { 770 int* ptr; 771 void memFun(int x) { 772 ptr = &x; 773 } 774 }; 775 } // namespace leaking_as_member 776 777 namespace origin_region_limitation { 778 void leaker(int ***leakerArg) { 779 int local; 780 clang_analyzer_dump(*leakerArg); // expected-warning{{&SymRegion{reg_$0<int ** arg>}}} 781 // Incorrect message: 'arg', after it is reinitialized with value returned by 'tweak' 782 // is no longer relevant. 783 // The message must refer to 'original_arg' instead, but there is no easy way to 784 // connect the SymRegion stored in 'original_arg' and 'original_arg' as variable. 785 **leakerArg = &local; // expected-warning{{ 'local' is still referred to by the caller variable 'arg'}} 786 } 787 788 int **tweak(); 789 790 void foo(int **arg) { 791 int **original_arg = arg; 792 arg = tweak(); 793 leaker(&original_arg); 794 } 795 } // namespace origin_region_limitation 796 797 namespace leaking_via_indirect_global_invalidated { 798 void** global_pp; 799 void opaque(); 800 void global_ptr_to_ptr() { 801 int local = 42; 802 *global_pp = &local; 803 opaque(); 804 *global_pp = nullptr; 805 } 806 } // namespace leaking_via_indirect_global_invalidated 807 808 namespace not_leaking_via_simple_ptr { 809 void simple_ptr(const char *p) { 810 char tmp; 811 p = &tmp; // no-warning 812 } 813 814 void ref_ptr(const char *&p) { 815 char tmp; 816 p = &tmp; // expected-warning{{variable 'tmp' is still referred to by the caller variable 'p'}} 817 } 818 819 struct S { 820 const char *p; 821 }; 822 823 void struct_ptr(S s) { 824 char tmp; 825 s.p = &tmp; // no-warning 826 } 827 828 void array(const char arr[2]) { 829 char tmp; 830 arr = &tmp; // no-warning 831 } 832 833 extern void copy(char *output, const char *input, unsigned size); 834 extern bool foo(const char *input); 835 extern void bar(char *output, unsigned count); 836 extern bool baz(char *output, const char *input); 837 838 void repo(const char *input, char *output) { 839 char temp[64]; 840 copy(temp, input, sizeof(temp)); 841 842 char result[64]; 843 input = temp; 844 if (foo(temp)) { 845 bar(result, sizeof(result)); 846 input = result; 847 } 848 if (!baz(output, input)) { 849 copy(output, input, sizeof(result)); 850 } 851 } 852 } // namespace not_leaking_via_simple_ptr 853 854 namespace early_reclaim_dead_limitation { 855 void foo(); 856 void top(char **p) { 857 char local; 858 *p = &local; 859 foo(); // no-warning FIXME: p binding is reclaimed before the function end 860 } 861 } // namespace early_reclaim_dead_limitation 862 863 namespace alloca_region_pointer { 864 void callee(char **pptr) { 865 char local; 866 *pptr = &local; 867 } // no crash 868 869 void top_alloca_no_crash_fn() { 870 char **pptr = (char**)__builtin_alloca(sizeof(char*)); 871 callee(pptr); 872 } 873 874 void top_malloc_no_crash_fn() { 875 char **pptr = (char**)malloc(sizeof(char*)); 876 callee(pptr); 877 free(pptr); 878 } 879 } // namespace alloca_region_pointer 880