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;
A()25   A() { x = 5; }
~A()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;
BB38   B() { y = 10; }
~BB39   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;
CC52   C() { z = 15; }
~CC53   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;
Derived()67   Derived() { w = 10; }
~Derived()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 
main()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