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