blob: e96e9b0e28d7e2e5c48c669a42f236745d7828a9 [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() {
Gabor Horvath15843342015-09-11 16:55:01 +0000302 []() { check(NoReturnDtor()); } != nullptr || check(Dtor());
Manuel Klimekb5616c92014-08-07 10:42:17 +0000303 }
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 }
Jordan Rose398fb002014-04-01 16:39:33 +0000335
Manuel Klimek264f9632014-05-05 09:58:03 +0000336 void testBinaryOperatorShortcut(bool value) {
337 if (value) {
338 if (false && false && check(NoReturnDtor()) && true) {
339 clang_analyzer_eval(true);
340 }
341 }
342 }
343
Manuel Klimekb5616c92014-08-07 10:42:17 +0000344 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 }
Manuel Klimek26f649f2014-08-11 14:54:30 +0000390
391 void f(Dtor d = Dtor());
392 void testDefaultParameters() {
393 f();
394 }
Manuel Klimekf67672e2014-08-13 15:25:55 +0000395
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 }
Pavel Labathd527cf82013-09-02 09:09:15 +0000416#endif // TEMPORARY_DTORS
Jordan Rosee15a8a42013-07-25 17:22:05 +0000417}
Pavel Labathcf878bb2013-07-26 11:50:42 +0000418
419void 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
Pavel Labathe4e30862013-07-26 12:50:30 +0000426#if __has_feature(cxx_thread_local)
Pavel Labathcf878bb2013-07-26 11:50:42 +0000427 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}
Pavel Labath375e18e2013-08-09 07:46:29 +0000434
435namespace 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}