• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 void clang_analyzer_checkInlined(bool);
6 
7 class A {
8 protected:
9   int x;
10 };
11 
12 class B : public A {
13 public:
14   void f();
15 };
16 
f()17 void B::f() {
18   x = 3;
19 }
20 
21 
22 class C : public B {
23 public:
g()24   void g() {
25     // This used to crash because we are upcasting through two bases.
26     x = 5;
27   }
28 };
29 
30 
31 namespace VirtualBaseClasses {
32   class A {
33   protected:
34     int x;
35   };
36 
37   class B : public virtual A {
38   public:
getX()39     int getX() { return x; }
40   };
41 
42   class C : public virtual A {
43   public:
setX()44     void setX() { x = 42; }
45   };
46 
47   class D : public B, public C {};
48   class DV : virtual public B, public C {};
49   class DV2 : public B, virtual public C {};
50 
test()51   void test() {
52     D d;
53     d.setX();
54     clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
55 
56     DV dv;
57     dv.setX();
58     clang_analyzer_eval(dv.getX() == 42); // expected-warning{{TRUE}}
59 
60     DV2 dv2;
61     dv2.setX();
62     clang_analyzer_eval(dv2.getX() == 42); // expected-warning{{TRUE}}
63   }
64 
65 
66   // Make sure we're consistent about the offset of the A subobject within an
67   // Intermediate virtual base class.
68   class Padding1 { int unused; };
69   class Padding2 { int unused; };
70   class Intermediate : public Padding1, public A, public Padding2 {};
71 
72   class BI : public virtual Intermediate {
73   public:
getX()74     int getX() { return x; }
75   };
76 
77   class CI : public virtual Intermediate {
78   public:
setX()79     void setX() { x = 42; }
80   };
81 
82   class DI : public BI, public CI {};
83 
testIntermediate()84   void testIntermediate() {
85     DI d;
86     d.setX();
87     clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
88   }
89 }
90 
91 
92 namespace DynamicVirtualUpcast {
93   class A {
94   public:
95     virtual ~A();
96   };
97 
98   class B : virtual public A {};
99   class C : virtual public B {};
100   class D : virtual public C {};
101 
testCast(A * a)102   bool testCast(A *a) {
103     return dynamic_cast<B*>(a) && dynamic_cast<C*>(a);
104   }
105 
test()106   void test() {
107     D d;
108     clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
109   }
110 }
111 
112 namespace DynamicMultipleInheritanceUpcast {
113   class B {
114   public:
115     virtual ~B();
116   };
117   class C {
118   public:
119     virtual ~C();
120   };
121   class D : public B, public C {};
122 
testCast(B * a)123   bool testCast(B *a) {
124     return dynamic_cast<C*>(a);
125   }
126 
test()127   void test() {
128     D d;
129     clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
130   }
131 
132 
133   class DV : virtual public B, virtual public C {};
134 
testVirtual()135   void testVirtual() {
136     DV d;
137     clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
138   }
139 }
140 
141 namespace LazyBindings {
142   struct Base {
143     int x;
144   };
145 
146   struct Derived : public Base {
147     int y;
148   };
149 
150   struct DoubleDerived : public Derived {
151     int z;
152   };
153 
getX(const Base & obj)154   int getX(const Base &obj) {
155     return obj.x;
156   }
157 
getY(const Derived & obj)158   int getY(const Derived &obj) {
159     return obj.y;
160   }
161 
testDerived()162   void testDerived() {
163     Derived d;
164     d.x = 1;
165     d.y = 2;
166     clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
167     clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
168 
169     Base b(d);
170     clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
171 
172     Derived d2(d);
173     clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
174     clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
175   }
176 
testDoubleDerived()177   void testDoubleDerived() {
178     DoubleDerived d;
179     d.x = 1;
180     d.y = 2;
181     clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
182     clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
183 
184     Base b(d);
185     clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
186 
187     Derived d2(d);
188     clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
189     clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
190 
191     DoubleDerived d3(d);
192     clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
193     clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
194   }
195 
196   namespace WithOffset {
197     struct Offset {
198       int padding;
199     };
200 
201     struct OffsetDerived : private Offset, public Base {
202       int y;
203     };
204 
205     struct DoubleOffsetDerived : public OffsetDerived {
206       int z;
207     };
208 
getY(const OffsetDerived & obj)209     int getY(const OffsetDerived &obj) {
210       return obj.y;
211     }
212 
testDerived()213     void testDerived() {
214       OffsetDerived d;
215       d.x = 1;
216       d.y = 2;
217       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
218       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
219 
220       Base b(d);
221       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
222 
223       OffsetDerived d2(d);
224       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
225       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
226     }
227 
testDoubleDerived()228     void testDoubleDerived() {
229       DoubleOffsetDerived d;
230       d.x = 1;
231       d.y = 2;
232       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
233       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
234 
235       Base b(d);
236       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
237 
238       OffsetDerived d2(d);
239       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
240       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
241 
242       DoubleOffsetDerived d3(d);
243       clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
244       clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
245     }
246   }
247 
248   namespace WithVTable {
249     struct DerivedVTBL : public Base {
250       int y;
251       virtual void method();
252     };
253 
254     struct DoubleDerivedVTBL : public DerivedVTBL {
255       int z;
256     };
257 
getY(const DerivedVTBL & obj)258     int getY(const DerivedVTBL &obj) {
259       return obj.y;
260     }
261 
getZ(const DoubleDerivedVTBL & obj)262     int getZ(const DoubleDerivedVTBL &obj) {
263       return obj.z;
264     }
265 
testDerived()266     void testDerived() {
267       DerivedVTBL d;
268       d.x = 1;
269       d.y = 2;
270       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
271       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
272 
273       Base b(d);
274       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
275 
276 #if CONSTRUCTORS
277       DerivedVTBL d2(d);
278       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
279       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
280 #endif
281     }
282 
283 #if CONSTRUCTORS
testDoubleDerived()284     void testDoubleDerived() {
285       DoubleDerivedVTBL d;
286       d.x = 1;
287       d.y = 2;
288       d.z = 3;
289       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
290       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
291       clang_analyzer_eval(getZ(d) == 3); // expected-warning{{TRUE}}
292 
293       Base b(d);
294       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
295 
296       DerivedVTBL d2(d);
297       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
298       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
299 
300       DoubleDerivedVTBL d3(d);
301       clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
302       clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
303       clang_analyzer_eval(getZ(d3) == 3); // expected-warning{{TRUE}}
304     }
305 #endif
306   }
307 
308 #if CONSTRUCTORS
309   namespace Nested {
310     struct NonTrivialCopy {
311       int padding;
NonTrivialCopyLazyBindings::Nested::NonTrivialCopy312       NonTrivialCopy() {}
NonTrivialCopyLazyBindings::Nested::NonTrivialCopy313       NonTrivialCopy(const NonTrivialCopy &) {}
314     };
315 
316     struct FullyDerived : private NonTrivialCopy, public Derived {
317       int z;
318     };
319 
320     struct Wrapper {
321       FullyDerived d;
322       int zz;
323 
WrapperLazyBindings::Nested::Wrapper324       Wrapper(const FullyDerived &d) : d(d), zz(0) {}
325     };
326 
test5()327     void test5() {
328       Wrapper w((FullyDerived()));
329       w.d.x = 1;
330 
331       Wrapper w2(w);
332       clang_analyzer_eval(getX(w2.d) == 1); // expected-warning{{TRUE}}
333     }
334   }
335 #endif
336 }
337 
338 namespace Redeclaration {
339   class Base;
340 
341   class Base {
342   public:
343     virtual int foo();
get()344     int get() { return value; }
345 
346     int value;
347   };
348 
349   class Derived : public Base {
350   public:
351     virtual int bar();
352   };
353 
test(Derived d)354   void test(Derived d) {
355     d.foo(); // don't crash
356     d.bar(); // sanity check
357 
358     Base &b = d;
359     b.foo(); // don't crash
360 
361     d.value = 42; // don't crash
362     clang_analyzer_eval(d.get() == 42); // expected-warning{{TRUE}}
363     clang_analyzer_eval(b.get() == 42); // expected-warning{{TRUE}}
364   }
365 };
366 
367 namespace PR15394 {
368   namespace Original {
369     class Base {
370     public:
371       virtual int f() = 0;
372       int i;
373     };
374 
375     class Derived1 : public Base {
376     public:
377       int j;
378     };
379 
380     class Derived2 : public Derived1 {
381     public:
f()382       virtual int f() {
383         clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
384         return i + j;
385       }
386     };
387 
testXXX()388     void testXXX() {
389       Derived1 *d1p = reinterpret_cast<Derived1*>(new Derived2);
390       d1p->i = 1;
391       d1p->j = 2;
392       clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}}
393     }
394   }
395 
396   namespace VirtualInDerived {
397     class Base {
398     public:
399       int i;
400     };
401 
402     class Derived1 : public Base {
403     public:
404       virtual int f() = 0;
405       int j;
406     };
407 
408     class Derived2 : public Derived1 {
409     public:
f()410       virtual int f() {
411         clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
412         return i + j;
413       }
414     };
415 
test()416     void test() {
417       Derived1 *d1p = reinterpret_cast<Derived1*>(new Derived2);
418       d1p->i = 1;
419       d1p->j = 2;
420       clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}}
421     }
422   }
423 
424   namespace NoCast {
425     class Base {
426     public:
427       int i;
428     };
429 
430     class Derived1 : public Base {
431     public:
432       virtual int f() = 0;
433       int j;
434     };
435 
436     class Derived2 : public Derived1 {
437     public:
f()438       virtual int f() {
439         clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
440         return i + j;
441       }
442     };
443 
test()444     void test() {
445       Derived1 *d1p = new Derived2;
446       d1p->i = 1;
447       d1p->j = 2;
448       clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}}
449     }
450   }
451 };
452 
453 namespace Bug16309 {
454   struct Incomplete;
455 
456   struct Base { virtual ~Base(); };
457 
458   struct Derived : public Base { int x; };
459 
f(Incomplete * i)460   void* f(Incomplete *i) {
461     Base *b = reinterpret_cast<Base *>(i);
462     // This used to crash because of the reinterpret_cast above.
463     Derived *d = dynamic_cast<Derived *>(b);
464     return d;
465   }
466 
467   // And check that reinterpret+dynamic casts work correctly after the fix.
g()468   void g() {
469     Derived d;
470     d.x = 47;
471     Base *b = &d;
472     Incomplete *i = reinterpret_cast<Incomplete *>(b);
473     Base *b2 = reinterpret_cast<Base *>(i);
474     Derived *d2 = dynamic_cast<Derived *>(b2);
475     clang_analyzer_eval(d2->x == 47); // expected-warning{{TRUE}}
476   }
477 }
478