1130 lines · cpp
1// RUN: %clang_analyze_cc1 \2// RUN: -analyzer-checker=core,debug.ExprInspection \3// RUN: -verify %s \4// RUN: -Wno-undefined-bool-conversion5// RUN: %clang_analyze_cc1 \6// RUN: -analyzer-checker=core,debug.ExprInspection,unix.Malloc \7// RUN: -verify %s \8// RUN: -Wno-undefined-bool-conversion9// unix.Malloc is necessary to model __builtin_alloca,10// which could trigger an "unexpected region" bug in StackAddrEscapeChecker.11 12typedef __INTPTR_TYPE__ intptr_t;13 14template <typename T>15void clang_analyzer_dump(T x);16 17using size_t = decltype(sizeof(int));18void * malloc(size_t size);19void free(void*);20 21const 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 26const 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 32const 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 39void g4() {40 static const int &x = 3; // no warning41}42 43int get_value();44 45const 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 47const 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 52const 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 58int global_var;59int *f1() {60 int &y = global_var;61 return &y;62}63 64int *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 70int *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 76const 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 82struct S {83 int x;84};85 86int *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 93int *return_assign_expr_leak() {94 int x = 1;95 int *y;96 return y = &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned}}97}98 99// Additional diagnostic from -Wreturn-stack-address in the simple case?100int *return_comma_separated_expressions_leak() {101 int x = 1;102 return (x=14), &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned to caller}} expected-warning{{address of stack memory associated with local variable 'x' returned}}103}104 105void *lf() {106 label:107 void *const &x = &&label; // expected-note {{binding reference variable 'x' here}}108 return x; // expected-warning {{returning address of label, which is local}}109}110 111template <typename T>112struct TS {113 int *get();114 int *m() {115 int *&x = get();116 return x;117 }118};119 120int* f5() {121 int& i = i; // expected-warning {{Assigned value is uninitialized}} expected-warning{{reference 'i' is not yet bound to a value when used within its own initialization}}122 return &i;123}124 125void *radar13226577() {126 void *p = &p;127 return p; // expected-warning {{stack memory associated with local variable 'p' returned to caller}}128}129 130namespace rdar13296133 {131 class ConvertsToBool {132 public:133 operator bool() const { return this; }134 };135 136 class ConvertsToIntptr {137 public:138 operator intptr_t() const { return reinterpret_cast<intptr_t>(this); }139 };140 141 class ConvertsToPointer {142 public:143 operator const void *() const { return this; }144 };145 146 intptr_t returnAsNonLoc() {147 ConvertsToIntptr obj;148 return obj; // expected-warning{{Address of stack memory associated with local variable 'obj' returned to caller}}149 }150 151 bool returnAsBool() {152 ConvertsToBool obj;153 return obj; // no-warning154 }155 156 intptr_t returnAsNonLocViaPointer() {157 ConvertsToPointer obj;158 return reinterpret_cast<intptr_t>(static_cast<const void *>(obj)); // expected-warning{{Address of stack memory associated with local variable 'obj' returned to caller}}159 }160 161 bool returnAsBoolViaPointer() {162 ConvertsToPointer obj;163 return obj; // no-warning164 }165} // namespace rdar13296133166 167void* ret_cpp_static_cast(short x) {168 return static_cast<void*>(&x); // expected-warning {{Address of stack memory associated with local variable 'x' returned to caller}} expected-warning {{address of stack memory}}169}170 171int* ret_cpp_reinterpret_cast(double x) {172 return reinterpret_cast<int*>(&x); // expected-warning {{Address of stack memory associated with local variable 'x' returned to caller}} expected-warning {{address of stack me}}173}174 175int* ret_cpp_const_cast(const int x) {176 return const_cast<int*>(&x); // expected-warning {{Address of stack memory associated with local variable 'x' returned to caller}} expected-warning {{address of stack memory}}177}178 179void write_stack_address_to(char **q) {180 char local;181 *q = &local;182 // expected-warning@-1 {{Address of stack memory associated with local \183variable 'local' is still referred to by the caller variable 'p' upon \184returning to the caller}}185}186 187void test_stack() {188 char *p;189 write_stack_address_to(&p);190}191 192struct C {193 ~C() {} // non-trivial class194};195 196C make1() {197 C c;198 return c; // no-warning199}200 201void test_copy_elision() {202 C c1 = make1();203}204 205C&& return_bind_rvalue_reference_to_temporary() {206 return C(); // expected-warning{{Address of stack memory associated with temporary object of type 'C' returned to caller}}207 // expected-warning@-1{{returning reference to local temporary object}} -Wreturn-stack-address208}209 210namespace leaking_via_direct_pointer {211void* returned_direct_pointer_top() {212 int local = 42;213 int* p = &local;214 return p; // expected-warning{{associated with local variable 'local' returned}}215}216 217int* returned_direct_pointer_callee() {218 int local = 42;219 int* p = &local;220 return p; // expected-warning{{associated with local variable 'local' returned}}221}222 223void returned_direct_pointer_caller() {224 int* loc_ptr = nullptr;225 loc_ptr = returned_direct_pointer_callee();226 (void)loc_ptr;227}228 229void* global_ptr;230 231void global_direct_pointer() {232 int local = 42;233 global_ptr = &local; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_ptr'}}234}235 236void static_direct_pointer_top() {237 int local = 42;238 static int* p = &local;239 (void)p; // expected-warning{{local variable 'local' is still referred to by the static variable 'p'}}240}241 242void static_direct_pointer_callee() {243 int local = 42;244 static int* p = &local;245 (void)p; // expected-warning{{local variable 'local' is still referred to by the static variable 'p'}}246}247 248void static_direct_pointer_caller() {249 static_direct_pointer_callee();250}251 252void lambda_to_global_direct_pointer() {253 auto lambda = [&] {254 int local = 42;255 global_ptr = &local; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_ptr'}}256 };257 lambda();258}259 260void lambda_to_context_direct_pointer() {261 int *p = nullptr;262 auto lambda = [&] {263 int local = 42;264 p = &local; // expected-warning{{local variable 'local' is still referred to by the caller variable 'p'}}265 };266 lambda();267 (void)p;268}269 270template<typename Callable>271class MyFunction {272 Callable* fptr;273 public:274 MyFunction(Callable* callable) :fptr(callable) {}275};276 277void* lambda_to_context_direct_pointer_uncalled() {278 int *p = nullptr;279 auto lambda = [&] {280 int local = 42;281 p = &local; // no-warning: analyzed only as top-level, ignored explicitly by the checker282 };283 return new MyFunction(&lambda); // expected-warning{{Address of stack memory associated with local variable 'lambda' returned to caller}}284}285 286void lambda_to_context_direct_pointer_lifetime_extended() {287 int *p = nullptr;288 auto lambda = [&] {289 int&& local = 42;290 p = &local; // expected-warning{{'int' lifetime extended by local variable 'local' is still referred to by the caller variable 'p'}}291 };292 lambda();293 (void)p;294}295 296template<typename Callback>297void lambda_param_capture_direct_pointer_callee(Callback& callee) {298 int local = 42;299 callee(local); // expected-warning{{'local' is still referred to by the caller variable 'p'}}300}301 302void lambda_param_capture_direct_pointer_caller() {303 int* p = nullptr;304 auto capt = [&p](int& param) {305 p = ¶m;306 };307 lambda_param_capture_direct_pointer_callee(capt);308}309} // namespace leaking_via_direct_pointer310 311namespace leaking_via_ptr_to_ptr {312void** returned_ptr_to_ptr_top() {313 int local = 42;314 int* p = &local;315 void** pp = (void**)&p;316 return pp; // expected-warning{{associated with local variable 'p' returned}}317}318 319void** global_pp;320 321void global_ptr_local_to_ptr() {322 int local = 42;323 int* p = &local;324 global_pp = (void**)&p; // expected-warning{{local variable 'p' is still referred to by the global variable 'global_pp'}}325}326 327void global_ptr_to_ptr() {328 int local = 42;329 *global_pp = &local; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_pp'}}330}331 332void *** global_ppp;333 334void global_ptr_to_ptr_to_ptr() {335 int local = 42;336 **global_ppp = &local; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_ppp'}}337}338 339void** get_some_pp();340 341void static_ptr_to_ptr() {342 int local = 42;343 static void** pp = get_some_pp();344 *pp = &local;345} // no-warning False Negative, requires relating multiple bindings to cross the invented pointer.346 347void param_ptr_to_ptr_top(void** pp) {348 int local = 42;349 *pp = &local; // expected-warning{{local variable 'local' is still referred to by the caller variable 'pp'}}350}351 352void param_ptr_to_ptr_callee(void** pp) {353 int local = 42;354 *pp = &local; // expected-warning{{local variable 'local' is still referred to by the caller variable 'p'}}355}356 357void param_ptr_to_ptr_caller() {358 void* p = nullptr;359 param_ptr_to_ptr_callee((void**)&p);360}361 362void param_ptr_to_ptr_to_ptr_top(void*** ppp) {363 int local = 42;364 **ppp = &local; // expected-warning {{local variable 'local' is still referred to by the caller variable 'ppp'}}365}366 367void param_ptr_to_ptr_to_ptr_callee(void*** ppp) {368 int local = 42;369 **ppp = &local; // expected-warning{{local variable 'local' is still referred to by the caller variable 'pp'}}370}371 372void ***param_ptr_to_ptr_to_ptr_return(void ***ppp) {373 int local = 0;374 **ppp = &local;375 return ppp;376 // expected-warning@-1 {{Address of stack memory associated with local variable 'local' is still referred to by the caller variable 'ppp' upon returning to the caller. This will be a dangling reference}}377}378 379void param_ptr_to_ptr_to_ptr_caller(void** pp) {380 param_ptr_to_ptr_to_ptr_callee(&pp);381}382 383void lambda_to_context_ptr_to_ptr(int **pp) {384 auto lambda = [&] {385 int local = 42;386 *pp = &local; // expected-warning{{local variable 'local' is still referred to by the caller variable 'pp'}}387 };388 lambda();389 (void)*pp;390}391 392void param_ptr_to_ptr_fptr(int **pp) {393 int local = 42;394 *pp = &local; // expected-warning{{local variable 'local' is still referred to by the caller variable 'p'}}395}396 397void param_ptr_to_ptr_fptr_caller(void (*fptr)(int**)) {398 int* p = nullptr;399 fptr(&p);400}401 402void param_ptr_to_ptr_caller_caller() {403 void (*fptr)(int**) = param_ptr_to_ptr_fptr;404 param_ptr_to_ptr_fptr_caller(fptr);405}406} // namespace leaking_via_ptr_to_ptr407 408namespace leaking_via_ref_to_ptr {409void** make_ptr_to_ptr();410void*& global_rtp = *make_ptr_to_ptr();411 412void global_ref_to_ptr() {413 int local = 42;414 int* p = &local;415 global_rtp = p; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_rtp'}}416}417 418void static_ref_to_ptr() {419 int local = 42;420 static void*& p = *make_ptr_to_ptr();421 p = &local;422 (void)p;423} // no-warning False Negative, requires relating multiple bindings to cross the invented pointer.424 425void param_ref_to_ptr_top(void*& rp) {426 int local = 42;427 int* p = &local;428 rp = p; // expected-warning{{local variable 'local' is still referred to by the caller variable 'rp'}}429}430 431void param_ref_to_ptr_callee(void*& rp) {432 int local = 42;433 int* p = &local;434 rp = p; // expected-warning{{local variable 'local' is still referred to by the caller variable 'p'}}435}436 437void param_ref_to_ptr_caller() {438 void* p = nullptr;439 param_ref_to_ptr_callee(p);440}441} // namespace leaking_via_ref_to_ptr442 443namespace leaking_via_arr_of_ptr_static_idx {444void** returned_arr_of_ptr_top() {445 int local = 42;446 int* p = &local;447 void** arr = new void*[2];448 arr[1] = p;449 return arr; // expected-warning{{Address of stack memory associated with local variable 'local' returned to caller}}450}451 452void** returned_arr_of_ptr_callee() {453 int local = 42;454 int* p = &local;455 void** arr = new void*[2];456 arr[1] = p;457 return arr; // expected-warning{{Address of stack memory associated with local variable 'local' returned to caller}}458}459 460void returned_arr_of_ptr_caller() {461 void** arr = returned_arr_of_ptr_callee();462 (void)arr[1];463}464 465void* global_aop[2];466 467void global_arr_of_ptr() {468 int local = 42;469 int* p = &local;470 global_aop[1] = p; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_aop'}}471}472 473void static_arr_of_ptr() {474 int local = 42;475 static void* arr[2];476 arr[1] = &local;477 (void)arr[1]; // expected-warning{{local variable 'local' is still referred to by the static variable 'arr'}}478}479 480void param_arr_of_ptr_top(void* arr[2]) {481 int local = 42;482 int* p = &local;483 arr[1] = p; // expected-warning{{local variable 'local' is still referred to by the caller variable 'arr'}}484}485 486void param_arr_of_ptr_callee(void* arr[2]) {487 int local = 42;488 int* p = &local;489 arr[1] = p; // expected-warning{{local variable 'local' is still referred to by the caller variable 'arrStack'}}490}491 492void param_arr_of_ptr_caller() {493 void* arrStack[2];494 param_arr_of_ptr_callee(arrStack);495 (void)arrStack[1];496}497} // namespace leaking_via_arr_of_ptr_static_idx498 499namespace leaking_via_arr_of_ptr_dynamic_idx {500void** returned_arr_of_ptr_top(int idx) {501 int local = 42;502 int* p = &local;503 void** arr = new void*[2];504 arr[idx] = p;505 return arr; // expected-warning{{Address of stack memory associated with local variable 'local' returned to caller}}506}507 508void** returned_arr_of_ptr_callee(int idx) {509 int local = 42;510 int* p = &local;511 void** arr = new void*[2];512 arr[idx] = p;513 return arr; // expected-warning{{Address of stack memory associated with local variable 'local' returned to caller}}514}515 516void returned_arr_of_ptr_caller(int idx) {517 void** arr = returned_arr_of_ptr_callee(idx);518 (void)arr[idx];519}520 521void* global_aop[2];522 523void global_arr_of_ptr(int idx) {524 int local = 42;525 int* p = &local;526 global_aop[idx] = p; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_aop'}}527}528 529void static_arr_of_ptr(int idx) {530 int local = 42;531 static void* arr[2];532 arr[idx] = &local;533 (void)arr[idx]; // expected-warning{{local variable 'local' is still referred to by the static variable 'arr'}}534}535 536void param_arr_of_ptr_top(void* arr[2], int idx) {537 int local = 42;538 int* p = &local;539 arr[idx] = p; // expected-warning{{local variable 'local' is still referred to by the caller variable 'arr'}}540}541 542void param_arr_of_ptr_callee(void* arr[2], int idx) {543 int local = 42;544 int* p = &local;545 arr[idx] = p; // expected-warning{{local variable 'local' is still referred to by the caller variable 'arrStack'}}546}547 548void param_arr_of_ptr_caller(int idx) {549 void* arrStack[2];550 param_arr_of_ptr_callee(arrStack, idx);551 (void)arrStack[idx];552}553} // namespace leaking_via_arr_of_ptr_dynamic_idx554 555namespace leaking_via_struct_with_ptr {556struct S {557 int* p;558};559 560S returned_struct_with_ptr_top() {561 int local = 42;562 S s;563 s.p = &local;564 return s; // expected-warning{{Address of stack memory associated with local variable 'local' returned to caller}}565}566 567S returned_struct_with_ptr_callee() {568 int local = 42;569 S s;570 s.p = &local;571 return s; // expected-warning {{Address of stack memory associated with local variable 'local' returned to caller}} expected-warning{{Address of stack memory associated with local variable 'local' is still referred to by the caller variable 's' upon returning to the caller. This will be a dangling reference}}572}573 574S leak_through_field_of_returned_object() {575 int local = 14;576 S s{&local};577 return s; // expected-warning {{Address of stack memory associated with local variable 'local' returned to caller}}578}579 580S leak_through_compound_literal() {581 int local = 0;582 return (S) { &local }; // expected-warning {{Address of stack memory associated with local variable 'local' returned to caller}}583}584 585void returned_struct_with_ptr_caller() {586 S s = returned_struct_with_ptr_callee();587 (void)s.p;588}589 590S global_s;591 592void global_struct_with_ptr() {593 int local = 42;594 global_s.p = &local; // expected-warning{{'local' is still referred to by the global variable 'global_s'}}595}596 597void static_struct_with_ptr() {598 int local = 42;599 static S s;600 s.p = &local;601 (void)s.p; // expected-warning{{'local' is still referred to by the static variable 's'}}602}603} // namespace leaking_via_struct_with_ptr604 605namespace leaking_via_nested_structs_with_ptr {606struct Inner {607 int *ptr;608};609 610struct Outer {611 Inner I;612};613 614struct Deriving : public Outer {};615 616Outer leaks_through_nested_objects() {617 int local = 0;618 Outer O{&local};619 return O; // expected-warning {{Address of stack memory associated with local variable 'local' returned to caller}}620}621 622Deriving leaks_through_base_objects() {623 int local = 0;624 Deriving D{&local};625 return D; // expected-warning {{Address of stack memory associated with local variable 'local' returned to caller}}626}627} // namespace leaking_via_nested_structs_with_ptr628 629namespace leaking_via_ref_to_struct_with_ptr {630struct S {631 int* p;632};633 634S &global_s = *(new S);635 636void global_ref_to_struct_with_ptr() {637 int local = 42;638 global_s.p = &local; // expected-warning{{'local' is still referred to by the global variable 'global_s'}}639}640 641void static_ref_to_struct_with_ptr() {642 int local = 42;643 static S &s = *(new S);644 s.p = &local;645 (void)s.p;646} // no-warning False Negative, requires relating multiple bindings to cross a heap region.647 648void param_ref_to_struct_with_ptr_top(S &s) {649 int local = 42;650 s.p = &local; // expected-warning{{'local' is still referred to by the caller variable 's'}}651}652 653void param_ref_to_struct_with_ptr_callee(S &s) {654 int local = 42;655 s.p = &local; // expected-warning{{'local' is still referred to by the caller variable 'sStack'}}656}657 658void param_ref_to_struct_with_ptr_caller() {659 S sStack;660 param_ref_to_struct_with_ptr_callee(sStack);661}662 663template<typename Callable>664void lambda_param_capture_callee(Callable& callee) {665 int local = 42;666 callee(local); // expected-warning{{'local' is still referred to by the caller variable 'p'}}667}668 669void lambda_param_capture_caller() {670 int* p = nullptr;671 auto capt = [&p](int& param) {672 p = ¶m;673 };674 lambda_param_capture_callee(capt);675}676} // namespace leaking_via_ref_to_struct_with_ptr677 678namespace leaking_via_ptr_to_struct_with_ptr {679struct S {680 int* p;681};682 683S* returned_ptr_to_struct_with_ptr_top() {684 int local = 42;685 S* s = new S;686 s->p = &local;687 return s; // expected-warning {{Address of stack memory associated with local variable 'local' returned to caller}}688}689 690S* returned_ptr_to_struct_with_ptr_callee() {691 int local = 42;692 S* s = new S;693 s->p = &local;694 return s; // expected-warning {{Address of stack memory associated with local variable 'local' returned to caller}}695}696 697void returned_ptr_to_struct_with_ptr_caller() {698 S* s = returned_ptr_to_struct_with_ptr_callee();699 (void)s->p;700}701 702S* global_s;703 704void global_ptr_to_struct_with_ptr() {705 int local = 42;706 global_s->p = &local; // expected-warning{{'local' is still referred to by the global variable 'global_s'}}707}708 709void static_ptr_to_struct_with_ptr_new() {710 int local = 42;711 static S* s = new S;712 s->p = &local;713 (void)s->p;714} // no-warning False Negative, requires relating multiple bindings to cross a heap region.715 716S* get_some_s();717 718void static_ptr_to_struct_with_ptr_generated() {719 int local = 42;720 static S* s = get_some_s();721 s->p = &local;722} // no-warning False Negative, requires relating multiple bindings to cross the invented pointer.723 724void param_ptr_to_struct_with_ptr_top(S* s) {725 int local = 42;726 s->p = &local; // expected-warning{{'local' is still referred to by the caller variable 's'}}727}728 729void param_ptr_to_struct_with_ptr_callee(S* s) {730 int local = 42;731 s->p = &local; // expected-warning{{'local' is still referred to by the caller variable 's'}}732}733 734void param_ptr_to_struct_with_ptr_caller() {735 S s;736 param_ptr_to_struct_with_ptr_callee(&s);737 (void)s.p;738}739} // namespace leaking_via_ptr_to_struct_with_ptr740 741namespace leaking_via_arr_of_struct_with_ptr {742struct S {743 int* p;744};745 746S* returned_ptr_to_struct_with_ptr_top() {747 int local = 42;748 S* s = new S[2];749 s[1].p = &local;750 return s; // expected-warning {{Address of stack memory associated with local variable 'local' returned to caller}}751}752 753S* returned_ptr_to_struct_with_ptr_callee() {754 int local = 42;755 S* s = new S[2];756 s[1].p = &local;757 return s; // expected-warning {{Address of stack memory associated with local variable 'local' returned to caller}}758}759 760void returned_ptr_to_struct_with_ptr_caller() {761 S* s = returned_ptr_to_struct_with_ptr_callee();762 (void)s[1].p;763}764 765S global_s[2];766 767void global_ptr_to_struct_with_ptr() {768 int local = 42;769 global_s[1].p = &local; // expected-warning{{'local' is still referred to by the global variable 'global_s'}}770}771 772void static_ptr_to_struct_with_ptr_new() {773 int local = 42;774 static S* s = new S[2];775 s[1].p = &local;776 (void)s[1].p;777}778 779S* get_some_s();780 781void static_ptr_to_struct_with_ptr_generated() {782 int local = 42;783 static S* s = get_some_s();784 s[1].p = &local;785} // no-warning False Negative, requires relating multiple bindings to cross the invented pointer.786 787void param_ptr_to_struct_with_ptr_top(S s[2]) {788 int local = 42;789 s[1].p = &local; // expected-warning{{'local' is still referred to by the caller variable 's'}}790}791 792void param_ptr_to_struct_with_ptr_callee(S s[2]) {793 int local = 42;794 s[1].p = &local; // expected-warning{{'local' is still referred to by the caller variable 's'}}795}796 797void param_ptr_to_struct_with_ptr_caller() {798 S s[2];799 param_ptr_to_struct_with_ptr_callee(s);800 (void)s[1].p;801}802} // namespace leaking_via_arr_of_struct_with_ptr803 804namespace leaking_via_nested_and_indirect {805struct NestedAndTransitive {806 int** p;807 NestedAndTransitive* next[3];808};809 810NestedAndTransitive global_nat;811 812void global_nested_and_transitive() {813 int local = 42;814 *global_nat.next[2]->next[1]->p = &local; // expected-warning{{'local' is still referred to by the global variable 'global_nat'}}815}816 817void param_nested_and_transitive_top(NestedAndTransitive* nat) {818 int local = 42;819 *nat->next[2]->next[1]->p = &local; // expected-warning{{'local' is still referred to by the caller variable 'nat'}}820}821 822void param_nested_and_transitive_callee(NestedAndTransitive* nat) {823 int local = 42;824 *nat->next[2]->next[1]->p = &local; // expected-warning{{'local' is still referred to by the caller variable 'natCaller'}}825}826 827void param_nested_and_transitive_caller(NestedAndTransitive natCaller) {828 param_nested_and_transitive_callee(&natCaller);829}830 831} // namespace leaking_via_nested_and_indirect832 833namespace leaking_as_member {834class CRef {835 int& ref; // expected-note{{reference member declared here}}836 CRef(int x) : ref(x) {}837 // expected-warning@-1 {{binding reference member 'ref' to stack allocated parameter 'x'}}838};839 840class CPtr {841 int* ptr;842 void memFun(int x) {843 ptr = &x;844 }845};846} // namespace leaking_as_member847 848namespace origin_region_limitation {849void leaker(int ***leakerArg) {850 int local;851 clang_analyzer_dump(*leakerArg); // expected-warning{{&SymRegion{reg_$0<int ** arg>}}}852 // Incorrect message: 'arg', after it is reinitialized with value returned by 'tweak'853 // is no longer relevant.854 // The message must refer to 'original_arg' instead, but there is no easy way to855 // connect the SymRegion stored in 'original_arg' and 'original_arg' as variable.856 **leakerArg = &local; // expected-warning{{ 'local' is still referred to by the caller variable 'arg'}}857}858 859int **tweak();860 861void foo(int **arg) {862 int **original_arg = arg;863 arg = tweak();864 leaker(&original_arg);865}866} // namespace origin_region_limitation867 868namespace leaking_via_indirect_global_invalidated {869void** global_pp;870void opaque();871void global_ptr_to_ptr() {872 int local = 42;873 *global_pp = &local;874 opaque();875 *global_pp = nullptr;876}877} // namespace leaking_via_indirect_global_invalidated878 879namespace not_leaking_via_simple_ptr {880void simple_ptr(const char *p) {881 char tmp;882 p = &tmp; // no-warning883}884 885void ref_ptr(const char *&p) {886 char tmp;887 p = &tmp; // expected-warning{{variable 'tmp' is still referred to by the caller variable 'p'}}888}889 890struct S {891 const char *p;892};893 894void struct_ptr(S s) {895 char tmp;896 s.p = &tmp; // no-warning897}898 899void array(const char arr[2]) {900 char tmp;901 arr = &tmp; // no-warning902}903 904extern void copy(char *output, const char *input, unsigned size);905extern bool foo(const char *input);906extern void bar(char *output, unsigned count);907extern bool baz(char *output, const char *input);908 909void repo(const char *input, char *output) {910 char temp[64];911 copy(temp, input, sizeof(temp));912 913 char result[64];914 input = temp;915 if (foo(temp)) {916 bar(result, sizeof(result));917 input = result;918 }919 if (!baz(output, input)) {920 copy(output, input, sizeof(result));921 }922}923} // namespace not_leaking_via_simple_ptr924 925namespace early_reclaim_dead_limitation {926void foo();927void top(char **p) {928 char local;929 *p = &local;930 foo(); // no-warning FIXME: p binding is reclaimed before the function end931}932} // namespace early_reclaim_dead_limitation933 934namespace alloca_region_pointer {935void callee(char **pptr) {936 char local;937 *pptr = &local;938} // no crash939 940void top_alloca_no_crash_fn() {941 char **pptr = (char**)__builtin_alloca(sizeof(char*));942 callee(pptr);943}944 945void top_malloc_no_crash_fn() {946 char **pptr = (char**)malloc(sizeof(char*));947 callee(pptr);948 free(pptr);949}950} // namespace alloca_region_pointer951 952// These all warn with -Wreturn-stack-address also953namespace return_address_of_true_positives {954int* ret_local_addrOf() {955 int x = 1;956 return &*&x; // expected-warning {{Address of stack memory associated with local variable 'x' returned to caller}} expected-warning {{address of stack memory associated with local variable 'x' returned}}957}958 959int* ret_local_addrOf_paren() {960 int x = 1;961 return (&(*(&x))); // expected-warning {{Address of stack memory associated with local variable 'x' returned to caller}} expected-warning {{address of stack memory associated with local variable 'x' returned}}962}963 964int* ret_local_addrOf_ptr_arith() {965 int x = 1;966 return &*(&x+1); // expected-warning {{Address of stack memory associated with local variable 'x' returned to caller}} expected-warning {{address of stack memory associated with local variable 'x' returned}}967}968 969int* ret_local_addrOf_ptr_arith2() {970 int x = 1;971 return &*(&x+1); // expected-warning {{Address of stack memory associated with local variable 'x' returned to caller}} expected-warning {{address of stack memory associated with local variable 'x' returned}}972}973 974int* ret_local_field() {975 struct { int x; } a;976 return &a.x; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}} expected-warning {{address of stack memory associated with local variable 'a' returned}}977}978 979int& ret_local_field_ref() {980 struct { int x; } a;981 return a.x; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}} expected-warning {{reference to stack memory associated with local variable 'a' returned}}982}983} //namespace return_address_of_true_positives984 985namespace return_from_child_block_scope {986struct S {987 int *p;988};989 990S return_child_stack_context() {991 S s;992 {993 int a = 1;994 s = (S){ &a };995 }996 return s; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}997}998 999S return_child_stack_context_field() {1000 S s;1001 {1002 int a = 1;1003 s.p = &a;1004 }1005 return s; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}1006}1007 1008// The below are reproducers from Issue #1234591009template <typename V>1010struct T {1011 V* q{};1012 T() = default;1013 T(T&& rhs) { q = rhs.q; rhs.q = nullptr;}1014 T& operator=(T&& rhs) { q = rhs.q; rhs.q = nullptr;}1015 void push_back(const V& v) { if (q == nullptr) q = new V(v); }1016 ~T() { delete q; }1017};1018 1019T<S> f() {1020 T<S> t;1021 {1022 int a = 1;1023 t.push_back({ &a });1024 }1025 return t; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}1026}1027 1028} // namespace return_from_child_block_scope1029 1030namespace true_negatives_return_expressions {1031struct Container { int *x; };1032 1033int test2() {1034 int x = 14;1035 return x; // no-warning1036}1037 1038void return_void() {1039 return void(); // no-warning1040}1041 1042int return_assign_expr_safe() {1043 int y, x = 14;1044 return y = x; // no-warning1045}1046 1047int return_comma_separated_expressions_safe() {1048 int x = 1;1049 int *y;1050 return (y=&x), (x=15); // no-warning1051}1052 1053int return_comma_separated_expressions_container_safe() {1054 int x = 1;1055 Container Other;1056 return Other = Container{&x}, x = 14; // no-warning1057}1058 1059int make_x();1060int return_symbol_safe() {1061 int x = make_x();1062 clang_analyzer_dump(x); // expected-warning-re {{conj_$2{int, {{.+}}}}}1063 return x; // no-warning1064}1065 1066int *return_symbolic_region_safe(int **ptr) {1067 return *ptr; // no-warning1068}1069 1070int *return_arg_ptr(int *arg) {1071 return arg; // no-warning1072}1073 1074// This has a false positive with -Wreturn-stack-address, but CSA should not1075// warn on this1076int *return_conditional_never_false(int *arg) {1077 int x = 14;1078 return true ? arg : &x; // expected-warning {{address of stack memory associated with local variable 'x' returned}}1079}1080 1081// This has a false positive with -Wreturn-stack-address, but CSA should not1082// warn on this1083int *return_conditional_never_true(int *arg) {1084 int x = 14;1085 return false ? &x : arg; // expected-warning {{address of stack memory associated with local variable 'x' returned}}1086}1087 1088int *return_conditional_path_split(int *arg, bool b) {1089 int x = 14;1090 return b ? arg : &x; // expected-warning {{Address of stack memory associated with local variable 'x' returned to caller}} expected-warning {{address of stack memory associated with local variable 'x' returned}} -Wreturn-stack-address1091}1092 1093// compare of two symbolic regions1094// maybe in some implementation, make_ptr returns interior pointers that are comparable1095int *make_ptr();1096bool return_symbolic_exxpression() {1097 int *a = make_ptr();1098 int *b = make_ptr();1099 return a < b; // no-warning1100}1101 1102int *return_static() {1103 static int x = 0;1104 return &x; // no-warning1105}1106 1107int* return_cpp_reinterpret_cast_no_warning(long x) {1108 return reinterpret_cast<int*>(x); // no-warning1109}1110}1111 1112// TODO: The tail call expression tree must not hold a reference to an arg or stack local:1113// "The lifetimes of all local variables and function parameters end immediately before the 1114// [tail] call to the function. This means that it is undefined behaviour to pass a pointer or 1115// reference to a local variable to the called function, which is not the case without the 1116// attribute."1117// These only warn from -Wreturn-stack-address for now1118namespace with_attr_musttail {1119void TakesIntAndPtr(int, int *);1120void PassAddressOfLocal(int a, int *b) {1121 int c;1122 [[clang::musttail]] return TakesIntAndPtr(0, &c); // expected-warning {{address of stack memory associated with local variable 'c' pass\1123ed to musttail function}} False-negative on CSA1124}1125void PassAddressOfParam(int a, int *b) {1126 [[clang::musttail]] return TakesIntAndPtr(0, &a); // expected-warning {{address of stack memory associated with parameter 'a' passed to\1127 musttail function}} False-negative on CSA1128}1129} // namespace with_attr_musttail1130