1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s 2 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s 3 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s -std=c++11 4 5 extern bool clang_analyzer_eval(bool); 6 extern bool clang_analyzer_warnIfReached(); 7 8 struct Trivial { 9 Trivial(int x) : value(x) {} 10 int value; 11 }; 12 13 struct NonTrivial : public Trivial { 14 NonTrivial(int x) : Trivial(x) {} 15 ~NonTrivial(); 16 }; 17 18 19 Trivial getTrivial() { 20 return Trivial(42); // no-warning 21 } 22 23 const Trivial &getTrivialRef() { 24 return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'Trivial' returned to caller}} 25 } 26 27 28 NonTrivial getNonTrivial() { 29 return NonTrivial(42); // no-warning 30 } 31 32 const NonTrivial &getNonTrivialRef() { 33 return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}} 34 } 35 36 namespace rdar13265460 { 37 struct TrivialSubclass : public Trivial { 38 TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {} 39 int anotherValue; 40 }; 41 42 TrivialSubclass getTrivialSub() { 43 TrivialSubclass obj(1); 44 obj.value = 42; 45 obj.anotherValue = -42; 46 return obj; 47 } 48 49 void testImmediate() { 50 TrivialSubclass obj = getTrivialSub(); 51 52 clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}} 53 clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}} 54 55 clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}} 56 clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}} 57 } 58 59 void testMaterializeTemporaryExpr() { 60 const TrivialSubclass &ref = getTrivialSub(); 61 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} 62 63 const Trivial &baseRef = getTrivialSub(); 64 clang_analyzer_eval(baseRef.value == 42); // expected-warning{{TRUE}} 65 } 66 } 67 68 namespace rdar13281951 { 69 struct Derived : public Trivial { 70 Derived(int value) : Trivial(value), value2(-value) {} 71 int value2; 72 }; 73 74 void test() { 75 Derived obj(1); 76 obj.value = 42; 77 const Trivial * const &pointerRef = &obj; 78 clang_analyzer_eval(pointerRef->value == 42); // expected-warning{{TRUE}} 79 } 80 } 81 82 namespace compound_literals { 83 struct POD { 84 int x, y; 85 }; 86 struct HasCtor { 87 HasCtor(int x, int y) : x(x), y(y) {} 88 int x, y; 89 }; 90 struct HasDtor { 91 int x, y; 92 ~HasDtor(); 93 }; 94 struct HasCtorDtor { 95 HasCtorDtor(int x, int y) : x(x), y(y) {} 96 ~HasCtorDtor(); 97 int x, y; 98 }; 99 100 void test() { 101 clang_analyzer_eval(((POD){1, 42}).y == 42); // expected-warning{{TRUE}} 102 clang_analyzer_eval(((HasDtor){1, 42}).y == 42); // expected-warning{{TRUE}} 103 104 #if __cplusplus >= 201103L 105 clang_analyzer_eval(((HasCtor){1, 42}).y == 42); // expected-warning{{TRUE}} 106 107 // FIXME: should be TRUE, but we don't inline the constructors of 108 // temporaries because we can't model their destructors yet. 109 clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}} 110 #endif 111 } 112 } 113 114 namespace destructors { 115 struct Dtor { 116 ~Dtor(); 117 }; 118 extern bool coin(); 119 extern bool check(const Dtor &); 120 121 void testPR16664andPR18159Crash() { 122 // Regression test: we used to assert here when tmp dtors are enabled. 123 // PR16664 and PR18159 124 if (coin() && (coin() || coin() || check(Dtor()))) { 125 Dtor(); 126 } 127 } 128 129 #ifdef TEMPORARY_DTORS 130 struct NoReturnDtor { 131 ~NoReturnDtor() __attribute__((noreturn)); 132 }; 133 134 void noReturnTemp(int *x) { 135 if (! x) NoReturnDtor(); 136 *x = 47; // no warning 137 } 138 139 void noReturnInline(int **x) { 140 NoReturnDtor(); 141 } 142 143 void callNoReturn() { 144 int *x; 145 noReturnInline(&x); 146 *x = 47; // no warning 147 } 148 149 extern bool check(const NoReturnDtor &); 150 151 void testConsistencyIf(int i) { 152 if (i != 5) 153 return; 154 if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) { 155 clang_analyzer_eval(true); // no warning, unreachable code 156 } 157 } 158 159 void testConsistencyTernary(int i) { 160 (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0; 161 162 clang_analyzer_eval(true); // expected-warning{{TRUE}} 163 164 if (i != 5) 165 return; 166 167 (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0; 168 169 clang_analyzer_eval(true); // no warning, unreachable code 170 } 171 172 // Regression test: we used to assert here. 173 // PR16664 and PR18159 174 void testConsistencyNested(int i) { 175 extern bool compute(bool); 176 177 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 178 clang_analyzer_eval(true); // expected-warning{{TRUE}} 179 180 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 181 clang_analyzer_eval(true); // expected-warning{{TRUE}} 182 183 if (i != 5) 184 return; 185 186 if (compute(i == 5 && 187 (i == 4 || compute(true) || 188 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 189 i != 4) { 190 clang_analyzer_eval(true); // expected-warning{{TRUE}} 191 } 192 193 if (compute(i == 5 && 194 (i == 4 || i == 4 || 195 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 196 i != 4) { 197 clang_analyzer_eval(true); // no warning, unreachable code 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 clang_analyzer_eval(true); // no warning, unreachable code 215 } 216 } 217 } 218 219 // PR16664 and PR18159 220 void testConsistencyNestedWarning(bool value) { 221 if (value) { 222 if (!value || value || check(NoReturnDtor())) { 223 clang_analyzer_eval(true); // expected-warning{{TRUE}} 224 } 225 } 226 } 227 // PR16664 and PR18159 228 void testConsistencyNestedComplexMidBranch(bool value) { 229 if (value) { 230 if (!value || !value || check(NoReturnDtor()) || value) { 231 clang_analyzer_eval(true); // no warning, unreachable code 232 } 233 } 234 } 235 236 // PR16664 and PR18159 237 void testConsistencyNestedComplexNestedBranch(bool value) { 238 if (value) { 239 if (!value || (!value || check(NoReturnDtor()) || value)) { 240 clang_analyzer_eval(true); // no warning, unreachable code 241 } 242 } 243 } 244 245 // PR16664 and PR18159 246 void testConsistencyNestedVariableModification(bool value) { 247 bool other = true; 248 if (value) { 249 if (!other || !value || (other = false) || check(NoReturnDtor()) || 250 !other) { 251 clang_analyzer_eval(true); // no warning, unreachable code 252 } 253 } 254 } 255 256 void testTernaryNoReturnTrueBranch(bool value) { 257 if (value) { 258 bool b = value && (value ? check(NoReturnDtor()) : true); 259 clang_analyzer_eval(true); // no warning, unreachable code 260 } 261 } 262 void testTernaryNoReturnFalseBranch(bool value) { 263 if (value) { 264 bool b = !value && !value ? true : check(NoReturnDtor()); 265 clang_analyzer_eval(true); // no warning, unreachable code 266 } 267 } 268 void testTernaryIgnoreNoreturnBranch(bool value) { 269 if (value) { 270 bool b = !value && !value ? check(NoReturnDtor()) : true; 271 clang_analyzer_eval(true); // expected-warning{{TRUE}} 272 } 273 } 274 void testTernaryTrueBranchReached(bool value) { 275 value ? clang_analyzer_warnIfReached() : // expected-warning{{REACHABLE}} 276 check(NoReturnDtor()); 277 } 278 void testTernaryFalseBranchReached(bool value) { 279 value ? check(NoReturnDtor()) : 280 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 281 } 282 283 void testLoop() { 284 for (int i = 0; i < 10; ++i) { 285 if (i < 3 && (i >= 2 || check(NoReturnDtor()))) { 286 clang_analyzer_eval(true); // no warning, unreachable code 287 } 288 } 289 } 290 291 bool testRecursiveFrames(bool isInner) { 292 if (isInner || 293 (clang_analyzer_warnIfReached(), false) || // expected-warning{{REACHABLE}} 294 check(NoReturnDtor()) || 295 testRecursiveFrames(true)) { 296 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 297 } 298 } 299 void testRecursiveFramesStart() { testRecursiveFrames(false); } 300 301 void testLambdas() { 302 []() { check(NoReturnDtor()); } != nullptr || check(Dtor()); 303 } 304 305 void testGnuExpressionStatements(int v) { 306 ({ ++v; v == 10 || check(NoReturnDtor()); v == 42; }) || v == 23; 307 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 308 309 ({ ++v; check(NoReturnDtor()); v == 42; }) || v == 23; 310 clang_analyzer_warnIfReached(); // no warning, unreachable code 311 } 312 313 void testGnuExpressionStatementsDestructionPoint(int v) { 314 // In normal context, the temporary destructor runs at the end of the full 315 // statement, thus the last statement is reached. 316 (++v, check(NoReturnDtor()), v == 42), 317 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 318 319 // GNU expression statements execute temporary destructors within the 320 // blocks, thus the last statement is not reached. 321 ({ ++v; check(NoReturnDtor()); v == 42; }), 322 clang_analyzer_warnIfReached(); // no warning, unreachable code 323 } 324 325 void testMultipleTemporaries(bool value) { 326 if (value) { 327 // FIXME: Find a way to verify construction order. 328 // ~Dtor should run before ~NoReturnDtor() because construction order is 329 // guaranteed by comma operator. 330 if (!value || check((NoReturnDtor(), Dtor())) || value) { 331 clang_analyzer_eval(true); // no warning, unreachable code 332 } 333 } 334 } 335 336 void testBinaryOperatorShortcut(bool value) { 337 if (value) { 338 if (false && false && check(NoReturnDtor()) && true) { 339 clang_analyzer_eval(true); 340 } 341 } 342 } 343 344 void testIfAtEndOfLoop() { 345 int y = 0; 346 while (true) { 347 if (y > 0) { 348 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 349 } 350 ++y; 351 // Test that the CFG gets hooked up correctly when temporary destructors 352 // are handled after a statically known branch condition. 353 if (true) (void)0; else (void)check(NoReturnDtor()); 354 } 355 } 356 357 void testTernaryAtEndOfLoop() { 358 int y = 0; 359 while (true) { 360 if (y > 0) { 361 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 362 } 363 ++y; 364 // Test that the CFG gets hooked up correctly when temporary destructors 365 // are handled after a statically known branch condition. 366 true ? (void)0 : (void)check(NoReturnDtor()); 367 } 368 } 369 370 void testNoReturnInComplexCondition() { 371 check(Dtor()) && 372 (check(NoReturnDtor()) || check(NoReturnDtor())) && check(Dtor()); 373 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 374 } 375 376 void testSequencingOfConditionalTempDtors(bool b) { 377 b || (check(Dtor()), check(NoReturnDtor())); 378 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 379 } 380 381 void testSequencingOfConditionalTempDtors2(bool b) { 382 (b || check(Dtor())), check(NoReturnDtor()); 383 clang_analyzer_warnIfReached(); // no warning, unreachable code 384 } 385 386 void testSequencingOfConditionalTempDtorsWithinBinaryOperators(bool b) { 387 b || (check(Dtor()) + check(NoReturnDtor())); 388 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 389 } 390 391 void f(Dtor d = Dtor()); 392 void testDefaultParameters() { 393 f(); 394 } 395 396 struct DefaultParam { 397 DefaultParam(int, const Dtor& d = Dtor()); 398 ~DefaultParam(); 399 }; 400 void testDefaultParamConstructorsInLoops() { 401 while (true) { 402 // FIXME: This exact pattern triggers the temporary cleanup logic 403 // to fail when adding a 'clean' state. 404 DefaultParam(42); 405 DefaultParam(42); 406 } 407 } 408 void testDefaultParamConstructorsInTernariesInLoops(bool value) { 409 while (true) { 410 // FIXME: This exact pattern triggers the temporary cleanup logic 411 // to visit the bind-temporary logic with a state that already has that 412 // temporary marked as executed. 413 value ? DefaultParam(42) : DefaultParam(42); 414 } 415 } 416 #else // !TEMPORARY_DTORS 417 418 // Test for fallback logic that conservatively stops exploration after 419 // executing a temporary constructor for a class with a no-return destructor 420 // when temporary destructors are not enabled in the CFG. 421 422 struct CtorWithNoReturnDtor { 423 CtorWithNoReturnDtor() = default; 424 425 ~CtorWithNoReturnDtor() __attribute__((noreturn)); 426 }; 427 428 void testDefaultContructorWithNoReturnDtor() { 429 CtorWithNoReturnDtor(); 430 clang_analyzer_warnIfReached(); // no-warning 431 } 432 433 void testLifeExtensionWithNoReturnDtor() { 434 const CtorWithNoReturnDtor &c = CtorWithNoReturnDtor(); 435 436 // This represents an (expected) loss of coverage, since the destructor 437 // of the lifetime-exended temporary is executed at at the end of 438 // scope. 439 clang_analyzer_warnIfReached(); // no-warning 440 } 441 442 #endif // TEMPORARY_DTORS 443 } 444 445 void testStaticMaterializeTemporaryExpr() { 446 static const Trivial &ref = getTrivial(); 447 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} 448 449 static const Trivial &directRef = Trivial(42); 450 clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}} 451 452 #if __has_feature(cxx_thread_local) 453 thread_local static const Trivial &threadRef = getTrivial(); 454 clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}} 455 456 thread_local static const Trivial &threadDirectRef = Trivial(42); 457 clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}} 458 #endif 459 } 460 461 namespace PR16629 { 462 struct A { 463 explicit A(int* p_) : p(p_) {} 464 int* p; 465 }; 466 467 extern void escape(const A*[]); 468 extern void check(int); 469 470 void callEscape(const A& a) { 471 const A* args[] = { &a }; 472 escape(args); 473 } 474 475 void testNoWarning() { 476 int x; 477 callEscape(A(&x)); 478 check(x); // Analyzer used to give a "x is uninitialized warning" here 479 } 480 481 void set(const A*a[]) { 482 *a[0]->p = 47; 483 } 484 485 void callSet(const A& a) { 486 const A* args[] = { &a }; 487 set(args); 488 } 489 490 void testConsistency() { 491 int x; 492 callSet(A(&x)); 493 clang_analyzer_eval(x == 47); // expected-warning{{TRUE}} 494 } 495 } 496