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
4void clang_analyzer_eval(bool);
5void clang_analyzer_checkInlined(bool);
6
7class A {
8protected:
9  int x;
10};
11
12class B : public A {
13public:
14  void f();
15};
16
17void B::f() {
18  x = 3;
19}
20
21
22class C : public B {
23public:
24  void g() {
25    // This used to crash because we are upcasting through two bases.
26    x = 5;
27  }
28};
29
30
31namespace VirtualBaseClasses {
32  class A {
33  protected:
34    int x;
35  };
36
37  class B : public virtual A {
38  public:
39    int getX() { return x; }
40  };
41
42  class C : public virtual A {
43  public:
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
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:
74    int getX() { return x; }
75  };
76
77  class CI : public virtual Intermediate {
78  public:
79    void setX() { x = 42; }
80  };
81
82  class DI : public BI, public CI {};
83
84  void testIntermediate() {
85    DI d;
86    d.setX();
87    clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
88  }
89}
90
91
92namespace 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
102  bool testCast(A *a) {
103    return dynamic_cast<B*>(a) && dynamic_cast<C*>(a);
104  }
105
106  void test() {
107    D d;
108    clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
109  }
110}
111
112namespace 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
123  bool testCast(B *a) {
124    return dynamic_cast<C*>(a);
125  }
126
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
135  void testVirtual() {
136    DV d;
137    clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
138  }
139}
140
141namespace 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
154  int getX(const Base &obj) {
155    return obj.x;
156  }
157
158  int getY(const Derived &obj) {
159    return obj.y;
160  }
161
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
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
209    int getY(const OffsetDerived &obj) {
210      return obj.y;
211    }
212
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
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
258    int getY(const DerivedVTBL &obj) {
259      return obj.y;
260    }
261
262    int getZ(const DoubleDerivedVTBL &obj) {
263      return obj.z;
264    }
265
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
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;
312      NonTrivialCopy() {}
313      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
324      Wrapper(const FullyDerived &d) : d(d), zz(0) {}
325    };
326
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
338namespace Redeclaration {
339  class Base;
340
341  class Base {
342  public:
343    virtual int foo();
344    int get() { return value; }
345
346    int value;
347  };
348
349  class Derived : public Base {
350  public:
351    virtual int bar();
352  };
353
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
367namespace 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:
382      virtual int f() {
383        clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
384        return i + j;
385      }
386    };
387
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:
410      virtual int f() {
411        clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
412        return i + j;
413      }
414    };
415
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:
438      virtual int f() {
439        clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
440        return i + j;
441      }
442    };
443
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
453namespace Bug16309 {
454  struct Incomplete;
455
456  struct Base { virtual ~Base(); };
457
458  struct Derived : public Base { int x; };
459
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.
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