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 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 
     17 void B::f() {
     18   x = 3;
     19 }
     20 
     21 
     22 class C : public B {
     23 public:
     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:
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    338 namespace 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 
    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:
    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 
    453 namespace 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