llvm-project/clang/test/Analysis/derived-to-base.cpp

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