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