Index: test/msan/dtor-multiple-inheritance.cc =================================================================== --- test/msan/dtor-multiple-inheritance.cc +++ test/msan/dtor-multiple-inheritance.cc @@ -14,24 +14,21 @@ #include #include +int *temp_x; +int *temp_y; +int *temp_z; +int *temp_w; + class A { public: int x; - int *y_ptr; - int *z_ptr; - int *w_ptr; A() { x = 5; } - void set_ptrs(int *y_ptr, int *z_ptr, int *w_ptr) { - this->y_ptr = y_ptr; - this->z_ptr = z_ptr; - this->w_ptr = w_ptr; - } virtual ~A() { assert(__msan_test_shadow(&this->x, sizeof(this->x) == -1)); - // bad access subclass member - assert(__msan_test_shadow(this->y_ptr, sizeof(*this->y_ptr)) != -1); - assert(__msan_test_shadow(this->z_ptr, sizeof(*this->z_ptr)) != -1); - assert(__msan_test_shadow(this->w_ptr, sizeof(*this->w_ptr)) != -1); + // Memory owned by subclasses is poisoned. + assert(__msan_test_shadow(temp_y, sizeof(*temp_y)) != -1); + assert(__msan_test_shadow(temp_z, sizeof(*temp_z)) != -1); + assert(__msan_test_shadow(temp_w, sizeof(*temp_w)) != -1); } }; @@ -40,13 +37,12 @@ int y; B() { y = 10; } virtual ~B() { - assert(__msan_test_shadow(&this->x, sizeof(this->x)) == -1); assert(__msan_test_shadow(&this->y, sizeof(this->y)) == -1); - assert(__msan_test_shadow(this->y_ptr, sizeof(*this->y_ptr)) == -1); - - // memory in subclasses is poisoned - assert(__msan_test_shadow(this->z_ptr, sizeof(*this->z_ptr)) != -1); - assert(__msan_test_shadow(this->w_ptr, sizeof(*this->w_ptr)) != -1); + // Memory accessible via vtable still reachable. + assert(__msan_test_shadow(&this->x, sizeof(this->x)) == -1); + // Memory in sibling and subclass is poisoned. + assert(__msan_test_shadow(temp_z, sizeof(*temp_z)) != -1); + assert(__msan_test_shadow(temp_w, sizeof(*temp_w)) != -1); } }; @@ -55,13 +51,13 @@ int z; C() { z = 15; } virtual ~C() { - assert(__msan_test_shadow(&this->x, sizeof(this->x)) == -1); assert(__msan_test_shadow(&this->z, sizeof(this->z)) == -1); - assert(__msan_test_shadow(this->y_ptr, sizeof(*this->y_ptr)) == -1); - assert(__msan_test_shadow(this->z_ptr, sizeof(*this->z_ptr) == -1)); - - // memory in subclasses is poisoned - assert(__msan_test_shadow(this->w_ptr, sizeof(*this->w_ptr)) != -1); + // Memory accessible via vtable still reachable. + assert(__msan_test_shadow(&this->x, sizeof(this->x)) == -1); + // Sibling class is unpoisoned. + assert(__msan_test_shadow(temp_y, sizeof(*temp_y)) == -1); + // Memory in subclasses is poisoned. + assert(__msan_test_shadow(temp_w, sizeof(*temp_w)) != -1); } }; @@ -71,26 +67,32 @@ Derived() { w = 10; } ~Derived() { assert(__msan_test_shadow(&this->x, sizeof(this->x)) == -1); + // Members accessed through the vtable are still accessible. assert(__msan_test_shadow(&this->y, sizeof(this->y)) == -1); + assert(__msan_test_shadow(&this->z, sizeof(this->z)) == -1); assert(__msan_test_shadow(&this->w, sizeof(this->w)) == -1); } }; + int main() { Derived *d = new Derived(); - d->set_ptrs(&d->y, &d->z, &d->w); + + // Keep track of members inherited from virtual bases, + // since the virtual base table is inaccessible after destruction. + temp_x = &d->x; + temp_y = &d->y; + temp_z = &d->z; + temp_w = &d->w; // Order of destruction: Derived, C, B, A d->~Derived(); // Verify that local pointer is unpoisoned, and that the object's // members are. assert(__msan_test_shadow(&d, sizeof(d)) == -1); - assert(__msan_test_shadow(&d->x, sizeof(d->x)) != -1); - assert(__msan_test_shadow(&d->y, sizeof(d->y)) != -1); - assert(__msan_test_shadow(&d->z, sizeof(d->z)) != -1); - assert(__msan_test_shadow(&d->w, sizeof(d->w)) != -1); - assert(__msan_test_shadow(&d->y_ptr, sizeof(d->y_ptr)) != -1); - assert(__msan_test_shadow(&d->z_ptr, sizeof(d->z_ptr)) != -1); - assert(__msan_test_shadow(&d->w_ptr, sizeof(d->w_ptr)) != -1); + assert(__msan_test_shadow(temp_x, sizeof(*temp_x)) != -1); + assert(__msan_test_shadow(temp_y, sizeof(*temp_y)) != -1); + assert(__msan_test_shadow(temp_z, sizeof(*temp_z)) != -1); + assert(__msan_test_shadow(temp_w, sizeof(*temp_w)) != -1); return 0; } Index: test/msan/dtor-trivial.cpp =================================================================== --- test/msan/dtor-trivial.cpp +++ test/msan/dtor-trivial.cpp @@ -4,7 +4,9 @@ // RUN: %clangxx_msan %s -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t >%t.out 2>&1 -// TODO Success pending on resolution of 596 +// TODO Success pending on resolution of +// https://github.com/google/sanitizers/issues/596 + // XFAIL: * #include Index: test/msan/dtor-vtable-multiple-inheritance.cc =================================================================== --- /dev/null +++ test/msan/dtor-vtable-multiple-inheritance.cc @@ -0,0 +1,72 @@ +// RUN: %clangxx_msan %s -O0 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -DCVPTR=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// RUN: %clangxx_msan %s -DEAVPTR=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// RUN: %clangxx_msan %s -DEDVPTR=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// Expected to quit due to invalid access when invoking +// function using vtable. + +class A { + public: + int x; + virtual ~A() { + // Should succeed + this->A_Foo(); + } + virtual void A_Foo() {} +}; + +class B : public virtual A { + public: + int y; + virtual ~B() {} + virtual void A_Foo() {} +}; + +class C : public B { + public: + int z; + ~C() {} +}; + +class D { + public: + int w; + ~D() {} + virtual void D_Foo() {} +}; + +class E : public virtual A, public virtual D { + public: + int u; + ~E() {} + void A_Foo() {} +}; + +int main() { + // Simple linear inheritance + C *c = new C(); + c->~C(); + // This fails +#ifdef CVPTR + c->A_Foo(); +#endif + + // Multiple inheritance, so has multiple vtables + E *e = new E(); + e->~E(); + // Both of these fail +#ifdef EAVPTR + e->A_Foo(); +#endif +#ifdef EDVPTR + e->D_Foo(); +#endif +} Index: test/msan/dtor-vtable.cc =================================================================== --- /dev/null +++ test/msan/dtor-vtable.cc @@ -0,0 +1,68 @@ +// RUN: %clangxx_msan %s -O0 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -DVPTRA=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// RUN: %clangxx_msan %s -DVPTRCA=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// RUN: %clangxx_msan %s -DVPTRCB=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// RUN: %clangxx_msan %s -DVPTRC=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// Expected to quit due to invalid access when invoking +// function using vtable. + +#include +#include +#include + +class A { +public: + int x; + ~A() {} + virtual void A_Foo() {} +}; + +class B { + public: + int y; + ~B() {} + virtual void B_Foo() {} +}; + +class C : public A, public B { + public: + int z; + ~C() {} + virtual void C_Foo() {} +}; + +int main() { + A *a = new A(); + a->~A(); + + // Shouldn't be allowed to invoke function via vtable. +#ifdef VPTRA + a->A_Foo(); +#endif + + C *c = new C(); + c->~C(); + +#ifdef VPTRCA + c->A_Foo(); +#endif + +#ifdef VPTRCB + c->B_Foo(); +#endif + +#ifdef VPTRC + c->C_Foo(); +#endif + + return 0; +}