xref: /llvm-project/clang/test/Analysis/stack-addr-ps.cpp (revision be0b1142df7733633354ef1f73d0379bcd2ccb54)
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 = &param;
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 = &param;
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