1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -fblocks -verify %s 2 3 int* f1(void) { 4 int x = 0; 5 return &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned}} expected-warning{{address of stack memory associated with local variable 'x' returned}} 6 } 7 8 int* f2(int y) { 9 return &y; // expected-warning{{Address of stack memory associated with local variable 'y' returned}} expected-warning{{address of stack memory associated with parameter 'y' returned}} 10 } 11 12 int* f3(int x, int *y) { 13 int w = 0; 14 15 if (x) 16 y = &w; 17 18 return y; // expected-warning{{Address of stack memory associated with local variable 'w' returned to caller}} 19 } 20 21 void* compound_literal(int x, int y) { 22 if (x) 23 return &(unsigned short){((unsigned short)0x22EF)}; 24 // expected-warning-re@-1{{Address of stack memory associated with a compound literal declared on line {{[0-9]+}} returned to caller [core.StackAddressEscape]}} 25 // expected-warning@-2{{address of stack memory}} 26 27 int* array[] = {}; 28 struct s { int z; double y; int w; }; 29 30 if (y) 31 return &((struct s){ 2, 0.4, 5 * 8 }); 32 // expected-warning-re@-1{{Address of stack memory associated with a compound literal declared on line {{[0-9]+}} returned to caller [core.StackAddressEscape]}} 33 // expected-warning@-2{{address of stack memory}} 34 35 void* p = &((struct s){ 42, 0.4, x ? 42 : 0 }); 36 return p; 37 // expected-warning-re@-1{{Address of stack memory associated with a compound literal declared on line {{[0-9]+}} returned to caller [core.StackAddressEscape]}} 38 } 39 40 void* alloca_test(void) { 41 void* p = __builtin_alloca(10); 42 return p; // expected-warning{{Address of stack memory}} 43 } 44 45 int array_test(int x[2]) { 46 return x[0]; // no-warning 47 } 48 49 struct baz { 50 int x; 51 int y[2]; 52 }; 53 54 int struct_test(struct baz byVal, int flag) { 55 if (flag) 56 return byVal.x; // no-warning 57 else { 58 return byVal.y[0]; // no-warning 59 } 60 } 61 62 typedef int (^ComparatorBlock)(int a, int b); 63 ComparatorBlock test_return_block(void) { 64 // This block is a global since it has no captures. 65 ComparatorBlock b = ^int(int a, int b){ return a > b; }; 66 return b; // no-warning 67 } 68 69 ComparatorBlock test_return_block_with_capture(int x) { 70 // This block is stack allocated because it has captures. 71 ComparatorBlock b = ^int(int a, int b){ return a > b + x; }; 72 return b; // expected-warning{{Address of stack-allocated block}} 73 } 74 75 ComparatorBlock test_return_block_neg_aux(void); 76 ComparatorBlock test_return_block_neg(void) { 77 ComparatorBlock b = test_return_block_neg_aux(); 78 return b; // no-warning 79 } 80 81 int *rdar_7523821_f2(void) { 82 int a[3]; 83 return a; // expected-warning 2 {{ddress of stack memory associated with local variable 'a' returned}} 84 }; 85 86 // Handle blocks that have no captures or are otherwise declared 'static'. 87 typedef int (^RDar10348049)(int value); 88 RDar10348049 test_rdar10348049(void) { 89 static RDar10348049 b = ^int(int x) { 90 return x + 2; 91 }; 92 return b; // no-warning 93 } 94 95 void testRegister(register const char *reg) { 96 if (reg) (void)reg[0]; 97 } 98 void callTestRegister(void) { 99 char buf[20]; 100 testRegister(buf); // no-warning 101 } 102 103 void top_level_leaking(int **out) { 104 int local = 42; 105 *out = &local; // expected-warning{{Address of stack memory associated with local variable 'local' is still referred to by the caller variable 'out'}} 106 } 107 108 void callee_leaking_via_param(int **out) { 109 int local = 1; 110 *out = &local; 111 // expected-warning@-1{{Address of stack memory associated with local variable 'local' is still referred to by the caller variable 'ptr'}} 112 } 113 114 void caller_for_leaking_callee() { 115 int *ptr = 0; 116 callee_leaking_via_param(&ptr); 117 } 118 119 void callee_nested_leaking(int **out) { 120 int local = 1; 121 *out = &local; 122 // expected-warning@-1{{Address of stack memory associated with local variable 'local' is still referred to by the caller variable 'ptr'}} 123 } 124 125 void caller_mid_for_nested_leaking(int **mid) { 126 callee_nested_leaking(mid); 127 } 128 129 void caller_for_nested_leaking() { 130 int *ptr = 0; 131 caller_mid_for_nested_leaking(&ptr); 132 } 133 134 // This used to crash StackAddrEscapeChecker because 135 // it features a symbol conj_$1{struct c *, LC1, S763, #1} 136 // that has no origin region. 137 struct a { 138 int member; 139 }; 140 141 struct c { 142 struct a *nested_ptr; 143 }; 144 void opaque(struct c*); 145 struct c* get_c(void); 146 void no_crash_for_symbol_without_origin_region(void) { 147 struct c *ptr = get_c(); 148 opaque(ptr); 149 ptr->nested_ptr->member++; 150 } // No crash at the end of the function 151