aboutsummaryrefslogtreecommitdiff
path: root/test/msan
diff options
context:
space:
mode:
Diffstat (limited to 'test/msan')
-rw-r--r--test/msan/Linux/forkpty.cc18
-rw-r--r--test/msan/Linux/mallinfo.cc1
-rw-r--r--test/msan/Linux/mincore.cc36
-rw-r--r--test/msan/Linux/process_vm_readv.cc67
-rw-r--r--test/msan/allocator_mapping.cc36
-rw-r--r--test/msan/ctermid.cc13
-rw-r--r--test/msan/dlerror.cc4
-rw-r--r--test/msan/dlopen_executable.cc17
-rw-r--r--test/msan/dtor-base-access.cc49
-rw-r--r--test/msan/dtor-bit-fields.cc70
-rw-r--r--test/msan/dtor-derived-class.cc39
-rw-r--r--test/msan/dtor-member.cc48
-rw-r--r--test/msan/dtor-multiple-inheritance-nontrivial-class-members.cc152
-rw-r--r--test/msan/dtor-multiple-inheritance.cc98
-rw-r--r--test/msan/dtor-trivial-class-members.cc55
-rw-r--r--test/msan/dtor-trivial.cpp41
-rw-r--r--test/msan/dtor-vtable-multiple-inheritance.cc72
-rw-r--r--test/msan/dtor-vtable.cc68
-rw-r--r--test/msan/icmp_slt_allones.cc20
-rw-r--r--test/msan/insertvalue_origin.cc1
-rw-r--r--test/msan/memcmp_test.cc15
-rw-r--r--test/msan/mmap.cc30
-rw-r--r--test/msan/mmap_below_shadow.cc3
-rw-r--r--test/msan/msan_copy_shadow.cc34
-rw-r--r--test/msan/param_tls_limit.cc4
-rw-r--r--test/msan/pthread_setcancelstate.cc19
-rw-r--r--test/msan/sem_getvalue.cc22
-rw-r--r--test/msan/signal_stress_test.cc2
-rw-r--r--test/msan/strlen_of_shadow.cc6
-rw-r--r--test/msan/test.h15
-rw-r--r--test/msan/use-after-dtor.cc45
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 000000000000..ae5c7d96ca8a
--- /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 3c3692969852..545ae934a611 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 000000000000..35f5713d4312
--- /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 000000000000..601c0d247dc2
--- /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 000000000000..f47d9a63e09f
--- /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 000000000000..a2818e630686
--- /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 d5510b65c4a5..0ad5b35f5218 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 000000000000..ac8a14b94078
--- /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 000000000000..bed66fb621db
--- /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 000000000000..4c6e322e6363
--- /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 000000000000..1f3db7f33378
--- /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 000000000000..13a059947bca
--- /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 000000000000..dd79e3cc6c5e
--- /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 000000000000..0704bf7b3191
--- /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 000000000000..8960dc647c69
--- /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 000000000000..3faa760cac90
--- /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 000000000000..8521fadd0725
--- /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 000000000000..9bbad26092d6
--- /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 000000000000..8eff2eac8ad9
--- /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 a0c70023f2f6..96d27f08937e 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 000000000000..95228eb127dd
--- /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 c09fcb76a827..27a8bb2d6eb5 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 563d8774f525..806b19da8ca6 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 000000000000..a1c6347ff4e3
--- /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 982ae1ebdc2e..1c504da42825 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 000000000000..087c2223a83d
--- /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 000000000000..07b95cd493a2
--- /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 654b9676f4ab..5bc6f59213b1 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 763b3a1c73c0..3066dd5b61ae 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 000000000000..a5dcdfccdaed
--- /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 000000000000..6c751a14f377
--- /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}}
+}