1242 lines · cpp
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=false5 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=false10 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_DTORS16 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_DTORS22 23 24extern bool clang_analyzer_eval(bool);25extern bool clang_analyzer_warnIfReached();26void clang_analyzer_checkInlined(bool);27 28#include "Inputs/system-header-simulator-cxx.h"29 30struct Trivial {31 Trivial(int x) : value(x) {}32 int value;33};34 35struct NonTrivial : public Trivial {36 NonTrivial(int x) : Trivial(x) {}37 ~NonTrivial();38};39 40 41Trivial getTrivial() {42 return Trivial(42); // no-warning43}44 45const 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 50NonTrivial getNonTrivial() {51 return NonTrivial(42); // no-warning52}53 54const NonTrivial &getNonTrivialRef() {55 return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}}56}57 58namespace 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 90namespace 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 104namespace 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 >= 201103L127 clang_analyzer_eval(((HasCtor){1, 42}).y == 42); // expected-warning{{TRUE}}128 129 // FIXME: should be TRUE, but we don't inline the constructors of130 // temporaries because we can't model their destructors yet.131 clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}}132#endif133 }134}135 136namespace 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 PR18159146 if (coin() && (coin() || coin() || check(Dtor()))) {147 Dtor();148 }149 }150 151#ifdef TEMPORARY_DTORS152 struct NoReturnDtor {153 ~NoReturnDtor() __attribute__((noreturn));154 };155 156 void noReturnTemp(int *x) {157 if (! x) NoReturnDtor();158 *x = 47; // no warning159 }160 161 void noReturnInline(int **x) {162 NoReturnDtor();163 }164 165 void callNoReturn() {166 int *x;167 noReturnInline(&x);168 *x = 47; // no warning169 }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 code178 }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 code192 }193 194 // Regression test: we used to assert here.195 // PR16664 and PR18159196 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 code220 }221 }222 223 // PR16664 and PR18159224 void testConsistencyNestedSimple(bool value) {225 if (value) {226 if (!value || check(NoReturnDtor())) {227 clang_analyzer_eval(true); // no warning, unreachable code228 }229 }230 }231 232 // PR16664 and PR18159233 void testConsistencyNestedComplex(bool value) {234 if (value) {235 if (!value || !value || check(NoReturnDtor())) {236 clang_analyzer_eval(true); // no warning, unreachable code237 }238 }239 }240 241 // PR16664 and PR18159242 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 PR18159250 void testConsistencyNestedComplexMidBranch(bool value) {251 if (value) {252 if (!value || !value || check(NoReturnDtor()) || value) {253 clang_analyzer_eval(true); // no warning, unreachable code254 }255 }256 }257 258 // PR16664 and PR18159259 void testConsistencyNestedComplexNestedBranch(bool value) {260 if (value) {261 if (!value || (!value || check(NoReturnDtor()) || value)) {262 clang_analyzer_eval(true); // no warning, unreachable code263 }264 }265 }266 267 // PR16664 and PR18159268 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 code274 }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 code282 }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 code288 }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 code309 }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 code333 }334 335 void testGnuExpressionStatementsDestructionPoint(int v) {336 // In normal context, the temporary destructor runs at the end of the full337 // 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 the342 // blocks, thus the last statement is not reached.343 ({ ++v; check(NoReturnDtor()); v == 42; }),344 clang_analyzer_warnIfReached(); // no warning, unreachable code345 }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 is351 // guaranteed by comma operator.352 if (!value || check((NoReturnDtor(), Dtor())) || value) {353 clang_analyzer_eval(true); // no warning, unreachable code354 }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 destructors374 // 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 destructors387 // 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 code406 }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 logic425 // 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 logic433 // to visit the bind-temporary logic with a state that already has that434 // temporary marked as executed.435 value ? DefaultParam(42) : DefaultParam(42);436 }437 }438#else // !TEMPORARY_DTORS439 440// Test for fallback logic that conservatively stops exploration after441// executing a temporary constructor for a class with a no-return destructor442// 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-warning449 }450 451 ~CtorWithNoReturnDtor() __attribute__((noreturn));452 };453 454 void testDefaultContructorWithNoReturnDtor() {455 CtorWithNoReturnDtor();456 clang_analyzer_warnIfReached(); // no-warning457 }458 459 void testLifeExtensionWithNoReturnDtor() {460 const CtorWithNoReturnDtor &c = CtorWithNoReturnDtor();461 462 // This represents an (expected) loss of coverage, since the destructor463 // of the lifetime-exended temporary is executed at the end of464 // scope.465 clang_analyzer_warnIfReached(); // no-warning466 }467 468#if __cplusplus >= 201103L469 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-crash480 }481#endif482 483#endif // TEMPORARY_DTORS484}485 486namespace default_param_elided_destructors {487struct a {488 ~a();489};490struct F {491 a d;492 F(char *, a = a());493};494void g() {495 char h[1];496 for (int i = 0;;)497 F j(i ? j : h);498}499} // namespace default_param_elided_destructors500 501void 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#endif515}516 517namespace 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" here535 }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 553namespace 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-crash558 NonTrivial(42);559 });560 }561}562 563namespace CopyToTemporaryCorrectly {564class Super {565public:566 void m() {567 mImpl();568 }569 virtual void mImpl() = 0;570};571class Sub : public Super {572public:573 Sub(const int &p) : j(p) {}574 virtual void mImpl() override {575 // Used to be undefined pointer dereference because we didn't copy576 // the subclass data (j) to the temporary object properly.577 (void)(j + 1); // no-warning578 if (j != 22) {579 clang_analyzer_warnIfReached(); // no-warning580 }581 }582 const int &j;583};584void run() {585 int i = 22;586 Sub(i).m();587}588}589 590namespace test_return_temporary {591class C {592 int x, y;593 594public: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 601class D: public C {602public:603 D() : C(1, 2) {}604 D(const D &d): C(d.getX(), d.getY()) {}605};606 607C returnTemporaryWithVariable() { C c(1, 2); return c; }608C returnTemporaryWithAnotherFunctionWithVariable() {609 return returnTemporaryWithVariable();610}611C returnTemporaryWithCopyConstructionWithVariable() {612 return C(returnTemporaryWithVariable());613}614 615C returnTemporaryWithConstruction() { return C(1, 2); }616C returnTemporaryWithAnotherFunctionWithConstruction() {617 return returnTemporaryWithConstruction();618}619C returnTemporaryWithCopyConstructionWithConstruction() {620 return C(returnTemporaryWithConstruction());621}622 623D returnTemporaryWithVariableAndNonTrivialCopy() { D d; return d; }624D returnTemporaryWithAnotherFunctionWithVariableAndNonTrivialCopy() {625 return returnTemporaryWithVariableAndNonTrivialCopy();626}627D returnTemporaryWithCopyConstructionWithVariableAndNonTrivialCopy() {628 return D(returnTemporaryWithVariableAndNonTrivialCopy());629}630 631#if __cplusplus >= 201103L632C returnTemporaryWithBraces() { return {1, 2}; }633C returnTemporaryWithAnotherFunctionWithBraces() {634 return returnTemporaryWithBraces();635}636C returnTemporaryWithCopyConstructionWithBraces() {637 return C(returnTemporaryWithBraces());638}639#endif // C++11640 641void 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 >= 201103L667 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++11681 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_temporary695 696 697namespace test_temporary_object_expr_without_dtor {698class C {699 int x;700public:701 C(int x) : x(x) {}702 int getX() const { return x; }703};704 705void test() {706 clang_analyzer_eval(C(3).getX() == 3); // expected-warning{{TRUE}}707};708}709 710namespace test_temporary_object_expr_with_dtor {711class C {712 int x;713 714public:715 C(int x) : x(x) {}716 ~C() {}717 int getX() const { return x; }718};719 720void test(int coin) {721 clang_analyzer_eval(C(3).getX() == 3);722#ifdef TEMPORARY_DTORS723 // expected-warning@-2{{TRUE}}724#else725 // expected-warning@-4{{UNKNOWN}}726#endif727 728 const C &c1 = coin ? C(1) : C(2);729 if (coin) {730 clang_analyzer_eval(c1.getX() == 1);731#ifdef TEMPORARY_DTORS732 // expected-warning@-2{{TRUE}}733#else734 // expected-warning@-4{{UNKNOWN}}735#endif736 } else {737 clang_analyzer_eval(c1.getX() == 2);738#ifdef TEMPORARY_DTORS739 // expected-warning@-2{{TRUE}}740#else741 // expected-warning@-4{{UNKNOWN}}742#endif743 }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_expr754 755namespace test_match_constructors_and_destructors {756class C {757public: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 764void 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_DTORS773 // expected-warning@-3{{TRUE}}774 // expected-warning@-3{{TRUE}}775#else776 // expected-warning@-6{{UNKNOWN}}777 // expected-warning@-6{{UNKNOWN}}778#endif779}780 781void 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 791void 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_DTORS801 // expected-warning@-3{{TRUE}}802 // expected-warning@-3{{TRUE}}803#else804 // expected-warning@-6{{UNKNOWN}}805 // expected-warning@-6{{UNKNOWN}}806#endif807 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_DTORS816 // expected-warning@-3{{TRUE}}817 // expected-warning@-3{{TRUE}}818#else819 // expected-warning@-6{{UNKNOWN}}820 // expected-warning@-6{{UNKNOWN}}821#endif822 }823}824 825void 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 clang_analyzer_eval(y == 1); // expected-warning{{TRUE}}834 clang_analyzer_eval(z == 0); // expected-warning{{TRUE}}835 clang_analyzer_eval(w == 0); // expected-warning{{TRUE}}836 837 } else {838 clang_analyzer_eval(x == 0); // expected-warning{{TRUE}}839 clang_analyzer_eval(y == 0); // expected-warning{{TRUE}}840 clang_analyzer_eval(z == 1); // expected-warning{{TRUE}}841 clang_analyzer_eval(w == 1); // expected-warning{{TRUE}}842 }843}844} // namespace test_match_constructors_and_destructors845 846namespace destructors_for_return_values {847 848class C {849public:850 ~C() {851 1 / 0; // expected-warning{{Division by zero}}852 }853};854 855C make();856 857void testFloatingCall() {858 make();859 // Should have divided by zero in the destructor.860 clang_analyzer_warnIfReached();861#ifndef TEMPORARY_DTORS862 // expected-warning@-2{{REACHABLE}}863#endif864}865 866void testLifetimeExtendedCall() {867 {868 const C &c = make();869 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}870 }871 // Should have divided by zero in the destructor.872 clang_analyzer_warnIfReached(); // no-warning873}874 875void testCopiedCall() {876 {877 C c = make();878 // Should have elided the constructor/destructor for the temporary879 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}880 }881 // Should have divided by zero in the destructor.882 clang_analyzer_warnIfReached(); // no-warning883}884} // namespace destructors_for_return_values885 886namespace dont_forget_destructor_around_logical_op {887int glob;888 889class C {890public:891 ~C() {892 glob = 1;893 clang_analyzer_checkInlined(true);894#ifdef TEMPORARY_DTORS895 // expected-warning@-2{{TRUE}}896#endif897 }898};899 900C get();901 902bool is(C);903 904 905void test(int coin) {906 // Here temporaries are being cleaned up after && is evaluated. There are two907 // temporaries: the return value of get() and the elidable copy constructor908 // of that return value into is(). According to the CFG, we need to cleanup909 // both of them depending on whether the temporary corresponding to the910 // return value of get() was initialized. However, we didn't track911 // temporaries returned from functions, so we took the wrong branch.912 coin && is(get()); // no-crash913 if (coin) {914 clang_analyzer_eval(glob);915#ifdef TEMPORARY_DTORS916 // expected-warning@-2{{TRUE}}917#else918 // expected-warning@-4{{UNKNOWN}}919#endif920 } else {921 // The destructor is not called on this branch.922 clang_analyzer_eval(glob); // expected-warning{{UNKNOWN}}923 }924}925} // namespace dont_forget_destructor_around_logical_op926 927#if __cplusplus >= 201103L928namespace temporary_list_crash {929class C {930public:931 C() {}932 ~C() {}933};934 935void test() {936 std::initializer_list<C>{C(), C()}; // no-crash937}938} // namespace temporary_list_crash939#endif // C++11940 941namespace implicit_constructor_conversion {942struct S {943 int x;944 S(int x) : x(x) {}945 ~S() {}946};947 948class C {949 int x;950 951public:952 C(const S &s) : x(s.x) {}953 ~C() {}954 int getX() const { return x; }955};956 957void test() {958 const C &c1 = S(10);959 clang_analyzer_eval(c1.getX() == 10);960#ifdef TEMPORARY_DTORS961 // expected-warning@-2{{TRUE}}962#else963 // expected-warning@-4{{UNKNOWN}}964#endif965 966 S s = 20;967 clang_analyzer_eval(s.x == 20); // expected-warning{{TRUE}}968 969 C c2 = s;970 clang_analyzer_eval(c2.getX() == 20); // expected-warning{{TRUE}}971}972} // end namespace implicit_constructor_conversion973 974namespace pass_references_through {975class C {976public:977 ~C() {}978};979 980const C &foo1();981C &&foo2();982 983// In these examples the foo() expression has record type, not reference type.984// Don't try to figure out how to perform construction of the record here.985const C &bar1() { return foo1(); } // no-crash986C &&bar2() { return foo2(); } // no-crash987} // end namespace pass_references_through988 989 990namespace arguments {991int glob;992 993struct S {994 int x;995 S(int x): x(x) {}996 S(const S &s) : x(s.x) {}997 ~S() {}998 999 S &operator+(S s) {1000 glob = s.x;1001 x += s.x;1002 return *this;1003 }1004};1005 1006class C {1007public:1008 virtual void bar3(S s) {}1009};1010 1011class D: public C {1012public:1013 D() {}1014 virtual void bar3(S s) override { glob = s.x; }1015};1016 1017void bar1(S s) {1018 glob = s.x;1019}1020 1021// Record-typed calls are a different CFGStmt, let's see if we handle that1022// as well.1023S bar2(S s) {1024 glob = s.x;1025 return S(3);1026}1027 1028void bar5(int, ...);1029 1030void foo(void (*bar4)(S)) {1031 bar1(S(1));1032 clang_analyzer_eval(glob == 1);1033#ifdef TEMPORARY_DTORS1034 // expected-warning@-2{{TRUE}}1035#else1036 // expected-warning@-4{{UNKNOWN}}1037#endif1038 1039 bar2(S(2));1040 clang_analyzer_eval(glob == 2);1041#ifdef TEMPORARY_DTORS1042 // expected-warning@-2{{TRUE}}1043#else1044 // expected-warning@-4{{UNKNOWN}}1045#endif1046 1047 C *c = new D();1048 c->bar3(S(3));1049 // FIXME: Should be TRUE.1050 clang_analyzer_eval(glob == 3); // expected-warning{{UNKNOWN}}1051 delete c;1052 1053 // What if we've no idea what we're calling?1054 bar4(S(4)); // no-crash1055 1056 S(5) + S(6);1057 clang_analyzer_eval(glob == 6);1058#ifdef TEMPORARY_DTORS1059 // expected-warning@-2{{TRUE}}1060#else1061 // expected-warning@-4{{UNKNOWN}}1062#endif1063 1064 // Variadic functions. This will __builtin_trap() because you cannot pass1065 // an object as a variadic argument.1066 bar5(7, S(7)); // no-crash1067 clang_analyzer_warnIfReached(); // no-warning1068}1069} // namespace arguments1070 1071namespace ctor_argument {1072// Stripped down unique_ptr<int>1073struct IntPtr {1074 IntPtr(): i(new int) {}1075 IntPtr(IntPtr &&o): i(o.i) { o.i = 0; }1076 ~IntPtr() { delete i; }1077 1078 int *i;1079};1080 1081struct Foo {1082 Foo(IntPtr);1083 void bar();1084 1085 IntPtr i;1086};1087 1088void bar() {1089 IntPtr ptr;1090 int *i = ptr.i;1091 Foo f(static_cast<IntPtr &&>(ptr));1092 *i = 99; // no-warning1093}1094} // namespace ctor_argument1095 1096namespace operator_implicit_argument {1097struct S {1098 bool x;1099 S(bool x): x(x) {}1100 operator bool() const { return x; }1101};1102 1103void foo() {1104 if (S(false)) {1105 clang_analyzer_warnIfReached(); // no-warning1106 }1107 if (S(true)) {1108 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}1109 }1110}1111} // namespace operator_implicit_argument1112 1113 1114#if __cplusplus >= 201103L1115namespace argument_lazy_bindings {1116int glob;1117 1118struct S {1119 int x, y, z;1120};1121 1122struct T {1123 S s;1124 int w;1125 T(int w): s{5, 6, 7}, w(w) {}1126};1127 1128void foo(T t) {1129 t.s = {1, 2, 3};1130 glob = t.w;1131}1132 1133void bar() {1134 foo(T(4));1135 clang_analyzer_eval(glob == 4); // expected-warning{{TRUE}}1136}1137} // namespace argument_lazy_bindings1138#endif1139 1140namespace operator_argument_cleanup {1141struct S {1142 S();1143};1144 1145class C {1146public:1147 void operator=(S);1148};1149 1150void foo() {1151 C c;1152 c = S(); // no-crash1153}1154} // namespace operator_argument_cleanup1155 1156namespace argument_decl_lookup {1157class C {};1158int foo(C);1159int bar(C c) { foo(c); }1160int foo(C c) {}1161} // namespace argument_decl_lookup1162 1163namespace argument_virtual_decl_lookup {1164class C {};1165 1166struct T {1167 virtual void foo(C);1168};1169 1170void run() {1171 T *t;1172 t->foo(C()); // no-crash // expected-warning{{Called C++ object pointer is uninitialized}}1173}1174 1175// This is after run() because the test is about picking the correct decl1176// for the parameter region, which should belong to the correct function decl,1177// and the non-definition decl should be found by direct lookup.1178void T::foo(C) {}1179} // namespace argument_virtual_decl_lookup1180 1181namespace union_indirect_field_crash {1182union U {1183 struct {1184 int x;1185 };1186};1187 1188template <typename T> class C {1189public:1190 void foo() const {1191 (void)(true ? U().x : 0);1192 }1193};1194 1195void test() {1196 C<int> c;1197 c.foo();1198}1199} // namespace union_indirect_field_crash1200 1201namespace return_from_top_frame {1202struct S {1203 int *p;1204 S() { p = new int; }1205 S(S &&s) : p(s.p) { s.p = 0; }1206 ~S(); // Presumably releases 'p'.1207};1208 1209S foo() {1210 S s;1211 return s;1212}1213 1214S bar1() {1215 return foo(); // no-warning1216}1217 1218S bar2() {1219 return S();1220}1221 1222S bar3(int coin) {1223 return coin ? S() : foo(); // no-warning1224}1225} // namespace return_from_top_frame1226 1227#if __cplusplus >= 201103L1228namespace arguments_of_operators {1229struct S {1230 S() {}1231 S(const S &) {}1232};1233 1234void test() {1235 int x = 0;1236 auto foo = [](S s, int &y) { y = 1; };1237 foo(S(), x);1238 clang_analyzer_eval(x == 1); // expected-warning{{TRUE}}1239}1240} // namespace arguments_of_operators1241#endif // __cplusplus >= 201103L1242