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 && %run %t >%t.out 2>&1 |
9 | |
10 | // RUN: %clangxx_msan %s -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && %run %t >%t.out 2>&1 |
11 | |
12 | // RUN: %clangxx_msan %s -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && %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 | |