| // 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); |
| |
| 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}} |
| } |
| }; |
| |