1 // RUN: %clang_analyze_cc1 -w -analyzer-checker=core,cplusplus\ 2 // RUN: -analyzer-checker debug.ExprInspection -Wno-non-pod-varargs\ 3 // RUN: -analyzer-config eagerly-assume=false -verify %s\ 4 // RUN: -std=c++03 -analyzer-config cfg-temporary-dtors=false 5 6 // RUN: %clang_analyze_cc1 -w -analyzer-checker=core,cplusplus\ 7 // RUN: -analyzer-checker debug.ExprInspection -Wno-non-pod-varargs\ 8 // RUN: -analyzer-config eagerly-assume=false -verify %s\ 9 // RUN: -std=c++11 -analyzer-config cfg-temporary-dtors=false 10 11 // RUN: %clang_analyze_cc1 -w -analyzer-checker=core,cplusplus\ 12 // RUN: -analyzer-checker debug.ExprInspection -Wno-non-pod-varargs\ 13 // RUN: -analyzer-config eagerly-assume=false -verify %s\ 14 // RUN: -std=c++11 -analyzer-config cfg-temporary-dtors=true\ 15 // RUN: -DTEMPORARY_DTORS 16 17 // RUN: %clang_analyze_cc1 -w -analyzer-checker=core,cplusplus\ 18 // RUN: -analyzer-checker debug.ExprInspection -Wno-non-pod-varargs\ 19 // RUN: -analyzer-config eagerly-assume=false -verify %s\ 20 // RUN: -std=c++17 -analyzer-config cfg-temporary-dtors=true\ 21 // RUN: -DTEMPORARY_DTORS 22 23 24 extern bool clang_analyzer_eval(bool); 25 extern bool clang_analyzer_warnIfReached(); 26 void clang_analyzer_checkInlined(bool); 27 28 #include "Inputs/system-header-simulator-cxx.h" 29 30 struct Trivial { 31 Trivial(int x) : value(x) {} 32 int value; 33 }; 34 35 struct NonTrivial : public Trivial { 36 NonTrivial(int x) : Trivial(x) {} 37 ~NonTrivial(); 38 }; 39 40 41 Trivial getTrivial() { 42 return Trivial(42); // no-warning 43 } 44 45 const Trivial &getTrivialRef() { 46 return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'Trivial' returned to caller}} 47 } 48 49 50 NonTrivial getNonTrivial() { 51 return NonTrivial(42); // no-warning 52 } 53 54 const NonTrivial &getNonTrivialRef() { 55 return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}} 56 } 57 58 namespace rdar13265460 { 59 struct TrivialSubclass : public Trivial { 60 TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {} 61 int anotherValue; 62 }; 63 64 TrivialSubclass getTrivialSub() { 65 TrivialSubclass obj(1); 66 obj.value = 42; 67 obj.anotherValue = -42; 68 return obj; 69 } 70 71 void testImmediate() { 72 TrivialSubclass obj = getTrivialSub(); 73 74 clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}} 75 clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}} 76 77 clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}} 78 clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}} 79 } 80 81 void testMaterializeTemporaryExpr() { 82 const TrivialSubclass &ref = getTrivialSub(); 83 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} 84 85 const Trivial &baseRef = getTrivialSub(); 86 clang_analyzer_eval(baseRef.value == 42); // expected-warning{{TRUE}} 87 } 88 } 89 90 namespace rdar13281951 { 91 struct Derived : public Trivial { 92 Derived(int value) : Trivial(value), value2(-value) {} 93 int value2; 94 }; 95 96 void test() { 97 Derived obj(1); 98 obj.value = 42; 99 const Trivial * const &pointerRef = &obj; 100 clang_analyzer_eval(pointerRef->value == 42); // expected-warning{{TRUE}} 101 } 102 } 103 104 namespace compound_literals { 105 struct POD { 106 int x, y; 107 }; 108 struct HasCtor { 109 HasCtor(int x, int y) : x(x), y(y) {} 110 int x, y; 111 }; 112 struct HasDtor { 113 int x, y; 114 ~HasDtor(); 115 }; 116 struct HasCtorDtor { 117 HasCtorDtor(int x, int y) : x(x), y(y) {} 118 ~HasCtorDtor(); 119 int x, y; 120 }; 121 122 void test() { 123 clang_analyzer_eval(((POD){1, 42}).y == 42); // expected-warning{{TRUE}} 124 clang_analyzer_eval(((HasDtor){1, 42}).y == 42); // expected-warning{{TRUE}} 125 126 #if __cplusplus >= 201103L 127 clang_analyzer_eval(((HasCtor){1, 42}).y == 42); // expected-warning{{TRUE}} 128 129 // FIXME: should be TRUE, but we don't inline the constructors of 130 // temporaries because we can't model their destructors yet. 131 clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}} 132 #endif 133 } 134 } 135 136 namespace destructors { 137 struct Dtor { 138 ~Dtor(); 139 }; 140 extern bool coin(); 141 extern bool check(const Dtor &); 142 143 void testPR16664andPR18159Crash() { 144 // Regression test: we used to assert here when tmp dtors are enabled. 145 // PR16664 and PR18159 146 if (coin() && (coin() || coin() || check(Dtor()))) { 147 Dtor(); 148 } 149 } 150 151 #ifdef TEMPORARY_DTORS 152 struct NoReturnDtor { 153 ~NoReturnDtor() __attribute__((noreturn)); 154 }; 155 156 void noReturnTemp(int *x) { 157 if (! x) NoReturnDtor(); 158 *x = 47; // no warning 159 } 160 161 void noReturnInline(int **x) { 162 NoReturnDtor(); 163 } 164 165 void callNoReturn() { 166 int *x; 167 noReturnInline(&x); 168 *x = 47; // no warning 169 } 170 171 extern bool check(const NoReturnDtor &); 172 173 void testConsistencyIf(int i) { 174 if (i != 5) 175 return; 176 if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) { 177 clang_analyzer_eval(true); // no warning, unreachable code 178 } 179 } 180 181 void testConsistencyTernary(int i) { 182 (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0; 183 184 clang_analyzer_eval(true); // expected-warning{{TRUE}} 185 186 if (i != 5) 187 return; 188 189 (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0; 190 191 clang_analyzer_eval(true); // no warning, unreachable code 192 } 193 194 // Regression test: we used to assert here. 195 // PR16664 and PR18159 196 void testConsistencyNested(int i) { 197 extern bool compute(bool); 198 199 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 200 clang_analyzer_eval(true); // expected-warning{{TRUE}} 201 202 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 203 clang_analyzer_eval(true); // expected-warning{{TRUE}} 204 205 if (i != 5) 206 return; 207 208 if (compute(i == 5 && 209 (i == 4 || compute(true) || 210 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 211 i != 4) { 212 clang_analyzer_eval(true); // expected-warning{{TRUE}} 213 } 214 215 if (compute(i == 5 && 216 (i == 4 || i == 4 || 217 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 218 i != 4) { 219 clang_analyzer_eval(true); // no warning, unreachable code 220 } 221 } 222 223 // PR16664 and PR18159 224 void testConsistencyNestedSimple(bool value) { 225 if (value) { 226 if (!value || check(NoReturnDtor())) { 227 clang_analyzer_eval(true); // no warning, unreachable code 228 } 229 } 230 } 231 232 // PR16664 and PR18159 233 void testConsistencyNestedComplex(bool value) { 234 if (value) { 235 if (!value || !value || check(NoReturnDtor())) { 236 clang_analyzer_eval(true); // no warning, unreachable code 237 } 238 } 239 } 240 241 // PR16664 and PR18159 242 void testConsistencyNestedWarning(bool value) { 243 if (value) { 244 if (!value || value || check(NoReturnDtor())) { 245 clang_analyzer_eval(true); // expected-warning{{TRUE}} 246 } 247 } 248 } 249 // PR16664 and PR18159 250 void testConsistencyNestedComplexMidBranch(bool value) { 251 if (value) { 252 if (!value || !value || check(NoReturnDtor()) || value) { 253 clang_analyzer_eval(true); // no warning, unreachable code 254 } 255 } 256 } 257 258 // PR16664 and PR18159 259 void testConsistencyNestedComplexNestedBranch(bool value) { 260 if (value) { 261 if (!value || (!value || check(NoReturnDtor()) || value)) { 262 clang_analyzer_eval(true); // no warning, unreachable code 263 } 264 } 265 } 266 267 // PR16664 and PR18159 268 void testConsistencyNestedVariableModification(bool value) { 269 bool other = true; 270 if (value) { 271 if (!other || !value || (other = false) || check(NoReturnDtor()) || 272 !other) { 273 clang_analyzer_eval(true); // no warning, unreachable code 274 } 275 } 276 } 277 278 void testTernaryNoReturnTrueBranch(bool value) { 279 if (value) { 280 bool b = value && (value ? check(NoReturnDtor()) : true); 281 clang_analyzer_eval(true); // no warning, unreachable code 282 } 283 } 284 void testTernaryNoReturnFalseBranch(bool value) { 285 if (value) { 286 bool b = !value && !value ? true : check(NoReturnDtor()); 287 clang_analyzer_eval(true); // no warning, unreachable code 288 } 289 } 290 void testTernaryIgnoreNoreturnBranch(bool value) { 291 if (value) { 292 bool b = !value && !value ? check(NoReturnDtor()) : true; 293 clang_analyzer_eval(true); // expected-warning{{TRUE}} 294 } 295 } 296 void testTernaryTrueBranchReached(bool value) { 297 value ? clang_analyzer_warnIfReached() : // expected-warning{{REACHABLE}} 298 check(NoReturnDtor()); 299 } 300 void testTernaryFalseBranchReached(bool value) { 301 value ? check(NoReturnDtor()) : 302 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 303 } 304 305 void testLoop() { 306 for (int i = 0; i < 10; ++i) { 307 if (i < 3 && (i >= 2 || check(NoReturnDtor()))) { 308 clang_analyzer_eval(true); // no warning, unreachable code 309 } 310 } 311 } 312 313 bool testRecursiveFrames(bool isInner) { 314 if (isInner || 315 (clang_analyzer_warnIfReached(), false) || // expected-warning{{REACHABLE}} 316 check(NoReturnDtor()) || 317 testRecursiveFrames(true)) { 318 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 319 } 320 } 321 void testRecursiveFramesStart() { testRecursiveFrames(false); } 322 323 void testLambdas() { 324 []() { check(NoReturnDtor()); } != nullptr || check(Dtor()); 325 } 326 327 void testGnuExpressionStatements(int v) { 328 ({ ++v; v == 10 || check(NoReturnDtor()); v == 42; }) || v == 23; 329 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 330 331 ({ ++v; check(NoReturnDtor()); v == 42; }) || v == 23; 332 clang_analyzer_warnIfReached(); // no warning, unreachable code 333 } 334 335 void testGnuExpressionStatementsDestructionPoint(int v) { 336 // In normal context, the temporary destructor runs at the end of the full 337 // statement, thus the last statement is reached. 338 (++v, check(NoReturnDtor()), v == 42), 339 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 340 341 // GNU expression statements execute temporary destructors within the 342 // blocks, thus the last statement is not reached. 343 ({ ++v; check(NoReturnDtor()); v == 42; }), 344 clang_analyzer_warnIfReached(); // no warning, unreachable code 345 } 346 347 void testMultipleTemporaries(bool value) { 348 if (value) { 349 // FIXME: Find a way to verify construction order. 350 // ~Dtor should run before ~NoReturnDtor() because construction order is 351 // guaranteed by comma operator. 352 if (!value || check((NoReturnDtor(), Dtor())) || value) { 353 clang_analyzer_eval(true); // no warning, unreachable code 354 } 355 } 356 } 357 358 void testBinaryOperatorShortcut(bool value) { 359 if (value) { 360 if (false && false && check(NoReturnDtor()) && true) { 361 clang_analyzer_eval(true); 362 } 363 } 364 } 365 366 void testIfAtEndOfLoop() { 367 int y = 0; 368 while (true) { 369 if (y > 0) { 370 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 371 } 372 ++y; 373 // Test that the CFG gets hooked up correctly when temporary destructors 374 // are handled after a statically known branch condition. 375 if (true) (void)0; else (void)check(NoReturnDtor()); 376 } 377 } 378 379 void testTernaryAtEndOfLoop() { 380 int y = 0; 381 while (true) { 382 if (y > 0) { 383 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 384 } 385 ++y; 386 // Test that the CFG gets hooked up correctly when temporary destructors 387 // are handled after a statically known branch condition. 388 true ? (void)0 : (void)check(NoReturnDtor()); 389 } 390 } 391 392 void testNoReturnInComplexCondition() { 393 check(Dtor()) && 394 (check(NoReturnDtor()) || check(NoReturnDtor())) && check(Dtor()); 395 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 396 } 397 398 void testSequencingOfConditionalTempDtors(bool b) { 399 b || (check(Dtor()), check(NoReturnDtor())); 400 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 401 } 402 403 void testSequencingOfConditionalTempDtors2(bool b) { 404 (b || check(Dtor())), check(NoReturnDtor()); 405 clang_analyzer_warnIfReached(); // no warning, unreachable code 406 } 407 408 void testSequencingOfConditionalTempDtorsWithinBinaryOperators(bool b) { 409 b || (check(Dtor()) + check(NoReturnDtor())); 410 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 411 } 412 413 void f(Dtor d = Dtor()); 414 void testDefaultParameters() { 415 f(); 416 } 417 418 struct DefaultParam { 419 DefaultParam(int, const Dtor& d = Dtor()); 420 ~DefaultParam(); 421 }; 422 void testDefaultParamConstructorsInLoops() { 423 while (true) { 424 // FIXME: This exact pattern triggers the temporary cleanup logic 425 // to fail when adding a 'clean' state. 426 DefaultParam(42); 427 DefaultParam(42); 428 } 429 } 430 void testDefaultParamConstructorsInTernariesInLoops(bool value) { 431 while (true) { 432 // FIXME: This exact pattern triggers the temporary cleanup logic 433 // to visit the bind-temporary logic with a state that already has that 434 // temporary marked as executed. 435 value ? DefaultParam(42) : DefaultParam(42); 436 } 437 } 438 #else // !TEMPORARY_DTORS 439 440 // Test for fallback logic that conservatively stops exploration after 441 // executing a temporary constructor for a class with a no-return destructor 442 // when temporary destructors are not enabled in the CFG. 443 444 struct CtorWithNoReturnDtor { 445 CtorWithNoReturnDtor() = default; 446 447 CtorWithNoReturnDtor(int x) { 448 clang_analyzer_checkInlined(false); // no-warning 449 } 450 451 ~CtorWithNoReturnDtor() __attribute__((noreturn)); 452 }; 453 454 void testDefaultContructorWithNoReturnDtor() { 455 CtorWithNoReturnDtor(); 456 clang_analyzer_warnIfReached(); // no-warning 457 } 458 459 void testLifeExtensionWithNoReturnDtor() { 460 const CtorWithNoReturnDtor &c = CtorWithNoReturnDtor(); 461 462 // This represents an (expected) loss of coverage, since the destructor 463 // of the lifetime-exended temporary is executed at the end of 464 // scope. 465 clang_analyzer_warnIfReached(); // no-warning 466 } 467 468 #if __cplusplus >= 201103L 469 struct CtorWithNoReturnDtor2 { 470 CtorWithNoReturnDtor2() = default; 471 472 CtorWithNoReturnDtor2(int x) { 473 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 474 } 475 476 ~CtorWithNoReturnDtor2() __attribute__((noreturn)); 477 }; 478 CtorWithNoReturnDtor2 returnNoReturnDtor() { 479 return {1}; // no-crash 480 } 481 #endif 482 483 #endif // TEMPORARY_DTORS 484 } 485 486 namespace default_param_elided_destructors { 487 struct a { 488 ~a(); 489 }; 490 struct F { 491 a d; 492 F(char *, a = a()); 493 }; 494 void g() { 495 char h[1]; 496 for (int i = 0;;) 497 F j(i ? j : h); 498 } 499 } // namespace default_param_elided_destructors 500 501 void testStaticMaterializeTemporaryExpr() { 502 static const Trivial &ref = getTrivial(); 503 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} 504 505 static const Trivial &directRef = Trivial(42); 506 clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}} 507 508 #if __has_feature(cxx_thread_local) 509 thread_local static const Trivial &threadRef = getTrivial(); 510 clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}} 511 512 thread_local static const Trivial &threadDirectRef = Trivial(42); 513 clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}} 514 #endif 515 } 516 517 namespace PR16629 { 518 struct A { 519 explicit A(int* p_) : p(p_) {} 520 int* p; 521 }; 522 523 extern void escape(const A*[]); 524 extern void check(int); 525 526 void callEscape(const A& a) { 527 const A* args[] = { &a }; 528 escape(args); 529 } 530 531 void testNoWarning() { 532 int x; 533 callEscape(A(&x)); 534 check(x); // Analyzer used to give a "x is uninitialized warning" here 535 } 536 537 void set(const A*a[]) { 538 *a[0]->p = 47; 539 } 540 541 void callSet(const A& a) { 542 const A* args[] = { &a }; 543 set(args); 544 } 545 546 void testConsistency() { 547 int x; 548 callSet(A(&x)); 549 clang_analyzer_eval(x == 47); // expected-warning{{TRUE}} 550 } 551 } 552 553 namespace PR32088 { 554 void testReturnFromStmtExprInitializer() { 555 // We shouldn't try to destroy the object pointed to by `obj' upon return. 556 const NonTrivial &obj = ({ 557 return; // no-crash 558 NonTrivial(42); 559 }); 560 } 561 } 562 563 namespace CopyToTemporaryCorrectly { 564 class Super { 565 public: 566 void m() { 567 mImpl(); 568 } 569 virtual void mImpl() = 0; 570 }; 571 class Sub : public Super { 572 public: 573 Sub(const int &p) : j(p) {} 574 virtual void mImpl() override { 575 // Used to be undefined pointer dereference because we didn't copy 576 // the subclass data (j) to the temporary object properly. 577 (void)(j + 1); // no-warning 578 if (j != 22) { 579 clang_analyzer_warnIfReached(); // no-warning 580 } 581 } 582 const int &j; 583 }; 584 void run() { 585 int i = 22; 586 Sub(i).m(); 587 } 588 } 589 590 namespace test_return_temporary { 591 class C { 592 int x, y; 593 594 public: 595 C(int x, int y) : x(x), y(y) {} 596 int getX() const { return x; } 597 int getY() const { return y; } 598 ~C() {} 599 }; 600 601 class D: public C { 602 public: 603 D() : C(1, 2) {} 604 D(const D &d): C(d.getX(), d.getY()) {} 605 }; 606 607 C returnTemporaryWithVariable() { C c(1, 2); return c; } 608 C returnTemporaryWithAnotherFunctionWithVariable() { 609 return returnTemporaryWithVariable(); 610 } 611 C returnTemporaryWithCopyConstructionWithVariable() { 612 return C(returnTemporaryWithVariable()); 613 } 614 615 C returnTemporaryWithConstruction() { return C(1, 2); } 616 C returnTemporaryWithAnotherFunctionWithConstruction() { 617 return returnTemporaryWithConstruction(); 618 } 619 C returnTemporaryWithCopyConstructionWithConstruction() { 620 return C(returnTemporaryWithConstruction()); 621 } 622 623 D returnTemporaryWithVariableAndNonTrivialCopy() { D d; return d; } 624 D returnTemporaryWithAnotherFunctionWithVariableAndNonTrivialCopy() { 625 return returnTemporaryWithVariableAndNonTrivialCopy(); 626 } 627 D returnTemporaryWithCopyConstructionWithVariableAndNonTrivialCopy() { 628 return D(returnTemporaryWithVariableAndNonTrivialCopy()); 629 } 630 631 #if __cplusplus >= 201103L 632 C returnTemporaryWithBraces() { return {1, 2}; } 633 C returnTemporaryWithAnotherFunctionWithBraces() { 634 return returnTemporaryWithBraces(); 635 } 636 C returnTemporaryWithCopyConstructionWithBraces() { 637 return C(returnTemporaryWithBraces()); 638 } 639 #endif // C++11 640 641 void test() { 642 C c1 = returnTemporaryWithVariable(); 643 clang_analyzer_eval(c1.getX() == 1); // expected-warning{{TRUE}} 644 clang_analyzer_eval(c1.getY() == 2); // expected-warning{{TRUE}} 645 646 C c2 = returnTemporaryWithAnotherFunctionWithVariable(); 647 clang_analyzer_eval(c2.getX() == 1); // expected-warning{{TRUE}} 648 clang_analyzer_eval(c2.getY() == 2); // expected-warning{{TRUE}} 649 650 C c3 = returnTemporaryWithCopyConstructionWithVariable(); 651 clang_analyzer_eval(c3.getX() == 1); // expected-warning{{TRUE}} 652 clang_analyzer_eval(c3.getY() == 2); // expected-warning{{TRUE}} 653 654 C c4 = returnTemporaryWithConstruction(); 655 clang_analyzer_eval(c4.getX() == 1); // expected-warning{{TRUE}} 656 clang_analyzer_eval(c4.getY() == 2); // expected-warning{{TRUE}} 657 658 C c5 = returnTemporaryWithAnotherFunctionWithConstruction(); 659 clang_analyzer_eval(c5.getX() == 1); // expected-warning{{TRUE}} 660 clang_analyzer_eval(c5.getY() == 2); // expected-warning{{TRUE}} 661 662 C c6 = returnTemporaryWithCopyConstructionWithConstruction(); 663 clang_analyzer_eval(c5.getX() == 1); // expected-warning{{TRUE}} 664 clang_analyzer_eval(c5.getY() == 2); // expected-warning{{TRUE}} 665 666 #if __cplusplus >= 201103L 667 668 C c7 = returnTemporaryWithBraces(); 669 clang_analyzer_eval(c7.getX() == 1); // expected-warning{{TRUE}} 670 clang_analyzer_eval(c7.getY() == 2); // expected-warning{{TRUE}} 671 672 C c8 = returnTemporaryWithAnotherFunctionWithBraces(); 673 clang_analyzer_eval(c8.getX() == 1); // expected-warning{{TRUE}} 674 clang_analyzer_eval(c8.getY() == 2); // expected-warning{{TRUE}} 675 676 C c9 = returnTemporaryWithCopyConstructionWithBraces(); 677 clang_analyzer_eval(c9.getX() == 1); // expected-warning{{TRUE}} 678 clang_analyzer_eval(c9.getY() == 2); // expected-warning{{TRUE}} 679 680 #endif // C++11 681 682 D d1 = returnTemporaryWithVariableAndNonTrivialCopy(); 683 clang_analyzer_eval(d1.getX() == 1); // expected-warning{{TRUE}} 684 clang_analyzer_eval(d1.getY() == 2); // expected-warning{{TRUE}} 685 686 D d2 = returnTemporaryWithAnotherFunctionWithVariableAndNonTrivialCopy(); 687 clang_analyzer_eval(d2.getX() == 1); // expected-warning{{TRUE}} 688 clang_analyzer_eval(d2.getY() == 2); // expected-warning{{TRUE}} 689 690 D d3 = returnTemporaryWithCopyConstructionWithVariableAndNonTrivialCopy(); 691 clang_analyzer_eval(d3.getX() == 1); // expected-warning{{TRUE}} 692 clang_analyzer_eval(d3.getY() == 2); // expected-warning{{TRUE}} 693 } 694 } // namespace test_return_temporary 695 696 697 namespace test_temporary_object_expr_without_dtor { 698 class C { 699 int x; 700 public: 701 C(int x) : x(x) {} 702 int getX() const { return x; } 703 }; 704 705 void test() { 706 clang_analyzer_eval(C(3).getX() == 3); // expected-warning{{TRUE}} 707 }; 708 } 709 710 namespace test_temporary_object_expr_with_dtor { 711 class C { 712 int x; 713 714 public: 715 C(int x) : x(x) {} 716 ~C() {} 717 int getX() const { return x; } 718 }; 719 720 void test(int coin) { 721 clang_analyzer_eval(C(3).getX() == 3); 722 #ifdef TEMPORARY_DTORS 723 // expected-warning@-2{{TRUE}} 724 #else 725 // expected-warning@-4{{UNKNOWN}} 726 #endif 727 728 const C &c1 = coin ? C(1) : C(2); 729 if (coin) { 730 clang_analyzer_eval(c1.getX() == 1); 731 #ifdef TEMPORARY_DTORS 732 // expected-warning@-2{{TRUE}} 733 #else 734 // expected-warning@-4{{UNKNOWN}} 735 #endif 736 } else { 737 clang_analyzer_eval(c1.getX() == 2); 738 #ifdef TEMPORARY_DTORS 739 // expected-warning@-2{{TRUE}} 740 #else 741 // expected-warning@-4{{UNKNOWN}} 742 #endif 743 } 744 745 C c2 = coin ? C(1) : C(2); 746 if (coin) { 747 clang_analyzer_eval(c2.getX() == 1); // expected-warning{{TRUE}} 748 } else { 749 clang_analyzer_eval(c2.getX() == 2); // expected-warning{{TRUE}} 750 } 751 } 752 753 } // namespace test_temporary_object_expr 754 755 namespace test_match_constructors_and_destructors { 756 class C { 757 public: 758 int &x, &y; 759 C(int &_x, int &_y) : x(_x), y(_y) { ++x; } 760 C(const C &c): x(c.x), y(c.y) { ++x; } 761 ~C() { ++y; } 762 }; 763 764 void test_simple_temporary() { 765 int x = 0, y = 0; 766 { 767 const C &c = C(x, y); 768 } 769 // One constructor and one destructor. 770 clang_analyzer_eval(x == 1); 771 clang_analyzer_eval(y == 1); 772 #ifdef TEMPORARY_DTORS 773 // expected-warning@-3{{TRUE}} 774 // expected-warning@-3{{TRUE}} 775 #else 776 // expected-warning@-6{{UNKNOWN}} 777 // expected-warning@-6{{UNKNOWN}} 778 #endif 779 } 780 781 void test_simple_temporary_with_copy() { 782 int x = 0, y = 0; 783 { 784 C c = C(x, y); 785 } 786 // Only one constructor directly into the variable, and one destructor. 787 clang_analyzer_eval(x == 1); // expected-warning{{TRUE}} 788 clang_analyzer_eval(y == 1); // expected-warning{{TRUE}} 789 } 790 791 void test_ternary_temporary(int coin) { 792 int x = 0, y = 0, z = 0, w = 0; 793 { 794 const C &c = coin ? C(x, y) : C(z, w); 795 } 796 // Only one constructor on every branch, and one automatic destructor. 797 if (coin) { 798 clang_analyzer_eval(x == 1); 799 clang_analyzer_eval(y == 1); 800 #ifdef TEMPORARY_DTORS 801 // expected-warning@-3{{TRUE}} 802 // expected-warning@-3{{TRUE}} 803 #else 804 // expected-warning@-6{{UNKNOWN}} 805 // expected-warning@-6{{UNKNOWN}} 806 #endif 807 clang_analyzer_eval(z == 0); // expected-warning{{TRUE}} 808 clang_analyzer_eval(w == 0); // expected-warning{{TRUE}} 809 810 } else { 811 clang_analyzer_eval(x == 0); // expected-warning{{TRUE}} 812 clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} 813 clang_analyzer_eval(z == 1); 814 clang_analyzer_eval(w == 1); 815 #ifdef TEMPORARY_DTORS 816 // expected-warning@-3{{TRUE}} 817 // expected-warning@-3{{TRUE}} 818 #else 819 // expected-warning@-6{{UNKNOWN}} 820 // expected-warning@-6{{UNKNOWN}} 821 #endif 822 } 823 } 824 825 void test_ternary_temporary_with_copy(int coin) { 826 int x = 0, y = 0, z = 0, w = 0; 827 { 828 C c = coin ? C(x, y) : C(z, w); 829 } 830 // On each branch the variable is constructed directly. 831 if (coin) { 832 clang_analyzer_eval(x == 1); // expected-warning{{TRUE}} 833 #if __cplusplus < 201703L 834 clang_analyzer_eval(y == 1); // expected-warning{{TRUE}} 835 #else 836 // FIXME: Destructor called twice in C++17? 837 clang_analyzer_eval(y == 2); // expected-warning{{TRUE}} 838 #endif 839 clang_analyzer_eval(z == 0); // expected-warning{{TRUE}} 840 clang_analyzer_eval(w == 0); // expected-warning{{TRUE}} 841 842 } else { 843 clang_analyzer_eval(x == 0); // expected-warning{{TRUE}} 844 clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} 845 clang_analyzer_eval(z == 1); // expected-warning{{TRUE}} 846 #if __cplusplus < 201703L 847 clang_analyzer_eval(w == 1); // expected-warning{{TRUE}} 848 #else 849 // FIXME: Destructor called twice in C++17? 850 clang_analyzer_eval(w == 2); // expected-warning{{TRUE}} 851 #endif 852 } 853 } 854 } // namespace test_match_constructors_and_destructors 855 856 namespace destructors_for_return_values { 857 858 class C { 859 public: 860 ~C() { 861 1 / 0; // expected-warning{{Division by zero}} 862 } 863 }; 864 865 C make(); 866 867 void testFloatingCall() { 868 make(); 869 // Should have divided by zero in the destructor. 870 clang_analyzer_warnIfReached(); 871 #ifndef TEMPORARY_DTORS 872 // expected-warning@-2{{REACHABLE}} 873 #endif 874 } 875 876 void testLifetimeExtendedCall() { 877 { 878 const C &c = make(); 879 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 880 } 881 // Should have divided by zero in the destructor. 882 clang_analyzer_warnIfReached(); // no-warning 883 } 884 885 void testCopiedCall() { 886 { 887 C c = make(); 888 // Should have elided the constructor/destructor for the temporary 889 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 890 } 891 // Should have divided by zero in the destructor. 892 clang_analyzer_warnIfReached(); // no-warning 893 } 894 } // namespace destructors_for_return_values 895 896 namespace dont_forget_destructor_around_logical_op { 897 int glob; 898 899 class C { 900 public: 901 ~C() { 902 glob = 1; 903 // FIXME: Why is destructor not inlined in C++17 904 clang_analyzer_checkInlined(true); 905 #ifdef TEMPORARY_DTORS 906 #if __cplusplus < 201703L 907 // expected-warning@-3{{TRUE}} 908 #endif 909 #endif 910 } 911 }; 912 913 C get(); 914 915 bool is(C); 916 917 918 void test(int coin) { 919 // Here temporaries are being cleaned up after && is evaluated. There are two 920 // temporaries: the return value of get() and the elidable copy constructor 921 // of that return value into is(). According to the CFG, we need to cleanup 922 // both of them depending on whether the temporary corresponding to the 923 // return value of get() was initialized. However, we didn't track 924 // temporaries returned from functions, so we took the wrong branch. 925 coin && is(get()); // no-crash 926 if (coin) { 927 // FIXME: Why is destructor not inlined in C++17 928 clang_analyzer_eval(glob); 929 #ifdef TEMPORARY_DTORS 930 #if __cplusplus < 201703L 931 // expected-warning@-3{{TRUE}} 932 #else 933 // expected-warning@-5{{UNKNOWN}} 934 #endif 935 #else 936 // expected-warning@-8{{UNKNOWN}} 937 #endif 938 } else { 939 // The destructor is not called on this branch. 940 clang_analyzer_eval(glob); // expected-warning{{UNKNOWN}} 941 } 942 } 943 } // namespace dont_forget_destructor_around_logical_op 944 945 #if __cplusplus >= 201103L 946 namespace temporary_list_crash { 947 class C { 948 public: 949 C() {} 950 ~C() {} 951 }; 952 953 void test() { 954 std::initializer_list<C>{C(), C()}; // no-crash 955 } 956 } // namespace temporary_list_crash 957 #endif // C++11 958 959 namespace implicit_constructor_conversion { 960 struct S { 961 int x; 962 S(int x) : x(x) {} 963 ~S() {} 964 }; 965 966 class C { 967 int x; 968 969 public: 970 C(const S &s) : x(s.x) {} 971 ~C() {} 972 int getX() const { return x; } 973 }; 974 975 void test() { 976 const C &c1 = S(10); 977 clang_analyzer_eval(c1.getX() == 10); 978 #ifdef TEMPORARY_DTORS 979 // expected-warning@-2{{TRUE}} 980 #else 981 // expected-warning@-4{{UNKNOWN}} 982 #endif 983 984 S s = 20; 985 clang_analyzer_eval(s.x == 20); // expected-warning{{TRUE}} 986 987 C c2 = s; 988 clang_analyzer_eval(c2.getX() == 20); // expected-warning{{TRUE}} 989 } 990 } // end namespace implicit_constructor_conversion 991 992 namespace pass_references_through { 993 class C { 994 public: 995 ~C() {} 996 }; 997 998 const C &foo1(); 999 C &&foo2(); 1000 1001 // In these examples the foo() expression has record type, not reference type. 1002 // Don't try to figure out how to perform construction of the record here. 1003 const C &bar1() { return foo1(); } // no-crash 1004 C &&bar2() { return foo2(); } // no-crash 1005 } // end namespace pass_references_through 1006 1007 1008 namespace arguments { 1009 int glob; 1010 1011 struct S { 1012 int x; 1013 S(int x): x(x) {} 1014 S(const S &s) : x(s.x) {} 1015 ~S() {} 1016 1017 S &operator+(S s) { 1018 glob = s.x; 1019 x += s.x; 1020 return *this; 1021 } 1022 }; 1023 1024 class C { 1025 public: 1026 virtual void bar3(S s) {} 1027 }; 1028 1029 class D: public C { 1030 public: 1031 D() {} 1032 virtual void bar3(S s) override { glob = s.x; } 1033 }; 1034 1035 void bar1(S s) { 1036 glob = s.x; 1037 } 1038 1039 // Record-typed calls are a different CFGStmt, let's see if we handle that 1040 // as well. 1041 S bar2(S s) { 1042 glob = s.x; 1043 return S(3); 1044 } 1045 1046 void bar5(int, ...); 1047 1048 void foo(void (*bar4)(S)) { 1049 bar1(S(1)); 1050 clang_analyzer_eval(glob == 1); 1051 #ifdef TEMPORARY_DTORS 1052 // expected-warning@-2{{TRUE}} 1053 #else 1054 // expected-warning@-4{{UNKNOWN}} 1055 #endif 1056 1057 bar2(S(2)); 1058 // FIXME: Why are we losing information in C++17? 1059 clang_analyzer_eval(glob == 2); 1060 #ifdef TEMPORARY_DTORS 1061 #if __cplusplus < 201703L 1062 // expected-warning@-3{{TRUE}} 1063 #else 1064 // expected-warning@-5{{UNKNOWN}} 1065 #endif 1066 #else 1067 // expected-warning@-8{{UNKNOWN}} 1068 #endif 1069 1070 C *c = new D(); 1071 c->bar3(S(3)); 1072 // FIXME: Should be TRUE. 1073 clang_analyzer_eval(glob == 3); // expected-warning{{UNKNOWN}} 1074 delete c; 1075 1076 // What if we've no idea what we're calling? 1077 bar4(S(4)); // no-crash 1078 1079 S(5) + S(6); 1080 clang_analyzer_eval(glob == 6); 1081 #ifdef TEMPORARY_DTORS 1082 // expected-warning@-2{{TRUE}} 1083 #else 1084 // expected-warning@-4{{UNKNOWN}} 1085 #endif 1086 1087 // Variadic functions. This will __builtin_trap() because you cannot pass 1088 // an object as a variadic argument. 1089 bar5(7, S(7)); // no-crash 1090 clang_analyzer_warnIfReached(); // no-warning 1091 } 1092 } // namespace arguments 1093 1094 namespace ctor_argument { 1095 // Stripped down unique_ptr<int> 1096 struct IntPtr { 1097 IntPtr(): i(new int) {} 1098 IntPtr(IntPtr &&o): i(o.i) { o.i = 0; } 1099 ~IntPtr() { delete i; } 1100 1101 int *i; 1102 }; 1103 1104 struct Foo { 1105 Foo(IntPtr); 1106 void bar(); 1107 1108 IntPtr i; 1109 }; 1110 1111 void bar() { 1112 IntPtr ptr; 1113 int *i = ptr.i; 1114 Foo f(static_cast<IntPtr &&>(ptr)); 1115 *i = 99; // no-warning 1116 } 1117 } // namespace ctor_argument 1118 1119 namespace operator_implicit_argument { 1120 struct S { 1121 bool x; 1122 S(bool x): x(x) {} 1123 operator bool() const { return x; } 1124 }; 1125 1126 void foo() { 1127 if (S(false)) { 1128 clang_analyzer_warnIfReached(); // no-warning 1129 } 1130 if (S(true)) { 1131 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 1132 } 1133 } 1134 } // namespace operator_implicit_argument 1135 1136 1137 #if __cplusplus >= 201103L 1138 namespace argument_lazy_bindings { 1139 int glob; 1140 1141 struct S { 1142 int x, y, z; 1143 }; 1144 1145 struct T { 1146 S s; 1147 int w; 1148 T(int w): s{5, 6, 7}, w(w) {} 1149 }; 1150 1151 void foo(T t) { 1152 t.s = {1, 2, 3}; 1153 glob = t.w; 1154 } 1155 1156 void bar() { 1157 foo(T(4)); 1158 clang_analyzer_eval(glob == 4); // expected-warning{{TRUE}} 1159 } 1160 } // namespace argument_lazy_bindings 1161 #endif 1162 1163 namespace operator_argument_cleanup { 1164 struct S { 1165 S(); 1166 }; 1167 1168 class C { 1169 public: 1170 void operator=(S); 1171 }; 1172 1173 void foo() { 1174 C c; 1175 c = S(); // no-crash 1176 } 1177 } // namespace operator_argument_cleanup 1178 1179 namespace argument_decl_lookup { 1180 class C {}; 1181 int foo(C); 1182 int bar(C c) { foo(c); } 1183 int foo(C c) {} 1184 } // namespace argument_decl_lookup 1185 1186 namespace argument_virtual_decl_lookup { 1187 class C {}; 1188 1189 struct T { 1190 virtual void foo(C); 1191 }; 1192 1193 void run() { 1194 T *t; 1195 t->foo(C()); // no-crash // expected-warning{{Called C++ object pointer is uninitialized}} 1196 } 1197 1198 // This is after run() because the test is about picking the correct decl 1199 // for the parameter region, which should belong to the correct function decl, 1200 // and the non-definition decl should be found by direct lookup. 1201 void T::foo(C) {} 1202 } // namespace argument_virtual_decl_lookup 1203 1204 namespace union_indirect_field_crash { 1205 union U { 1206 struct { 1207 int x; 1208 }; 1209 }; 1210 1211 template <typename T> class C { 1212 public: 1213 void foo() const { 1214 (void)(true ? U().x : 0); 1215 } 1216 }; 1217 1218 void test() { 1219 C<int> c; 1220 c.foo(); 1221 } 1222 } // namespace union_indirect_field_crash 1223 1224 namespace return_from_top_frame { 1225 struct S { 1226 int *p; 1227 S() { p = new int; } 1228 S(S &&s) : p(s.p) { s.p = 0; } 1229 ~S(); // Presumably releases 'p'. 1230 }; 1231 1232 S foo() { 1233 S s; 1234 return s; 1235 } 1236 1237 S bar1() { 1238 return foo(); // no-warning 1239 } 1240 1241 S bar2() { 1242 return S(); 1243 } 1244 1245 S bar3(int coin) { 1246 return coin ? S() : foo(); // no-warning 1247 } 1248 } // namespace return_from_top_frame 1249