• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
TrivialTrivial9   Trivial(int x) : value(x) {}
10   int value;
11 };
12 
13 struct NonTrivial : public Trivial {
NonTrivialNonTrivial14   NonTrivial(int x) : Trivial(x) {}
15   ~NonTrivial();
16 };
17 
18 
getTrivial()19 Trivial getTrivial() {
20   return Trivial(42); // no-warning
21 }
22 
getTrivialRef()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 
getNonTrivial()28 NonTrivial getNonTrivial() {
29   return NonTrivial(42); // no-warning
30 }
31 
getNonTrivialRef()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 {
TrivialSubclassrdar13265460::TrivialSubclass38     TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {}
39     int anotherValue;
40   };
41 
getTrivialSub()42   TrivialSubclass getTrivialSub() {
43     TrivialSubclass obj(1);
44     obj.value = 42;
45     obj.anotherValue = -42;
46     return obj;
47   }
48 
testImmediate()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 
testMaterializeTemporaryExpr()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 {
Derivedrdar13281951::Derived70     Derived(int value) : Trivial(value), value2(-value) {}
71     int value2;
72   };
73 
test()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 {
HasCtorcompound_literals::HasCtor87     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 {
HasCtorDtorcompound_literals::HasCtorDtor95     HasCtorDtor(int x, int y) : x(x), y(y) {}
96     ~HasCtorDtor();
97     int x, y;
98   };
99 
test()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 
testPR16664andPR18159Crash()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 
noReturnTemp(int * x)134   void noReturnTemp(int *x) {
135     if (! x) NoReturnDtor();
136     *x = 47; // no warning
137   }
138 
noReturnInline(int ** x)139   void noReturnInline(int **x) {
140     NoReturnDtor();
141   }
142 
callNoReturn()143   void callNoReturn() {
144     int *x;
145     noReturnInline(&x);
146     *x = 47; // no warning
147   }
148 
149   extern bool check(const NoReturnDtor &);
150 
testConsistencyIf(int i)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 
testConsistencyTernary(int i)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
testConsistencyNested(int i)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
testConsistencyNestedSimple(bool value)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
testConsistencyNestedComplex(bool value)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
testConsistencyNestedWarning(bool value)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
testConsistencyNestedComplexMidBranch(bool value)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
testConsistencyNestedComplexNestedBranch(bool value)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
testConsistencyNestedVariableModification(bool value)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 
testTernaryNoReturnTrueBranch(bool value)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   }
testTernaryNoReturnFalseBranch(bool value)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   }
testTernaryIgnoreNoreturnBranch(bool value)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   }
testTernaryTrueBranchReached(bool value)274   void testTernaryTrueBranchReached(bool value) {
275     value ? clang_analyzer_warnIfReached() : // expected-warning{{REACHABLE}}
276             check(NoReturnDtor());
277   }
testTernaryFalseBranchReached(bool value)278   void testTernaryFalseBranchReached(bool value) {
279     value ? check(NoReturnDtor()) :
280             clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
281   }
282 
testLoop()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 
testRecursiveFrames(bool isInner)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   }
testRecursiveFramesStart()299   void testRecursiveFramesStart() { testRecursiveFrames(false); }
300 
testLambdas()301   void testLambdas() {
302     []() { check(NoReturnDtor()); } != nullptr || check(Dtor());
303   }
304 
testGnuExpressionStatements(int v)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 
testGnuExpressionStatementsDestructionPoint(int v)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 
testMultipleTemporaries(bool value)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 
testBinaryOperatorShortcut(bool value)336   void testBinaryOperatorShortcut(bool value) {
337     if (value) {
338       if (false && false && check(NoReturnDtor()) && true) {
339         clang_analyzer_eval(true);
340       }
341     }
342   }
343 
testIfAtEndOfLoop()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 
testTernaryAtEndOfLoop()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 
testNoReturnInComplexCondition()370   void testNoReturnInComplexCondition() {
371     check(Dtor()) &&
372         (check(NoReturnDtor()) || check(NoReturnDtor())) && check(Dtor());
373     clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
374   }
375 
testSequencingOfConditionalTempDtors(bool b)376   void testSequencingOfConditionalTempDtors(bool b) {
377     b || (check(Dtor()), check(NoReturnDtor()));
378     clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
379   }
380 
testSequencingOfConditionalTempDtors2(bool b)381   void testSequencingOfConditionalTempDtors2(bool b) {
382     (b || check(Dtor())), check(NoReturnDtor());
383     clang_analyzer_warnIfReached();  // no warning, unreachable code
384   }
385 
testSequencingOfConditionalTempDtorsWithinBinaryOperators(bool b)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());
testDefaultParameters()392   void testDefaultParameters() {
393     f();
394   }
395 
396   struct DefaultParam {
397     DefaultParam(int, const Dtor& d = Dtor());
398     ~DefaultParam();
399   };
testDefaultParamConstructorsInLoops()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   }
testDefaultParamConstructorsInTernariesInLoops(bool value)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 
testStaticMaterializeTemporaryExpr()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 {
APR16629::A437     explicit A(int* p_) : p(p_) {}
438     int* p;
439   };
440 
441   extern void escape(const A*[]);
442   extern void check(int);
443 
callEscape(const A & a)444   void callEscape(const A& a) {
445     const A* args[] = { &a };
446     escape(args);
447   }
448 
testNoWarning()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 
set(const A * a[])455   void set(const A*a[]) {
456     *a[0]->p = 47;
457   }
458 
callSet(const A & a)459   void callSet(const A& a) {
460     const A* args[] = { &a };
461     set(args);
462   }
463 
testConsistency()464   void testConsistency() {
465     int x;
466     callSet(A(&x));
467     clang_analyzer_eval(x == 47); // expected-warning{{TRUE}}
468   }
469 }
470