1 // Defines diamond multiple inheritance structure 2 // A 3 // / \ 4 // B C 5 // \ / 6 // Derived 7 8 // RUN: %clangxx_msan %s -O0 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t >%t.out 2>&1 9 10 // RUN: %clangxx_msan %s -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t >%t.out 2>&1 11 12 // 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 13 14 #include <sanitizer/msan_interface.h> 15 #include <assert.h> 16 17 int *temp_x; 18 int *temp_y; 19 int *temp_z; 20 int *temp_w; 21 22 class A { 23 public: 24 int x; 25 A() { x = 5; } 26 virtual ~A() { 27 assert(__msan_test_shadow(&this->x, sizeof(this->x) == -1)); 28 // Memory owned by subclasses is poisoned. 29 assert(__msan_test_shadow(temp_y, sizeof(*temp_y)) != -1); 30 assert(__msan_test_shadow(temp_z, sizeof(*temp_z)) != -1); 31 assert(__msan_test_shadow(temp_w, sizeof(*temp_w)) != -1); 32 } 33 }; 34 35 struct B : virtual public A { 36 public: 37 int y; 38 B() { y = 10; } 39 virtual ~B() { 40 assert(__msan_test_shadow(&this->y, sizeof(this->y)) == -1); 41 // Memory accessible via vtable still reachable. 42 assert(__msan_test_shadow(&this->x, sizeof(this->x)) == -1); 43 // Memory in sibling and subclass is poisoned. 44 assert(__msan_test_shadow(temp_z, sizeof(*temp_z)) != -1); 45 assert(__msan_test_shadow(temp_w, sizeof(*temp_w)) != -1); 46 } 47 }; 48 49 struct C : virtual public A { 50 public: 51 int z; 52 C() { z = 15; } 53 virtual ~C() { 54 assert(__msan_test_shadow(&this->z, sizeof(this->z)) == -1); 55 // Memory accessible via vtable still reachable. 56 assert(__msan_test_shadow(&this->x, sizeof(this->x)) == -1); 57 // Sibling class is unpoisoned. 58 assert(__msan_test_shadow(temp_y, sizeof(*temp_y)) == -1); 59 // Memory in subclasses is poisoned. 60 assert(__msan_test_shadow(temp_w, sizeof(*temp_w)) != -1); 61 } 62 }; 63 64 class Derived : public B, public C { 65 public: 66 int w; 67 Derived() { w = 10; } 68 ~Derived() { 69 assert(__msan_test_shadow(&this->x, sizeof(this->x)) == -1); 70 // Members accessed through the vtable are still accessible. 71 assert(__msan_test_shadow(&this->y, sizeof(this->y)) == -1); 72 assert(__msan_test_shadow(&this->z, sizeof(this->z)) == -1); 73 assert(__msan_test_shadow(&this->w, sizeof(this->w)) == -1); 74 } 75 }; 76 77 78 int main() { 79 Derived *d = new Derived(); 80 81 // Keep track of members inherited from virtual bases, 82 // since the virtual base table is inaccessible after destruction. 83 temp_x = &d->x; 84 temp_y = &d->y; 85 temp_z = &d->z; 86 temp_w = &d->w; 87 88 // Order of destruction: Derived, C, B, A 89 d->~Derived(); 90 // Verify that local pointer is unpoisoned, and that the object's 91 // members are. 92 assert(__msan_test_shadow(&d, sizeof(d)) == -1); 93 assert(__msan_test_shadow(temp_x, sizeof(*temp_x)) != -1); 94 assert(__msan_test_shadow(temp_y, sizeof(*temp_y)) != -1); 95 assert(__msan_test_shadow(temp_z, sizeof(*temp_z)) != -1); 96 assert(__msan_test_shadow(temp_w, sizeof(*temp_w)) != -1); 97 return 0; 98 } 99