1 // RUN: %clang_analyze_cc1 \
2 // RUN: -analyzer-checker=core,debug.ExprInspection \
4 // RUN: -Wno-undefined-bool-conversion
5 // RUN: %clang_analyze_cc1 \
6 // RUN: -analyzer-checker=core,debug.ExprInspection,unix.Malloc \
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.
12 typedef __INTPTR_TYPE__
intptr_t;
15 void clang_analyzer_dump(T x
);
17 using size_t = decltype(sizeof(int));
18 void * malloc(size_t size
);
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}}
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}}
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}}
40 static const int &x
= 3; // no warning
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}}
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}}
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}}
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}}
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}}
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}}
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}}
95 void *const &x
= &&label
; // expected-note {{binding reference variable 'x' here}}
96 return x
; // expected-warning {{returning address of label, which is local}}
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}}
113 void *radar13226577() {
115 return p
; // expected-warning {{stack memory associated with local variable 'p' returned to caller}}
118 namespace rdar13296133
{
119 class ConvertsToBool
{
121 operator bool() const { return this; }
124 class ConvertsToIntptr
{
126 operator intptr_t() const { return reinterpret_cast<intptr_t>(this); }
129 class ConvertsToPointer
{
131 operator const void *() const { return this; }
134 intptr_t returnAsNonLoc() {
135 ConvertsToIntptr obj
;
136 return obj
; // expected-warning{{Address of stack memory associated with local variable 'obj' returned to caller}}
139 bool returnAsBool() {
141 return obj
; // no-warning
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}}
149 bool returnAsBoolViaPointer() {
150 ConvertsToPointer obj
;
151 return obj
; // no-warning
153 } // namespace rdar13296133
155 void write_stack_address_to(char **q
) {
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
}}
165 write_stack_address_to(&p
);
169 ~C() {} // non-trivial class
174 return c
; // no-warning
177 void test_copy_elision() {
181 namespace leaking_via_direct_pointer
{
182 void* returned_direct_pointer_top() {
185 return p
; // expected-warning{{associated with local variable 'local' returned}}
188 int* returned_direct_pointer_callee() {
191 return p
; // expected-warning{{associated with local variable 'local' returned}}
194 void returned_direct_pointer_caller() {
195 int* loc_ptr
= nullptr;
196 loc_ptr
= returned_direct_pointer_callee();
202 void global_direct_pointer() {
204 global_ptr
= &local
; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_ptr'}}
207 void static_direct_pointer_top() {
209 static int* p
= &local
;
210 (void)p
; // expected-warning{{local variable 'local' is still referred to by the static variable 'p'}}
213 void static_direct_pointer_callee() {
215 static int* p
= &local
;
216 (void)p
; // expected-warning{{local variable 'local' is still referred to by the static variable 'p'}}
219 void static_direct_pointer_caller() {
220 static_direct_pointer_callee();
223 void lambda_to_global_direct_pointer() {
226 global_ptr
= &local
; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_ptr'}}
231 void lambda_to_context_direct_pointer() {
235 p
= &local
; // expected-warning{{local variable 'local' is still referred to by the caller variable 'p'}}
241 template<typename Callable
>
245 MyFunction(Callable
* callable
) :fptr(callable
) {}
248 void* lambda_to_context_direct_pointer_uncalled() {
252 p
= &local
; // no-warning: analyzed only as top-level, ignored explicitly by the checker
254 return new MyFunction(&lambda
);
257 void lambda_to_context_direct_pointer_lifetime_extended() {
261 p
= &local
; // expected-warning{{'int' lifetime extended by local variable 'local' is still referred to by the caller variable 'p'}}
267 template<typename Callback
>
268 void lambda_param_capture_direct_pointer_callee(Callback
& callee
) {
270 callee(local
); // expected-warning{{'local' is still referred to by the caller variable 'p'}}
273 void lambda_param_capture_direct_pointer_caller() {
275 auto capt
= [&p
](int& param
) {
278 lambda_param_capture_direct_pointer_callee(capt
);
280 } // namespace leaking_via_direct_pointer
282 namespace leaking_via_ptr_to_ptr
{
283 void** returned_ptr_to_ptr_top() {
286 void** pp
= (void**)&p
;
287 return pp
; // expected-warning{{associated with local variable 'p' returned}}
292 void global_ptr_local_to_ptr() {
295 global_pp
= (void**)&p
; // expected-warning{{local variable 'p' is still referred to by the global variable 'global_pp'}}
298 void global_ptr_to_ptr() {
300 *global_pp
= &local
; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_pp'}}
305 void global_ptr_to_ptr_to_ptr() {
307 **global_ppp
= &local
; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_ppp'}}
310 void** get_some_pp();
312 void static_ptr_to_ptr() {
314 static void** pp
= get_some_pp();
316 } // no-warning False Negative, requires relating multiple bindings to cross the invented pointer.
318 void param_ptr_to_ptr_top(void** pp
) {
320 *pp
= &local
; // expected-warning{{local variable 'local' is still referred to by the caller variable 'pp'}}
323 void param_ptr_to_ptr_callee(void** pp
) {
325 *pp
= &local
; // expected-warning{{local variable 'local' is still referred to by the caller variable 'p'}}
328 void param_ptr_to_ptr_caller() {
330 param_ptr_to_ptr_callee((void**)&p
);
333 void param_ptr_to_ptr_to_ptr_top(void*** ppp
) {
335 **ppp
= &local
; // expected-warning {{local variable 'local' is still referred to by the caller variable 'ppp'}}
338 void param_ptr_to_ptr_to_ptr_callee(void*** ppp
) {
340 **ppp
= &local
; // expected-warning{{local variable 'local' is still referred to by the caller variable 'pp'}}
343 void param_ptr_to_ptr_to_ptr_caller(void** pp
) {
344 param_ptr_to_ptr_to_ptr_callee(&pp
);
347 void lambda_to_context_ptr_to_ptr(int **pp
) {
350 *pp
= &local
; // expected-warning{{local variable 'local' is still referred to by the caller variable 'pp'}}
356 void param_ptr_to_ptr_fptr(int **pp
) {
358 *pp
= &local
; // expected-warning{{local variable 'local' is still referred to by the caller variable 'p'}}
361 void param_ptr_to_ptr_fptr_caller(void (*fptr
)(int**)) {
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
);
370 } // namespace leaking_via_ptr_to_ptr
372 namespace leaking_via_ref_to_ptr
{
373 void** make_ptr_to_ptr();
374 void*& global_rtp
= *make_ptr_to_ptr();
376 void global_ref_to_ptr() {
379 global_rtp
= p
; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_rtp'}}
382 void static_ref_to_ptr() {
384 static void*& p
= *make_ptr_to_ptr();
387 } // no-warning False Negative, requires relating multiple bindings to cross the invented pointer.
389 void param_ref_to_ptr_top(void*& rp
) {
392 rp
= p
; // expected-warning{{local variable 'local' is still referred to by the caller variable 'rp'}}
395 void param_ref_to_ptr_callee(void*& rp
) {
398 rp
= p
; // expected-warning{{local variable 'local' is still referred to by the caller variable 'p'}}
401 void param_ref_to_ptr_caller() {
403 param_ref_to_ptr_callee(p
);
405 } // namespace leaking_via_ref_to_ptr
407 namespace leaking_via_arr_of_ptr_static_idx
{
408 void** returned_arr_of_ptr_top() {
411 void** arr
= new void*[2];
414 } // no-warning False Negative
416 void** returned_arr_of_ptr_callee() {
419 void** arr
= new void*[2];
422 } // no-warning False Negative
424 void returned_arr_of_ptr_caller() {
425 void** arr
= returned_arr_of_ptr_callee();
431 void global_arr_of_ptr() {
434 global_aop
[1] = p
; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_aop'}}
437 void static_arr_of_ptr() {
441 (void)arr
[1]; // expected-warning{{local variable 'local' is still referred to by the static variable 'arr'}}
444 void param_arr_of_ptr_top(void* arr
[2]) {
447 arr
[1] = p
; // expected-warning{{local variable 'local' is still referred to by the caller variable 'arr'}}
450 void param_arr_of_ptr_callee(void* arr
[2]) {
453 arr
[1] = p
; // expected-warning{{local variable 'local' is still referred to by the caller variable 'arrStack'}}
456 void param_arr_of_ptr_caller() {
458 param_arr_of_ptr_callee(arrStack
);
461 } // namespace leaking_via_arr_of_ptr_static_idx
463 namespace leaking_via_arr_of_ptr_dynamic_idx
{
464 void** returned_arr_of_ptr_top(int idx
) {
467 void** arr
= new void*[2];
470 } // no-warning False Negative
472 void** returned_arr_of_ptr_callee(int idx
) {
475 void** arr
= new void*[2];
478 } // no-warning False Negative
480 void returned_arr_of_ptr_caller(int idx
) {
481 void** arr
= returned_arr_of_ptr_callee(idx
);
487 void global_arr_of_ptr(int idx
) {
490 global_aop
[idx
] = p
; // expected-warning{{local variable 'local' is still referred to by the global variable 'global_aop'}}
493 void static_arr_of_ptr(int idx
) {
497 (void)arr
[idx
]; // expected-warning{{local variable 'local' is still referred to by the static variable 'arr'}}
500 void param_arr_of_ptr_top(void* arr
[2], int idx
) {
503 arr
[idx
] = p
; // expected-warning{{local variable 'local' is still referred to by the caller variable 'arr'}}
506 void param_arr_of_ptr_callee(void* arr
[2], int idx
) {
509 arr
[idx
] = p
; // expected-warning{{local variable 'local' is still referred to by the caller variable 'arrStack'}}
512 void param_arr_of_ptr_caller(int idx
) {
514 param_arr_of_ptr_callee(arrStack
, idx
);
517 } // namespace leaking_via_arr_of_ptr_dynamic_idx
519 namespace leaking_via_struct_with_ptr
{
524 S
returned_struct_with_ptr_top() {
529 } // no-warning False Negative, requires traversing returned LazyCompoundVals
531 S
returned_struct_with_ptr_callee() {
535 return s
; // expected-warning{{'local' is still referred to by the caller variable 's'}}
538 void returned_struct_with_ptr_caller() {
539 S s
= returned_struct_with_ptr_callee();
545 void global_struct_with_ptr() {
547 global_s
.p
= &local
; // expected-warning{{'local' is still referred to by the global variable 'global_s'}}
550 void static_struct_with_ptr() {
554 (void)s
.p
; // expected-warning{{'local' is still referred to by the static variable 's'}}
556 } // namespace leaking_via_struct_with_ptr
558 namespace leaking_via_ref_to_struct_with_ptr
{
563 S
&global_s
= *(new S
);
565 void global_ref_to_struct_with_ptr() {
567 global_s
.p
= &local
; // expected-warning{{'local' is still referred to by the global variable 'global_s'}}
570 void static_ref_to_struct_with_ptr() {
572 static S
&s
= *(new S
);
575 } // no-warning False Negative, requires relating multiple bindings to cross a heap region.
577 void param_ref_to_struct_with_ptr_top(S
&s
) {
579 s
.p
= &local
; // expected-warning{{'local' is still referred to by the caller variable 's'}}
582 void param_ref_to_struct_with_ptr_callee(S
&s
) {
584 s
.p
= &local
; // expected-warning{{'local' is still referred to by the caller variable 'sStack'}}
587 void param_ref_to_struct_with_ptr_caller() {
589 param_ref_to_struct_with_ptr_callee(sStack
);
592 template<typename Callable
>
593 void lambda_param_capture_callee(Callable
& callee
) {
595 callee(local
); // expected-warning{{'local' is still referred to by the caller variable 'p'}}
598 void lambda_param_capture_caller() {
600 auto capt
= [&p
](int& param
) {
603 lambda_param_capture_callee(capt
);
605 } // namespace leaking_via_ref_to_struct_with_ptr
607 namespace leaking_via_ptr_to_struct_with_ptr
{
612 S
* returned_ptr_to_struct_with_ptr_top() {
617 } // no-warning False Negative
619 S
* returned_ptr_to_struct_with_ptr_callee() {
624 } // no-warning False Negative
626 void returned_ptr_to_struct_with_ptr_caller() {
627 S
* s
= returned_ptr_to_struct_with_ptr_callee();
633 void global_ptr_to_struct_with_ptr() {
635 global_s
->p
= &local
; // expected-warning{{'local' is still referred to by the global variable 'global_s'}}
638 void static_ptr_to_struct_with_ptr_new() {
643 } // no-warning False Negative, requires relating multiple bindings to cross a heap region.
647 void static_ptr_to_struct_with_ptr_generated() {
649 static S
* s
= get_some_s();
651 } // no-warning False Negative, requires relating multiple bindings to cross the invented pointer.
653 void param_ptr_to_struct_with_ptr_top(S
* s
) {
655 s
->p
= &local
; // expected-warning{{'local' is still referred to by the caller variable 's'}}
658 void param_ptr_to_struct_with_ptr_callee(S
* s
) {
660 s
->p
= &local
; // expected-warning{{'local' is still referred to by the caller variable 's'}}
663 void param_ptr_to_struct_with_ptr_caller() {
665 param_ptr_to_struct_with_ptr_callee(&s
);
668 } // namespace leaking_via_ptr_to_struct_with_ptr
670 namespace leaking_via_arr_of_struct_with_ptr
{
675 S
* returned_ptr_to_struct_with_ptr_top() {
680 } // no-warning False Negative
682 S
* returned_ptr_to_struct_with_ptr_callee() {
687 } // no-warning False Negative
689 void returned_ptr_to_struct_with_ptr_caller() {
690 S
* s
= returned_ptr_to_struct_with_ptr_callee();
696 void global_ptr_to_struct_with_ptr() {
698 global_s
[1].p
= &local
; // expected-warning{{'local' is still referred to by the global variable 'global_s'}}
701 void static_ptr_to_struct_with_ptr_new() {
703 static S
* s
= new S
[2];
710 void static_ptr_to_struct_with_ptr_generated() {
712 static S
* s
= get_some_s();
714 } // no-warning False Negative, requires relating multiple bindings to cross the invented pointer.
716 void param_ptr_to_struct_with_ptr_top(S s
[2]) {
718 s
[1].p
= &local
; // expected-warning{{'local' is still referred to by the caller variable 's'}}
721 void param_ptr_to_struct_with_ptr_callee(S s
[2]) {
723 s
[1].p
= &local
; // expected-warning{{'local' is still referred to by the caller variable 's'}}
726 void param_ptr_to_struct_with_ptr_caller() {
728 param_ptr_to_struct_with_ptr_callee(s
);
731 } // namespace leaking_via_arr_of_struct_with_ptr
733 namespace leaking_via_nested_and_indirect
{
734 struct NestedAndTransitive
{
736 NestedAndTransitive
* next
[3];
739 NestedAndTransitive global_nat
;
741 void global_nested_and_transitive() {
743 *global_nat
.next
[2]->next
[1]->p
= &local
; // expected-warning{{'local' is still referred to by the global variable 'global_nat'}}
746 void param_nested_and_transitive_top(NestedAndTransitive
* nat
) {
748 *nat
->next
[2]->next
[1]->p
= &local
; // expected-warning{{'local' is still referred to by the caller variable 'nat'}}
751 void param_nested_and_transitive_callee(NestedAndTransitive
* nat
) {
753 *nat
->next
[2]->next
[1]->p
= &local
; // expected-warning{{'local' is still referred to by the caller variable 'natCaller'}}
756 void param_nested_and_transitive_caller(NestedAndTransitive natCaller
) {
757 param_nested_and_transitive_callee(&natCaller
);
760 } // namespace leaking_via_nested_and_indirect
762 namespace leaking_as_member
{
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'}}
775 } // namespace leaking_as_member
777 namespace origin_region_limitation
{
778 void leaker(int ***leakerArg
) {
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'}}
790 void foo(int **arg
) {
791 int **original_arg
= arg
;
793 leaker(&original_arg
);
795 } // namespace origin_region_limitation
797 namespace leaking_via_indirect_global_invalidated
{
800 void global_ptr_to_ptr() {
804 *global_pp
= nullptr;
806 } // namespace leaking_via_indirect_global_invalidated
808 namespace not_leaking_via_simple_ptr
{
809 void simple_ptr(const char *p
) {
811 p
= &tmp
; // no-warning
814 void ref_ptr(const char *&p
) {
816 p
= &tmp
; // expected-warning{{variable 'tmp' is still referred to by the caller variable 'p'}}
823 void struct_ptr(S s
) {
825 s
.p
= &tmp
; // no-warning
828 void array(const char arr
[2]) {
830 arr
= &tmp
; // no-warning
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
);
838 void repo(const char *input
, char *output
) {
840 copy(temp
, input
, sizeof(temp
));
845 bar(result
, sizeof(result
));
848 if (!baz(output
, input
)) {
849 copy(output
, input
, sizeof(result
));
852 } // namespace not_leaking_via_simple_ptr
854 namespace early_reclaim_dead_limitation
{
859 foo(); // no-warning FIXME: p binding is reclaimed before the function end
861 } // namespace early_reclaim_dead_limitation
863 namespace alloca_region_pointer
{
864 void callee(char **pptr
) {
869 void top_alloca_no_crash_fn() {
870 char **pptr
= (char**)__builtin_alloca(sizeof(char*));
874 void top_malloc_no_crash_fn() {
875 char **pptr
= (char**)malloc(sizeof(char*));
879 } // namespace alloca_region_pointer