forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			478 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			478 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
| // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
 | |
| // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DCONSTRUCTORS=1 -analyzer-config c++-inlining=constructors -verify %s
 | |
| 
 | |
| void clang_analyzer_eval(bool);
 | |
| void clang_analyzer_checkInlined(bool);
 | |
| 
 | |
| class A {
 | |
| protected:
 | |
|   int x;
 | |
| };
 | |
| 
 | |
| class B : public A {
 | |
| public:
 | |
|   void f();
 | |
| };
 | |
| 
 | |
| void B::f() {
 | |
|   x = 3;
 | |
| }
 | |
| 
 | |
| 
 | |
| class C : public B {
 | |
| public:
 | |
|   void g() {
 | |
|     // This used to crash because we are upcasting through two bases.
 | |
|     x = 5;
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| namespace VirtualBaseClasses {
 | |
|   class A {
 | |
|   protected:
 | |
|     int x;
 | |
|   };
 | |
| 
 | |
|   class B : public virtual A {
 | |
|   public:
 | |
|     int getX() { return x; }
 | |
|   };
 | |
| 
 | |
|   class C : public virtual A {
 | |
|   public:
 | |
|     void setX() { x = 42; }
 | |
|   };
 | |
| 
 | |
|   class D : public B, public C {};
 | |
|   class DV : virtual public B, public C {};
 | |
|   class DV2 : public B, virtual public C {};
 | |
| 
 | |
|   void test() {
 | |
|     D d;
 | |
|     d.setX();
 | |
|     clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
 | |
| 
 | |
|     DV dv;
 | |
|     dv.setX();
 | |
|     clang_analyzer_eval(dv.getX() == 42); // expected-warning{{TRUE}}
 | |
| 
 | |
|     DV2 dv2;
 | |
|     dv2.setX();
 | |
|     clang_analyzer_eval(dv2.getX() == 42); // expected-warning{{TRUE}}
 | |
|   }
 | |
| 
 | |
| 
 | |
|   // Make sure we're consistent about the offset of the A subobject within an
 | |
|   // Intermediate virtual base class.
 | |
|   class Padding1 { int unused; };
 | |
|   class Padding2 { int unused; };
 | |
|   class Intermediate : public Padding1, public A, public Padding2 {};
 | |
| 
 | |
|   class BI : public virtual Intermediate {
 | |
|   public:
 | |
|     int getX() { return x; }
 | |
|   };
 | |
| 
 | |
|   class CI : public virtual Intermediate {
 | |
|   public:
 | |
|     void setX() { x = 42; }
 | |
|   };
 | |
| 
 | |
|   class DI : public BI, public CI {};
 | |
| 
 | |
|   void testIntermediate() {
 | |
|     DI d;
 | |
|     d.setX();
 | |
|     clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| namespace DynamicVirtualUpcast {
 | |
|   class A {
 | |
|   public:
 | |
|     virtual ~A();
 | |
|   };
 | |
| 
 | |
|   class B : virtual public A {};
 | |
|   class C : virtual public B {};
 | |
|   class D : virtual public C {};
 | |
| 
 | |
|   bool testCast(A *a) {
 | |
|     return dynamic_cast<B*>(a) && dynamic_cast<C*>(a);
 | |
|   }
 | |
| 
 | |
|   void test() {
 | |
|     D d;
 | |
|     clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
 | |
|   }
 | |
| }
 | |
| 
 | |
| namespace DynamicMultipleInheritanceUpcast {
 | |
|   class B {
 | |
|   public:
 | |
|     virtual ~B();
 | |
|   };
 | |
|   class C {
 | |
|   public:
 | |
|     virtual ~C();
 | |
|   };
 | |
|   class D : public B, public C {};
 | |
| 
 | |
|   bool testCast(B *a) {
 | |
|     return dynamic_cast<C*>(a);
 | |
|   }
 | |
| 
 | |
|   void test() {
 | |
|     D d;
 | |
|     clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
 | |
|   }
 | |
| 
 | |
| 
 | |
|   class DV : virtual public B, virtual public C {};
 | |
| 
 | |
|   void testVirtual() {
 | |
|     DV d;
 | |
|     clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
 | |
|   }
 | |
| }
 | |
| 
 | |
| namespace LazyBindings {
 | |
|   struct Base {
 | |
|     int x;
 | |
|   };
 | |
| 
 | |
|   struct Derived : public Base {
 | |
|     int y;
 | |
|   };
 | |
| 
 | |
|   struct DoubleDerived : public Derived {
 | |
|     int z;
 | |
|   };
 | |
| 
 | |
|   int getX(const Base &obj) {
 | |
|     return obj.x;
 | |
|   }
 | |
| 
 | |
|   int getY(const Derived &obj) {
 | |
|     return obj.y;
 | |
|   }
 | |
| 
 | |
|   void testDerived() {
 | |
|     Derived d;
 | |
|     d.x = 1;
 | |
|     d.y = 2;
 | |
|     clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
 | |
|     clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
 | |
| 
 | |
|     Base b(d);
 | |
|     clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
 | |
| 
 | |
|     Derived d2(d);
 | |
|     clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
 | |
|     clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
 | |
|   }
 | |
| 
 | |
|   void testDoubleDerived() {
 | |
|     DoubleDerived d;
 | |
|     d.x = 1;
 | |
|     d.y = 2;
 | |
|     clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
 | |
|     clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
 | |
| 
 | |
|     Base b(d);
 | |
|     clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
 | |
| 
 | |
|     Derived d2(d);
 | |
|     clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
 | |
|     clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
 | |
| 
 | |
|     DoubleDerived d3(d);
 | |
|     clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
 | |
|     clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
 | |
|   }
 | |
| 
 | |
|   namespace WithOffset {
 | |
|     struct Offset {
 | |
|       int padding;
 | |
|     };
 | |
| 
 | |
|     struct OffsetDerived : private Offset, public Base {
 | |
|       int y;
 | |
|     };
 | |
| 
 | |
|     struct DoubleOffsetDerived : public OffsetDerived {
 | |
|       int z;
 | |
|     };
 | |
| 
 | |
|     int getY(const OffsetDerived &obj) {
 | |
|       return obj.y;
 | |
|     }
 | |
| 
 | |
|     void testDerived() {
 | |
|       OffsetDerived d;
 | |
|       d.x = 1;
 | |
|       d.y = 2;
 | |
|       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
 | |
|       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
 | |
| 
 | |
|       Base b(d);
 | |
|       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
 | |
| 
 | |
|       OffsetDerived d2(d);
 | |
|       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
 | |
|       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
 | |
|     }
 | |
| 
 | |
|     void testDoubleDerived() {
 | |
|       DoubleOffsetDerived d;
 | |
|       d.x = 1;
 | |
|       d.y = 2;
 | |
|       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
 | |
|       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
 | |
| 
 | |
|       Base b(d);
 | |
|       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
 | |
| 
 | |
|       OffsetDerived d2(d);
 | |
|       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
 | |
|       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
 | |
| 
 | |
|       DoubleOffsetDerived d3(d);
 | |
|       clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
 | |
|       clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   namespace WithVTable {
 | |
|     struct DerivedVTBL : public Base {
 | |
|       int y;
 | |
|       virtual void method();
 | |
|     };
 | |
| 
 | |
|     struct DoubleDerivedVTBL : public DerivedVTBL {
 | |
|       int z;
 | |
|     };
 | |
| 
 | |
|     int getY(const DerivedVTBL &obj) {
 | |
|       return obj.y;
 | |
|     }
 | |
| 
 | |
|     int getZ(const DoubleDerivedVTBL &obj) {
 | |
|       return obj.z;
 | |
|     }
 | |
| 
 | |
|     void testDerived() {
 | |
|       DerivedVTBL d;
 | |
|       d.x = 1;
 | |
|       d.y = 2;
 | |
|       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
 | |
|       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
 | |
| 
 | |
|       Base b(d);
 | |
|       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
 | |
| 
 | |
| #if CONSTRUCTORS
 | |
|       DerivedVTBL d2(d);
 | |
|       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
 | |
|       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
 | |
| #endif
 | |
|     }
 | |
| 
 | |
| #if CONSTRUCTORS
 | |
|     void testDoubleDerived() {
 | |
|       DoubleDerivedVTBL d;
 | |
|       d.x = 1;
 | |
|       d.y = 2;
 | |
|       d.z = 3;
 | |
|       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
 | |
|       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
 | |
|       clang_analyzer_eval(getZ(d) == 3); // expected-warning{{TRUE}}
 | |
| 
 | |
|       Base b(d);
 | |
|       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
 | |
| 
 | |
|       DerivedVTBL d2(d);
 | |
|       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
 | |
|       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
 | |
| 
 | |
|       DoubleDerivedVTBL d3(d);
 | |
|       clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
 | |
|       clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
 | |
|       clang_analyzer_eval(getZ(d3) == 3); // expected-warning{{TRUE}}
 | |
|     }
 | |
| #endif
 | |
|   }
 | |
| 
 | |
| #if CONSTRUCTORS
 | |
|   namespace Nested {
 | |
|     struct NonTrivialCopy {
 | |
|       int padding;
 | |
|       NonTrivialCopy() {}
 | |
|       NonTrivialCopy(const NonTrivialCopy &) {}
 | |
|     };
 | |
| 
 | |
|     struct FullyDerived : private NonTrivialCopy, public Derived {
 | |
|       int z;
 | |
|     };
 | |
| 
 | |
|     struct Wrapper {
 | |
|       FullyDerived d;
 | |
|       int zz;
 | |
| 
 | |
|       Wrapper(const FullyDerived &d) : d(d), zz(0) {}
 | |
|     };
 | |
| 
 | |
|     void test5() {
 | |
|       Wrapper w((FullyDerived()));
 | |
|       w.d.x = 1;
 | |
| 
 | |
|       Wrapper w2(w);
 | |
|       clang_analyzer_eval(getX(w2.d) == 1); // expected-warning{{TRUE}}
 | |
|     }
 | |
|   }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| namespace Redeclaration {
 | |
|   class Base;
 | |
| 
 | |
|   class Base {
 | |
|   public:
 | |
|     virtual int foo();
 | |
|     int get() { return value; }
 | |
| 
 | |
|     int value;
 | |
|   };
 | |
| 
 | |
|   class Derived : public Base {
 | |
|   public:
 | |
|     virtual int bar();
 | |
|   };
 | |
| 
 | |
|   void test(Derived d) {
 | |
|     d.foo(); // don't crash
 | |
|     d.bar(); // sanity check
 | |
| 
 | |
|     Base &b = d;
 | |
|     b.foo(); // don't crash
 | |
| 
 | |
|     d.value = 42; // don't crash
 | |
|     clang_analyzer_eval(d.get() == 42); // expected-warning{{TRUE}}
 | |
|     clang_analyzer_eval(b.get() == 42); // expected-warning{{TRUE}}
 | |
|   }
 | |
| };
 | |
| 
 | |
| namespace PR15394 {
 | |
|   namespace Original {
 | |
|     class Base {
 | |
|     public:
 | |
|       virtual int f() = 0;
 | |
|       int i;
 | |
|     };
 | |
| 
 | |
|     class Derived1 : public Base {
 | |
|     public:
 | |
|       int j;
 | |
|     };
 | |
| 
 | |
|     class Derived2 : public Derived1 {
 | |
|     public:
 | |
|       virtual int f() {
 | |
|         clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
 | |
|         return i + j;
 | |
|       }
 | |
|     };
 | |
| 
 | |
|     void testXXX() {
 | |
|       Derived1 *d1p = reinterpret_cast<Derived1*>(new Derived2);
 | |
|       d1p->i = 1;
 | |
|       d1p->j = 2;
 | |
|       clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}}
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   namespace VirtualInDerived {
 | |
|     class Base {
 | |
|     public:
 | |
|       int i;
 | |
|     };
 | |
| 
 | |
|     class Derived1 : public Base {
 | |
|     public:
 | |
|       virtual int f() = 0;
 | |
|       int j;
 | |
|     };
 | |
| 
 | |
|     class Derived2 : public Derived1 {
 | |
|     public:
 | |
|       virtual int f() {
 | |
|         clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
 | |
|         return i + j;
 | |
|       }
 | |
|     };
 | |
| 
 | |
|     void test() {
 | |
|       Derived1 *d1p = reinterpret_cast<Derived1*>(new Derived2);
 | |
|       d1p->i = 1;
 | |
|       d1p->j = 2;
 | |
|       clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}}
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   namespace NoCast {
 | |
|     class Base {
 | |
|     public:
 | |
|       int i;
 | |
|     };
 | |
| 
 | |
|     class Derived1 : public Base {
 | |
|     public:
 | |
|       virtual int f() = 0;
 | |
|       int j;
 | |
|     };
 | |
| 
 | |
|     class Derived2 : public Derived1 {
 | |
|     public:
 | |
|       virtual int f() {
 | |
|         clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
 | |
|         return i + j;
 | |
|       }
 | |
|     };
 | |
| 
 | |
|     void test() {
 | |
|       Derived1 *d1p = new Derived2;
 | |
|       d1p->i = 1;
 | |
|       d1p->j = 2;
 | |
|       clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}}
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| namespace Bug16309 {
 | |
|   struct Incomplete;
 | |
| 
 | |
|   struct Base { virtual ~Base(); };
 | |
| 
 | |
|   struct Derived : public Base { int x; };
 | |
| 
 | |
|   void* f(Incomplete *i) {
 | |
|     Base *b = reinterpret_cast<Base *>(i);
 | |
|     // This used to crash because of the reinterpret_cast above.
 | |
|     Derived *d = dynamic_cast<Derived *>(b);
 | |
|     return d;
 | |
|   }
 | |
| 
 | |
|   // And check that reinterpret+dynamic casts work correctly after the fix.
 | |
|   void g() {
 | |
|     Derived d;
 | |
|     d.x = 47;
 | |
|     Base *b = &d;
 | |
|     Incomplete *i = reinterpret_cast<Incomplete *>(b);
 | |
|     Base *b2 = reinterpret_cast<Base *>(i);
 | |
|     Derived *d2 = dynamic_cast<Derived *>(b2);
 | |
|     clang_analyzer_eval(d2->x == 47); // expected-warning{{TRUE}}
 | |
|   }
 | |
| }
 |