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}}
 | 
						|
  }
 | 
						|
}
 |