Home | History | Annotate | Download | only in Analysis
      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