1 | // RUN: %clang_analyze_cc1 -w -analyzer-checker=core,cplusplus\ |
2 | // RUN: -analyzer-checker debug.ExprInspection -Wno-non-pod-varargs\ |
3 | // RUN: -analyzer-config eagerly-assume=false -verify %s\ |
4 | // RUN: -std=c++03 -analyzer-config cfg-temporary-dtors=false |
5 | |
6 | // RUN: %clang_analyze_cc1 -w -analyzer-checker=core,cplusplus\ |
7 | // RUN: -analyzer-checker debug.ExprInspection -Wno-non-pod-varargs\ |
8 | // RUN: -analyzer-config eagerly-assume=false -verify %s\ |
9 | // RUN: -std=c++11 -analyzer-config cfg-temporary-dtors=false |
10 | |
11 | // RUN: %clang_analyze_cc1 -w -analyzer-checker=core,cplusplus\ |
12 | // RUN: -analyzer-checker debug.ExprInspection -Wno-non-pod-varargs\ |
13 | // RUN: -analyzer-config eagerly-assume=false -verify %s\ |
14 | // RUN: -std=c++11 -analyzer-config cfg-temporary-dtors=true\ |
15 | // RUN: -DTEMPORARY_DTORS |
16 | |
17 | // RUN: %clang_analyze_cc1 -w -analyzer-checker=core,cplusplus\ |
18 | // RUN: -analyzer-checker debug.ExprInspection -Wno-non-pod-varargs\ |
19 | // RUN: -analyzer-config eagerly-assume=false -verify %s\ |
20 | // RUN: -std=c++17 -analyzer-config cfg-temporary-dtors=true\ |
21 | // RUN: -DTEMPORARY_DTORS |
22 | |
23 | |
24 | extern bool clang_analyzer_eval(bool); |
25 | extern bool clang_analyzer_warnIfReached(); |
26 | void clang_analyzer_checkInlined(bool); |
27 | |
28 | #include "Inputs/system-header-simulator-cxx.h" |
29 | |
30 | struct Trivial { |
31 | Trivial(int x) : value(x) {} |
32 | int value; |
33 | }; |
34 | |
35 | struct NonTrivial : public Trivial { |
36 | NonTrivial(int x) : Trivial(x) {} |
37 | ~NonTrivial(); |
38 | }; |
39 | |
40 | |
41 | Trivial getTrivial() { |
42 | return Trivial(42); // no-warning |
43 | } |
44 | |
45 | const Trivial &getTrivialRef() { |
46 | return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'Trivial' returned to caller}} |
47 | } |
48 | |
49 | |
50 | NonTrivial getNonTrivial() { |
51 | return NonTrivial(42); // no-warning |
52 | } |
53 | |
54 | const NonTrivial &getNonTrivialRef() { |
55 | return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}} |
56 | } |
57 | |
58 | namespace rdar13265460 { |
59 | struct TrivialSubclass : public Trivial { |
60 | TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {} |
61 | int anotherValue; |
62 | }; |
63 | |
64 | TrivialSubclass getTrivialSub() { |
65 | TrivialSubclass obj(1); |
66 | obj.value = 42; |
67 | obj.anotherValue = -42; |
68 | return obj; |
69 | } |
70 | |
71 | void testImmediate() { |
72 | TrivialSubclass obj = getTrivialSub(); |
73 | |
74 | clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}} |
75 | clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}} |
76 | |
77 | clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}} |
78 | clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}} |
79 | } |
80 | |
81 | void testMaterializeTemporaryExpr() { |
82 | const TrivialSubclass &ref = getTrivialSub(); |
83 | clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} |
84 | |
85 | const Trivial &baseRef = getTrivialSub(); |
86 | clang_analyzer_eval(baseRef.value == 42); // expected-warning{{TRUE}} |
87 | } |
88 | } |
89 | |
90 | namespace rdar13281951 { |
91 | struct Derived : public Trivial { |
92 | Derived(int value) : Trivial(value), value2(-value) {} |
93 | int value2; |
94 | }; |
95 | |
96 | void test() { |
97 | Derived obj(1); |
98 | obj.value = 42; |
99 | const Trivial * const &pointerRef = &obj; |
100 | clang_analyzer_eval(pointerRef->value == 42); // expected-warning{{TRUE}} |
101 | } |
102 | } |
103 | |
104 | namespace compound_literals { |
105 | struct POD { |
106 | int x, y; |
107 | }; |
108 | struct HasCtor { |
109 | HasCtor(int x, int y) : x(x), y(y) {} |
110 | int x, y; |
111 | }; |
112 | struct HasDtor { |
113 | int x, y; |
114 | ~HasDtor(); |
115 | }; |
116 | struct HasCtorDtor { |
117 | HasCtorDtor(int x, int y) : x(x), y(y) {} |
118 | ~HasCtorDtor(); |
119 | int x, y; |
120 | }; |
121 | |
122 | void test() { |
123 | clang_analyzer_eval(((POD){1, 42}).y == 42); // expected-warning{{TRUE}} |
124 | clang_analyzer_eval(((HasDtor){1, 42}).y == 42); // expected-warning{{TRUE}} |
125 | |
126 | #if __cplusplus >= 201103L |
127 | clang_analyzer_eval(((HasCtor){1, 42}).y == 42); // expected-warning{{TRUE}} |
128 | |
129 | // FIXME: should be TRUE, but we don't inline the constructors of |
130 | // temporaries because we can't model their destructors yet. |
131 | clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}} |
132 | #endif |
133 | } |
134 | } |
135 | |
136 | namespace destructors { |
137 | struct Dtor { |
138 | ~Dtor(); |
139 | }; |
140 | extern bool coin(); |
141 | extern bool check(const Dtor &); |
142 | |
143 | void testPR16664andPR18159Crash() { |
144 | // Regression test: we used to assert here when tmp dtors are enabled. |
145 | // PR16664 and PR18159 |
146 | if (coin() && (coin() || coin() || check(Dtor()))) { |
147 | Dtor(); |
148 | } |
149 | } |
150 | |
151 | #ifdef TEMPORARY_DTORS |
152 | struct NoReturnDtor { |
153 | ~NoReturnDtor() __attribute__((noreturn)); |
154 | }; |
155 | |
156 | void noReturnTemp(int *x) { |
157 | if (! x) NoReturnDtor(); |
158 | *x = 47; // no warning |
159 | } |
160 | |
161 | void noReturnInline(int **x) { |
162 | NoReturnDtor(); |
163 | } |
164 | |
165 | void callNoReturn() { |
166 | int *x; |
167 | noReturnInline(&x); |
168 | *x = 47; // no warning |
169 | } |
170 | |
171 | extern bool check(const NoReturnDtor &); |
172 | |
173 | void testConsistencyIf(int i) { |
174 | if (i != 5) |
175 | return; |
176 | if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) { |
177 | clang_analyzer_eval(true); // no warning, unreachable code |
178 | } |
179 | } |
180 | |
181 | void testConsistencyTernary(int i) { |
182 | (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0; |
183 | |
184 | clang_analyzer_eval(true); // expected-warning{{TRUE}} |
185 | |
186 | if (i != 5) |
187 | return; |
188 | |
189 | (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0; |
190 | |
191 | clang_analyzer_eval(true); // no warning, unreachable code |
192 | } |
193 | |
194 | // Regression test: we used to assert here. |
195 | // PR16664 and PR18159 |
196 | void testConsistencyNested(int i) { |
197 | extern bool compute(bool); |
198 | |
199 | if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) |
200 | clang_analyzer_eval(true); // expected-warning{{TRUE}} |
201 | |
202 | if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) |
203 | clang_analyzer_eval(true); // expected-warning{{TRUE}} |
204 | |
205 | if (i != 5) |
206 | return; |
207 | |
208 | if (compute(i == 5 && |
209 | (i == 4 || compute(true) || |
210 | compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || |
211 | i != 4) { |
212 | clang_analyzer_eval(true); // expected-warning{{TRUE}} |
213 | } |
214 | |
215 | if (compute(i == 5 && |
216 | (i == 4 || i == 4 || |
217 | compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || |
218 | i != 4) { |
219 | clang_analyzer_eval(true); // no warning, unreachable code |
220 | } |
221 | } |
222 | |
223 | // PR16664 and PR18159 |
224 | void testConsistencyNestedSimple(bool value) { |
225 | if (value) { |
226 | if (!value || check(NoReturnDtor())) { |
227 | clang_analyzer_eval(true); // no warning, unreachable code |
228 | } |
229 | } |
230 | } |
231 | |
232 | // PR16664 and PR18159 |
233 | void testConsistencyNestedComplex(bool value) { |
234 | if (value) { |
235 | if (!value || !value || check(NoReturnDtor())) { |
236 | clang_analyzer_eval(true); // no warning, unreachable code |
237 | } |
238 | } |
239 | } |
240 | |
241 | // PR16664 and PR18159 |
242 | void testConsistencyNestedWarning(bool value) { |
243 | if (value) { |
244 | if (!value || value || check(NoReturnDtor())) { |
245 | clang_analyzer_eval(true); // expected-warning{{TRUE}} |
246 | } |
247 | } |
248 | } |
249 | // PR16664 and PR18159 |
250 | void testConsistencyNestedComplexMidBranch(bool value) { |
251 | if (value) { |
252 | if (!value || !value || check(NoReturnDtor()) || value) { |
253 | clang_analyzer_eval(true); // no warning, unreachable code |
254 | } |
255 | } |
256 | } |
257 | |
258 | // PR16664 and PR18159 |
259 | void testConsistencyNestedComplexNestedBranch(bool value) { |
260 | if (value) { |
261 | if (!value || (!value || check(NoReturnDtor()) || value)) { |
262 | clang_analyzer_eval(true); // no warning, unreachable code |
263 | } |
264 | } |
265 | } |
266 | |
267 | // PR16664 and PR18159 |
268 | void testConsistencyNestedVariableModification(bool value) { |
269 | bool other = true; |
270 | if (value) { |
271 | if (!other || !value || (other = false) || check(NoReturnDtor()) || |
272 | !other) { |
273 | clang_analyzer_eval(true); // no warning, unreachable code |
274 | } |
275 | } |
276 | } |
277 | |
278 | void testTernaryNoReturnTrueBranch(bool value) { |
279 | if (value) { |
280 | bool b = value && (value ? check(NoReturnDtor()) : true); |
281 | clang_analyzer_eval(true); // no warning, unreachable code |
282 | } |
283 | } |
284 | void testTernaryNoReturnFalseBranch(bool value) { |
285 | if (value) { |
286 | bool b = !value && !value ? true : check(NoReturnDtor()); |
287 | clang_analyzer_eval(true); // no warning, unreachable code |
288 | } |
289 | } |
290 | void testTernaryIgnoreNoreturnBranch(bool value) { |
291 | if (value) { |
292 | bool b = !value && !value ? check(NoReturnDtor()) : true; |
293 | clang_analyzer_eval(true); // expected-warning{{TRUE}} |
294 | } |
295 | } |
296 | void testTernaryTrueBranchReached(bool value) { |
297 | value ? clang_analyzer_warnIfReached() : // expected-warning{{REACHABLE}} |
298 | check(NoReturnDtor()); |
299 | } |
300 | void testTernaryFalseBranchReached(bool value) { |
301 | value ? check(NoReturnDtor()) : |
302 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
303 | } |
304 | |
305 | void testLoop() { |
306 | for (int i = 0; i < 10; ++i) { |
307 | if (i < 3 && (i >= 2 || check(NoReturnDtor()))) { |
308 | clang_analyzer_eval(true); // no warning, unreachable code |
309 | } |
310 | } |
311 | } |
312 | |
313 | bool testRecursiveFrames(bool isInner) { |
314 | if (isInner || |
315 | (clang_analyzer_warnIfReached(), false) || // expected-warning{{REACHABLE}} |
316 | check(NoReturnDtor()) || |
317 | testRecursiveFrames(true)) { |
318 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
319 | } |
320 | } |
321 | void testRecursiveFramesStart() { testRecursiveFrames(false); } |
322 | |
323 | void testLambdas() { |
324 | []() { check(NoReturnDtor()); } != nullptr || check(Dtor()); |
325 | } |
326 | |
327 | void testGnuExpressionStatements(int v) { |
328 | ({ ++v; v == 10 || check(NoReturnDtor()); v == 42; }) || v == 23; |
329 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
330 | |
331 | ({ ++v; check(NoReturnDtor()); v == 42; }) || v == 23; |
332 | clang_analyzer_warnIfReached(); // no warning, unreachable code |
333 | } |
334 | |
335 | void testGnuExpressionStatementsDestructionPoint(int v) { |
336 | // In normal context, the temporary destructor runs at the end of the full |
337 | // statement, thus the last statement is reached. |
338 | (++v, check(NoReturnDtor()), v == 42), |
339 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
340 | |
341 | // GNU expression statements execute temporary destructors within the |
342 | // blocks, thus the last statement is not reached. |
343 | ({ ++v; check(NoReturnDtor()); v == 42; }), |
344 | clang_analyzer_warnIfReached(); // no warning, unreachable code |
345 | } |
346 | |
347 | void testMultipleTemporaries(bool value) { |
348 | if (value) { |
349 | // FIXME: Find a way to verify construction order. |
350 | // ~Dtor should run before ~NoReturnDtor() because construction order is |
351 | // guaranteed by comma operator. |
352 | if (!value || check((NoReturnDtor(), Dtor())) || value) { |
353 | clang_analyzer_eval(true); // no warning, unreachable code |
354 | } |
355 | } |
356 | } |
357 | |
358 | void testBinaryOperatorShortcut(bool value) { |
359 | if (value) { |
360 | if (false && false && check(NoReturnDtor()) && true) { |
361 | clang_analyzer_eval(true); |
362 | } |
363 | } |
364 | } |
365 | |
366 | void testIfAtEndOfLoop() { |
367 | int y = 0; |
368 | while (true) { |
369 | if (y > 0) { |
370 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
371 | } |
372 | ++y; |
373 | // Test that the CFG gets hooked up correctly when temporary destructors |
374 | // are handled after a statically known branch condition. |
375 | if (true) (void)0; else (void)check(NoReturnDtor()); |
376 | } |
377 | } |
378 | |
379 | void testTernaryAtEndOfLoop() { |
380 | int y = 0; |
381 | while (true) { |
382 | if (y > 0) { |
383 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
384 | } |
385 | ++y; |
386 | // Test that the CFG gets hooked up correctly when temporary destructors |
387 | // are handled after a statically known branch condition. |
388 | true ? (void)0 : (void)check(NoReturnDtor()); |
389 | } |
390 | } |
391 | |
392 | void testNoReturnInComplexCondition() { |
393 | check(Dtor()) && |
394 | (check(NoReturnDtor()) || check(NoReturnDtor())) && check(Dtor()); |
395 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
396 | } |
397 | |
398 | void testSequencingOfConditionalTempDtors(bool b) { |
399 | b || (check(Dtor()), check(NoReturnDtor())); |
400 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
401 | } |
402 | |
403 | void testSequencingOfConditionalTempDtors2(bool b) { |
404 | (b || check(Dtor())), check(NoReturnDtor()); |
405 | clang_analyzer_warnIfReached(); // no warning, unreachable code |
406 | } |
407 | |
408 | void testSequencingOfConditionalTempDtorsWithinBinaryOperators(bool b) { |
409 | b || (check(Dtor()) + check(NoReturnDtor())); |
410 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
411 | } |
412 | |
413 | void f(Dtor d = Dtor()); |
414 | void testDefaultParameters() { |
415 | f(); |
416 | } |
417 | |
418 | struct DefaultParam { |
419 | DefaultParam(int, const Dtor& d = Dtor()); |
420 | ~DefaultParam(); |
421 | }; |
422 | void testDefaultParamConstructorsInLoops() { |
423 | while (true) { |
424 | // FIXME: This exact pattern triggers the temporary cleanup logic |
425 | // to fail when adding a 'clean' state. |
426 | DefaultParam(42); |
427 | DefaultParam(42); |
428 | } |
429 | } |
430 | void testDefaultParamConstructorsInTernariesInLoops(bool value) { |
431 | while (true) { |
432 | // FIXME: This exact pattern triggers the temporary cleanup logic |
433 | // to visit the bind-temporary logic with a state that already has that |
434 | // temporary marked as executed. |
435 | value ? DefaultParam(42) : DefaultParam(42); |
436 | } |
437 | } |
438 | #else // !TEMPORARY_DTORS |
439 | |
440 | // Test for fallback logic that conservatively stops exploration after |
441 | // executing a temporary constructor for a class with a no-return destructor |
442 | // when temporary destructors are not enabled in the CFG. |
443 | |
444 | struct CtorWithNoReturnDtor { |
445 | CtorWithNoReturnDtor() = default; |
446 | |
447 | CtorWithNoReturnDtor(int x) { |
448 | clang_analyzer_checkInlined(false); // no-warning |
449 | } |
450 | |
451 | ~CtorWithNoReturnDtor() __attribute__((noreturn)); |
452 | }; |
453 | |
454 | void testDefaultContructorWithNoReturnDtor() { |
455 | CtorWithNoReturnDtor(); |
456 | clang_analyzer_warnIfReached(); // no-warning |
457 | } |
458 | |
459 | void testLifeExtensionWithNoReturnDtor() { |
460 | const CtorWithNoReturnDtor &c = CtorWithNoReturnDtor(); |
461 | |
462 | // This represents an (expected) loss of coverage, since the destructor |
463 | // of the lifetime-exended temporary is executed at the end of |
464 | // scope. |
465 | clang_analyzer_warnIfReached(); // no-warning |
466 | } |
467 | |
468 | #if __cplusplus >= 201103L |
469 | struct CtorWithNoReturnDtor2 { |
470 | CtorWithNoReturnDtor2() = default; |
471 | |
472 | CtorWithNoReturnDtor2(int x) { |
473 | clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} |
474 | } |
475 | |
476 | ~CtorWithNoReturnDtor2() __attribute__((noreturn)); |
477 | }; |
478 | CtorWithNoReturnDtor2 returnNoReturnDtor() { |
479 | return {1}; // no-crash |
480 | } |
481 | #endif |
482 | |
483 | #endif // TEMPORARY_DTORS |
484 | } |
485 | |
486 | namespace default_param_elided_destructors { |
487 | struct a { |
488 | ~a(); |
489 | }; |
490 | struct F { |
491 | a d; |
492 | F(char *, a = a()); |
493 | }; |
494 | void g() { |
495 | char h[1]; |
496 | for (int i = 0;;) |
497 | F j(i ? j : h); |
498 | } |
499 | } // namespace default_param_elided_destructors |
500 | |
501 | void testStaticMaterializeTemporaryExpr() { |
502 | static const Trivial &ref = getTrivial(); |
503 | clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} |
504 | |
505 | static const Trivial &directRef = Trivial(42); |
506 | clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}} |
507 | |
508 | #if __has_feature(cxx_thread_local) |
509 | thread_local static const Trivial &threadRef = getTrivial(); |
510 | clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}} |
511 | |
512 | thread_local static const Trivial &threadDirectRef = Trivial(42); |
513 | clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}} |
514 | #endif |
515 | } |
516 | |
517 | namespace PR16629 { |
518 | struct A { |
519 | explicit A(int* p_) : p(p_) {} |
520 | int* p; |
521 | }; |
522 | |
523 | extern void escape(const A*[]); |
524 | extern void check(int); |
525 | |
526 | void callEscape(const A& a) { |
527 | const A* args[] = { &a }; |
528 | escape(args); |
529 | } |
530 | |
531 | void testNoWarning() { |
532 | int x; |
533 | callEscape(A(&x)); |
534 | check(x); // Analyzer used to give a "x is uninitialized warning" here |
535 | } |
536 | |
537 | void set(const A*a[]) { |
538 | *a[0]->p = 47; |
539 | } |
540 | |
541 | void callSet(const A& a) { |
542 | const A* args[] = { &a }; |
543 | set(args); |
544 | } |
545 | |
546 | void testConsistency() { |
547 | int x; |
548 | callSet(A(&x)); |
549 | clang_analyzer_eval(x == 47); // expected-warning{{TRUE}} |
550 | } |
551 | } |
552 | |
553 | namespace PR32088 { |
554 | void testReturnFromStmtExprInitializer() { |
555 | // We shouldn't try to destroy the object pointed to by `obj' upon return. |
556 | const NonTrivial &obj = ({ |
557 | return; // no-crash |
558 | NonTrivial(42); |
559 | }); |
560 | } |
561 | } |
562 | |
563 | namespace CopyToTemporaryCorrectly { |
564 | class Super { |
565 | public: |
566 | void m() { |
567 | mImpl(); |
568 | } |
569 | virtual void mImpl() = 0; |
570 | }; |
571 | class Sub : public Super { |
572 | public: |
573 | Sub(const int &p) : j(p) {} |
574 | virtual void mImpl() override { |
575 | // Used to be undefined pointer dereference because we didn't copy |
576 | // the subclass data (j) to the temporary object properly. |
577 | (void)(j + 1); // no-warning |
578 | if (j != 22) { |
579 | clang_analyzer_warnIfReached(); // no-warning |
580 | } |
581 | } |
582 | const int &j; |
583 | }; |
584 | void run() { |
585 | int i = 22; |
586 | Sub(i).m(); |
587 | } |
588 | } |
589 | |
590 | namespace test_return_temporary { |
591 | class C { |
592 | int x, y; |
593 | |
594 | public: |
595 | C(int x, int y) : x(x), y(y) {} |
596 | int getX() const { return x; } |
597 | int getY() const { return y; } |
598 | ~C() {} |
599 | }; |
600 | |
601 | class D: public C { |
602 | public: |
603 | D() : C(1, 2) {} |
604 | D(const D &d): C(d.getX(), d.getY()) {} |
605 | }; |
606 | |
607 | C returnTemporaryWithVariable() { C c(1, 2); return c; } |
608 | C returnTemporaryWithAnotherFunctionWithVariable() { |
609 | return returnTemporaryWithVariable(); |
610 | } |
611 | C returnTemporaryWithCopyConstructionWithVariable() { |
612 | return C(returnTemporaryWithVariable()); |
613 | } |
614 | |
615 | C returnTemporaryWithConstruction() { return C(1, 2); } |
616 | C returnTemporaryWithAnotherFunctionWithConstruction() { |
617 | return returnTemporaryWithConstruction(); |
618 | } |
619 | C returnTemporaryWithCopyConstructionWithConstruction() { |
620 | return C(returnTemporaryWithConstruction()); |
621 | } |
622 | |
623 | D returnTemporaryWithVariableAndNonTrivialCopy() { D d; return d; } |
624 | D returnTemporaryWithAnotherFunctionWithVariableAndNonTrivialCopy() { |
625 | return returnTemporaryWithVariableAndNonTrivialCopy(); |
626 | } |
627 | D returnTemporaryWithCopyConstructionWithVariableAndNonTrivialCopy() { |
628 | return D(returnTemporaryWithVariableAndNonTrivialCopy()); |
629 | } |
630 | |
631 | #if __cplusplus >= 201103L |
632 | C returnTemporaryWithBraces() { return {1, 2}; } |
633 | C returnTemporaryWithAnotherFunctionWithBraces() { |
634 | return returnTemporaryWithBraces(); |
635 | } |
636 | C returnTemporaryWithCopyConstructionWithBraces() { |
637 | return C(returnTemporaryWithBraces()); |
638 | } |
639 | #endif // C++11 |
640 | |
641 | void test() { |
642 | C c1 = returnTemporaryWithVariable(); |
643 | clang_analyzer_eval(c1.getX() == 1); // expected-warning{{TRUE}} |
644 | clang_analyzer_eval(c1.getY() == 2); // expected-warning{{TRUE}} |
645 | |
646 | C c2 = returnTemporaryWithAnotherFunctionWithVariable(); |
647 | clang_analyzer_eval(c2.getX() == 1); // expected-warning{{TRUE}} |
648 | clang_analyzer_eval(c2.getY() == 2); // expected-warning{{TRUE}} |
649 | |
650 | C c3 = returnTemporaryWithCopyConstructionWithVariable(); |
651 | clang_analyzer_eval(c3.getX() == 1); // expected-warning{{TRUE}} |
652 | clang_analyzer_eval(c3.getY() == 2); // expected-warning{{TRUE}} |
653 | |
654 | C c4 = returnTemporaryWithConstruction(); |
655 | clang_analyzer_eval(c4.getX() == 1); // expected-warning{{TRUE}} |
656 | clang_analyzer_eval(c4.getY() == 2); // expected-warning{{TRUE}} |
657 | |
658 | C c5 = returnTemporaryWithAnotherFunctionWithConstruction(); |
659 | clang_analyzer_eval(c5.getX() == 1); // expected-warning{{TRUE}} |
660 | clang_analyzer_eval(c5.getY() == 2); // expected-warning{{TRUE}} |
661 | |
662 | C c6 = returnTemporaryWithCopyConstructionWithConstruction(); |
663 | clang_analyzer_eval(c5.getX() == 1); // expected-warning{{TRUE}} |
664 | clang_analyzer_eval(c5.getY() == 2); // expected-warning{{TRUE}} |
665 | |
666 | #if __cplusplus >= 201103L |
667 | |
668 | C c7 = returnTemporaryWithBraces(); |
669 | clang_analyzer_eval(c7.getX() == 1); // expected-warning{{TRUE}} |
670 | clang_analyzer_eval(c7.getY() == 2); // expected-warning{{TRUE}} |
671 | |
672 | C c8 = returnTemporaryWithAnotherFunctionWithBraces(); |
673 | clang_analyzer_eval(c8.getX() == 1); // expected-warning{{TRUE}} |
674 | clang_analyzer_eval(c8.getY() == 2); // expected-warning{{TRUE}} |
675 | |
676 | C c9 = returnTemporaryWithCopyConstructionWithBraces(); |
677 | clang_analyzer_eval(c9.getX() == 1); // expected-warning{{TRUE}} |
678 | clang_analyzer_eval(c9.getY() == 2); // expected-warning{{TRUE}} |
679 | |
680 | #endif // C++11 |
681 | |
682 | D d1 = returnTemporaryWithVariableAndNonTrivialCopy(); |
683 | clang_analyzer_eval(d1.getX() == 1); // expected-warning{{TRUE}} |
684 | clang_analyzer_eval(d1.getY() == 2); // expected-warning{{TRUE}} |
685 | |
686 | D d2 = returnTemporaryWithAnotherFunctionWithVariableAndNonTrivialCopy(); |
687 | clang_analyzer_eval(d2.getX() == 1); // expected-warning{{TRUE}} |
688 | clang_analyzer_eval(d2.getY() == 2); // expected-warning{{TRUE}} |
689 | |
690 | D d3 = returnTemporaryWithCopyConstructionWithVariableAndNonTrivialCopy(); |
691 | clang_analyzer_eval(d3.getX() == 1); // expected-warning{{TRUE}} |
692 | clang_analyzer_eval(d3.getY() == 2); // expected-warning{{TRUE}} |
693 | } |
694 | } // namespace test_return_temporary |
695 | |
696 | |
697 | namespace test_temporary_object_expr_without_dtor { |
698 | class C { |
699 | int x; |
700 | public: |
701 | C(int x) : x(x) {} |
702 | int getX() const { return x; } |
703 | }; |
704 | |
705 | void test() { |
706 | clang_analyzer_eval(C(3).getX() == 3); // expected-warning{{TRUE}} |
707 | }; |
708 | } |
709 | |
710 | namespace test_temporary_object_expr_with_dtor { |
711 | class C { |
712 | int x; |
713 | |
714 | public: |
715 | C(int x) : x(x) {} |
716 | ~C() {} |
717 | int getX() const { return x; } |
718 | }; |
719 | |
720 | void test(int coin) { |
721 | clang_analyzer_eval(C(3).getX() == 3); |
722 | #ifdef TEMPORARY_DTORS |
723 | // expected-warning@-2{{TRUE}} |
724 | #else |
725 | // expected-warning@-4{{UNKNOWN}} |
726 | #endif |
727 | |
728 | const C &c1 = coin ? C(1) : C(2); |
729 | if (coin) { |
730 | clang_analyzer_eval(c1.getX() == 1); |
731 | #ifdef TEMPORARY_DTORS |
732 | // expected-warning@-2{{TRUE}} |
733 | #else |
734 | // expected-warning@-4{{UNKNOWN}} |
735 | #endif |
736 | } else { |
737 | clang_analyzer_eval(c1.getX() == 2); |
738 | #ifdef TEMPORARY_DTORS |
739 | // expected-warning@-2{{TRUE}} |
740 | #else |
741 | // expected-warning@-4{{UNKNOWN}} |
742 | #endif |
743 | } |
744 | |
745 | C c2 = coin ? C(1) : C(2); |
746 | if (coin) { |
747 | clang_analyzer_eval(c2.getX() == 1); // expected-warning{{TRUE}} |
748 | } else { |
749 | clang_analyzer_eval(c2.getX() == 2); // expected-warning{{TRUE}} |
750 | } |
751 | } |
752 | |
753 | } // namespace test_temporary_object_expr |
754 | |
755 | namespace test_match_constructors_and_destructors { |
756 | class C { |
757 | public: |
758 | int &x, &y; |
759 | C(int &_x, int &_y) : x(_x), y(_y) { ++x; } |
760 | C(const C &c): x(c.x), y(c.y) { ++x; } |
761 | ~C() { ++y; } |
762 | }; |
763 | |
764 | void test_simple_temporary() { |
765 | int x = 0, y = 0; |
766 | { |
767 | const C &c = C(x, y); |
768 | } |
769 | // One constructor and one destructor. |
770 | clang_analyzer_eval(x == 1); |
771 | clang_analyzer_eval(y == 1); |
772 | #ifdef TEMPORARY_DTORS |
773 | // expected-warning@-3{{TRUE}} |
774 | // expected-warning@-3{{TRUE}} |
775 | #else |
776 | // expected-warning@-6{{UNKNOWN}} |
777 | // expected-warning@-6{{UNKNOWN}} |
778 | #endif |
779 | } |
780 | |
781 | void test_simple_temporary_with_copy() { |
782 | int x = 0, y = 0; |
783 | { |
784 | C c = C(x, y); |
785 | } |
786 | // Only one constructor directly into the variable, and one destructor. |
787 | clang_analyzer_eval(x == 1); // expected-warning{{TRUE}} |
788 | clang_analyzer_eval(y == 1); // expected-warning{{TRUE}} |
789 | } |
790 | |
791 | void test_ternary_temporary(int coin) { |
792 | int x = 0, y = 0, z = 0, w = 0; |
793 | { |
794 | const C &c = coin ? C(x, y) : C(z, w); |
795 | } |
796 | // Only one constructor on every branch, and one automatic destructor. |
797 | if (coin) { |
798 | clang_analyzer_eval(x == 1); |
799 | clang_analyzer_eval(y == 1); |
800 | #ifdef TEMPORARY_DTORS |
801 | // expected-warning@-3{{TRUE}} |
802 | // expected-warning@-3{{TRUE}} |
803 | #else |
804 | // expected-warning@-6{{UNKNOWN}} |
805 | // expected-warning@-6{{UNKNOWN}} |
806 | #endif |
807 | clang_analyzer_eval(z == 0); // expected-warning{{TRUE}} |
808 | clang_analyzer_eval(w == 0); // expected-warning{{TRUE}} |
809 | |
810 | } else { |
811 | clang_analyzer_eval(x == 0); // expected-warning{{TRUE}} |
812 | clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} |
813 | clang_analyzer_eval(z == 1); |
814 | clang_analyzer_eval(w == 1); |
815 | #ifdef TEMPORARY_DTORS |
816 | // expected-warning@-3{{TRUE}} |
817 | // expected-warning@-3{{TRUE}} |
818 | #else |
819 | // expected-warning@-6{{UNKNOWN}} |
820 | // expected-warning@-6{{UNKNOWN}} |
821 | #endif |
822 | } |
823 | } |
824 | |
825 | void test_ternary_temporary_with_copy(int coin) { |
826 | int x = 0, y = 0, z = 0, w = 0; |
827 | { |
828 | C c = coin ? C(x, y) : C(z, w); |
829 | } |
830 | // On each branch the variable is constructed directly. |
831 | if (coin) { |
832 | clang_analyzer_eval(x == 1); // expected-warning{{TRUE}} |
833 | #if __cplusplus < 201703L |
834 | clang_analyzer_eval(y == 1); // expected-warning{{TRUE}} |
835 | #else |
836 | // FIXME: Destructor called twice in C++17? |
837 | clang_analyzer_eval(y == 2); // expected-warning{{TRUE}} |
838 | #endif |
839 | clang_analyzer_eval(z == 0); // expected-warning{{TRUE}} |
840 | clang_analyzer_eval(w == 0); // expected-warning{{TRUE}} |
841 | |
842 | } else { |
843 | clang_analyzer_eval(x == 0); // expected-warning{{TRUE}} |
844 | clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} |
845 | clang_analyzer_eval(z == 1); // expected-warning{{TRUE}} |
846 | #if __cplusplus < 201703L |
847 | clang_analyzer_eval(w == 1); // expected-warning{{TRUE}} |
848 | #else |
849 | // FIXME: Destructor called twice in C++17? |
850 | clang_analyzer_eval(w == 2); // expected-warning{{TRUE}} |
851 | #endif |
852 | } |
853 | } |
854 | } // namespace test_match_constructors_and_destructors |
855 | |
856 | namespace destructors_for_return_values { |
857 | |
858 | class C { |
859 | public: |
860 | ~C() { |
861 | 1 / 0; // expected-warning{{Division by zero}} |
862 | } |
863 | }; |
864 | |
865 | C make(); |
866 | |
867 | void testFloatingCall() { |
868 | make(); |
869 | // Should have divided by zero in the destructor. |
870 | clang_analyzer_warnIfReached(); |
871 | #ifndef TEMPORARY_DTORS |
872 | // expected-warning@-2{{REACHABLE}} |
873 | #endif |
874 | } |
875 | |
876 | void testLifetimeExtendedCall() { |
877 | { |
878 | const C &c = make(); |
879 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
880 | } |
881 | // Should have divided by zero in the destructor. |
882 | clang_analyzer_warnIfReached(); // no-warning |
883 | } |
884 | |
885 | void testCopiedCall() { |
886 | { |
887 | C c = make(); |
888 | // Should have elided the constructor/destructor for the temporary |
889 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
890 | } |
891 | // Should have divided by zero in the destructor. |
892 | clang_analyzer_warnIfReached(); // no-warning |
893 | } |
894 | } // namespace destructors_for_return_values |
895 | |
896 | namespace dont_forget_destructor_around_logical_op { |
897 | int glob; |
898 | |
899 | class C { |
900 | public: |
901 | ~C() { |
902 | glob = 1; |
903 | // FIXME: Why is destructor not inlined in C++17 |
904 | clang_analyzer_checkInlined(true); |
905 | #ifdef TEMPORARY_DTORS |
906 | #if __cplusplus < 201703L |
907 | // expected-warning@-3{{TRUE}} |
908 | #endif |
909 | #endif |
910 | } |
911 | }; |
912 | |
913 | C get(); |
914 | |
915 | bool is(C); |
916 | |
917 | |
918 | void test(int coin) { |
919 | // Here temporaries are being cleaned up after && is evaluated. There are two |
920 | // temporaries: the return value of get() and the elidable copy constructor |
921 | // of that return value into is(). According to the CFG, we need to cleanup |
922 | // both of them depending on whether the temporary corresponding to the |
923 | // return value of get() was initialized. However, we didn't track |
924 | // temporaries returned from functions, so we took the wrong branch. |
925 | coin && is(get()); // no-crash |
926 | if (coin) { |
927 | // FIXME: Why is destructor not inlined in C++17 |
928 | clang_analyzer_eval(glob); |
929 | #ifdef TEMPORARY_DTORS |
930 | #if __cplusplus < 201703L |
931 | // expected-warning@-3{{TRUE}} |
932 | #else |
933 | // expected-warning@-5{{UNKNOWN}} |
934 | #endif |
935 | #else |
936 | // expected-warning@-8{{UNKNOWN}} |
937 | #endif |
938 | } else { |
939 | // The destructor is not called on this branch. |
940 | clang_analyzer_eval(glob); // expected-warning{{UNKNOWN}} |
941 | } |
942 | } |
943 | } // namespace dont_forget_destructor_around_logical_op |
944 | |
945 | #if __cplusplus >= 201103L |
946 | namespace temporary_list_crash { |
947 | class C { |
948 | public: |
949 | C() {} |
950 | ~C() {} |
951 | }; |
952 | |
953 | void test() { |
954 | std::initializer_list<C>{C(), C()}; // no-crash |
955 | } |
956 | } // namespace temporary_list_crash |
957 | #endif // C++11 |
958 | |
959 | namespace implicit_constructor_conversion { |
960 | struct S { |
961 | int x; |
962 | S(int x) : x(x) {} |
963 | ~S() {} |
964 | }; |
965 | |
966 | class C { |
967 | int x; |
968 | |
969 | public: |
970 | C(const S &s) : x(s.x) {} |
971 | ~C() {} |
972 | int getX() const { return x; } |
973 | }; |
974 | |
975 | void test() { |
976 | const C &c1 = S(10); |
977 | clang_analyzer_eval(c1.getX() == 10); |
978 | #ifdef TEMPORARY_DTORS |
979 | // expected-warning@-2{{TRUE}} |
980 | #else |
981 | // expected-warning@-4{{UNKNOWN}} |
982 | #endif |
983 | |
984 | S s = 20; |
985 | clang_analyzer_eval(s.x == 20); // expected-warning{{TRUE}} |
986 | |
987 | C c2 = s; |
988 | clang_analyzer_eval(c2.getX() == 20); // expected-warning{{TRUE}} |
989 | } |
990 | } // end namespace implicit_constructor_conversion |
991 | |
992 | namespace pass_references_through { |
993 | class C { |
994 | public: |
995 | ~C() {} |
996 | }; |
997 | |
998 | const C &foo1(); |
999 | C &&foo2(); |
1000 | |
1001 | // In these examples the foo() expression has record type, not reference type. |
1002 | // Don't try to figure out how to perform construction of the record here. |
1003 | const C &bar1() { return foo1(); } // no-crash |
1004 | C &&bar2() { return foo2(); } // no-crash |
1005 | } // end namespace pass_references_through |
1006 | |
1007 | |
1008 | namespace arguments { |
1009 | int glob; |
1010 | |
1011 | struct S { |
1012 | int x; |
1013 | S(int x): x(x) {} |
1014 | S(const S &s) : x(s.x) {} |
1015 | ~S() {} |
1016 | |
1017 | S &operator+(S s) { |
1018 | glob = s.x; |
1019 | x += s.x; |
1020 | return *this; |
1021 | } |
1022 | }; |
1023 | |
1024 | class C { |
1025 | public: |
1026 | virtual void bar3(S s) {} |
1027 | }; |
1028 | |
1029 | class D: public C { |
1030 | public: |
1031 | D() {} |
1032 | virtual void bar3(S s) override { glob = s.x; } |
1033 | }; |
1034 | |
1035 | void bar1(S s) { |
1036 | glob = s.x; |
1037 | } |
1038 | |
1039 | // Record-typed calls are a different CFGStmt, let's see if we handle that |
1040 | // as well. |
1041 | S bar2(S s) { |
1042 | glob = s.x; |
1043 | return S(3); |
1044 | } |
1045 | |
1046 | void bar5(int, ...); |
1047 | |
1048 | void foo(void (*bar4)(S)) { |
1049 | bar1(S(1)); |
1050 | clang_analyzer_eval(glob == 1); |
1051 | #ifdef TEMPORARY_DTORS |
1052 | // expected-warning@-2{{TRUE}} |
1053 | #else |
1054 | // expected-warning@-4{{UNKNOWN}} |
1055 | #endif |
1056 | |
1057 | bar2(S(2)); |
1058 | // FIXME: Why are we losing information in C++17? |
1059 | clang_analyzer_eval(glob == 2); |
1060 | #ifdef TEMPORARY_DTORS |
1061 | #if __cplusplus < 201703L |
1062 | // expected-warning@-3{{TRUE}} |
1063 | #else |
1064 | // expected-warning@-5{{UNKNOWN}} |
1065 | #endif |
1066 | #else |
1067 | // expected-warning@-8{{UNKNOWN}} |
1068 | #endif |
1069 | |
1070 | C *c = new D(); |
1071 | c->bar3(S(3)); |
1072 | // FIXME: Should be TRUE. |
1073 | clang_analyzer_eval(glob == 3); // expected-warning{{UNKNOWN}} |
1074 | delete c; |
1075 | |
1076 | // What if we've no idea what we're calling? |
1077 | bar4(S(4)); // no-crash |
1078 | |
1079 | S(5) + S(6); |
1080 | clang_analyzer_eval(glob == 6); |
1081 | #ifdef TEMPORARY_DTORS |
1082 | // expected-warning@-2{{TRUE}} |
1083 | #else |
1084 | // expected-warning@-4{{UNKNOWN}} |
1085 | #endif |
1086 | |
1087 | // Variadic functions. This will __builtin_trap() because you cannot pass |
1088 | // an object as a variadic argument. |
1089 | bar5(7, S(7)); // no-crash |
1090 | clang_analyzer_warnIfReached(); // no-warning |
1091 | } |
1092 | } // namespace arguments |
1093 | |
1094 | namespace ctor_argument { |
1095 | // Stripped down unique_ptr<int> |
1096 | struct IntPtr { |
1097 | IntPtr(): i(new int) {} |
1098 | IntPtr(IntPtr &&o): i(o.i) { o.i = 0; } |
1099 | ~IntPtr() { delete i; } |
1100 | |
1101 | int *i; |
1102 | }; |
1103 | |
1104 | struct Foo { |
1105 | Foo(IntPtr); |
1106 | void bar(); |
1107 | |
1108 | IntPtr i; |
1109 | }; |
1110 | |
1111 | void bar() { |
1112 | IntPtr ptr; |
1113 | int *i = ptr.i; |
1114 | Foo f(static_cast<IntPtr &&>(ptr)); |
1115 | *i = 99; // no-warning |
1116 | } |
1117 | } // namespace ctor_argument |
1118 | |
1119 | namespace operator_implicit_argument { |
1120 | struct S { |
1121 | bool x; |
1122 | S(bool x): x(x) {} |
1123 | operator bool() const { return x; } |
1124 | }; |
1125 | |
1126 | void foo() { |
1127 | if (S(false)) { |
1128 | clang_analyzer_warnIfReached(); // no-warning |
1129 | } |
1130 | if (S(true)) { |
1131 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
1132 | } |
1133 | } |
1134 | } // namespace operator_implicit_argument |
1135 | |
1136 | |
1137 | #if __cplusplus >= 201103L |
1138 | namespace argument_lazy_bindings { |
1139 | int glob; |
1140 | |
1141 | struct S { |
1142 | int x, y, z; |
1143 | }; |
1144 | |
1145 | struct T { |
1146 | S s; |
1147 | int w; |
1148 | T(int w): s{5, 6, 7}, w(w) {} |
1149 | }; |
1150 | |
1151 | void foo(T t) { |
1152 | t.s = {1, 2, 3}; |
1153 | glob = t.w; |
1154 | } |
1155 | |
1156 | void bar() { |
1157 | foo(T(4)); |
1158 | clang_analyzer_eval(glob == 4); // expected-warning{{TRUE}} |
1159 | } |
1160 | } // namespace argument_lazy_bindings |
1161 | #endif |
1162 | |
1163 | namespace operator_argument_cleanup { |
1164 | struct S { |
1165 | S(); |
1166 | }; |
1167 | |
1168 | class C { |
1169 | public: |
1170 | void operator=(S); |
1171 | }; |
1172 | |
1173 | void foo() { |
1174 | C c; |
1175 | c = S(); // no-crash |
1176 | } |
1177 | } // namespace operator_argument_cleanup |
1178 | |
1179 | namespace argument_decl_lookup { |
1180 | class C {}; |
1181 | int foo(C); |
1182 | int bar(C c) { foo(c); } |
1183 | int foo(C c) {} |
1184 | } // namespace argument_decl_lookup |
1185 | |
1186 | namespace argument_virtual_decl_lookup { |
1187 | class C {}; |
1188 | |
1189 | struct T { |
1190 | virtual void foo(C); |
1191 | }; |
1192 | |
1193 | void run() { |
1194 | T *t; |
1195 | t->foo(C()); // no-crash // expected-warning{{Called C++ object pointer is uninitialized}} |
1196 | } |
1197 | |
1198 | // This is after run() because the test is about picking the correct decl |
1199 | // for the parameter region, which should belong to the correct function decl, |
1200 | // and the non-definition decl should be found by direct lookup. |
1201 | void T::foo(C) {} |
1202 | } // namespace argument_virtual_decl_lookup |
1203 | |
1204 | namespace union_indirect_field_crash { |
1205 | union U { |
1206 | struct { |
1207 | int x; |
1208 | }; |
1209 | }; |
1210 | |
1211 | template <typename T> class C { |
1212 | public: |
1213 | void foo() const { |
1214 | (void)(true ? U().x : 0); |
1215 | } |
1216 | }; |
1217 | |
1218 | void test() { |
1219 | C<int> c; |
1220 | c.foo(); |
1221 | } |
1222 | } // namespace union_indirect_field_crash |
1223 | |
1224 | namespace return_from_top_frame { |
1225 | struct S { |
1226 | int *p; |
1227 | S() { p = new int; } |
1228 | S(S &&s) : p(s.p) { s.p = 0; } |
1229 | ~S(); // Presumably releases 'p'. |
1230 | }; |
1231 | |
1232 | S foo() { |
1233 | S s; |
1234 | return s; |
1235 | } |
1236 | |
1237 | S bar1() { |
1238 | return foo(); // no-warning |
1239 | } |
1240 | |
1241 | S bar2() { |
1242 | return S(); |
1243 | } |
1244 | |
1245 | S bar3(int coin) { |
1246 | return coin ? S() : foo(); // no-warning |
1247 | } |
1248 | } // namespace return_from_top_frame |
1249 | |