1// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s 2// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s 3// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s 4 5extern bool clang_analyzer_eval(bool); 6 7struct Trivial { 8 Trivial(int x) : value(x) {} 9 int value; 10}; 11 12struct NonTrivial : public Trivial { 13 NonTrivial(int x) : Trivial(x) {} 14 ~NonTrivial(); 15}; 16 17 18Trivial getTrivial() { 19 return Trivial(42); // no-warning 20} 21 22const Trivial &getTrivialRef() { 23 return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'Trivial' returned to caller}} 24} 25 26 27NonTrivial getNonTrivial() { 28 return NonTrivial(42); // no-warning 29} 30 31const NonTrivial &getNonTrivialRef() { 32 return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}} 33} 34 35namespace rdar13265460 { 36 struct TrivialSubclass : public Trivial { 37 TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {} 38 int anotherValue; 39 }; 40 41 TrivialSubclass getTrivialSub() { 42 TrivialSubclass obj(1); 43 obj.value = 42; 44 obj.anotherValue = -42; 45 return obj; 46 } 47 48 void testImmediate() { 49 TrivialSubclass obj = getTrivialSub(); 50 51 clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}} 52 clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}} 53 54 clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}} 55 clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}} 56 } 57 58 void testMaterializeTemporaryExpr() { 59 const TrivialSubclass &ref = getTrivialSub(); 60 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} 61 62 const Trivial &baseRef = getTrivialSub(); 63 clang_analyzer_eval(baseRef.value == 42); // expected-warning{{TRUE}} 64 } 65} 66 67namespace rdar13281951 { 68 struct Derived : public Trivial { 69 Derived(int value) : Trivial(value), value2(-value) {} 70 int value2; 71 }; 72 73 void test() { 74 Derived obj(1); 75 obj.value = 42; 76 const Trivial * const &pointerRef = &obj; 77 clang_analyzer_eval(pointerRef->value == 42); // expected-warning{{TRUE}} 78 } 79} 80 81namespace compound_literals { 82 struct POD { 83 int x, y; 84 }; 85 struct HasCtor { 86 HasCtor(int x, int y) : x(x), y(y) {} 87 int x, y; 88 }; 89 struct HasDtor { 90 int x, y; 91 ~HasDtor(); 92 }; 93 struct HasCtorDtor { 94 HasCtorDtor(int x, int y) : x(x), y(y) {} 95 ~HasCtorDtor(); 96 int x, y; 97 }; 98 99 void test() { 100 clang_analyzer_eval(((POD){1, 42}).y == 42); // expected-warning{{TRUE}} 101 clang_analyzer_eval(((HasDtor){1, 42}).y == 42); // expected-warning{{TRUE}} 102 103#if __cplusplus >= 201103L 104 clang_analyzer_eval(((HasCtor){1, 42}).y == 42); // expected-warning{{TRUE}} 105 106 // FIXME: should be TRUE, but we don't inline the constructors of 107 // temporaries because we can't model their destructors yet. 108 clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}} 109#endif 110 } 111} 112 113namespace destructors { 114 void testPR16664andPR18159Crash() { 115 struct Dtor { 116 ~Dtor(); 117 }; 118 extern bool coin(); 119 extern bool check(const Dtor &); 120 121 // Regression test: we used to assert here when tmp dtors are enabled. 122 // PR16664 and PR18159 123 if (coin() && (coin() || coin() || check(Dtor()))) { 124 Dtor(); 125 } 126 } 127 128#ifdef TEMPORARY_DTORS 129 struct NoReturnDtor { 130 ~NoReturnDtor() __attribute__((noreturn)); 131 }; 132 133 void noReturnTemp(int *x) { 134 if (! x) NoReturnDtor(); 135 *x = 47; // no warning 136 } 137 138 void noReturnInline(int **x) { 139 NoReturnDtor(); 140 } 141 142 void callNoReturn() { 143 int *x; 144 noReturnInline(&x); 145 *x = 47; // no warning 146 } 147 148 extern bool check(const NoReturnDtor &); 149 150 void testConsistencyIf(int i) { 151 if (i != 5) 152 return; 153 if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) { 154 clang_analyzer_eval(true); // no warning, unreachable code 155 } 156 } 157 158 void testConsistencyTernary(int i) { 159 (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0; 160 161 clang_analyzer_eval(true); // expected-warning{{TRUE}} 162 163 if (i != 5) 164 return; 165 166 (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0; 167 168 clang_analyzer_eval(true); // no warning, unreachable code 169 } 170 171 // Regression test: we used to assert here. 172 // PR16664 and PR18159 173 void testConsistencyNested(int i) { 174 extern bool compute(bool); 175 176 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 177 clang_analyzer_eval(true); // expected-warning{{TRUE}} 178 179 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 180 clang_analyzer_eval(true); // expected-warning{{TRUE}} 181 182 if (i != 5) 183 return; 184 185 if (compute(i == 5 && 186 (i == 4 || compute(true) || 187 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 188 i != 4) { 189 clang_analyzer_eval(true); // expected-warning{{TRUE}} 190 } 191 192 if (compute(i == 5 && 193 (i == 4 || i == 4 || 194 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 195 i != 4) { 196 // FIXME: This shouldn't cause a warning. 197 clang_analyzer_eval(true); // expected-warning{{TRUE}} 198 } 199 } 200 201 // PR16664 and PR18159 202 void testConsistencyNestedSimple(bool value) { 203 if (value) { 204 if (!value || check(NoReturnDtor())) { 205 clang_analyzer_eval(true); // no warning, unreachable code 206 } 207 } 208 } 209 210 // PR16664 and PR18159 211 void testConsistencyNestedComplex(bool value) { 212 if (value) { 213 if (!value || !value || check(NoReturnDtor())) { 214 // FIXME: This shouldn't cause a warning. 215 clang_analyzer_eval(true); // expected-warning{{TRUE}} 216 } 217 } 218 } 219 220 // PR16664 and PR18159 221 void testConsistencyNestedWarning(bool value) { 222 if (value) { 223 if (!value || value || check(NoReturnDtor())) { 224 clang_analyzer_eval(true); // expected-warning{{TRUE}} 225 } 226 } 227 } 228 229 void testBinaryOperatorShortcut(bool value) { 230 if (value) { 231 if (false && false && check(NoReturnDtor()) && true) { 232 clang_analyzer_eval(true); 233 } 234 } 235 } 236 237#endif // TEMPORARY_DTORS 238} 239 240void testStaticMaterializeTemporaryExpr() { 241 static const Trivial &ref = getTrivial(); 242 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} 243 244 static const Trivial &directRef = Trivial(42); 245 clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}} 246 247#if __has_feature(cxx_thread_local) 248 thread_local static const Trivial &threadRef = getTrivial(); 249 clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}} 250 251 thread_local static const Trivial &threadDirectRef = Trivial(42); 252 clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}} 253#endif 254} 255 256namespace PR16629 { 257 struct A { 258 explicit A(int* p_) : p(p_) {} 259 int* p; 260 }; 261 262 extern void escape(const A*[]); 263 extern void check(int); 264 265 void callEscape(const A& a) { 266 const A* args[] = { &a }; 267 escape(args); 268 } 269 270 void testNoWarning() { 271 int x; 272 callEscape(A(&x)); 273 check(x); // Analyzer used to give a "x is uninitialized warning" here 274 } 275 276 void set(const A*a[]) { 277 *a[0]->p = 47; 278 } 279 280 void callSet(const A& a) { 281 const A* args[] = { &a }; 282 set(args); 283 } 284 285 void testConsistency() { 286 int x; 287 callSet(A(&x)); 288 clang_analyzer_eval(x == 47); // expected-warning{{TRUE}} 289 } 290} 291