1 // RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -analyzer-config eagerly-assume=false %s
2 // RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -DTEMPORARIES -verify -analyzer-config eagerly-assume=false %s
3 // RUN: %clang_analyze_cc1 -Wno-unused -std=c++17 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -DTEMPORARIES -analyzer-config eagerly-assume=false %s
4 // RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -DMOVES -verify -analyzer-config eagerly-assume=false %s
5 // RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -DTEMPORARIES -DMOVES -verify -analyzer-config eagerly-assume=false %s
6 // RUN: %clang_analyze_cc1 -Wno-unused -std=c++17 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -DTEMPORARIES -DMOVES -analyzer-config eagerly-assume=false %s
7 
8 // Note: The C++17 run-lines don't -verify yet - it is a no-crash test.
9 
10 void clang_analyzer_eval(bool);
11 void clang_analyzer_checkInlined(bool);
12 
13 namespace pr17001_call_wrong_destructor {
14 bool x;
15 struct A {
16   int *a;
Apr17001_call_wrong_destructor::A17   A() {}
~Apr17001_call_wrong_destructor::A18   ~A() {}
19 };
20 struct B : public A {
Bpr17001_call_wrong_destructor::B21   B() {}
~Bpr17001_call_wrong_destructor::B22   ~B() { x = true; }
23 };
24 
f()25 void f() {
26   {
27     const A &a = B();
28   }
29   clang_analyzer_eval(x); // expected-warning{{TRUE}}
30 }
31 } // end namespace pr17001_call_wrong_destructor
32 
33 namespace pr19539_crash_on_destroying_an_integer {
34 struct A {
35   int i;
36   int j[2];
Apr19539_crash_on_destroying_an_integer::A37   A() : i(1) {
38     j[0] = 2;
39     j[1] = 3;
40   }
~Apr19539_crash_on_destroying_an_integer::A41   ~A() {}
42 };
43 
f()44 void f() {
45   const int &x = A().i; // no-crash
46   const int &y = A().j[1]; // no-crash
47   const int &z = (A().j[1], A().j[0]); // no-crash
48 
49   clang_analyzer_eval(x == 1);
50   clang_analyzer_eval(y == 3);
51   clang_analyzer_eval(z == 2);
52 #ifdef TEMPORARIES
53   // expected-warning@-4{{TRUE}}
54   // expected-warning@-4{{TRUE}}
55   // expected-warning@-4{{TRUE}}
56 #else
57   // expected-warning@-8{{UNKNOWN}}
58   // expected-warning@-8{{UNKNOWN}}
59   // expected-warning@-8{{UNKNOWN}}
60 #endif
61 }
62 } // end namespace pr19539_crash_on_destroying_an_integer
63 
64 namespace maintain_original_object_address_on_lifetime_extension {
65 class C {
66   C **after, **before;
67 
68 public:
69   bool x;
70 
C(bool x,C ** after,C ** before)71   C(bool x, C **after, C **before) : x(x), after(after), before(before) {
72     *before = this;
73   }
74 
75   // Don't track copies in our tests.
C(const C & c)76   C(const C &c) : x(c.x), after(nullptr), before(nullptr) {}
77 
~C()78   ~C() { if (after) *after = this; }
79 
operator bool() const80   operator bool() const { return x; }
81 
make(C ** after,C ** before)82   static C make(C **after, C **before) { return C(false, after, before); }
83 };
84 
f1()85 void f1() {
86   C *after, *before;
87   {
88     const C &c = C(true, &after, &before);
89   }
90   clang_analyzer_eval(after == before);
91 #ifdef TEMPORARIES
92   // expected-warning@-2{{TRUE}}
93 #else
94   // expected-warning@-4{{UNKNOWN}}
95 #endif
96 }
97 
f2()98 void f2() {
99   C *after, *before;
100   {
101     C c = C(1, &after, &before);
102   }
103   clang_analyzer_eval(after == before); // expected-warning{{TRUE}}
104 }
105 
f3(bool coin)106 void f3(bool coin) {
107   C *after, *before;
108   {
109     const C &c = coin ? C(true, &after, &before) : C(false, &after, &before);
110   }
111   clang_analyzer_eval(after == before);
112 #ifdef TEMPORARIES
113   // expected-warning@-2{{TRUE}}
114 #else
115   // expected-warning@-4{{UNKNOWN}}
116 #endif
117 }
118 
f4(bool coin)119 void f4(bool coin) {
120   C *after, *before;
121   {
122     // no-crash
123     const C &c = C(coin, &after, &before) ?: C(false, &after, &before);
124   }
125   // FIXME: Add support for lifetime extension through binary conditional
126   // operator. Ideally also add support for the binary conditional operator in
127   // C++. Because for now it calls the constructor for the condition twice.
128   if (coin) {
129     // FIXME: Should not warn.
130     clang_analyzer_eval(after == before);
131 #ifdef TEMPORARIES
132   // expected-warning@-2{{The left operand of '==' is a garbage value}}
133 #else
134   // expected-warning@-4{{UNKNOWN}}
135 #endif
136   } else {
137     // FIXME: Should be TRUE.
138     clang_analyzer_eval(after == before);
139 #ifdef TEMPORARIES
140   // expected-warning@-2{{FALSE}}
141 #else
142   // expected-warning@-4{{UNKNOWN}}
143 #endif
144   }
145 }
146 
f5()147 void f5() {
148   C *after, *before;
149   {
150     const bool &x = C(true, &after, &before).x; // no-crash
151   }
152   clang_analyzer_eval(after == before);
153 #ifdef TEMPORARIES
154   // expected-warning@-2{{TRUE}}
155 #else
156   // expected-warning@-4{{UNKNOWN}}
157 #endif
158 }
159 
160 struct A { // A is an aggregate.
161   const C &c;
162 };
163 
f6()164 void f6() {
165   C *after, *before;
166   {
167     A a{C(true, &after, &before)};
168   }
169   // FIXME: Should be TRUE. Should not warn about garbage value.
170   clang_analyzer_eval(after == before); // expected-warning{{UNKNOWN}}
171 }
172 
f7()173 void f7() {
174   C *after, *before;
175   {
176     A a = {C(true, &after, &before)};
177   }
178   // FIXME: Should be TRUE. Should not warn about garbage value.
179   clang_analyzer_eval(after == before); // expected-warning{{UNKNOWN}}
180 }
181 
f8()182 void f8() {
183   C *after, *before;
184   {
185     A a[2] = {C(false, nullptr, nullptr), C(true, &after, &before)};
186   }
187   // FIXME: Should be TRUE. Should not warn about garbage value.
188   clang_analyzer_eval(after == before); // expected-warning{{UNKNOWN}}
189 }
190 } // end namespace maintain_original_object_address_on_lifetime_extension
191 
192 namespace maintain_original_object_address_on_move {
193 class C {
194   int *x;
195 
196 public:
C()197   C() : x(nullptr) {}
C(int * x)198   C(int *x) : x(x) {}
199   C(const C &c) = delete;
C(C && c)200   C(C &&c) : x(c.x) { c.x = nullptr; }
operator =(C && c)201   C &operator=(C &&c) {
202     x = c.x;
203     c.x = nullptr;
204     return *this;
205   }
~C()206   ~C() {
207     // This was triggering the division by zero warning in f1() and f2():
208     // Because move-elision materialization was incorrectly causing the object
209     // to be relocated from one address to another before move, but destructor
210     // was operating on the old address, it was still thinking that 'x' is set.
211     if (x)
212       *x = 0;
213   }
214 };
215 
f1()216 void f1() {
217   int x = 1;
218   // &x is replaced with nullptr in move-constructor before the temporary dies.
219   C c = C(&x);
220   // Hence x was not set to 0 yet.
221   1 / x; // no-warning
222 }
f2()223 void f2() {
224   int x = 1;
225   C c;
226   // &x is replaced with nullptr in move-assignment before the temporary dies.
227   c = C(&x);
228   // Hence x was not set to 0 yet.
229   1 / x; // no-warning
230 }
231 } // end namespace maintain_original_object_address_on_move
232 
233 namespace maintain_address_of_copies {
234 class C;
235 
236 struct AddressVector {
237   C *buf[10];
238   int len;
239 
AddressVectormaintain_address_of_copies::AddressVector240   AddressVector() : len(0) {}
241 
pushmaintain_address_of_copies::AddressVector242   void push(C *c) {
243     buf[len] = c;
244     ++len;
245   }
246 };
247 
248 class C {
249   AddressVector &v;
250 
251 public:
C(AddressVector & v)252   C(AddressVector &v) : v(v) { v.push(this); }
~C()253   ~C() { v.push(this); }
254 
255 #ifdef MOVES
C(C && c)256   C(C &&c) : v(c.v) { v.push(this); }
257 #endif
258 
259   // Note how return-statements prefer move-constructors when available.
C(const C & c)260   C(const C &c) : v(c.v) {
261 #ifdef MOVES
262     clang_analyzer_checkInlined(false); // no-warning
263 #else
264     v.push(this);
265 #endif
266   } // no-warning
267 
make(AddressVector & v)268   static C make(AddressVector &v) { return C(v); }
269 };
270 
f1()271 void f1() {
272   AddressVector v;
273   {
274     C c = C(v);
275   }
276   // 0. Construct variable 'c' (copy/move elided).
277   // 1. Destroy variable 'c'.
278   clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
279   clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
280 }
281 
f2()282 void f2() {
283   AddressVector v;
284   {
285     const C &c = C::make(v);
286   }
287   // 0. Construct the return value of make() (copy/move elided) and
288   //    lifetime-extend it directly via reference 'c',
289   // 1. Destroy the temporary lifetime-extended by 'c'.
290   clang_analyzer_eval(v.len == 2);
291   clang_analyzer_eval(v.buf[0] == v.buf[1]);
292 #ifdef TEMPORARIES
293   // expected-warning@-3{{TRUE}}
294   // expected-warning@-3{{TRUE}}
295 #else
296   // expected-warning@-6{{UNKNOWN}}
297   // expected-warning@-6{{UNKNOWN}}
298 #endif
299 }
300 
f3()301 void f3() {
302   AddressVector v;
303   {
304     C &&c = C::make(v);
305   }
306   // 0. Construct the return value of make() (copy/move elided) and
307   //    lifetime-extend it directly via reference 'c',
308   // 1. Destroy the temporary lifetime-extended by 'c'.
309   clang_analyzer_eval(v.len == 2);
310   clang_analyzer_eval(v.buf[0] == v.buf[1]);
311 #ifdef TEMPORARIES
312   // expected-warning@-3{{TRUE}}
313   // expected-warning@-3{{TRUE}}
314 #else
315   // expected-warning@-6{{UNKNOWN}}
316   // expected-warning@-6{{UNKNOWN}}
317 #endif
318 }
319 
doubleMake(AddressVector & v)320 C doubleMake(AddressVector &v) {
321   return C::make(v);
322 }
323 
f4()324 void f4() {
325   AddressVector v;
326   {
327     C c = doubleMake(v);
328   }
329   // 0. Construct variable 'c' (all copies/moves elided),
330   // 1. Destroy variable 'c'.
331   clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
332   clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
333 }
334 } // end namespace maintain_address_of_copies
335