1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
2 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DCONSTRUCTORS=1 -analyzer-config c++-inlining=constructors -verify %s
3 
4 void clang_analyzer_eval(bool);
5 
6 class A {
7 protected:
8   int x;
9 };
10 
11 class B : public A {
12 public:
13   void f();
14 };
15 
16 void B::f() {
17   x = 3;
18 }
19 
20 
21 class C : public B {
22 public:
23   void g() {
24     // This used to crash because we are upcasting through two bases.
25     x = 5;
26   }
27 };
28 
29 
30 namespace VirtualBaseClasses {
31   class A {
32   protected:
33     int x;
34   };
35 
36   class B : public virtual A {
37   public:
38     int getX() { return x; }
39   };
40 
41   class C : public virtual A {
42   public:
43     void setX() { x = 42; }
44   };
45 
46   class D : public B, public C {};
47   class DV : virtual public B, public C {};
48   class DV2 : public B, virtual public C {};
49 
50   void test() {
51     D d;
52     d.setX();
53     clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
54 
55     DV dv;
56     dv.setX();
57     clang_analyzer_eval(dv.getX() == 42); // expected-warning{{TRUE}}
58 
59     DV2 dv2;
60     dv2.setX();
61     clang_analyzer_eval(dv2.getX() == 42); // expected-warning{{TRUE}}
62   }
63 
64 
65   // Make sure we're consistent about the offset of the A subobject within an
66   // Intermediate virtual base class.
67   class Padding1 { int unused; };
68   class Padding2 { int unused; };
69   class Intermediate : public Padding1, public A, public Padding2 {};
70 
71   class BI : public virtual Intermediate {
72   public:
73     int getX() { return x; }
74   };
75 
76   class CI : public virtual Intermediate {
77   public:
78     void setX() { x = 42; }
79   };
80 
81   class DI : public BI, public CI {};
82 
83   void testIntermediate() {
84     DI d;
85     d.setX();
86     clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
87   }
88 }
89 
90 
91 namespace DynamicVirtualUpcast {
92   class A {
93   public:
94     virtual ~A();
95   };
96 
97   class B : virtual public A {};
98   class C : virtual public B {};
99   class D : virtual public C {};
100 
101   bool testCast(A *a) {
102     return dynamic_cast<B*>(a) && dynamic_cast<C*>(a);
103   }
104 
105   void test() {
106     D d;
107     clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
108   }
109 }
110 
111 namespace DynamicMultipleInheritanceUpcast {
112   class B {
113   public:
114     virtual ~B();
115   };
116   class C {
117   public:
118     virtual ~C();
119   };
120   class D : public B, public C {};
121 
122   bool testCast(B *a) {
123     return dynamic_cast<C*>(a);
124   }
125 
126   void test() {
127     D d;
128     clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
129   }
130 
131 
132   class DV : virtual public B, virtual public C {};
133 
134   void testVirtual() {
135     DV d;
136     clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
137   }
138 }
139 
140 namespace LazyBindings {
141   struct Base {
142     int x;
143   };
144 
145   struct Derived : public Base {
146     int y;
147   };
148 
149   struct DoubleDerived : public Derived {
150     int z;
151   };
152 
153   int getX(const Base &obj) {
154     return obj.x;
155   }
156 
157   int getY(const Derived &obj) {
158     return obj.y;
159   }
160 
161   void testDerived() {
162     Derived d;
163     d.x = 1;
164     d.y = 2;
165     clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
166     clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
167 
168     Base b(d);
169     clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
170 
171     Derived d2(d);
172     clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
173     clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
174   }
175 
176   void testDoubleDerived() {
177     DoubleDerived d;
178     d.x = 1;
179     d.y = 2;
180     clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
181     clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
182 
183     Base b(d);
184     clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
185 
186     Derived d2(d);
187     clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
188     clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
189 
190     DoubleDerived d3(d);
191     clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
192     clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
193   }
194 
195   namespace WithOffset {
196     struct Offset {
197       int padding;
198     };
199 
200     struct OffsetDerived : private Offset, public Base {
201       int y;
202     };
203 
204     struct DoubleOffsetDerived : public OffsetDerived {
205       int z;
206     };
207 
208     int getY(const OffsetDerived &obj) {
209       return obj.y;
210     }
211 
212     void testDerived() {
213       OffsetDerived d;
214       d.x = 1;
215       d.y = 2;
216       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
217       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
218 
219       Base b(d);
220       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
221 
222       OffsetDerived d2(d);
223       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
224       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
225     }
226 
227     void testDoubleDerived() {
228       DoubleOffsetDerived d;
229       d.x = 1;
230       d.y = 2;
231       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
232       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
233 
234       Base b(d);
235       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
236 
237       OffsetDerived d2(d);
238       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
239       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
240 
241       DoubleOffsetDerived d3(d);
242       clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
243       clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
244     }
245   }
246 
247   namespace WithVTable {
248     struct DerivedVTBL : public Base {
249       int y;
250       virtual void method();
251     };
252 
253     struct DoubleDerivedVTBL : public DerivedVTBL {
254       int z;
255     };
256 
257     int getY(const DerivedVTBL &obj) {
258       return obj.y;
259     }
260 
261     int getZ(const DoubleDerivedVTBL &obj) {
262       return obj.z;
263     }
264 
265     void testDerived() {
266       DerivedVTBL d;
267       d.x = 1;
268       d.y = 2;
269       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
270       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
271 
272       Base b(d);
273       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
274 
275 #if CONSTRUCTORS
276       DerivedVTBL d2(d);
277       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
278       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
279 #endif
280     }
281 
282 #if CONSTRUCTORS
283     void testDoubleDerived() {
284       DoubleDerivedVTBL d;
285       d.x = 1;
286       d.y = 2;
287       d.z = 3;
288       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
289       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
290       clang_analyzer_eval(getZ(d) == 3); // expected-warning{{TRUE}}
291 
292       Base b(d);
293       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
294 
295       DerivedVTBL d2(d);
296       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
297       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
298 
299       DoubleDerivedVTBL d3(d);
300       clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
301       clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
302       clang_analyzer_eval(getZ(d3) == 3); // expected-warning{{TRUE}}
303     }
304 #endif
305   }
306 
307 #if CONSTRUCTORS
308   namespace Nested {
309     struct NonTrivialCopy {
310       int padding;
311       NonTrivialCopy() {}
312       NonTrivialCopy(const NonTrivialCopy &) {}
313     };
314 
315     struct FullyDerived : private NonTrivialCopy, public Derived {
316       int z;
317     };
318 
319     struct Wrapper {
320       FullyDerived d;
321       int zz;
322 
323       Wrapper(const FullyDerived &d) : d(d), zz(0) {}
324     };
325 
326     void test5() {
327       Wrapper w((FullyDerived()));
328       w.d.x = 1;
329 
330       Wrapper w2(w);
331       clang_analyzer_eval(getX(w2.d) == 1); // expected-warning{{TRUE}}
332     }
333   }
334 #endif
335 }
336 
337 namespace Redeclaration {
338   class Base;
339 
340   class Base {
341   public:
342     virtual int foo();
343     int get() { return value; }
344 
345     int value;
346   };
347 
348   class Derived : public Base {
349   public:
350     virtual int bar();
351   };
352 
353   void test(Derived d) {
354     d.foo(); // don't crash
355     d.bar(); // sanity check
356 
357     Base &b = d;
358     b.foo(); // don't crash
359 
360     d.value = 42; // don't crash
361     clang_analyzer_eval(d.get() == 42); // expected-warning{{TRUE}}
362     clang_analyzer_eval(b.get() == 42); // expected-warning{{TRUE}}
363   }
364 };
365 
366