diff options
Diffstat (limited to 'test/msan')
31 files changed, 1096 insertions, 4 deletions
diff --git a/test/msan/Linux/forkpty.cc b/test/msan/Linux/forkpty.cc new file mode 100644 index 0000000000000..ae5c7d96ca8a3 --- /dev/null +++ b/test/msan/Linux/forkpty.cc @@ -0,0 +1,18 @@ +// RUN: %clangxx_msan -O0 -g %s -lutil -o %t && %run %t +#include <assert.h> +#include <pty.h> + +#include <sanitizer/msan_interface.h> + +int +main (int argc, char** argv) +{ + int master, slave; + openpty(&master, &slave, NULL, NULL, NULL); + assert(__msan_test_shadow(&master, sizeof(master)) == -1); + assert(__msan_test_shadow(&slave, sizeof(slave)) == -1); + + int master2; + forkpty(&master2, NULL, NULL, NULL); + assert(__msan_test_shadow(&master2, sizeof(master2)) == -1); +} diff --git a/test/msan/Linux/mallinfo.cc b/test/msan/Linux/mallinfo.cc index 3c3692969852f..545ae934a6111 100644 --- a/test/msan/Linux/mallinfo.cc +++ b/test/msan/Linux/mallinfo.cc @@ -1,4 +1,5 @@ // RUN: %clangxx_msan -O0 -g %s -o %t && %run %t +// REQUIRES: stable-runtime #include <assert.h> #include <malloc.h> diff --git a/test/msan/Linux/mincore.cc b/test/msan/Linux/mincore.cc new file mode 100644 index 0000000000000..35f5713d43125 --- /dev/null +++ b/test/msan/Linux/mincore.cc @@ -0,0 +1,36 @@ +// RUN: %clangxx_msan -std=c++11 -O0 %s -o %t && %run %t + +#include <assert.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sanitizer/msan_interface.h> + +int main(void) { + unsigned char vec[20]; + int res; + size_t PS = sysconf(_SC_PAGESIZE); + void *addr = mmap(nullptr, 20 * PS, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + + __msan_poison(&vec, sizeof(vec)); + res = mincore(addr, 10 * PS, vec); + assert(res == 0); + assert(__msan_test_shadow(vec, sizeof(vec)) == 10); + + __msan_poison(&vec, sizeof(vec)); + res = mincore(addr, 10 * PS + 42, vec); + assert(res == 0); + assert(__msan_test_shadow(vec, sizeof(vec)) == 11); + + __msan_poison(&vec, sizeof(vec)); + res = mincore(addr, 10 * PS - 1, vec); + assert(res == 0); + assert(__msan_test_shadow(vec, sizeof(vec)) == 10); + + __msan_poison(&vec, sizeof(vec)); + res = mincore(addr, 1, vec); + assert(res == 0); + assert(__msan_test_shadow(vec, sizeof(vec)) == 1); + + return 0; +} diff --git a/test/msan/Linux/process_vm_readv.cc b/test/msan/Linux/process_vm_readv.cc new file mode 100644 index 0000000000000..601c0d247dc24 --- /dev/null +++ b/test/msan/Linux/process_vm_readv.cc @@ -0,0 +1,67 @@ +// RUN: %clangxx_msan -std=c++11 -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -std=c++11 -O0 %s -o %t -DPOSITIVE && not %run %t |& FileCheck %s + +#include <assert.h> +#include <dlfcn.h> +#include <sanitizer/msan_interface.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <unistd.h> + +typedef ssize_t (*process_vm_readwritev_fn)(pid_t, const iovec *, unsigned long, + const iovec *, unsigned long, + unsigned long); + +int main(void) { + // This requires glibc 2.15. + process_vm_readwritev_fn libc_process_vm_readv = + (process_vm_readwritev_fn)dlsym(RTLD_NEXT, "process_vm_readv"); + if (!libc_process_vm_readv) { +// Exit with success, emulating the expected output. +#ifdef POSITIVE + printf("process_vm_readv not found!\n"); + printf( + "WARNING: MemorySanitizer: use-of-uninitialized-value (not really)\n"); + return 1; +#else + return 0; +#endif + } + + process_vm_readwritev_fn process_vm_readv = + (process_vm_readwritev_fn)dlsym(RTLD_DEFAULT, "process_vm_readv"); + process_vm_readwritev_fn process_vm_writev = + (process_vm_readwritev_fn)dlsym(RTLD_DEFAULT, "process_vm_writev"); + + char a[100]; + memset(a, 0xab, 100); + + char b[100]; + iovec iov_a[] = {{(void *)a, 20}, (void *)(a + 50), 10}; + iovec iov_b[] = {{(void *)(b + 10), 10}, (void *)(b + 30), 20}; + + __msan_poison(&b, sizeof(b)); + ssize_t res = process_vm_readv(getpid(), iov_b, 2, iov_a, 2, 0); + assert(res == 30); + __msan_check_mem_is_initialized(b + 10, 10); + __msan_check_mem_is_initialized(b + 30, 20); + assert(__msan_test_shadow(b + 9, 1) == 0); + assert(__msan_test_shadow(b + 20, 1) == 0); + assert(__msan_test_shadow(b + 29, 1) == 0); + assert(__msan_test_shadow(b + 50, 1) == 0); + +#ifdef POSITIVE + __msan_unpoison(&b, sizeof(b)); + __msan_poison(b + 32, 1); + res = process_vm_writev(getpid(), iov_b, 2, iov_a, 2, 0); +// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value +#else + __msan_unpoison(&b, sizeof(b)); + res = process_vm_writev(getpid(), iov_b, 2, iov_a, 2, 0); + assert(res == 30); +#endif + + return 0; +} diff --git a/test/msan/allocator_mapping.cc b/test/msan/allocator_mapping.cc new file mode 100644 index 0000000000000..f47d9a63e09f8 --- /dev/null +++ b/test/msan/allocator_mapping.cc @@ -0,0 +1,36 @@ +// Test that a module constructor can not map memory over the MSan heap +// (without MAP_FIXED, of course). Current implementation ensures this by +// mapping the heap early, in __msan_init. +// +// RUN: %clangxx_msan -O0 %s -o %t_1 +// RUN: %clangxx_msan -O0 -DHEAP_ADDRESS=$(%run %t_1) %s -o %t_2 && %run %t_2 +// +// This test only makes sense for the 64-bit allocator. The 32-bit allocator +// does not have a fixed mapping. Exclude platforms that use the 32-bit +// allocator. +// UNSUPPORTED: mips64,aarch64 + +#include <assert.h> +#include <stdio.h> +#include <sys/mman.h> +#include <stdlib.h> + +#ifdef HEAP_ADDRESS +struct A { + A() { + void *const hint = reinterpret_cast<void *>(HEAP_ADDRESS); + void *p = mmap(hint, 4096, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + // This address must be already mapped. Check that mmap() succeeds, but at a + // different address. + assert(p != reinterpret_cast<void *>(-1)); + assert(p != hint); + } +} a; +#endif + +int main() { + void *p = malloc(10); + printf("0x%zx\n", reinterpret_cast<size_t>(p) & (~0xfff)); + free(p); +} diff --git a/test/msan/ctermid.cc b/test/msan/ctermid.cc new file mode 100644 index 0000000000000..a2818e6306864 --- /dev/null +++ b/test/msan/ctermid.cc @@ -0,0 +1,13 @@ +// RUN: %clangxx_msan -std=c++11 -O0 %s -o %t && %run %t + +#include <sanitizer/msan_interface.h> +#include <stdio.h> +#include <string.h> + +int main(void) { + unsigned char s[L_ctermid + 1]; + char *res = ctermid((char *)s); + if (res) + printf("%zd\n", strlen(res)); + return 0; +} diff --git a/test/msan/dlerror.cc b/test/msan/dlerror.cc index d5510b65c4a5b..0ad5b35f52180 100644 --- a/test/msan/dlerror.cc +++ b/test/msan/dlerror.cc @@ -1,4 +1,8 @@ // RUN: %clangxx_msan -O0 %s -o %t && %run %t +// +// AArch64 shows fails with uninitialized bytes in __interceptor_strcmp from +// dlfcn/dlerror.c:107 (glibc). +// XFAIL: aarch64 #include <assert.h> #include <dlfcn.h> diff --git a/test/msan/dlopen_executable.cc b/test/msan/dlopen_executable.cc new file mode 100644 index 0000000000000..ac8a14b940785 --- /dev/null +++ b/test/msan/dlopen_executable.cc @@ -0,0 +1,17 @@ +// RUN: %clangxx_msan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <dlfcn.h> +#include <stdlib.h> + +static int my_global; + +int main(void) { + int *uninit = (int*)malloc(sizeof(int)); + my_global = *uninit; + void *p = dlopen(0, RTLD_NOW); + assert(p && "failed to get handle to executable"); + return my_global; + // CHECK: MemorySanitizer: use-of-uninitialized-value + // CHECK: #0 {{.*}} in main{{.*}}dlopen_executable.cc:[[@LINE-2]] +} diff --git a/test/msan/dtor-base-access.cc b/test/msan/dtor-base-access.cc new file mode 100644 index 0000000000000..bed66fb621db0 --- /dev/null +++ b/test/msan/dtor-base-access.cc @@ -0,0 +1,49 @@ +// 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 + +// 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 + +// 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 + +#include <sanitizer/msan_interface.h> +#include <assert.h> + +class Base { + public: + int *x_ptr; + Base(int *y_ptr) { + // store value of subclass member + x_ptr = y_ptr; + } + virtual ~Base(); +}; + +class Derived : public Base { + public: + int y; + Derived():Base(&y) { + y = 10; + } + ~Derived(); +}; + +Base::~Base() { + // ok access its own member + assert(__msan_test_shadow(&this->x_ptr, sizeof(this->x_ptr)) == -1); + // bad access subclass member + assert(__msan_test_shadow(this->x_ptr, sizeof(*this->x_ptr)) != -1); +} + +Derived::~Derived() { + // ok to access its own members + assert(__msan_test_shadow(&this->y, sizeof(this->y)) == -1); + // ok access base class members + assert(__msan_test_shadow(&this->x_ptr, sizeof(this->x_ptr)) == -1); +} + +int main() { + Derived *d = new Derived(); + assert(__msan_test_shadow(&d->x_ptr, sizeof(d->x_ptr)) == -1); + d->~Derived(); + assert(__msan_test_shadow(&d->x_ptr, sizeof(d->x_ptr)) != -1); + return 0; +} diff --git a/test/msan/dtor-bit-fields.cc b/test/msan/dtor-bit-fields.cc new file mode 100644 index 0000000000000..4c6e322e63639 --- /dev/null +++ b/test/msan/dtor-bit-fields.cc @@ -0,0 +1,70 @@ +// RUN: %clangxx_msan %s -O0 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +#include <sanitizer/msan_interface.h> +#include <assert.h> + +// TODO: remove empty dtors when msan use-after-dtor poisons +// for trivial classes with undeclared dtors + +// 24 bytes total +struct Packed { + // Packed into 4 bytes + unsigned int a : 1; + unsigned int b : 1; + // Force alignment to next 4 bytes + unsigned int : 0; + unsigned int c : 1; + // Force alignment, 8 more bytes + double d = 5.0; + // 4 bytes + unsigned int e : 1; + ~Packed() {} +}; + +// 1 byte total +struct Empty { + unsigned int : 0; + ~Empty() {} +}; + +// 4 byte total +struct Simple { + unsigned int a : 1; + ~Simple() {} +}; + +struct Anon { + unsigned int a : 1; + unsigned int b : 2; + unsigned int : 0; + unsigned int c : 1; + ~Anon() {} +}; + +int main() { + Packed *p = new Packed(); + p->~Packed(); + for (int i = 0; i < 4; i++) + assert(__msan_test_shadow(((char*)p) + i, sizeof(char)) != -1); + assert(__msan_test_shadow(&p->d, sizeof(double)) != -1); + assert(__msan_test_shadow(((char*)(&p->d)) + sizeof(double), sizeof(char)) != + -1); + + Empty *e = new Empty(); + e->~Empty(); + assert(__msan_test_shadow(e, sizeof(*e)) != -1); + + Simple *s = new Simple(); + s->~Simple(); + assert(__msan_test_shadow(s, sizeof(*s)) != -1); + + Anon *a = new Anon(); + a->~Anon(); + assert(__msan_test_shadow(a, sizeof(*a)) != -1); + + return 0; +} diff --git a/test/msan/dtor-derived-class.cc b/test/msan/dtor-derived-class.cc new file mode 100644 index 0000000000000..1f3db7f33378f --- /dev/null +++ b/test/msan/dtor-derived-class.cc @@ -0,0 +1,39 @@ +// 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 +// 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 +// 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 + +#include <sanitizer/msan_interface.h> +#include <assert.h> + +struct Base { + int x; + Base() { x = 5; } + virtual ~Base() {} +}; + +struct Derived : public Base { + int y; + Derived() { y = 10; } + ~Derived() {} +}; + +int main() { + Derived *d = new Derived(); + d->~Derived(); + + // Verify that local pointer is unpoisoned, and that the object's + // members are. + assert(__msan_test_shadow(&d, sizeof(d)) == -1); + assert(__msan_test_shadow(&d->x, sizeof(d->x)) != -1); + assert(__msan_test_shadow(&d->y, sizeof(d->y)) != -1); + + Base *b = new Derived(); + b->~Base(); + + // Verify that local pointer is unpoisoned, and that the object's + // members are. + assert(__msan_test_shadow(&b, sizeof(b)) == -1); + assert(__msan_test_shadow(&b->x, sizeof(b->x)) != -1); + + return 0; +} diff --git a/test/msan/dtor-member.cc b/test/msan/dtor-member.cc new file mode 100644 index 0000000000000..13a059947bca3 --- /dev/null +++ b/test/msan/dtor-member.cc @@ -0,0 +1,48 @@ +// RUN: %clangxx_msan %s -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// 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 +// RUN: FileCheck %s < %t.out + +// 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 +// RUN: FileCheck %s < %t.out + +// RUN: %clangxx_msan %s -fsanitize=memory -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK-NO-FLAG < %t.out + +// RUN: %clangxx_msan -fsanitize=memory -fsanitize-memory-use-after-dtor %s -o %t && MSAN_OPTIONS=poison_in_dtor=0 %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK-NO-FLAG < %t.out + +#include <sanitizer/msan_interface.h> +#include <assert.h> +#include <stdio.h> +#include <new> + +struct Simple { + int x_; + Simple() { + x_ = 5; + } + ~Simple() { } +}; + +int main() { + unsigned long buf[1]; + assert(sizeof(Simple) <= sizeof(buf)); + + // The placement new operator forces the object to be constructed in the + // memory location &buf. Since objects made in this way must be explicitly + // destroyed, there are no implicit calls inserted that would interfere with + // test behavior. + Simple *s = new(&buf) Simple(); + s->~Simple(); + + if (__msan_test_shadow(s, sizeof(*s)) != -1) + printf("s is poisoned\n"); + else + printf("s is not poisoned\n"); + // CHECK: s is poisoned + // CHECK-NO-FLAG: s is not poisoned + + return 0; +} diff --git a/test/msan/dtor-multiple-inheritance-nontrivial-class-members.cc b/test/msan/dtor-multiple-inheritance-nontrivial-class-members.cc new file mode 100644 index 0000000000000..dd79e3cc6c5eb --- /dev/null +++ b/test/msan/dtor-multiple-inheritance-nontrivial-class-members.cc @@ -0,0 +1,152 @@ +// 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 + +// 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 + +// 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 + +#include <sanitizer/msan_interface.h> +#include <assert.h> + +template <class T> class Vector { +public: + int size; + ~Vector() { + assert(__msan_test_shadow(&this->size, sizeof(this->size)) == -1); + } +}; + +struct VirtualBase { +public: + Vector<int> virtual_v; + int virtual_a; + // Pointer to subclass member + int *intermediate_a_ptr; + + VirtualBase() { + virtual_v.size = 1; + virtual_a = 9; + } + void set_ptr(int *intermediate_a) { + this->intermediate_a_ptr = intermediate_a; + } + virtual ~VirtualBase() { + assert(__msan_test_shadow(&virtual_v, sizeof(virtual_v)) == -1); + assert(__msan_test_shadow(&virtual_a, sizeof(virtual_a)) == -1); + // Derived class member is poisoned + assert(__msan_test_shadow(intermediate_a_ptr, + sizeof(*intermediate_a_ptr)) != -1); + } +}; + +struct Intermediate : virtual public VirtualBase { +public: + int intermediate_a; + + Intermediate() { intermediate_a = 5; } + virtual ~Intermediate() { + assert(__msan_test_shadow(&this->intermediate_a, + sizeof(this->intermediate_a)) == -1); + // Members inherited from VirtualBase unpoisoned + assert(__msan_test_shadow(&virtual_v, sizeof(virtual_v)) == -1); + assert(__msan_test_shadow(&virtual_a, sizeof(virtual_a)) == -1); + assert(__msan_test_shadow(intermediate_a_ptr, + sizeof(*intermediate_a_ptr)) == -1); + } +}; + +struct Base { + int base_a; + Vector<int> base_v; + double base_b; + // Pointers to subclass members + int *derived_a_ptr; + Vector<int> *derived_v1_ptr; + Vector<int> *derived_v2_ptr; + double *derived_b_ptr; + double *derived_c_ptr; + + Base(int *derived_a, Vector<int> *derived_v1, Vector<int> *derived_v2, + double *derived_b, double *derived_c) { + base_a = 2; + base_v.size = 1; + base_b = 13.2324; + derived_a_ptr = derived_a; + derived_v1_ptr = derived_v1; + derived_v2_ptr = derived_v2; + derived_b_ptr = derived_b; + derived_c_ptr = derived_c; + } + virtual ~Base() { + assert(__msan_test_shadow(&base_a, sizeof(base_a)) == -1); + assert(__msan_test_shadow(&base_v, sizeof(base_v)) == -1); + assert(__msan_test_shadow(&base_b, sizeof(base_b)) == -1); + // Derived class members are poisoned + assert(__msan_test_shadow(derived_a_ptr, sizeof(*derived_a_ptr)) != -1); + assert(__msan_test_shadow(derived_v1_ptr, sizeof(*derived_v1_ptr)) != -1); + assert(__msan_test_shadow(derived_v2_ptr, sizeof(*derived_v2_ptr)) != -1); + assert(__msan_test_shadow(derived_b_ptr, sizeof(*derived_b_ptr)) != -1); + assert(__msan_test_shadow(derived_c_ptr, sizeof(*derived_c_ptr)) != -1); + } +}; + +struct Derived : public Base, public Intermediate { + int derived_a; + Vector<int> derived_v1; + Vector<int> derived_v2; + double derived_b; + double derived_c; + + Derived() + : Base(&derived_a, &derived_v1, &derived_v2, &derived_b, &derived_c) { + derived_a = 5; + derived_v1.size = 1; + derived_v2.size = 1; + derived_b = 7; + derived_c = 10; + } + ~Derived() { + assert(__msan_test_shadow(&derived_a, sizeof(derived_a)) == -1); + assert(__msan_test_shadow(&derived_v1, sizeof(derived_v1)) == -1); + assert(__msan_test_shadow(&derived_v2, sizeof(derived_v2)) == -1); + assert(__msan_test_shadow(&derived_b, sizeof(derived_b)) == -1); + assert(__msan_test_shadow(&derived_c, sizeof(derived_c)) == -1); + } +}; + +int main() { + Derived *d = new Derived(); + d->set_ptr(&d->intermediate_a); + + // Keep track of members of VirtualBase, since the virtual base table + // is inaccessible after destruction + Vector<int> *temp_virtual_v = &d->virtual_v; + int *temp_virtual_a = &d->virtual_a; + int **temp_intermediate_a_ptr = &d->intermediate_a_ptr; + + d->~Derived(); + assert(__msan_test_shadow(&d->derived_a, sizeof(d->derived_a)) != -1); + assert(__msan_test_shadow(&d->derived_v1, sizeof(d->derived_v1)) != -1); + assert(__msan_test_shadow(&d->derived_v2, sizeof(d->derived_v2)) != -1); + assert(__msan_test_shadow(&d->derived_b, sizeof(d->derived_b)) != -1); + assert(__msan_test_shadow(&d->derived_c, sizeof(d->derived_c)) != -1); + + // Inherited from base + assert(__msan_test_shadow(&d->base_a, sizeof(d->base_a)) != -1); + assert(__msan_test_shadow(&d->base_v, sizeof(d->base_v)) != -1); + assert(__msan_test_shadow(&d->base_b, sizeof(d->base_b)) != -1); + assert(__msan_test_shadow(&d->derived_a_ptr, sizeof(d->derived_a_ptr)) != -1); + assert(__msan_test_shadow(&d->derived_v1_ptr, sizeof(d->derived_v1_ptr)) != + -1); + assert(__msan_test_shadow(&d->derived_v2_ptr, sizeof(d->derived_v2_ptr)) != + -1); + assert(__msan_test_shadow(&d->derived_b_ptr, sizeof(d->derived_b_ptr)) != -1); + assert(__msan_test_shadow(&d->derived_c_ptr, sizeof(d->derived_c_ptr)) != -1); + + // Inherited from intermediate + assert(__msan_test_shadow(temp_virtual_v, sizeof(*temp_virtual_v)) != -1); + assert(__msan_test_shadow(temp_virtual_a, sizeof(*temp_virtual_a)) != -1); + assert(__msan_test_shadow(temp_intermediate_a_ptr, + sizeof(*temp_intermediate_a_ptr)) != -1); + + return 0; +} diff --git a/test/msan/dtor-multiple-inheritance.cc b/test/msan/dtor-multiple-inheritance.cc new file mode 100644 index 0000000000000..0704bf7b31916 --- /dev/null +++ b/test/msan/dtor-multiple-inheritance.cc @@ -0,0 +1,98 @@ +// Defines diamond multiple inheritance structure +// A +// / \ +// B C +// \ / +// Derived + +// 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 + +// 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 + +// 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 + +#include <sanitizer/msan_interface.h> +#include <assert.h> + +int *temp_x; +int *temp_y; +int *temp_z; +int *temp_w; + +class A { +public: + int x; + A() { x = 5; } + virtual ~A() { + assert(__msan_test_shadow(&this->x, sizeof(this->x) == -1)); + // Memory owned by subclasses is poisoned. + assert(__msan_test_shadow(temp_y, sizeof(*temp_y)) != -1); + assert(__msan_test_shadow(temp_z, sizeof(*temp_z)) != -1); + assert(__msan_test_shadow(temp_w, sizeof(*temp_w)) != -1); + } +}; + +struct B : virtual public A { +public: + int y; + B() { y = 10; } + virtual ~B() { + assert(__msan_test_shadow(&this->y, sizeof(this->y)) == -1); + // Memory accessible via vtable still reachable. + assert(__msan_test_shadow(&this->x, sizeof(this->x)) == -1); + // Memory in sibling and subclass is poisoned. + assert(__msan_test_shadow(temp_z, sizeof(*temp_z)) != -1); + assert(__msan_test_shadow(temp_w, sizeof(*temp_w)) != -1); + } +}; + +struct C : virtual public A { +public: + int z; + C() { z = 15; } + virtual ~C() { + assert(__msan_test_shadow(&this->z, sizeof(this->z)) == -1); + // Memory accessible via vtable still reachable. + assert(__msan_test_shadow(&this->x, sizeof(this->x)) == -1); + // Sibling class is unpoisoned. + assert(__msan_test_shadow(temp_y, sizeof(*temp_y)) == -1); + // Memory in subclasses is poisoned. + assert(__msan_test_shadow(temp_w, sizeof(*temp_w)) != -1); + } +}; + +class Derived : public B, public C { +public: + int w; + Derived() { w = 10; } + ~Derived() { + assert(__msan_test_shadow(&this->x, sizeof(this->x)) == -1); + // Members accessed through the vtable are still accessible. + assert(__msan_test_shadow(&this->y, sizeof(this->y)) == -1); + assert(__msan_test_shadow(&this->z, sizeof(this->z)) == -1); + assert(__msan_test_shadow(&this->w, sizeof(this->w)) == -1); + } +}; + + +int main() { + Derived *d = new Derived(); + + // Keep track of members inherited from virtual bases, + // since the virtual base table is inaccessible after destruction. + temp_x = &d->x; + temp_y = &d->y; + temp_z = &d->z; + temp_w = &d->w; + + // Order of destruction: Derived, C, B, A + d->~Derived(); + // Verify that local pointer is unpoisoned, and that the object's + // members are. + assert(__msan_test_shadow(&d, sizeof(d)) == -1); + assert(__msan_test_shadow(temp_x, sizeof(*temp_x)) != -1); + assert(__msan_test_shadow(temp_y, sizeof(*temp_y)) != -1); + assert(__msan_test_shadow(temp_z, sizeof(*temp_z)) != -1); + assert(__msan_test_shadow(temp_w, sizeof(*temp_w)) != -1); + return 0; +} diff --git a/test/msan/dtor-trivial-class-members.cc b/test/msan/dtor-trivial-class-members.cc new file mode 100644 index 0000000000000..8960dc647c690 --- /dev/null +++ b/test/msan/dtor-trivial-class-members.cc @@ -0,0 +1,55 @@ +// 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 + +// 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 + +// 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 + +#include <sanitizer/msan_interface.h> +#include <assert.h> +#include <stdio.h> + +template <class T> +class Vector { +public: + int size; + ~Vector() { + printf("~V %p %lu\n", &size, sizeof(size)); + assert(__msan_test_shadow(&this->size, sizeof(this->size)) == -1); + } +}; + +struct Derived { + int derived_a; + Vector<int> derived_v1; + Vector<int> derived_v2; + double derived_b; + double derived_c; + Derived() { + derived_a = 5; + derived_v1.size = 1; + derived_v2.size = 1; + derived_b = 7; + derived_c = 10; + } + ~Derived() { + printf("~D %p %p %p %lu\n", &derived_a, &derived_v1, &derived_c, sizeof(*this)); + assert(__msan_test_shadow(&derived_a, sizeof(derived_a)) == -1); + assert(__msan_test_shadow(&derived_v1, sizeof(derived_v1)) == -1); + assert(__msan_test_shadow(&derived_v2, sizeof(derived_v2)) == -1); + assert(__msan_test_shadow(&derived_b, sizeof(derived_b)) == -1); + assert(__msan_test_shadow(&derived_c, sizeof(derived_c)) == -1); + } +}; + +int main() { + Derived *d = new Derived(); + d->~Derived(); + + assert(__msan_test_shadow(&d->derived_a, sizeof(d->derived_a)) != -1); + assert(__msan_test_shadow(&d->derived_v1, sizeof(d->derived_v1)) != -1); + assert(__msan_test_shadow(&d->derived_v2, sizeof(d->derived_v2)) != -1); + assert(__msan_test_shadow(&d->derived_b, sizeof(d->derived_b)) != -1); + assert(__msan_test_shadow(&d->derived_c, sizeof(d->derived_c)) != -1); + + return 0; +} diff --git a/test/msan/dtor-trivial.cpp b/test/msan/dtor-trivial.cpp new file mode 100644 index 0000000000000..3faa760cac90d --- /dev/null +++ b/test/msan/dtor-trivial.cpp @@ -0,0 +1,41 @@ +// 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 + +// 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 + +// 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 + +// TODO Success pending on resolution of +// https://github.com/google/sanitizers/issues/596 + +// XFAIL: * + +#include <assert.h> +#include <sanitizer/msan_interface.h> + +template <class T> class Vector { + public: + int size; + ~Vector() {} +}; + +struct NonTrivial { + int a; + Vector<int> v; +}; + +struct Trivial { + int a; + int b; +}; + +int main() { + NonTrivial *nt = new NonTrivial(); + nt->~NonTrivial(); + assert(__msan_test_shadow(nt, sizeof(*nt)) != -1); + + Trivial *t = new Trivial(); + t->~Trivial(); + assert(__msan_test_shadow(t, sizeof(*t)) != -1); + + return 0; +} diff --git a/test/msan/dtor-vtable-multiple-inheritance.cc b/test/msan/dtor-vtable-multiple-inheritance.cc new file mode 100644 index 0000000000000..8521fadd0725f --- /dev/null +++ b/test/msan/dtor-vtable-multiple-inheritance.cc @@ -0,0 +1,72 @@ +// RUN: %clangxx_msan %s -O0 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -DCVPTR=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// RUN: %clangxx_msan %s -DEAVPTR=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// RUN: %clangxx_msan %s -DEDVPTR=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// Expected to quit due to invalid access when invoking +// function using vtable. + +class A { + public: + int x; + virtual ~A() { + // Should succeed + this->A_Foo(); + } + virtual void A_Foo() {} +}; + +class B : public virtual A { + public: + int y; + virtual ~B() {} + virtual void A_Foo() {} +}; + +class C : public B { + public: + int z; + ~C() {} +}; + +class D { + public: + int w; + ~D() {} + virtual void D_Foo() {} +}; + +class E : public virtual A, public virtual D { + public: + int u; + ~E() {} + void A_Foo() {} +}; + +int main() { + // Simple linear inheritance + C *c = new C(); + c->~C(); + // This fails +#ifdef CVPTR + c->A_Foo(); +#endif + + // Multiple inheritance, so has multiple vtables + E *e = new E(); + e->~E(); + // Both of these fail +#ifdef EAVPTR + e->A_Foo(); +#endif +#ifdef EDVPTR + e->D_Foo(); +#endif +} diff --git a/test/msan/dtor-vtable.cc b/test/msan/dtor-vtable.cc new file mode 100644 index 0000000000000..9bbad26092d6e --- /dev/null +++ b/test/msan/dtor-vtable.cc @@ -0,0 +1,68 @@ +// RUN: %clangxx_msan %s -O0 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 %run %t + +// RUN: %clangxx_msan %s -DVPTRA=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// RUN: %clangxx_msan %s -DVPTRCA=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// RUN: %clangxx_msan %s -DVPTRCB=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// RUN: %clangxx_msan %s -DVPTRC=1 -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t + +// Expected to quit due to invalid access when invoking +// function using vtable. + +#include <sanitizer/msan_interface.h> +#include <stdio.h> +#include <assert.h> + +class A { +public: + int x; + ~A() {} + virtual void A_Foo() {} +}; + +class B { + public: + int y; + ~B() {} + virtual void B_Foo() {} +}; + +class C : public A, public B { + public: + int z; + ~C() {} + virtual void C_Foo() {} +}; + +int main() { + A *a = new A(); + a->~A(); + + // Shouldn't be allowed to invoke function via vtable. +#ifdef VPTRA + a->A_Foo(); +#endif + + C *c = new C(); + c->~C(); + +#ifdef VPTRCA + c->A_Foo(); +#endif + +#ifdef VPTRCB + c->B_Foo(); +#endif + +#ifdef VPTRC + c->C_Foo(); +#endif + + return 0; +} diff --git a/test/msan/icmp_slt_allones.cc b/test/msan/icmp_slt_allones.cc new file mode 100644 index 0000000000000..8eff2eac8ad92 --- /dev/null +++ b/test/msan/icmp_slt_allones.cc @@ -0,0 +1,20 @@ +// PR24561 +// RUN: %clangxx_msan -O2 -g %s -o %t && %run %t + +#include <stdio.h> + +struct A { + int c1 : 7; + int c8 : 1; + int c9 : 1; + A(); +}; + +__attribute__((noinline)) A::A() : c8(1) {} + +int main() { + A* a = new A(); + if (a->c8 == 0) + printf("zz\n"); + return 0; +} diff --git a/test/msan/insertvalue_origin.cc b/test/msan/insertvalue_origin.cc index a0c70023f2f6f..96d27f08937e0 100644 --- a/test/msan/insertvalue_origin.cc +++ b/test/msan/insertvalue_origin.cc @@ -4,6 +4,7 @@ // RUN: FileCheck %s < %t.out && FileCheck %s < %t.out // Test origin propagation through insertvalue IR instruction. +// REQUIRES: stable-runtime #include <stdio.h> #include <stdint.h> diff --git a/test/msan/memcmp_test.cc b/test/msan/memcmp_test.cc new file mode 100644 index 0000000000000..95228eb127dd8 --- /dev/null +++ b/test/msan/memcmp_test.cc @@ -0,0 +1,15 @@ +// RUN: %clangxx_msan -O0 -g %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: MSAN_OPTIONS=intercept_memcmp=0 %run %t + +#include <string.h> +int main(int argc, char **argv) { + char a1[4]; + char a2[4]; + for (int i = 0; i < argc * 3; i++) + a2[i] = a1[i] = i; + int res = memcmp(a1, a2, 4); + return res; + // CHECK: Uninitialized bytes in __interceptor_memcmp at offset 3 + // CHECK: MemorySanitizer: use-of-uninitialized-value +} diff --git a/test/msan/mmap.cc b/test/msan/mmap.cc index c09fcb76a8279..27a8bb2d6eb5c 100644 --- a/test/msan/mmap.cc +++ b/test/msan/mmap.cc @@ -7,23 +7,49 @@ #include <stdint.h> #include <sys/mman.h> #include <stdio.h> +#include <stdlib.h> +#include "test.h" bool AddrIsApp(void *p) { uintptr_t addr = (uintptr_t)p; #if defined(__FreeBSD__) && defined(__x86_64__) return addr < 0x010000000000ULL || addr >= 0x600000000000ULL; #elif defined(__x86_64__) - return addr >= 0x600000000000ULL; + return (addr >= 0x000000000000ULL && addr < 0x010000000000ULL) || + (addr >= 0x510000000000ULL && addr < 0x600000000000ULL) || + (addr >= 0x700000000000ULL && addr < 0x800000000000ULL); #elif defined(__mips64) return addr >= 0x00e000000000ULL; #elif defined(__powerpc64__) return addr < 0x000100000000ULL || addr >= 0x300000000000ULL; +#elif defined(__aarch64__) + + struct AddrMapping { + uintptr_t start; + uintptr_t end; + } mappings[] = { + {0x05000000000ULL, 0x06000000000ULL}, + {0x07000000000ULL, 0x08000000000ULL}, + {0x0F000000000ULL, 0x10000000000ULL}, + {0x11000000000ULL, 0x12000000000ULL}, + {0x20000000000ULL, 0x21000000000ULL}, + {0x2A000000000ULL, 0x2B000000000ULL}, + {0x2E000000000ULL, 0x2F000000000ULL}, + {0x3B000000000ULL, 0x3C000000000ULL}, + {0x3F000000000ULL, 0x40000000000ULL}, + }; + const size_t mappingsSize = sizeof (mappings) / sizeof (mappings[0]); + + for (int i=0; i<mappingsSize; ++i) + if (addr >= mappings[i].start && addr < mappings[i].end) + return true; + return false; #endif } int main() { // Large enough to quickly exhaust the entire address space. -#if defined(__mips64) +#if defined(__mips64) || defined(__aarch64__) const size_t kMapSize = 0x100000000ULL; #else const size_t kMapSize = 0x1000000000ULL; diff --git a/test/msan/mmap_below_shadow.cc b/test/msan/mmap_below_shadow.cc index 563d8774f5253..806b19da8ca67 100644 --- a/test/msan/mmap_below_shadow.cc +++ b/test/msan/mmap_below_shadow.cc @@ -27,6 +27,9 @@ int main(void) { #elif defined (__powerpc64__) uintptr_t hint = 0x2f0000000000ULL; const uintptr_t app_start = 0x300000000000ULL; +#elif defined (__aarch64__) + uintptr_t hint = 0x4f0000000ULL; + const uintptr_t app_start = 0x7000000000ULL; #endif uintptr_t p = (uintptr_t)mmap( (void *)hint, 4096, PROT_WRITE, diff --git a/test/msan/msan_copy_shadow.cc b/test/msan/msan_copy_shadow.cc new file mode 100644 index 0000000000000..a1c6347ff4e3c --- /dev/null +++ b/test/msan/msan_copy_shadow.cc @@ -0,0 +1,34 @@ +// Test that __msan_copy_shadow copies shadow, updates origin and does not touch +// the application memory. +// RUN: %clangxx_msan -fsanitize-memory-track-origins=0 -O0 %s -o %t && not %run %t 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <string.h> +#include <sanitizer/msan_interface.h> + +int main() { + char *a = new char[4]; + char *b = new char[4]; + a[1] = 1; + a[3] = 2; + memset(b, 42, 4); + + // Test that __msan_copy_shadow does not touch the contents of b[]. + __msan_copy_shadow(b, a, 4); + __msan_unpoison(b, 4); + assert(b[0] == 42 && b[1] == 42 && b[2] == 42 && b[3] == 42); + + // Test that __msan_copy_shadow correctly updates shadow and origin of b[]. + __msan_copy_shadow(b, a, 4); + assert(__msan_test_shadow(b, 4) == 0); + assert(__msan_test_shadow(b + 1, 3) == 1); + assert(__msan_test_shadow(b + 3, 1) == -1); + __msan_check_mem_is_initialized(b, 4); + // CHECK: use-of-uninitialized-value + // CHECK: {{in main.*msan_copy_shadow.cc:}}[[@LINE-2]] + // CHECK: Uninitialized value was stored to memory at + // CHECK: {{in main.*msan_copy_shadow.cc:}}[[@LINE-8]] + // CHECK: Uninitialized value was created by a heap allocation + // CHECK: {{in main.*msan_copy_shadow.cc:}}[[@LINE-22]] +} diff --git a/test/msan/param_tls_limit.cc b/test/msan/param_tls_limit.cc index 982ae1ebdc2e0..1c504da428254 100644 --- a/test/msan/param_tls_limit.cc +++ b/test/msan/param_tls_limit.cc @@ -4,6 +4,10 @@ // RUN: %clangxx_msan -O0 %s -o %t && %run %t // RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && %run %t // RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O0 %s -o %t && %run %t +// +// AArch64 fails with: +// void f801(S<801>): Assertion `__msan_test_shadow(&s, sizeof(s)) == -1' failed +// XFAIL: aarch64 #include <sanitizer/msan_interface.h> #include <assert.h> diff --git a/test/msan/pthread_setcancelstate.cc b/test/msan/pthread_setcancelstate.cc new file mode 100644 index 0000000000000..087c2223a83d2 --- /dev/null +++ b/test/msan/pthread_setcancelstate.cc @@ -0,0 +1,19 @@ +// RUN: %clangxx_msan -O0 %s -o %t && %run %t + +#include <assert.h> +#include <pthread.h> +#include <sanitizer/msan_interface.h> + +int main(void) { + int oldstate; + int oldtype; + int res = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); + assert(res == 0); + __msan_check_mem_is_initialized(&oldstate, sizeof(oldstate)); + + res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); + assert(res == 0); + __msan_check_mem_is_initialized(&oldtype, sizeof(oldtype)); + + return 0; +} diff --git a/test/msan/sem_getvalue.cc b/test/msan/sem_getvalue.cc new file mode 100644 index 0000000000000..07b95cd493a29 --- /dev/null +++ b/test/msan/sem_getvalue.cc @@ -0,0 +1,22 @@ +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t + +#include <assert.h> +#include <sanitizer/msan_interface.h> +#include <semaphore.h> + +int main(void) { + sem_t sem; + int res = sem_init(&sem, 0, 42); + assert(res == 0); + + int v; + res = sem_getvalue(&sem, &v); + assert(res == 0); + __msan_check_mem_is_initialized(&v, sizeof(v)); + assert(v == 42); + + res = sem_destroy(&sem); + assert(res == 0); + + return 0; +} diff --git a/test/msan/signal_stress_test.cc b/test/msan/signal_stress_test.cc index 654b9676f4abd..5bc6f59213b14 100644 --- a/test/msan/signal_stress_test.cc +++ b/test/msan/signal_stress_test.cc @@ -1,5 +1,5 @@ // RUN: %clangxx_msan -std=c++11 -O0 %s -o %t && %run %t - +// // Test that va_arg shadow from a signal handler does not leak outside. #include <signal.h> diff --git a/test/msan/strlen_of_shadow.cc b/test/msan/strlen_of_shadow.cc index 763b3a1c73c09..3066dd5b61ae9 100644 --- a/test/msan/strlen_of_shadow.cc +++ b/test/msan/strlen_of_shadow.cc @@ -7,16 +7,20 @@ #include <stdint.h> #include <stdio.h> #include <string.h> +#include <stdlib.h> +#include "test.h" const char *mem_to_shadow(const char *p) { #if defined(__x86_64__) - return (char *)((uintptr_t)p & ~0x400000000000ULL); + return (char *)((uintptr_t)p ^ 0x500000000000ULL); #elif defined (__mips64) return (char *)((uintptr_t)p & ~0x4000000000ULL); #elif defined(__powerpc64__) #define LINEARIZE_MEM(mem) \ (((uintptr_t)(mem) & ~0x200000000000ULL) ^ 0x100000000000ULL) return (char *)(LINEARIZE_MEM(p) + 0x080000000000ULL); +#elif defined(__aarch64__) + return (char *)((uintptr_t)p ^ 0x6000000000ULL); #endif } diff --git a/test/msan/test.h b/test/msan/test.h new file mode 100644 index 0000000000000..a5dcdfccdaed2 --- /dev/null +++ b/test/msan/test.h @@ -0,0 +1,15 @@ +#if __LP64__ +# define SANITIZER_WORDSIZE 64 +#else +# define SANITIZER_WORDSIZE 32 +#endif + +// This is a simplified version of GetMaxVirtualAddress function. +unsigned long SystemVMA () { +#if SANITIZER_WORDSIZE == 64 + unsigned long vma = (unsigned long)__builtin_frame_address(0); + return SANITIZER_WORDSIZE - __builtin_clzll(vma); +#else + return SANITIZER_WORDSIZE; +#endif +} diff --git a/test/msan/use-after-dtor.cc b/test/msan/use-after-dtor.cc new file mode 100644 index 0000000000000..6c751a14f3774 --- /dev/null +++ b/test/msan/use-after-dtor.cc @@ -0,0 +1,45 @@ +// RUN: %clangxx_msan %s -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// RUN: %clangxx_msan %s -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// RUN: %clangxx_msan %s -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// RUN: %clangxx_msan %s -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -fsanitize-memory-track-origins -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out + +#include <sanitizer/msan_interface.h> +#include <assert.h> +#include <stdio.h> +#include <new> + +struct Simple { + int x_; + Simple() { + x_ = 5; + } + ~Simple() { + x_ += 1; + } +}; + +int main() { + unsigned long buf[1]; + assert(sizeof(Simple) <= sizeof(buf)); + + Simple *s = new(&buf) Simple(); + s->~Simple(); + + return s->x_; + + // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value + // CHECK: {{#0 0x.* in main.*use-after-dtor.cc:}}[[@LINE-3]] + + // CHECK-ORIGINS: Memory was marked as uninitialized + // CHECK-ORIGINS: {{#0 0x.* in __sanitizer_dtor_callback}} + // CHECK-ORIGINS: {{#1 0x.* in Simple::~Simple}} + + // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*main}} +} |