// RUN: %clangxx_msan %s -O0 -fsanitize-memory-use-after-dtor -fsanitize-memory-track-origins -o %t && %run %t 2>&1 | FileCheck %s // RUN: %clangxx_msan %s -O1 -fsanitize-memory-use-after-dtor -fsanitize-memory-track-origins -o %t && %run %t 2>&1 | FileCheck %s // RUN: %clangxx_msan %s -O2 -fsanitize-memory-use-after-dtor -fsanitize-memory-track-origins -o %t && %run %t 2>&1 | FileCheck %s #include #include class Base { public: int b; Base() { b = 1; } ~Base(); }; class TrivialBaseBefore { public: int tb0; TrivialBaseBefore() { tb0 = 1; } }; class TrivialBaseAfter { public: int tb1; TrivialBaseAfter() { tb1 = 1; } }; class Derived : public TrivialBaseBefore, public Base, public TrivialBaseAfter { public: int d; Derived() { d = 1; } ~Derived(); }; Derived *g; Base::~Base() { // ok to access its own members and earlier bases assert(__msan_test_shadow(&g->tb0, sizeof(g->tb0)) == -1); assert(__msan_test_shadow(&g->b, sizeof(g->b)) == -1); // not ok to access others assert(__msan_test_shadow(&g->tb1, sizeof(g->tb1)) == 0); assert(__msan_test_shadow(&g->d, sizeof(g->d)) == 0); } Derived::~Derived() { // ok to access everything assert(__msan_test_shadow(&g->tb0, sizeof(g->tb0)) == -1); assert(__msan_test_shadow(&g->b, sizeof(g->b)) == -1); assert(__msan_test_shadow(&g->tb1, sizeof(g->tb1)) == -1); assert(__msan_test_shadow(&g->d, sizeof(g->d)) == -1); } int main() { g = new Derived(); // ok to access everything assert(__msan_test_shadow(&g->tb0, sizeof(g->tb0)) == -1); assert(__msan_test_shadow(&g->b, sizeof(g->b)) == -1); assert(__msan_test_shadow(&g->tb1, sizeof(g->tb1)) == -1); assert(__msan_test_shadow(&g->d, sizeof(g->d)) == -1); g->~Derived(); // not ok to access everything assert(__msan_test_shadow(&g->tb0, sizeof(g->tb0)) == 0); assert(__msan_test_shadow(&g->b, sizeof(g->b)) == 0); assert(__msan_test_shadow(&g->tb1, sizeof(g->tb1)) == 0); assert(__msan_test_shadow(&g->d, sizeof(g->d)) == 0); __msan_print_shadow(&g->tb0, sizeof(g->tb0)); // CHECK: Member fields were destroyed // CHECK: {{#0 0x.* in __sanitizer_dtor_callback}} // CHECK: {{#1 0x.* in .*~Derived.*cpp:}}[[@LINE-56]]: // CHECK: {{#2 0x.* in .*~Derived.*cpp:}}[[@LINE-21]]: __msan_print_shadow(&g->b, sizeof(g->b)); // CHECK: Member fields were destroyed // CHECK: {{#0 0x.* in __sanitizer_dtor_callback}} // CHECK: {{#1 0x.* in .*~Base.*cpp:}}[[@LINE-67]]: // CHECK: {{#2 0x.* in .*~Base.*cpp:}}[[@LINE-35]]: __msan_print_shadow(&g->tb1, sizeof(g->tb1)); // CHECK: Member fields were destroyed // CHECK: {{#0 0x.* in __sanitizer_dtor_callback}} // CHECK: {{#1 0x.* in .*~Derived.*cpp:}}[[@LINE-62]]: // CHECK: {{#2 0x.* in .*~Derived.*cpp:}}[[@LINE-33]]: return 0; }