blob: 6e476339cb7735afd141b2c4aa56b2d8664354d4 [file] [log] [blame]
Jordan Rose5d2abef2013-05-06 16:48:20 +00001// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s
Pavel Labathe4e30862013-07-26 12:50:30 +00002// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s
Manuel Klimekb5616c92014-08-07 10:42:17 +00003// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s -std=c++11
Jordan Rose2c625dd2012-08-29 01:11:59 +00004
Jordan Rosefe03e402013-02-21 23:57:17 +00005extern bool clang_analyzer_eval(bool);
Manuel Klimekb5616c92014-08-07 10:42:17 +00006extern bool clang_analyzer_warnIfReached();
Jordan Rosefe03e402013-02-21 23:57:17 +00007
Jordan Rose2c625dd2012-08-29 01:11:59 +00008struct Trivial {
9 Trivial(int x) : value(x) {}
10 int value;
11};
12
13struct NonTrivial : public Trivial {
14 NonTrivial(int x) : Trivial(x) {}
15 ~NonTrivial();
16};
17
18
19Trivial getTrivial() {
20 return Trivial(42); // no-warning
21}
22
23const Trivial &getTrivialRef() {
Jordan Rosec9487092013-02-26 01:21:21 +000024 return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'Trivial' returned to caller}}
Jordan Rose2c625dd2012-08-29 01:11:59 +000025}
26
27
28NonTrivial getNonTrivial() {
29 return NonTrivial(42); // no-warning
30}
31
32const NonTrivial &getNonTrivialRef() {
Jordan Rosec9487092013-02-26 01:21:21 +000033 return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}}
Jordan Rose2c625dd2012-08-29 01:11:59 +000034}
35
Jordan Rosefe03e402013-02-21 23:57:17 +000036namespace 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
Jordan Rose5772f822013-02-22 01:51:15 +000049 void testImmediate() {
Jordan Rosefe03e402013-02-21 23:57:17 +000050 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 }
Jordan Rose5772f822013-02-22 01:51:15 +000058
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 }
Jordan Rosefe03e402013-02-21 23:57:17 +000066}
67
Jordan Rose861a1742013-02-26 01:21:27 +000068namespace 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
Jordan Rose5d2abef2013-05-06 16:48:20 +000082namespace 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
Jordan Rosee15a8a42013-07-25 17:22:05 +0000114namespace destructors {
Manuel Klimekb5616c92014-08-07 10:42:17 +0000115 struct Dtor {
116 ~Dtor();
117 };
118 extern bool coin();
119 extern bool check(const Dtor &);
Rui Ueyamaa89f9c82014-08-06 22:01:54 +0000120
Manuel Klimekb5616c92014-08-07 10:42:17 +0000121 void testPR16664andPR18159Crash() {
Manuel Klimek264f9632014-05-05 09:58:03 +0000122 // Regression test: we used to assert here when tmp dtors are enabled.
Jordan Rose398fb002014-04-01 16:39:33 +0000123 // PR16664 and PR18159
Jordan Rosee15a8a42013-07-25 17:22:05 +0000124 if (coin() && (coin() || coin() || check(Dtor()))) {
125 Dtor();
126 }
127 }
128
Pavel Labathd527cf82013-09-02 09:09:15 +0000129#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) {
Jordan Rosee15a8a42013-07-25 17:22:05 +0000152 if (i != 5)
153 return;
154 if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) {
Pavel Labathd527cf82013-09-02 09:09:15 +0000155 clang_analyzer_eval(true); // no warning, unreachable code
Jordan Rosee15a8a42013-07-25 17:22:05 +0000156 }
157 }
Pavel Labathd527cf82013-09-02 09:09:15 +0000158
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
Manuel Klimek264f9632014-05-05 09:58:03 +0000172 // Regression test: we used to assert here.
Jordan Rose398fb002014-04-01 16:39:33 +0000173 // PR16664 and PR18159
Pavel Labathd527cf82013-09-02 09:09:15 +0000174 void testConsistencyNested(int i) {
175 extern bool compute(bool);
Manuel Klimek264f9632014-05-05 09:58:03 +0000176
Pavel Labathd527cf82013-09-02 09:09:15 +0000177 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
Manuel Klimek264f9632014-05-05 09:58:03 +0000178 clang_analyzer_eval(true); // expected-warning{{TRUE}}
179
Anna Zakscf8d2162013-12-06 18:56:29 +0000180 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
Manuel Klimek264f9632014-05-05 09:58:03 +0000181 clang_analyzer_eval(true); // expected-warning{{TRUE}}
Pavel Labathd527cf82013-09-02 09:09:15 +0000182
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) {
Manuel Klimek264f9632014-05-05 09:58:03 +0000190 clang_analyzer_eval(true); // expected-warning{{TRUE}}
Pavel Labathd527cf82013-09-02 09:09:15 +0000191 }
192
193 if (compute(i == 5 &&
194 (i == 4 || i == 4 ||
195 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
196 i != 4) {
Manuel Klimekb5616c92014-08-07 10:42:17 +0000197 clang_analyzer_eval(true); // no warning, unreachable code
Pavel Labathd527cf82013-09-02 09:09:15 +0000198 }
Manuel Klimek264f9632014-05-05 09:58:03 +0000199 }
Jordan Rose398fb002014-04-01 16:39:33 +0000200
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())) {
Manuel Klimekb5616c92014-08-07 10:42:17 +0000214 clang_analyzer_eval(true); // no warning, unreachable code
Jordan Rose398fb002014-04-01 16:39:33 +0000215 }
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 }
Manuel Klimekb5616c92014-08-07 10:42:17 +0000227 // 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 // 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
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
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
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 }
Jordan Rose398fb002014-04-01 16:39:33 +0000341
Manuel Klimek264f9632014-05-05 09:58:03 +0000342 void testBinaryOperatorShortcut(bool value) {
343 if (value) {
344 if (false && false && check(NoReturnDtor()) && true) {
345 clang_analyzer_eval(true);
346 }
347 }
348 }
349
Manuel Klimekb5616c92014-08-07 10:42:17 +0000350 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
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
376 void testNoReturnInComplexCondition() {
377 check(Dtor()) &&
378 (check(NoReturnDtor()) || check(NoReturnDtor())) && check(Dtor());
379 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
380 }
381
382 void testSequencingOfConditionalTempDtors(bool b) {
383 b || (check(Dtor()), check(NoReturnDtor()));
384 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
385 }
386
387 void testSequencingOfConditionalTempDtors2(bool b) {
388 (b || check(Dtor())), check(NoReturnDtor());
389 clang_analyzer_warnIfReached(); // no warning, unreachable code
390 }
391
392 void testSequencingOfConditionalTempDtorsWithinBinaryOperators(bool b) {
393 b || (check(Dtor()) + check(NoReturnDtor()));
394 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
395 }
Manuel Klimek26f649f2014-08-11 14:54:30 +0000396
397 void f(Dtor d = Dtor());
398 void testDefaultParameters() {
399 f();
400 }
Manuel Klimekf67672e2014-08-13 15:25:55 +0000401
402 struct DefaultParam {
403 DefaultParam(int, const Dtor& d = Dtor());
404 ~DefaultParam();
405 };
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 }
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 }
Pavel Labathd527cf82013-09-02 09:09:15 +0000422#endif // TEMPORARY_DTORS
Jordan Rosee15a8a42013-07-25 17:22:05 +0000423}
Pavel Labathcf878bb2013-07-26 11:50:42 +0000424
425void 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
Pavel Labathe4e30862013-07-26 12:50:30 +0000432#if __has_feature(cxx_thread_local)
Pavel Labathcf878bb2013-07-26 11:50:42 +0000433 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}
Pavel Labath375e18e2013-08-09 07:46:29 +0000440
441namespace PR16629 {
442 struct A {
443 explicit A(int* p_) : p(p_) {}
444 int* p;
445 };
446
447 extern void escape(const A*[]);
448 extern void check(int);
449
450 void callEscape(const A& a) {
451 const A* args[] = { &a };
452 escape(args);
453 }
454
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
461 void set(const A*a[]) {
462 *a[0]->p = 47;
463 }
464
465 void callSet(const A& a) {
466 const A* args[] = { &a };
467 set(args);
468 }
469
470 void testConsistency() {
471 int x;
472 callSet(A(&x));
473 clang_analyzer_eval(x == 47); // expected-warning{{TRUE}}
474 }
475}