Home | History | Annotate | Download | only in Analysis
      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 -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 #endif // TEMPORARY_DTORS
    417 }
    418 
    419 void testStaticMaterializeTemporaryExpr() {
    420   static const Trivial &ref = getTrivial();
    421   clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
    422 
    423   static const Trivial &directRef = Trivial(42);
    424   clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}}
    425 
    426 #if __has_feature(cxx_thread_local)
    427   thread_local static const Trivial &threadRef = getTrivial();
    428   clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}}
    429 
    430   thread_local static const Trivial &threadDirectRef = Trivial(42);
    431   clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}}
    432 #endif
    433 }
    434 
    435 namespace PR16629 {
    436   struct A {
    437     explicit A(int* p_) : p(p_) {}
    438     int* p;
    439   };
    440 
    441   extern void escape(const A*[]);
    442   extern void check(int);
    443 
    444   void callEscape(const A& a) {
    445     const A* args[] = { &a };
    446     escape(args);
    447   }
    448 
    449   void testNoWarning() {
    450     int x;
    451     callEscape(A(&x));
    452     check(x); // Analyzer used to give a "x is uninitialized warning" here
    453   }
    454 
    455   void set(const A*a[]) {
    456     *a[0]->p = 47;
    457   }
    458 
    459   void callSet(const A& a) {
    460     const A* args[] = { &a };
    461     set(args);
    462   }
    463 
    464   void testConsistency() {
    465     int x;
    466     callSet(A(&x));
    467     clang_analyzer_eval(x == 47); // expected-warning{{TRUE}}
    468   }
    469 }
    470