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 // This is the test we would like to write:
303 // []() { check(NoReturnDtor()); } != nullptr || check(Dtor());
304 // But currently the analyzer stops when it encounters a lambda:
305 [] {};
306 // The CFG for this now looks correct, but we still do not reach the line
307 // below.
308 clang_analyzer_warnIfReached(); // FIXME: Should warn.
309 }
310
testGnuExpressionStatements(int v)311 void testGnuExpressionStatements(int v) {
312 ({ ++v; v == 10 || check(NoReturnDtor()); v == 42; }) || v == 23;
313 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
314
315 ({ ++v; check(NoReturnDtor()); v == 42; }) || v == 23;
316 clang_analyzer_warnIfReached(); // no warning, unreachable code
317 }
318
testGnuExpressionStatementsDestructionPoint(int v)319 void testGnuExpressionStatementsDestructionPoint(int v) {
320 // In normal context, the temporary destructor runs at the end of the full
321 // statement, thus the last statement is reached.
322 (++v, check(NoReturnDtor()), v == 42),
323 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
324
325 // GNU expression statements execute temporary destructors within the
326 // blocks, thus the last statement is not reached.
327 ({ ++v; check(NoReturnDtor()); v == 42; }),
328 clang_analyzer_warnIfReached(); // no warning, unreachable code
329 }
330
testMultipleTemporaries(bool value)331 void testMultipleTemporaries(bool value) {
332 if (value) {
333 // FIXME: Find a way to verify construction order.
334 // ~Dtor should run before ~NoReturnDtor() because construction order is
335 // guaranteed by comma operator.
336 if (!value || check((NoReturnDtor(), Dtor())) || value) {
337 clang_analyzer_eval(true); // no warning, unreachable code
338 }
339 }
340 }
341
testBinaryOperatorShortcut(bool value)342 void testBinaryOperatorShortcut(bool value) {
343 if (value) {
344 if (false && false && check(NoReturnDtor()) && true) {
345 clang_analyzer_eval(true);
346 }
347 }
348 }
349
testIfAtEndOfLoop()350 void testIfAtEndOfLoop() {
351 int y = 0;
352 while (true) {
353 if (y > 0) {
354 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
355 }
356 ++y;
357 // Test that the CFG gets hooked up correctly when temporary destructors
358 // are handled after a statically known branch condition.
359 if (true) (void)0; else (void)check(NoReturnDtor());
360 }
361 }
362
testTernaryAtEndOfLoop()363 void testTernaryAtEndOfLoop() {
364 int y = 0;
365 while (true) {
366 if (y > 0) {
367 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
368 }
369 ++y;
370 // Test that the CFG gets hooked up correctly when temporary destructors
371 // are handled after a statically known branch condition.
372 true ? (void)0 : (void)check(NoReturnDtor());
373 }
374 }
375
testNoReturnInComplexCondition()376 void testNoReturnInComplexCondition() {
377 check(Dtor()) &&
378 (check(NoReturnDtor()) || check(NoReturnDtor())) && check(Dtor());
379 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
380 }
381
testSequencingOfConditionalTempDtors(bool b)382 void testSequencingOfConditionalTempDtors(bool b) {
383 b || (check(Dtor()), check(NoReturnDtor()));
384 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
385 }
386
testSequencingOfConditionalTempDtors2(bool b)387 void testSequencingOfConditionalTempDtors2(bool b) {
388 (b || check(Dtor())), check(NoReturnDtor());
389 clang_analyzer_warnIfReached(); // no warning, unreachable code
390 }
391
testSequencingOfConditionalTempDtorsWithinBinaryOperators(bool b)392 void testSequencingOfConditionalTempDtorsWithinBinaryOperators(bool b) {
393 b || (check(Dtor()) + check(NoReturnDtor()));
394 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
395 }
396
397 void f(Dtor d = Dtor());
testDefaultParameters()398 void testDefaultParameters() {
399 f();
400 }
401
402 struct DefaultParam {
403 DefaultParam(int, const Dtor& d = Dtor());
404 ~DefaultParam();
405 };
testDefaultParamConstructorsInLoops()406 void testDefaultParamConstructorsInLoops() {
407 while (true) {
408 // FIXME: This exact pattern triggers the temporary cleanup logic
409 // to fail when adding a 'clean' state.
410 DefaultParam(42);
411 DefaultParam(42);
412 }
413 }
testDefaultParamConstructorsInTernariesInLoops(bool value)414 void testDefaultParamConstructorsInTernariesInLoops(bool value) {
415 while (true) {
416 // FIXME: This exact pattern triggers the temporary cleanup logic
417 // to visit the bind-temporary logic with a state that already has that
418 // temporary marked as executed.
419 value ? DefaultParam(42) : DefaultParam(42);
420 }
421 }
422 #endif // TEMPORARY_DTORS
423 }
424
testStaticMaterializeTemporaryExpr()425 void testStaticMaterializeTemporaryExpr() {
426 static const Trivial &ref = getTrivial();
427 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
428
429 static const Trivial &directRef = Trivial(42);
430 clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}}
431
432 #if __has_feature(cxx_thread_local)
433 thread_local static const Trivial &threadRef = getTrivial();
434 clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}}
435
436 thread_local static const Trivial &threadDirectRef = Trivial(42);
437 clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}}
438 #endif
439 }
440
441 namespace PR16629 {
442 struct A {
APR16629::A443 explicit A(int* p_) : p(p_) {}
444 int* p;
445 };
446
447 extern void escape(const A*[]);
448 extern void check(int);
449
callEscape(const A & a)450 void callEscape(const A& a) {
451 const A* args[] = { &a };
452 escape(args);
453 }
454
testNoWarning()455 void testNoWarning() {
456 int x;
457 callEscape(A(&x));
458 check(x); // Analyzer used to give a "x is uninitialized warning" here
459 }
460
set(const A * a[])461 void set(const A*a[]) {
462 *a[0]->p = 47;
463 }
464
callSet(const A & a)465 void callSet(const A& a) {
466 const A* args[] = { &a };
467 set(args);
468 }
469
testConsistency()470 void testConsistency() {
471 int x;
472 callSet(A(&x));
473 clang_analyzer_eval(x == 47); // expected-warning{{TRUE}}
474 }
475 }
476