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