summaryrefslogtreecommitdiff
path: root/test/msan
diff options
context:
space:
mode:
Diffstat (limited to 'test/msan')
-rw-r--r--test/msan/CMakeLists.txt23
-rw-r--r--test/msan/Linux/getresid.cc25
-rw-r--r--test/msan/Linux/glob.cc27
-rw-r--r--test/msan/Linux/glob_altdirfunc.cc78
-rw-r--r--test/msan/Linux/glob_nomatch.cc21
-rw-r--r--test/msan/Linux/glob_test_root/aa0
-rw-r--r--test/msan/Linux/glob_test_root/ab0
-rw-r--r--test/msan/Linux/glob_test_root/ba0
-rw-r--r--test/msan/Linux/lit.local.cfg9
-rw-r--r--test/msan/Linux/sunrpc.cc40
-rw-r--r--test/msan/Linux/sunrpc_bytes.cc38
-rw-r--r--test/msan/Linux/sunrpc_string.cc35
-rw-r--r--test/msan/Linux/syscalls.cc115
-rw-r--r--test/msan/Linux/tcgetattr.cc21
-rw-r--r--test/msan/Linux/xattr.cc145
-rw-r--r--test/msan/Linux/xattr_test_root/a0
-rw-r--r--test/msan/Unit/lit.site.cfg.in14
-rw-r--r--test/msan/allocator_returns_null.cc81
-rw-r--r--test/msan/backtrace.cc26
-rw-r--r--test/msan/c-strdup.c17
-rw-r--r--test/msan/chained_origin.cc66
-rw-r--r--test/msan/chained_origin_empty_stack.cc34
-rw-r--r--test/msan/chained_origin_limits.cc178
-rw-r--r--test/msan/chained_origin_memcpy.cc61
-rw-r--r--test/msan/chained_origin_with_signals.cc36
-rw-r--r--test/msan/check_mem_is_initialized.cc33
-rw-r--r--test/msan/coverage-levels.cc28
-rw-r--r--test/msan/cxa_atexit.cc28
-rw-r--r--test/msan/death-callback.cc39
-rw-r--r--test/msan/default_blacklist.cc3
-rw-r--r--test/msan/dlerror.cc14
-rw-r--r--test/msan/dso-origin.cc48
-rw-r--r--test/msan/dtls_test.c60
-rw-r--r--test/msan/errno.cc17
-rw-r--r--test/msan/fork.cc121
-rw-r--r--test/msan/ftime.cc14
-rw-r--r--test/msan/getaddrinfo-positive.cc23
-rw-r--r--test/msan/getaddrinfo.cc24
-rw-r--r--test/msan/getc_unlocked.c32
-rw-r--r--test/msan/getline.cc36
-rw-r--r--test/msan/heap-origin.cc31
-rw-r--r--test/msan/iconv.cc48
-rw-r--r--test/msan/if_indextoname.cc23
-rw-r--r--test/msan/ifaddrs.cc50
-rw-r--r--test/msan/initgroups.cc11
-rw-r--r--test/msan/inline.cc20
-rw-r--r--test/msan/insertvalue_origin.cc35
-rw-r--r--test/msan/ioctl.cc20
-rw-r--r--test/msan/ioctl_custom.cc33
-rw-r--r--test/msan/ioctl_sound.cc29
-rw-r--r--test/msan/keep-going-dso.cc33
-rw-r--r--test/msan/keep-going.cc34
-rw-r--r--test/msan/lit.cfg30
-rw-r--r--test/msan/lit.site.cfg.in5
-rw-r--r--test/msan/mallinfo.cc12
-rw-r--r--test/msan/mktime.cc26
-rw-r--r--test/msan/mmap_below_shadow.cc28
-rw-r--r--test/msan/msan_check_mem_is_initialized.cc28
-rw-r--r--test/msan/msan_dump_shadow.cc22
-rw-r--r--test/msan/msan_print_shadow.cc122
-rw-r--r--test/msan/msan_print_shadow2.cc49
-rw-r--r--test/msan/msan_print_shadow3.cc16
-rw-r--r--test/msan/mul_by_const.cc27
-rw-r--r--test/msan/no_sanitize_memory.cc34
-rw-r--r--test/msan/no_sanitize_memory_prop.cc24
-rw-r--r--test/msan/obstack.cc37
-rw-r--r--test/msan/param_tls_limit.cc74
-rw-r--r--test/msan/poison_in_free.cc16
-rw-r--r--test/msan/print_stats.cc45
-rw-r--r--test/msan/pthread_getattr_np_deadlock.cc22
-rw-r--r--test/msan/rand_r.cc18
-rw-r--r--test/msan/readdir64.cc27
-rw-r--r--test/msan/report-demangling.cc19
-rw-r--r--test/msan/scandir.cc56
-rw-r--r--test/msan/scandir_null.cc34
-rw-r--r--test/msan/scandir_test_root/aaa0
-rw-r--r--test/msan/scandir_test_root/aab0
-rw-r--r--test/msan/scandir_test_root/bbb0
-rw-r--r--test/msan/select.cc22
-rw-r--r--test/msan/select_float_origin.cc24
-rw-r--r--test/msan/select_origin.cc22
-rw-r--r--test/msan/setlocale.cc13
-rw-r--r--test/msan/signal_stress_test.cc71
-rw-r--r--test/msan/sigwait.cc30
-rw-r--r--test/msan/sigwaitinfo.cc31
-rw-r--r--test/msan/stack-origin.cc31
-rw-r--r--test/msan/stack-origin2.cc41
-rw-r--r--test/msan/strerror_r-non-gnu.c18
-rw-r--r--test/msan/strlen_of_shadow.cc24
-rw-r--r--test/msan/strxfrm.cc15
-rw-r--r--test/msan/sync_lock_set_and_test.cc7
-rw-r--r--test/msan/textdomain.cc12
-rw-r--r--test/msan/times.cc20
-rw-r--r--test/msan/tls_reuse.cc26
-rw-r--r--test/msan/tsearch.cc36
-rw-r--r--test/msan/tzset.cc16
-rw-r--r--test/msan/unaligned_read_origin.cc16
-rw-r--r--test/msan/unpoison_string.cc16
-rw-r--r--test/msan/use-after-free.cc34
-rw-r--r--test/msan/vector_cvt.cc23
-rw-r--r--test/msan/vector_select.cc13
101 files changed, 3309 insertions, 0 deletions
diff --git a/test/msan/CMakeLists.txt b/test/msan/CMakeLists.txt
new file mode 100644
index 0000000000000..08786ee777ebd
--- /dev/null
+++ b/test/msan/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(MSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+
+set(MSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND MSAN_TEST_DEPS msan)
+endif()
+
+if(COMPILER_RT_INCLUDE_TESTS AND COMPILER_RT_HAS_LIBCXX_SOURCES)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg)
+ list(APPEND MSAN_TEST_DEPS MsanUnitTests)
+endif()
+
+add_lit_testsuite(check-msan "Running the MemorySanitizer tests"
+ ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${MSAN_TEST_DEPS}
+ )
+set_target_properties(check-msan PROPERTIES FOLDER "MSan tests")
diff --git a/test/msan/Linux/getresid.cc b/test/msan/Linux/getresid.cc
new file mode 100644
index 0000000000000..385351dfdcde8
--- /dev/null
+++ b/test/msan/Linux/getresid.cc
@@ -0,0 +1,25 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1
+
+#include <assert.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char *argv[]) {
+ uid_t uids[6];
+ assert(0 == __msan_test_shadow(uids, 6 * sizeof(uid_t)));
+ assert(0 == getresuid(&uids[0], &uids[2], &uids[4]));
+ for (int i = 0; i < 3; i++)
+ assert(sizeof(uid_t) ==
+ __msan_test_shadow(uids + 2 * i, 2 * sizeof(uid_t)));
+
+ gid_t gids[6];
+ assert(0 == __msan_test_shadow(gids, 6 * sizeof(gid_t)));
+ assert(0 == getresgid(&gids[0], &gids[2], &gids[4]));
+ for (int i = 0; i < 3; i++)
+ assert(sizeof(gid_t) ==
+ __msan_test_shadow(gids + 2 * i, 2 * sizeof(gid_t)));
+ return 0;
+}
diff --git a/test/msan/Linux/glob.cc b/test/msan/Linux/glob.cc
new file mode 100644
index 0000000000000..8604e4d76265b
--- /dev/null
+++ b/test/msan/Linux/glob.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*a");
+
+ glob_t globbuf;
+ int res = glob(buf, 0, 0, &globbuf);
+
+ printf("%d %s\n", errno, strerror(errno));
+ assert(res == 0);
+ assert(globbuf.gl_pathc == 2);
+ printf("%zu\n", strlen(globbuf.gl_pathv[0]));
+ printf("%zu\n", strlen(globbuf.gl_pathv[1]));
+ printf("PASS\n");
+ // CHECK: PASS
+ return 0;
+}
diff --git a/test/msan/Linux/glob_altdirfunc.cc b/test/msan/Linux/glob_altdirfunc.cc
new file mode 100644
index 0000000000000..2c02e735e05e4
--- /dev/null
+++ b/test/msan/Linux/glob_altdirfunc.cc
@@ -0,0 +1,78 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+static void my_gl_closedir(void *dir) {
+ if (!dir)
+ exit(1);
+ closedir((DIR *)dir);
+}
+
+static struct dirent *my_gl_readdir(void *dir) {
+ if (!dir)
+ exit(1);
+ struct dirent *d = readdir((DIR *)dir);
+ if (d) __msan_poison(d, d->d_reclen); // hehe
+ return d;
+}
+
+static void *my_gl_opendir(const char *s) {
+ assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1);
+ return opendir(s);
+}
+
+static int my_gl_lstat(const char *s, struct stat *st) {
+ assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1);
+ if (!st)
+ exit(1);
+ return lstat(s, st);
+}
+
+static int my_gl_stat(const char *s, struct stat *st) {
+ assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1);
+ if (!st)
+ exit(1);
+ return lstat(s, st);
+}
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*a");
+
+ glob_t globbuf;
+ globbuf.gl_closedir = my_gl_closedir;
+ globbuf.gl_readdir = my_gl_readdir;
+ globbuf.gl_opendir = my_gl_opendir;
+ globbuf.gl_lstat = my_gl_lstat;
+ globbuf.gl_stat = my_gl_stat;
+ for (int i = 0; i < 10000; ++i) {
+ int res = glob(buf, GLOB_ALTDIRFUNC | GLOB_MARK, 0, &globbuf);
+ assert(res == 0);
+ printf("%d %s\n", errno, strerror(errno));
+ assert(globbuf.gl_pathc == 2);
+ printf("%zu\n", strlen(globbuf.gl_pathv[0]));
+ printf("%zu\n", strlen(globbuf.gl_pathv[1]));
+ __msan_poison(globbuf.gl_pathv[0], strlen(globbuf.gl_pathv[0]) + 1);
+ __msan_poison(globbuf.gl_pathv[1], strlen(globbuf.gl_pathv[1]) + 1);
+ globfree(&globbuf);
+ }
+
+ printf("PASS\n");
+ // CHECK: PASS
+ return 0;
+}
diff --git a/test/msan/Linux/glob_nomatch.cc b/test/msan/Linux/glob_nomatch.cc
new file mode 100644
index 0000000000000..bc35c30d6d07f
--- /dev/null
+++ b/test/msan/Linux/glob_nomatch.cc
@@ -0,0 +1,21 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*c");
+
+ glob_t globbuf;
+ int res = glob(buf, 0, 0, &globbuf);
+ assert(res == GLOB_NOMATCH);
+ assert(globbuf.gl_pathc == 0);
+ if (globbuf.gl_pathv == 0)
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/Linux/glob_test_root/aa b/test/msan/Linux/glob_test_root/aa
new file mode 100644
index 0000000000000..e69de29bb2d1d
--- /dev/null
+++ b/test/msan/Linux/glob_test_root/aa
diff --git a/test/msan/Linux/glob_test_root/ab b/test/msan/Linux/glob_test_root/ab
new file mode 100644
index 0000000000000..e69de29bb2d1d
--- /dev/null
+++ b/test/msan/Linux/glob_test_root/ab
diff --git a/test/msan/Linux/glob_test_root/ba b/test/msan/Linux/glob_test_root/ba
new file mode 100644
index 0000000000000..e69de29bb2d1d
--- /dev/null
+++ b/test/msan/Linux/glob_test_root/ba
diff --git a/test/msan/Linux/lit.local.cfg b/test/msan/Linux/lit.local.cfg
new file mode 100644
index 0000000000000..57271b8078a49
--- /dev/null
+++ b/test/msan/Linux/lit.local.cfg
@@ -0,0 +1,9 @@
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+if root.host_os not in ['Linux']:
+ config.unsupported = True
diff --git a/test/msan/Linux/sunrpc.cc b/test/msan/Linux/sunrpc.cc
new file mode 100644
index 0000000000000..78645a7dcbf2a
--- /dev/null
+++ b/test/msan/Linux/sunrpc.cc
@@ -0,0 +1,40 @@
+// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=int -DFN=xdr_int %s -o %t && \
+// RUN: %run %t 2>&1
+// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=int -DFN=xdr_int -DUNINIT=1 %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=double -DFN=xdr_double %s -o %t && \
+// RUN: %run %t 2>&1
+// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=double -DFN=xdr_double -DUNINIT=1 %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=u_quad_t -DFN=xdr_u_longlong_t %s -o %t && \
+// RUN: %run %t 2>&1
+// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=u_quad_t -DFN=xdr_u_longlong_t -DUNINIT=1 %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <rpc/xdr.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char *argv[]) {
+ XDR xdrs;
+ char buf[100];
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE);
+ TYPE x;
+#ifndef UNINIT
+ x = 42;
+#endif
+ bool_t res = FN(&xdrs, &x);
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{in main.*sunrpc.cc:}}[[@LINE-2]]
+ assert(res == TRUE);
+ xdr_destroy(&xdrs);
+
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_DECODE);
+ TYPE y;
+ res = FN(&xdrs, &y);
+ assert(res == TRUE);
+ assert(__msan_test_shadow(&y, sizeof(y)) == -1);
+ xdr_destroy(&xdrs);
+ return 0;
+}
diff --git a/test/msan/Linux/sunrpc_bytes.cc b/test/msan/Linux/sunrpc_bytes.cc
new file mode 100644
index 0000000000000..f0c35746f34dd
--- /dev/null
+++ b/test/msan/Linux/sunrpc_bytes.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx_msan -m64 -g -O0 %s -o %t && \
+// RUN: %run %t 2>&1
+// RUN: %clangxx_msan -m64 -g -O0 -DUNINIT=1 %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <string.h>
+#include <rpc/xdr.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char *argv[]) {
+ XDR xdrs;
+ char buf[100];
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE);
+ char s[20];
+#ifndef UNINIT
+ strcpy(s, "hello");
+#endif
+ char *sp = s;
+ unsigned sz = 6;
+ bool_t res = xdr_bytes(&xdrs, &sp, &sz, sizeof(s));
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{in main.*sunrpc_bytes.cc:}}[[@LINE-2]]
+ assert(res == TRUE);
+ xdr_destroy(&xdrs);
+
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_DECODE);
+ char s2[20];
+ char *sp2 = s2;
+ unsigned sz2;
+ res = xdr_bytes(&xdrs, &sp2, &sz2, sizeof(s2));
+ assert(res == TRUE);
+ assert(sz == sz2);
+ assert(strcmp(s, s2) == 0);
+ xdr_destroy(&xdrs);
+ return 0;
+}
diff --git a/test/msan/Linux/sunrpc_string.cc b/test/msan/Linux/sunrpc_string.cc
new file mode 100644
index 0000000000000..3f44a96d114cb
--- /dev/null
+++ b/test/msan/Linux/sunrpc_string.cc
@@ -0,0 +1,35 @@
+// RUN: %clangxx_msan -m64 -g -O0 %s -o %t && \
+// RUN: %run %t 2>&1
+// RUN: %clangxx_msan -m64 -g -O0 -DUNINIT=1 %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <string.h>
+#include <rpc/xdr.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char *argv[]) {
+ XDR xdrs;
+ char buf[100];
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE);
+ char s[20];
+#ifndef UNINIT
+ strcpy(s, "hello");
+#endif
+ char *sp = s;
+ bool_t res = xdr_string(&xdrs, &sp, sizeof(s));
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{in main.*sunrpc_string.cc:}}[[@LINE-2]]
+ assert(res == TRUE);
+ xdr_destroy(&xdrs);
+
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_DECODE);
+ char s2[20];
+ char *sp2 = s2;
+ res = xdr_string(&xdrs, &sp2, sizeof(s2));
+ assert(res == TRUE);
+ assert(strcmp(s, s2) == 0);
+ xdr_destroy(&xdrs);
+ return 0;
+}
diff --git a/test/msan/Linux/syscalls.cc b/test/msan/Linux/syscalls.cc
new file mode 100644
index 0000000000000..4dd97e7451480
--- /dev/null
+++ b/test/msan/Linux/syscalls.cc
@@ -0,0 +1,115 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t 2>&1
+
+#include <assert.h>
+#include <errno.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <linux/aio_abi.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <sanitizer/linux_syscall_hooks.h>
+#include <sanitizer/msan_interface.h>
+
+/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general
+ sanity of their behaviour. */
+
+int main(int argc, char *argv[]) {
+ char buf[1000];
+ const int kTen = 10;
+ const int kFortyTwo = 42;
+ memset(buf, 0, sizeof(buf));
+ __msan_unpoison(buf, sizeof(buf));
+ __sanitizer_syscall_pre_recvmsg(0, buf, 0);
+ __sanitizer_syscall_pre_rt_sigpending(buf, kTen);
+ __sanitizer_syscall_pre_getdents(0, buf, kTen);
+ __sanitizer_syscall_pre_getdents64(0, buf, kTen);
+
+ __msan_unpoison(buf, sizeof(buf));
+ __sanitizer_syscall_post_recvmsg(0, 0, buf, 0);
+ __sanitizer_syscall_post_rt_sigpending(-1, buf, kTen);
+ __sanitizer_syscall_post_getdents(0, 0, buf, kTen);
+ __sanitizer_syscall_post_getdents64(0, 0, buf, kTen);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == -1);
+
+ __msan_unpoison(buf, sizeof(buf));
+ __sanitizer_syscall_post_recvmsg(kTen, 0, buf, 0);
+
+ // Tell the kernel that the output struct size is 10 bytes, verify that those
+ // bytes are unpoisoned, and the next byte is not.
+ __msan_poison(buf, kTen + 1);
+ __sanitizer_syscall_post_rt_sigpending(0, buf, kTen);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
+
+ __msan_poison(buf, kTen + 1);
+ __sanitizer_syscall_post_getdents(kTen, 0, buf, kTen);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
+
+ __msan_poison(buf, kTen + 1);
+ __sanitizer_syscall_post_getdents64(kTen, 0, buf, kTen);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
+
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_clock_getres(0, 0, buf);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(long) * 2);
+
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_clock_gettime(0, 0, buf);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(long) * 2);
+
+ // Failed syscall does not write to the buffer.
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_clock_gettime(-1, 0, buf);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == 0);
+
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_read(5, 42, buf, 10);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == 5);
+
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_newfstatat(0, 5, "/path/to/file", buf, 0);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(struct stat));
+
+ __msan_poison(buf, sizeof(buf));
+ int prio = 0;
+ __sanitizer_syscall_post_mq_timedreceive(kFortyTwo, 5, buf, sizeof(buf), &prio, 0);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == kFortyTwo);
+ assert(__msan_test_shadow(&prio, sizeof(prio)) == -1);
+
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_ptrace(0, PTRACE_PEEKUSER, kFortyTwo, 0xABCD, buf);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(void *));
+
+ __msan_poison(buf, sizeof(buf));
+ struct iocb iocb[3];
+ struct iocb *iocbp[3] = { &iocb[0], &iocb[1], &iocb[2] };
+ memset(iocb, 0, sizeof(iocb));
+ iocb[0].aio_lio_opcode = IOCB_CMD_PREAD;
+ iocb[0].aio_buf = (__u64)buf;
+ iocb[0].aio_nbytes = 10;
+ iocb[1].aio_lio_opcode = IOCB_CMD_PREAD;
+ iocb[1].aio_buf = (__u64)(&buf[20]);
+ iocb[1].aio_nbytes = 15;
+ struct iovec vec[2] = { {&buf[40], 3}, {&buf[50], 20} };
+ iocb[2].aio_lio_opcode = IOCB_CMD_PREADV;
+ iocb[2].aio_buf = (__u64)(&vec);
+ iocb[2].aio_nbytes = 2;
+ __sanitizer_syscall_pre_io_submit(0, 3, &iocbp);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == 10);
+ assert(__msan_test_shadow(buf + 20, sizeof(buf) - 20) == 15);
+ assert(__msan_test_shadow(buf + 40, sizeof(buf) - 40) == 3);
+ assert(__msan_test_shadow(buf + 50, sizeof(buf) - 50) == 20);
+
+ __msan_poison(buf, sizeof(buf));
+ char *p = buf;
+ __msan_poison(&p, sizeof(p));
+ __sanitizer_syscall_post_io_setup(0, 1, &p);
+ assert(__msan_test_shadow(&p, sizeof(p)) == -1);
+ assert(__msan_test_shadow(buf, sizeof(buf)) >= 32);
+
+ return 0;
+}
diff --git a/test/msan/Linux/tcgetattr.cc b/test/msan/Linux/tcgetattr.cc
new file mode 100644
index 0000000000000..e1425b84f5504
--- /dev/null
+++ b/test/msan/Linux/tcgetattr.cc
@@ -0,0 +1,21 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[]) {
+ int fd = getpt();
+ assert(fd >= 0);
+
+ struct termios t;
+ int res = tcgetattr(fd, &t);
+ assert(!res);
+
+ if (t.c_iflag == 0)
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/Linux/xattr.cc b/test/msan/Linux/xattr.cc
new file mode 100644
index 0000000000000..1beba117d574b
--- /dev/null
+++ b/test/msan/Linux/xattr.cc
@@ -0,0 +1,145 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1
+
+#include <argz.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sanitizer/msan_interface.h>
+
+// Do not depend on libattr headers.
+#ifndef ENOATTR
+#define ENOATTR ENODATA
+#endif
+
+extern "C" {
+ssize_t listxattr(const char *path, char *list, size_t size);
+ssize_t llistxattr(const char *path, char *list, size_t size);
+ssize_t flistxattr(int fd, char *list, size_t size);
+ssize_t getxattr(const char *path, const char *name, void *value, size_t size);
+ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size);
+ssize_t fgetxattr(int fd, const char *name, void *value, size_t size);
+}
+
+char g_path[1024];
+int g_fd;
+
+// Life before closures...
+ssize_t listxattr_wrapper(char *buf, size_t size) {
+ return listxattr(g_path, buf, size);
+}
+
+ssize_t llistxattr_wrapper(char *buf, size_t size) {
+ return llistxattr(g_path, buf, size);
+}
+
+ssize_t flistxattr_wrapper(char *buf, size_t size) {
+ return flistxattr(g_fd, buf, size);
+}
+
+ssize_t getxattr_wrapper(const char *name, char *buf, size_t size) {
+ return getxattr(g_path, name, buf, size);
+}
+
+ssize_t lgetxattr_wrapper(const char *name, char *buf, size_t size) {
+ return lgetxattr(g_path, name, buf, size);
+}
+
+ssize_t fgetxattr_wrapper(const char *name, char *buf, size_t size) {
+ return fgetxattr(g_fd, name, buf, size);
+}
+
+size_t test_list(ssize_t fun(char*, size_t), char **buf) {
+ int buf_size = 1024;
+ while (true) {
+ *buf = (char *)malloc(buf_size);
+ assert(__msan_test_shadow(*buf, buf_size) != -1);
+ ssize_t res = fun(*buf, buf_size);
+ if (res >= 0) {
+ assert(__msan_test_shadow(*buf, buf_size) == res);
+ return res;
+ }
+ if (errno == ENOTSUP) {
+ printf("Extended attributes are disabled. *xattr test is a no-op.\n");
+ exit(0);
+ }
+ assert(errno == ERANGE);
+ free(*buf);
+ buf_size *= 2;
+ }
+}
+
+// True means success. False means result inconclusive because we don't have
+// access to this attribute.
+bool test_get_single_attr(ssize_t fun(const char *, char *, size_t),
+ const char *attr_name) {
+ char *buf;
+ int buf_size = 1024;
+ while (true) {
+ buf = (char *)malloc(buf_size);
+ assert(__msan_test_shadow(buf, buf_size) != -1);
+ ssize_t res = fun(attr_name, buf, buf_size);
+ if (res >= 0) {
+ assert(__msan_test_shadow(buf, buf_size) == res);
+ free(buf);
+ return true;
+ }
+ if (errno == ENOTSUP) {
+ printf("Extended attributes are disabled. *xattr test is a no-op.\n");
+ exit(0);
+ }
+ if (errno == ENOATTR)
+ return false;
+ assert(errno == ERANGE);
+ free(buf);
+ buf_size *= 2;
+ }
+}
+
+void test_get(ssize_t fun(const char *, char *, size_t), const char *attr_list,
+ size_t attr_list_size) {
+ // Try every attribute, until we see one we can access. Attribute names are
+ // null-separated strings in attr_list.
+ size_t attr_list_len = argz_count(attr_list, attr_list_size);
+ size_t argv_size = (attr_list_len + 1) * sizeof(char *);
+ char **attrs = (char **)malloc(argv_size);
+ argz_extract(attr_list, attr_list_size, attrs);
+ // TODO(smatveev): we need proper argz_* interceptors
+ __msan_unpoison(attrs, argv_size);
+ for (size_t i = 0; (i < attr_list_len) && attrs[i]; i++) {
+ if (test_get_single_attr(fun, attrs[i]))
+ return;
+ }
+ printf("*xattr test could not access any attributes.\n");
+}
+
+// TODO: set some attributes before trying to retrieve them with *getxattr.
+// Currently the list is empty, so *getxattr is not tested.
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ snprintf(g_path, sizeof(g_path), "%s/%s", argv[1], "xattr_test_root/a");
+
+ g_fd = open(g_path, O_RDONLY);
+ assert(g_fd);
+
+ char *attr_list;
+ size_t attr_list_size;
+ attr_list_size = test_list(listxattr_wrapper, &attr_list);
+ free(attr_list);
+ attr_list_size = test_list(llistxattr_wrapper, &attr_list);
+ free(attr_list);
+ attr_list_size = test_list(flistxattr_wrapper, &attr_list);
+
+ test_get(getxattr_wrapper, attr_list, attr_list_size);
+ test_get(lgetxattr_wrapper, attr_list, attr_list_size);
+ test_get(fgetxattr_wrapper, attr_list, attr_list_size);
+
+ free(attr_list);
+ return 0;
+}
diff --git a/test/msan/Linux/xattr_test_root/a b/test/msan/Linux/xattr_test_root/a
new file mode 100644
index 0000000000000..e69de29bb2d1d
--- /dev/null
+++ b/test/msan/Linux/xattr_test_root/a
diff --git a/test/msan/Unit/lit.site.cfg.in b/test/msan/Unit/lit.site.cfg.in
new file mode 100644
index 0000000000000..dc0e9613d59ec
--- /dev/null
+++ b/test/msan/Unit/lit.site.cfg.in
@@ -0,0 +1,14 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Load common config for all compiler-rt unit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured")
+
+# Setup config name.
+config.name = 'MemorySanitizer-Unit'
+
+# Setup test source and exec root. For unit tests, we define
+# it as build directory with MSan unit tests.
+# FIXME: Don't use hardcoded path to MSan unit tests.
+config.test_exec_root = "@COMPILER_RT_BINARY_DIR@/lib/msan/tests"
+config.test_source_root = config.test_exec_root
diff --git a/test/msan/allocator_returns_null.cc b/test/msan/allocator_returns_null.cc
new file mode 100644
index 0000000000000..f4ea51d588726
--- /dev/null
+++ b/test/msan/allocator_returns_null.cc
@@ -0,0 +1,81 @@
+// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
+// By default (allocator_may_return_null=0) the process should crash.
+// With allocator_may_return_null=1 the allocator should return 0.
+//
+// RUN: %clangxx_msan -O0 %s -o %t
+// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits>
+int main(int argc, char **argv) {
+ volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
+ assert(argc == 2);
+ char *x = 0;
+ if (!strcmp(argv[1], "malloc")) {
+ fprintf(stderr, "malloc:\n");
+ x = (char*)malloc(size);
+ }
+ if (!strcmp(argv[1], "calloc")) {
+ fprintf(stderr, "calloc:\n");
+ x = (char*)calloc(size / 4, 4);
+ }
+
+ if (!strcmp(argv[1], "calloc-overflow")) {
+ fprintf(stderr, "calloc-overflow:\n");
+ volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
+ size_t kArraySize = 4096;
+ volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
+ x = (char*)calloc(kArraySize, kArraySize2);
+ }
+
+ if (!strcmp(argv[1], "realloc")) {
+ fprintf(stderr, "realloc:\n");
+ x = (char*)realloc(0, size);
+ }
+ if (!strcmp(argv[1], "realloc-after-malloc")) {
+ fprintf(stderr, "realloc-after-malloc:\n");
+ char *t = (char*)malloc(100);
+ *t = 42;
+ x = (char*)realloc(t, size);
+ assert(*t == 42);
+ }
+ // The NULL pointer is printed differently on different systems, while (long)0
+ // is always the same.
+ fprintf(stderr, "x: %lx\n", (long)x);
+ return x != 0;
+}
+// CHECK-mCRASH: malloc:
+// CHECK-mCRASH: MemorySanitizer's allocator is terminating the process
+// CHECK-cCRASH: calloc:
+// CHECK-cCRASH: MemorySanitizer's allocator is terminating the process
+// CHECK-coCRASH: calloc-overflow:
+// CHECK-coCRASH: MemorySanitizer's allocator is terminating the process
+// CHECK-rCRASH: realloc:
+// CHECK-rCRASH: MemorySanitizer's allocator is terminating the process
+// CHECK-mrCRASH: realloc-after-malloc:
+// CHECK-mrCRASH: MemorySanitizer's allocator is terminating the process
+
+// CHECK-mNULL: malloc:
+// CHECK-mNULL: x: 0
+// CHECK-cNULL: calloc:
+// CHECK-cNULL: x: 0
+// CHECK-coNULL: calloc-overflow:
+// CHECK-coNULL: x: 0
+// CHECK-rNULL: realloc:
+// CHECK-rNULL: x: 0
+// CHECK-mrNULL: realloc-after-malloc:
+// CHECK-mrNULL: x: 0
diff --git a/test/msan/backtrace.cc b/test/msan/backtrace.cc
new file mode 100644
index 0000000000000..473e0ae8f88b7
--- /dev/null
+++ b/test/msan/backtrace.cc
@@ -0,0 +1,26 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <assert.h>
+#include <execinfo.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+__attribute__((noinline))
+void f() {
+ void *buf[10];
+ int sz = backtrace(buf, sizeof(buf) / sizeof(*buf));
+ assert(sz > 0);
+ for (int i = 0; i < sz; ++i)
+ if (!buf[i])
+ exit(1);
+ char **s = backtrace_symbols(buf, sz);
+ assert(s > 0);
+ for (int i = 0; i < sz; ++i)
+ printf("%d\n", strlen(s[i]));
+}
+
+int main(void) {
+ f();
+ return 0;
+}
diff --git a/test/msan/c-strdup.c b/test/msan/c-strdup.c
new file mode 100644
index 0000000000000..059300e4205ab
--- /dev/null
+++ b/test/msan/c-strdup.c
@@ -0,0 +1,17 @@
+// RUN: %clang_msan -m64 -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clang_msan -m64 -O1 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clang_msan -m64 -O2 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clang_msan -m64 -O3 %s -o %t && %run %t >%t.out 2>&1
+
+// Test that strdup in C programs is intercepted.
+// GLibC headers translate strdup to __strdup at -O1 and higher.
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+ char buf[] = "abc";
+ char *p = strdup(buf);
+ if (*p)
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/chained_origin.cc b/test/msan/chained_origin.cc
new file mode 100644
index 0000000000000..336bbd852cb33
--- /dev/null
+++ b/test/msan/chained_origin.cc
@@ -0,0 +1,66 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-STACK < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DHEAP=1 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-HEAP < %t.out
+
+
+// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-STACK < %t.out
+
+// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DHEAP=1 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-HEAP < %t.out
+
+
+#include <stdio.h>
+
+volatile int x, y;
+
+__attribute__((noinline))
+void fn_g(int a) {
+ x = a;
+}
+
+__attribute__((noinline))
+void fn_f(int a) {
+ fn_g(a);
+}
+
+__attribute__((noinline))
+void fn_h() {
+ y = x;
+}
+
+int main(int argc, char *argv[]) {
+#ifdef HEAP
+ int * volatile zz = new int;
+ int z = *zz;
+#else
+ int volatile z;
+#endif
+ fn_f(z);
+ fn_h();
+ return y;
+}
+
+// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK: {{#0 .* in main.*chained_origin.cc:47}}
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: {{#0 .* in fn_h.*chained_origin.cc:35}}
+// CHECK: {{#1 .* in main.*chained_origin.cc:46}}
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: {{#0 .* in fn_g.*chained_origin.cc:25}}
+// CHECK: {{#1 .* in fn_f.*chained_origin.cc:30}}
+// CHECK: {{#2 .* in main.*chained_origin.cc:45}}
+
+// CHECK-STACK: Uninitialized value was created by an allocation of 'z' in the stack frame of function 'main'
+// CHECK-STACK: {{#0 .* in main.*chained_origin.cc:38}}
+
+// CHECK-HEAP: Uninitialized value was created by a heap allocation
+// CHECK-HEAP: {{#1 .* in main.*chained_origin.cc:40}}
diff --git a/test/msan/chained_origin_empty_stack.cc b/test/msan/chained_origin_empty_stack.cc
new file mode 100644
index 0000000000000..36727e3d7aa74
--- /dev/null
+++ b/test/msan/chained_origin_empty_stack.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \
+// RUN: MSAN_OPTIONS=store_context_size=1 not %run %t 2>&1 | FileCheck %s
+
+// Test that stack trace for the intermediate store is not empty.
+
+// CHECK: MemorySanitizer: use-of-uninitialized-value
+// CHECK: #0 {{.*}} in main
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: #0 {{.*}} in fn_g
+// CHECK-NOT: #1
+
+// CHECK: Uninitialized value was created by an allocation of 'z' in the stack frame of function 'main'
+// CHECK: #0 {{.*}} in main
+
+#include <stdio.h>
+
+volatile int x;
+
+__attribute__((noinline))
+void fn_g(int a) {
+ x = a;
+}
+
+__attribute__((noinline))
+void fn_f(int a) {
+ fn_g(a);
+}
+
+int main(int argc, char *argv[]) {
+ int volatile z;
+ fn_f(z);
+ return x;
+}
diff --git a/test/msan/chained_origin_limits.cc b/test/msan/chained_origin_limits.cc
new file mode 100644
index 0000000000000..0cc57f32a6ac1
--- /dev/null
+++ b/test/msan/chained_origin_limits.cc
@@ -0,0 +1,178 @@
+// This test program creates a very large number of unique histories.
+
+// Heap origin.
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t
+
+// RUN: MSAN_OPTIONS=origin_history_size=7 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=2 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK2 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+// Stack origin.
+// RUN: %clangxx_msan -DSTACK -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t
+
+// RUN: MSAN_OPTIONS=origin_history_size=7 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=2 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK2 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+
+// Heap origin, with calls.
+// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t
+
+// RUN: MSAN_OPTIONS=origin_history_size=7 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=2 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK2 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+
+// Stack origin, with calls.
+// RUN: %clangxx_msan -DSTACK -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t
+
+// RUN: MSAN_OPTIONS=origin_history_size=7 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=2 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK2 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static char *buf, *cur, *end;
+void init() {
+ buf = new char[1000];
+#ifdef STACK
+ char stackbuf[1000];
+ char *volatile p = stackbuf;
+ memcpy(buf, p, 1000);
+#endif
+ cur = buf;
+ end = buf + 1000;
+}
+
+void line_flush() {
+ char *p;
+ for (p = cur - 1; p >= buf; --p)
+ if (*p == '\n')
+ break;
+ if (p >= buf) {
+ size_t write_sz = p - buf + 1;
+ // write(2, buf, write_sz);
+ memmove(buf, p + 1, end - p - 1);
+ cur -= write_sz;
+ }
+}
+
+void buffered_write(const char *p, size_t sz) {
+ while (sz > 0) {
+ size_t copy_sz = end - cur;
+ if (sz < copy_sz) copy_sz = sz;
+ memcpy(cur, p, copy_sz);
+ cur += copy_sz;
+ sz -= copy_sz;
+ line_flush();
+ }
+}
+
+void fn1() {
+ buffered_write("a\n", 2);
+}
+
+void fn2() {
+ buffered_write("a\n", 2);
+}
+
+void fn3() {
+ buffered_write("a\n", 2);
+}
+
+int main(void) {
+ init();
+ for (int i = 0; i < 2000; ++i) {
+ fn1();
+ fn2();
+ fn3();
+ }
+ return buf[50];
+}
+
+// CHECK7: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was stored to memory at
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was stored to memory at
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was stored to memory at
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was stored to memory at
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was stored to memory at
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was stored to memory at
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was created
+
+// CHECK2: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK2-NOT: Uninitialized value was stored to memory at
+// CHECK2: Uninitialized value was stored to memory at
+// CHECK2-NOT: Uninitialized value was stored to memory at
+// CHECK2: Uninitialized value was created
+
+// CHECK-PER-STACK: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK-PER-STACK: Uninitialized value was stored to memory at
+// CHECK-PER-STACK: in fn3
+// CHECK-PER-STACK: Uninitialized value was stored to memory at
+// CHECK-PER-STACK: in fn2
+// CHECK-PER-STACK: Uninitialized value was stored to memory at
+// CHECK-PER-STACK: in fn1
+// CHECK-PER-STACK: Uninitialized value was created
+
+// CHECK-UNLIMITED: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was created
diff --git a/test/msan/chained_origin_memcpy.cc b/test/msan/chained_origin_memcpy.cc
new file mode 100644
index 0000000000000..f4c2f7fcac876
--- /dev/null
+++ b/test/msan/chained_origin_memcpy.cc
@@ -0,0 +1,61 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -DOFFSET=0 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DOFFSET=10 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 < %t.out
+
+
+// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -DOFFSET=0 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 < %t.out
+
+// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DOFFSET=10 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 < %t.out
+
+
+#include <stdio.h>
+#include <string.h>
+
+int xx[10000];
+int yy[10000];
+volatile int idx = 30;
+
+__attribute__((noinline))
+void fn_g(int a, int b) {
+ xx[idx] = a; xx[idx + 10] = b;
+}
+
+__attribute__((noinline))
+void fn_f(int a, int b) {
+ fn_g(a, b);
+}
+
+__attribute__((noinline))
+void fn_h() {
+ memcpy(&yy, &xx, sizeof(xx));
+}
+
+int main(int argc, char *argv[]) {
+ int volatile z1;
+ int volatile z2;
+ fn_f(z1, z2);
+ fn_h();
+ return yy[idx + OFFSET];
+}
+
+// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK: {{#0 .* in main .*chained_origin_memcpy.cc:46}}
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: {{#1 .* in fn_h.*chained_origin_memcpy.cc:38}}
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: {{#0 .* in fn_g.*chained_origin_memcpy.cc:28}}
+// CHECK: {{#1 .* in fn_f.*chained_origin_memcpy.cc:33}}
+
+// CHECK-Z1: Uninitialized value was created by an allocation of 'z1' in the stack frame of function 'main'
+// CHECK-Z2: Uninitialized value was created by an allocation of 'z2' in the stack frame of function 'main'
+// CHECK: {{#0 .* in main.*chained_origin_memcpy.cc:41}}
diff --git a/test/msan/chained_origin_with_signals.cc b/test/msan/chained_origin_with_signals.cc
new file mode 100644
index 0000000000000..2841e34a1f1da
--- /dev/null
+++ b/test/msan/chained_origin_with_signals.cc
@@ -0,0 +1,36 @@
+// Check that stores in signal handlers are not recorded in origin history.
+// This is, in fact, undesired behavior caused by our chained origins
+// implementation being not async-signal-safe.
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <signal.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+volatile int x, y;
+
+void SignalHandler(int signo) {
+ y = x;
+}
+
+int main(int argc, char *argv[]) {
+ int volatile z;
+ x = z;
+
+ signal(SIGHUP, SignalHandler);
+ kill(getpid(), SIGHUP);
+ signal(SIGHUP, SIG_DFL);
+
+ return y;
+}
+
+// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK-NOT: in SignalHandler
diff --git a/test/msan/check_mem_is_initialized.cc b/test/msan/check_mem_is_initialized.cc
new file mode 100644
index 0000000000000..7d2328810d902
--- /dev/null
+++ b/test/msan/check_mem_is_initialized.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+
+#include <sanitizer/msan_interface.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+ int *volatile p = (int *)malloc(sizeof(int));
+
+ __msan_check_mem_is_initialized(p, sizeof(*p));
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*check_mem_is_initialized.cc:}}[[@LINE-2]]
+
+ // CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+ // CHECK-ORIGINS: {{#0 0x.* in .*malloc}}
+ // CHECK-ORIGINS: {{#1 0x.* in main .*check_mem_is_initialized.cc:}}[[@LINE-8]]
+ return 0;
+}
diff --git a/test/msan/coverage-levels.cc b/test/msan/coverage-levels.cc
new file mode 100644
index 0000000000000..7c2e143d3ab8a
--- /dev/null
+++ b/test/msan/coverage-levels.cc
@@ -0,0 +1,28 @@
+// Test various levels of coverage
+//
+// RUN: %clangxx_msan -DINIT_VAR=1 -O1 -fsanitize-coverage=1 %s -o %t
+// RUN: mkdir -p %T/coverage-levels
+// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN
+// RUN: %clangxx_msan -O1 -fsanitize-coverage=1 %s -o %t
+// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_WARN
+// RUN: %clangxx_msan -O1 -fsanitize-coverage=2 %s -o %t
+// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 --check-prefix=CHECK_WARN
+// RUN: %clangxx_msan -O1 -fsanitize-coverage=3 %s -o %t
+// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --check-prefix=CHECK_WARN
+//
+volatile int sink;
+int main(int argc, char **argv) {
+ int var;
+#if INIT_VAR
+ var = 0;
+#endif
+ if (argc == 0)
+ sink = 0;
+ return *(volatile int*)&var;
+}
+
+// CHECK_WARN: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK_NOWARN-NOT: ERROR
+// CHECK1: 1 PCs written
+// CHECK2: 2 PCs written
+// CHECK3: 3 PCs written
diff --git a/test/msan/cxa_atexit.cc b/test/msan/cxa_atexit.cc
new file mode 100644
index 0000000000000..0aa36ecee0117
--- /dev/null
+++ b/test/msan/cxa_atexit.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p
+
+// PR17377: C++ module destructors get stale argument shadow.
+
+#include <stdio.h>
+#include <stdlib.h>
+class A {
+public:
+ // This destructor get stale argument shadow left from the call to f().
+ ~A() {
+ if (this)
+ exit(0);
+ }
+};
+
+A a;
+
+__attribute__((noinline))
+void f(long x) {
+}
+
+int main(void) {
+ long x;
+ long * volatile p = &x;
+ // This call poisons TLS shadow for the first function argument.
+ f(*p);
+ return 0;
+}
diff --git a/test/msan/death-callback.cc b/test/msan/death-callback.cc
new file mode 100644
index 0000000000000..6d04883399987
--- /dev/null
+++ b/test/msan/death-callback.cc
@@ -0,0 +1,39 @@
+// RUN: %clangxx_msan -m64 -DERROR %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOCB
+// RUN: %clangxx_msan -m64 -DERROR -DMSANCB_SET %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-CB
+// RUN: %clangxx_msan -m64 -DERROR -DMSANCB_SET -DMSANCB_CLEAR %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOCB
+// RUN: %clangxx_msan -m64 -DMSANCB_SET %s -o %t && %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOCB
+
+#include <sanitizer/msan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void cb(void) {
+ fprintf(stderr, "msan-death-callback\n");
+}
+
+int main(int argc, char **argv) {
+ int *volatile p = (int *)malloc(sizeof(int));
+ *p = 42;
+ free(p);
+
+#ifdef MSANCB_SET
+ __msan_set_death_callback(cb);
+#endif
+
+#ifdef MSANCB_CLEAR
+ __msan_set_death_callback(0);
+#endif
+
+#ifdef ERROR
+ if (*p)
+ exit(0);
+#endif
+ // CHECK-CB: msan-death-callback
+ // CHECK-NOCB-NOT: msan-death-callback
+ fprintf(stderr, "done\n");
+ return 0;
+}
diff --git a/test/msan/default_blacklist.cc b/test/msan/default_blacklist.cc
new file mode 100644
index 0000000000000..32cc02257cb09
--- /dev/null
+++ b/test/msan/default_blacklist.cc
@@ -0,0 +1,3 @@
+// Test that MSan uses the default blacklist from resource directory.
+// RUN: %clangxx_msan -### %s 2>&1 | FileCheck %s
+// CHECK: fsanitize-blacklist={{.*}}msan_blacklist.txt
diff --git a/test/msan/dlerror.cc b/test/msan/dlerror.cc
new file mode 100644
index 0000000000000..2c726d36041ef
--- /dev/null
+++ b/test/msan/dlerror.cc
@@ -0,0 +1,14 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(void) {
+ void *p = dlopen("/bad/file/name", RTLD_NOW);
+ assert(!p);
+ char *s = dlerror();
+ printf("%s, %zu\n", s, strlen(s));
+ return 0;
+}
diff --git a/test/msan/dso-origin.cc b/test/msan/dso-origin.cc
new file mode 100644
index 0000000000000..ba008c00718d1
--- /dev/null
+++ b/test/msan/dso-origin.cc
@@ -0,0 +1,48 @@
+// Build a library with origin tracking and an executable w/o origin tracking.
+// Test that origin tracking is enabled at runtime.
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -DBUILD_SO -fPIC -shared -o %t-so.so
+// RUN: %clangxx_msan -m64 -O0 %s %t-so.so -o %t && not %run %t 2>&1 | FileCheck %s
+
+#ifdef BUILD_SO
+
+#include <stdlib.h>
+
+extern "C" {
+void my_access(int *p) {
+ volatile int tmp;
+ // Force initialize-ness check.
+ if (*p)
+ tmp = 1;
+}
+
+void *my_alloc(unsigned sz) {
+ return malloc(sz);
+}
+} // extern "C"
+
+#else // BUILD_SO
+
+#include <stdlib.h>
+
+extern "C" {
+void my_access(int *p);
+void *my_alloc(unsigned sz);
+}
+
+int main(int argc, char **argv) {
+ int *x = (int *)my_alloc(sizeof(int));
+ my_access(x);
+ delete x;
+
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in my_access .*dso-origin.cc:}}
+ // CHECK: {{#1 0x.* in main .*dso-origin.cc:}}[[@LINE-5]]
+ // CHECK: Uninitialized value was created by a heap allocation
+ // CHECK: {{#0 0x.* in .*malloc}}
+ // CHECK: {{#1 0x.* in my_alloc .*dso-origin.cc:}}
+ // CHECK: {{#2 0x.* in main .*dso-origin.cc:}}[[@LINE-10]]
+ // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*dso-origin.cc:.* my_access}}
+ return 0;
+}
+
+#endif // BUILD_SO
diff --git a/test/msan/dtls_test.c b/test/msan/dtls_test.c
new file mode 100644
index 0000000000000..cb88ede2f0a60
--- /dev/null
+++ b/test/msan/dtls_test.c
@@ -0,0 +1,60 @@
+/* RUN: %clang_msan -g -m64 %s -o %t
+ RUN: %clang_msan -g -m64 %s -DBUILD_SO -fPIC -o %t-so.so -shared
+ RUN: %run %t 2>&1
+
+ Regression test for a bug in msan/glibc integration,
+ see https://sourceware.org/bugzilla/show_bug.cgi?id=16291
+ and https://code.google.com/p/memory-sanitizer/issues/detail?id=44
+*/
+
+#ifndef BUILD_SO
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+typedef long *(* get_t)();
+get_t GetTls;
+void *Thread1(void *unused) {
+ long uninitialized;
+ long *x = GetTls();
+ if (*x)
+ fprintf(stderr, "bar\n");
+ *x = uninitialized;
+ fprintf(stderr, "stack: %p dtls: %p\n", &x, x);
+ return 0;
+}
+
+void *Thread2(void *unused) {
+ long *x = GetTls();
+ fprintf(stderr, "stack: %p dtls: %p\n", &x, x);
+ if (*x)
+ fprintf(stderr, "foo\n"); // False negative here.
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ char path[4096];
+ snprintf(path, sizeof(path), "%s-so.so", argv[0]);
+ int i;
+
+ void *handle = dlopen(path, RTLD_LAZY);
+ if (!handle) fprintf(stderr, "%s\n", dlerror());
+ assert(handle != 0);
+ GetTls = (get_t)dlsym(handle, "GetTls");
+ assert(dlerror() == 0);
+
+ pthread_t t;
+ pthread_create(&t, 0, Thread1, 0);
+ pthread_join(t, 0);
+ pthread_create(&t, 0, Thread2, 0);
+ pthread_join(t, 0);
+ return 0;
+}
+#else // BUILD_SO
+__thread long huge_thread_local_array[1 << 17];
+long *GetTls() {
+ return &huge_thread_local_array[0];
+}
+#endif
diff --git a/test/msan/errno.cc b/test/msan/errno.cc
new file mode 100644
index 0000000000000..8af8eb5ee6f93
--- /dev/null
+++ b/test/msan/errno.cc
@@ -0,0 +1,17 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main()
+{
+ int x;
+ int *volatile p = &x;
+ errno = *p;
+ int res = read(-1, 0, 0);
+ assert(res == -1);
+ if (errno) printf("errno %d\n", errno);
+ return 0;
+}
diff --git a/test/msan/fork.cc b/test/msan/fork.cc
new file mode 100644
index 0000000000000..10de8a9379d8a
--- /dev/null
+++ b/test/msan/fork.cc
@@ -0,0 +1,121 @@
+// Test that chained origins are fork-safe.
+// Run a number of threads that create new chained origins, then fork
+// and verify that origin reads do not deadlock in the child process.
+
+// RUN: %clangxx_msan -std=c++11 -fsanitize-memory-track-origins=2 -g -m64 -O3 %s -o %t
+// RUN: MSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t |& FileCheck %s
+
+// Fun fact: if test output is redirected to a file (as opposed to
+// being piped directly to FileCheck), we may lose some "done"s due to
+// a kernel bug:
+// https://lkml.org/lkml/2014/2/17/324
+
+
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <sanitizer/msan_interface.h>
+
+int done;
+
+void copy_uninit_thread2() {
+ volatile int x;
+ volatile int v;
+ while (true) {
+ v = x;
+ x = v;
+ if (__atomic_load_n(&done, __ATOMIC_RELAXED))
+ return;
+ }
+}
+
+void copy_uninit_thread1(int level) {
+ if (!level)
+ copy_uninit_thread2();
+ else
+ copy_uninit_thread1(level - 1);
+}
+
+void *copy_uninit_thread(void *id) {
+ copy_uninit_thread1((long)id);
+ return 0;
+}
+
+// Run through stackdepot in the child process.
+// If any of the hash table cells are locked, this may deadlock.
+void child() {
+ volatile int x;
+ volatile int v;
+ for (int i = 0; i < 10000; ++i) {
+ v = x;
+ x = v;
+ }
+ write(2, "done\n", 5);
+}
+
+void test() {
+ const int kThreads = 10;
+ pthread_t t[kThreads];
+ for (int i = 0; i < kThreads; ++i)
+ pthread_create(&t[i], NULL, copy_uninit_thread, (void*)(long)i);
+ usleep(100000);
+ pid_t pid = fork();
+ if (pid) {
+ // parent
+ __atomic_store_n(&done, 1, __ATOMIC_RELAXED);
+ pid_t p;
+ while ((p = wait(NULL)) == -1) { }
+ } else {
+ // child
+ child();
+ }
+}
+
+int main() {
+ const int kChildren = 20;
+ for (int i = 0; i < kChildren; ++i) {
+ pid_t pid = fork();
+ if (pid) {
+ // parent
+ } else {
+ test();
+ exit(0);
+ }
+ }
+
+ for (int i = 0; i < kChildren; ++i) {
+ pid_t p;
+ while ((p = wait(NULL)) == -1) { }
+ }
+
+ return 0;
+}
+
+// Expect 20 (== kChildren) "done" messages.
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
diff --git a/test/msan/ftime.cc b/test/msan/ftime.cc
new file mode 100644
index 0000000000000..2d0935d18037a
--- /dev/null
+++ b/test/msan/ftime.cc
@@ -0,0 +1,14 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <sys/timeb.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ struct timeb tb;
+ int res = ftime(&tb);
+ assert(!res);
+ assert(__msan_test_shadow(&tb, sizeof(tb)) == -1);
+ return 0;
+}
diff --git a/test/msan/getaddrinfo-positive.cc b/test/msan/getaddrinfo-positive.cc
new file mode 100644
index 0000000000000..7658cd504dba0
--- /dev/null
+++ b/test/msan/getaddrinfo-positive.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdlib.h>
+
+volatile int z;
+
+int main(void) {
+ struct addrinfo *ai;
+ struct addrinfo hint;
+ int res = getaddrinfo("localhost", NULL, NULL, &ai);
+ if (ai) z = 1; // OK
+ res = getaddrinfo("localhost", NULL, &hint, &ai);
+ // CHECK: Uninitialized bytes in __interceptor_getaddrinfo at offset 0 inside [0x{{.*}}, 48)
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #0 {{.*}} in main {{.*}}getaddrinfo-positive.cc:[[@LINE-3]]
+ return 0;
+}
diff --git a/test/msan/getaddrinfo.cc b/test/msan/getaddrinfo.cc
new file mode 100644
index 0000000000000..abab8bd78f750
--- /dev/null
+++ b/test/msan/getaddrinfo.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdlib.h>
+
+void poison_stack_ahead() {
+ char buf[100000];
+ // With -O0 this poisons a large chunk of stack.
+}
+
+int main(void) {
+ poison_stack_ahead();
+
+ struct addrinfo *ai;
+
+ // This should trigger loading of libnss_dns and friends.
+ // Those libraries are typically uninstrumented.They will call strlen() on a
+ // stack-allocated buffer, which is very likely to be poisoned. Test that we
+ // don't report this as an UMR.
+ int res = getaddrinfo("not-in-etc-hosts", NULL, NULL, &ai);
+ return 0;
+}
diff --git a/test/msan/getc_unlocked.c b/test/msan/getc_unlocked.c
new file mode 100644
index 0000000000000..7df958ad657a5
--- /dev/null
+++ b/test/msan/getc_unlocked.c
@@ -0,0 +1,32 @@
+// RUN: %clangxx_msan -DGETC -m64 -O0 -g -xc++ %s -o %t && %run %t
+// RUN: %clangxx_msan -DGETC -m64 -O3 -g -xc++ %s -o %t && %run %t
+// RUN: %clang_msan -DGETC -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clang_msan -DGETC -m64 -O3 -g %s -o %t && %run %t
+
+// RUN: %clangxx_msan -DGETCHAR -m64 -O0 -g -xc++ %s -o %t && %run %t
+// RUN: %clangxx_msan -DGETCHAR -m64 -O3 -g -xc++ %s -o %t && %run %t
+// RUN: %clang_msan -DGETCHAR -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clang_msan -DGETCHAR -m64 -O3 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main() {
+ FILE *stream = fopen("/dev/zero", "r");
+ flockfile (stream);
+ int c;
+#if defined(GETCHAR)
+ int res = dup2(fileno(stream), 0);
+ assert(res == 0);
+ c = getchar_unlocked();
+#elif defined(GETC)
+ c = getc_unlocked (stream);
+#endif
+ funlockfile (stream);
+ if (c == EOF)
+ return 1;
+ printf("%c\n", (char)c);
+ fclose(stream);
+ return 0;
+}
diff --git a/test/msan/getline.cc b/test/msan/getline.cc
new file mode 100644
index 0000000000000..51e105e0be5c5
--- /dev/null
+++ b/test/msan/getline.cc
@@ -0,0 +1,36 @@
+// RUN: echo "abcde" > %t-testdata
+// RUN: echo "12345" >> %t-testdata
+// RUN: %clangxx_msan -O0 %s -o %t && %run %t %t-testdata
+// RUN: %clangxx_msan -O2 %s -o %t && %run %t %t-testdata
+// RUN: %clang_msan -O0 -xc %s -o %t && %run %t %t-testdata
+// RUN: %clang_msan -O2 -xc %s -o %t && %run %t %t-testdata
+// RUN: %clang_msan -O0 -xc -D_GNU_SOURCE=1 %s -o %t && %run %t %t-testdata
+// RUN: %clang_msan -O2 -xc -D_GNU_SOURCE=1 %s -o %t && %run %t %t-testdata
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ assert(argc == 2);
+ printf("%s\n", argv[1]);
+
+ FILE *fp = fopen(argv[1], "r");
+ assert(fp);
+
+ char *line = 0;
+ size_t len = 0;
+ int n = getline(&line, &len, fp);
+ assert(n == 6);
+ assert(strcmp(line, "abcde\n") == 0);
+
+ n = getline(&line, &len, fp);
+ assert(n == 6);
+ assert(strcmp(line, "12345\n") == 0);
+
+ free(line);
+ fclose(fp);
+
+ return 0;
+}
diff --git a/test/msan/heap-origin.cc b/test/msan/heap-origin.cc
new file mode 100644
index 0000000000000..0920001beed71
--- /dev/null
+++ b/test/msan/heap-origin.cc
@@ -0,0 +1,31 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+
+#include <stdlib.h>
+int main(int argc, char **argv) {
+ char *volatile x = (char*)malloc(5 * sizeof(char));
+ return *x;
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*heap-origin.cc:}}[[@LINE-2]]
+
+ // CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+ // CHECK-ORIGINS: {{#0 0x.* in .*malloc}}
+ // CHECK-ORIGINS: {{#1 0x.* in main .*heap-origin.cc:}}[[@LINE-7]]
+
+ // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*heap-origin.cc:.* main}}
+}
diff --git a/test/msan/iconv.cc b/test/msan/iconv.cc
new file mode 100644
index 0000000000000..ea6958b79b967
--- /dev/null
+++ b/test/msan/iconv.cc
@@ -0,0 +1,48 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -g -DPOSITIVE %s -o %t && not %run %t |& FileCheck %s
+
+#include <assert.h>
+#include <iconv.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+int main(void) {
+ iconv_t cd = iconv_open("ASCII", "ASCII");
+ assert(cd != (iconv_t)-1);
+
+ char inbuf_[100];
+ strcpy(inbuf_, "sample text");
+ char outbuf_[100];
+ char *inbuf = inbuf_;
+ char *outbuf = outbuf_;
+ size_t inbytesleft = strlen(inbuf_);
+ size_t outbytesleft = sizeof(outbuf_);
+
+#ifdef POSITIVE
+ {
+ char u;
+ char *volatile p = &u;
+ inbuf_[5] = *p;
+ }
+#endif
+
+ size_t res;
+ res = iconv(cd, 0, 0, 0, 0);
+ assert(res != (size_t)-1);
+
+ res = iconv(cd, 0, 0, &outbuf, &outbytesleft);
+ assert(res != (size_t)-1);
+
+ res = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #0 {{.*}} in main {{.*}}iconv.cc:[[@LINE-2]]
+ assert(res != (size_t)-1);
+ assert(inbytesleft == 0);
+
+ assert(memcmp(inbuf_, outbuf_, strlen(inbuf_)) == 0);
+
+ iconv_close(cd);
+ return 0;
+}
diff --git a/test/msan/if_indextoname.cc b/test/msan/if_indextoname.cc
new file mode 100644
index 0000000000000..b74aec16c98ae
--- /dev/null
+++ b/test/msan/if_indextoname.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t 2>&1
+
+#include <assert.h>
+#include <errno.h>
+#include <net/if.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char *argv[]) {
+ char ifname[IF_NAMESIZE + 1];
+ assert(0 == __msan_test_shadow(ifname, sizeof(ifname)));
+ if (!if_indextoname(1, ifname)) {
+ assert(errno == ENXIO);
+ printf("No network interfaces found.\n");
+ return 0;
+ }
+ assert(strlen(ifname) + 1 == __msan_test_shadow(ifname, sizeof(ifname)));
+ return 0;
+}
diff --git a/test/msan/ifaddrs.cc b/test/msan/ifaddrs.cc
new file mode 100644
index 0000000000000..6a0db3a5b71fe
--- /dev/null
+++ b/test/msan/ifaddrs.cc
@@ -0,0 +1,50 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1
+
+#include <assert.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <vector>
+
+#include <sanitizer/msan_interface.h>
+
+#define CHECK_AND_PUSH(addr, size) \
+ if (addr) { \
+ assert(-1 == __msan_test_shadow(addr, sizeof(size))); \
+ ranges.push_back(std::make_pair((void *)addr, (size_t)size)); \
+ }
+
+int main(int argc, char *argv[]) {
+ struct ifaddrs *ifas;
+
+ assert(0 == __msan_test_shadow(&ifas, sizeof(ifaddrs *)));
+ int res = getifaddrs(&ifas);
+ if (res == -1) {
+ assert(errno == ENOSYS);
+ printf("getifaddrs() is not implemented\n");
+ return 0;
+ }
+ assert(res == 0);
+ assert(-1 == __msan_test_shadow(&ifas, sizeof(ifaddrs *)));
+
+ std::vector<std::pair<void *, size_t> > ranges;
+ ifaddrs *p = ifas;
+ while (p) {
+ CHECK_AND_PUSH(p, sizeof(ifaddrs));
+ CHECK_AND_PUSH(p->ifa_name, strlen(p->ifa_name) + 1);
+ CHECK_AND_PUSH(p->ifa_addr, sizeof(*p->ifa_addr));
+ CHECK_AND_PUSH(p->ifa_netmask, sizeof(*p->ifa_netmask));
+ CHECK_AND_PUSH(p->ifa_broadaddr, sizeof(*p->ifa_broadaddr));
+ CHECK_AND_PUSH(p->ifa_dstaddr, sizeof(*p->ifa_dstaddr));
+ p = p->ifa_next;
+ }
+
+ freeifaddrs(ifas);
+ for (int i = 0; i < ranges.size(); i++)
+ assert(0 == __msan_test_shadow(ranges[i].first, ranges[i].second));
+ return 0;
+}
diff --git a/test/msan/initgroups.cc b/test/msan/initgroups.cc
new file mode 100644
index 0000000000000..94f6cd8252f38
--- /dev/null
+++ b/test/msan/initgroups.cc
@@ -0,0 +1,11 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <sys/types.h>
+#include <grp.h>
+
+int main(void) {
+ initgroups("root", 0);
+ // The above fails unless you are root. Does not matter, MSan false positive
+ // (which we are testing for) happens anyway.
+ return 0;
+}
diff --git a/test/msan/inline.cc b/test/msan/inline.cc
new file mode 100644
index 0000000000000..b2fa961508569
--- /dev/null
+++ b/test/msan/inline.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_msan -O3 %s -o %t && %run %t
+
+// Test that no_sanitize_memory attribute applies even when the function would
+// be normally inlined.
+
+#include <stdlib.h>
+
+__attribute__((no_sanitize_memory))
+int f(int *p) {
+ if (*p) // BOOOM?? Nope!
+ exit(0);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int x;
+ int * volatile p = &x;
+ int res = f(p);
+ return 0;
+}
diff --git a/test/msan/insertvalue_origin.cc b/test/msan/insertvalue_origin.cc
new file mode 100644
index 0000000000000..545debffaad50
--- /dev/null
+++ b/test/msan/insertvalue_origin.cc
@@ -0,0 +1,35 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
+
+// Test origin propagation through insertvalue IR instruction.
+
+#include <stdio.h>
+#include <stdint.h>
+
+struct mypair {
+ int64_t x;
+ int y;
+};
+
+mypair my_make_pair(int64_t x, int y) {
+ mypair p;
+ p.x = x;
+ p.y = y;
+ return p;
+}
+
+int main() {
+ int64_t * volatile p = new int64_t;
+ mypair z = my_make_pair(*p, 0);
+ if (z.x)
+ printf("zzz\n");
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{in main .*insertvalue_origin.cc:}}[[@LINE-3]]
+
+ // CHECK: Uninitialized value was created by a heap allocation
+ // CHECK: {{in main .*insertvalue_origin.cc:}}[[@LINE-8]]
+ delete p;
+ return 0;
+}
diff --git a/test/msan/ioctl.cc b/test/msan/ioctl.cc
new file mode 100644
index 0000000000000..caa5c274f5eba
--- /dev/null
+++ b/test/msan/ioctl.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+ unsigned int z;
+ int res = ioctl(fd, FIOGETOWN, &z);
+ assert(res == 0);
+ close(fd);
+ if (z)
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/ioctl_custom.cc b/test/msan/ioctl_custom.cc
new file mode 100644
index 0000000000000..7c7fde4bd5d02
--- /dev/null
+++ b/test/msan/ioctl_custom.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %run %t
+
+// RUN: %clangxx_msan -DPOSITIVE -m64 -O0 -g %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -DPOSITIVE -m64 -O3 -g %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdlib.h>
+#include <net/if.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+
+ struct ifreq ifreqs[20];
+ struct ifconf ifc;
+ ifc.ifc_ifcu.ifcu_req = ifreqs;
+#ifndef POSITIVE
+ ifc.ifc_len = sizeof(ifreqs);
+#endif
+ int res = ioctl(fd, SIOCGIFCONF, (void *)&ifc);
+ // CHECK: Uninitialized bytes in ioctl{{.*}} at offset 0 inside [0x{{.*}}, 4)
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #{{.*}} in main {{.*}}ioctl_custom.cc:[[@LINE-3]]
+ assert(res == 0);
+ for (int i = 0; i < ifc.ifc_len / sizeof(*ifc.ifc_ifcu.ifcu_req); ++i)
+ printf("%d %zu %s\n", i, strlen(ifreqs[i].ifr_name), ifreqs[i].ifr_name);
+ return 0;
+}
diff --git a/test/msan/ioctl_sound.cc b/test/msan/ioctl_sound.cc
new file mode 100644
index 0000000000000..ed896f761181f
--- /dev/null
+++ b/test/msan/ioctl_sound.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <fcntl.h>
+#include <sound/asound.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char **argv) {
+ int fd = open("/dev/snd/controlC0", O_RDONLY);
+ if (fd < 0) {
+ printf("Unable to open sound device.");
+ return 0;
+ }
+ const unsigned sz = sizeof(snd_ctl_card_info);
+ void *info = malloc(sz + 1);
+ assert(__msan_test_shadow(info, sz) == 0);
+ assert(ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, info) >= 0);
+ assert(__msan_test_shadow(info, sz + 1) == sz);
+ close(fd);
+ free(info);
+ return 0;
+}
diff --git a/test/msan/keep-going-dso.cc b/test/msan/keep-going-dso.cc
new file mode 100644
index 0000000000000..7975306c557fb
--- /dev/null
+++ b/test/msan/keep-going-dso.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+
+// Test how -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going affect reports
+// from interceptors.
+// -mllvm -msan-keep-going provides the default value of keep_going flag, but is
+// always overwritten by MSAN_OPTIONS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ char *volatile x = (char*)malloc(5 * sizeof(char));
+ x[4] = 0;
+ if (strlen(x) < 3)
+ exit(0);
+ fprintf(stderr, "Done\n");
+ // CHECK-NOT: Done
+ // CHECK-KEEP-GOING: Done
+ return 0;
+}
diff --git a/test/msan/keep-going.cc b/test/msan/keep-going.cc
new file mode 100644
index 0000000000000..6426574a9e502
--- /dev/null
+++ b/test/msan/keep-going.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=1 not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=0 not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+
+// Test behaviour of -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going.
+// -mllvm -msan-keep-going provides the default value of keep_going flag; value
+// of 1 can be overwritten by MSAN_OPTIONS, value of 0 can not.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+ char *volatile x = (char*)malloc(5 * sizeof(char));
+ if (x[0])
+ exit(0);
+ fprintf(stderr, "Done\n");
+ // CHECK-NOT: Done
+ // CHECK-KEEP-GOING: Done
+ return 0;
+}
diff --git a/test/msan/lit.cfg b/test/msan/lit.cfg
new file mode 100644
index 0000000000000..f425e25957ac1
--- /dev/null
+++ b/test/msan/lit.cfg
@@ -0,0 +1,30 @@
+# -*- Python -*-
+
+import os
+
+# Setup config name.
+config.name = 'MemorySanitizer'
+
+# Setup source root.
+config.test_source_root = os.path.dirname(__file__)
+
+# Setup default compiler flags used with -fsanitize=memory option.
+clang_msan_cflags = ["-fsanitize=memory",
+ "-mno-omit-leaf-frame-pointer",
+ "-fno-omit-frame-pointer",
+ "-fno-optimize-sibling-calls",
+ "-m64"] + config.debug_info_flags
+clang_msan_cxxflags = config.cxx_mode_flags + clang_msan_cflags
+
+def build_invocation(compile_flags):
+ return " " + " ".join([config.clang] + compile_flags) + " "
+
+config.substitutions.append( ("%clang_msan ", build_invocation(clang_msan_cflags)) )
+config.substitutions.append( ("%clangxx_msan ", build_invocation(clang_msan_cxxflags)) )
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp']
+
+# MemorySanitizer tests are currently supported on Linux only.
+if config.host_os not in ['Linux']:
+ config.unsupported = True
diff --git a/test/msan/lit.site.cfg.in b/test/msan/lit.site.cfg.in
new file mode 100644
index 0000000000000..fb22a57a9e665
--- /dev/null
+++ b/test/msan/lit.site.cfg.in
@@ -0,0 +1,5 @@
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Load tool-specific config that would do the real work.
+lit_config.load_config(config, "@MSAN_LIT_SOURCE_DIR@/lit.cfg")
diff --git a/test/msan/mallinfo.cc b/test/msan/mallinfo.cc
new file mode 100644
index 0000000000000..3f308683077ef
--- /dev/null
+++ b/test/msan/mallinfo.cc
@@ -0,0 +1,12 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <malloc.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ struct mallinfo mi = mallinfo();
+ assert(__msan_test_shadow(&mi, sizeof(mi)) == -1);
+ return 0;
+}
diff --git a/test/msan/mktime.cc b/test/msan/mktime.cc
new file mode 100644
index 0000000000000..c419057c39079
--- /dev/null
+++ b/test/msan/mktime.cc
@@ -0,0 +1,26 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -g -DUNINIT %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <time.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ struct tm tm;
+ tm.tm_year = 2014;
+ tm.tm_mon = 3;
+ tm.tm_mday = 28;
+#ifndef UNINIT
+ tm.tm_hour = 13;
+#endif
+ tm.tm_min = 4;
+ tm.tm_sec = 42;
+ tm.tm_isdst = -1;
+ time_t t = mktime(&tm);
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: in main{{.*}}mktime.cc:[[@LINE-2]]
+ assert(t != -1);
+ assert(__msan_test_shadow(&tm, sizeof(tm)) == -1);
+ return 0;
+}
diff --git a/test/msan/mmap_below_shadow.cc b/test/msan/mmap_below_shadow.cc
new file mode 100644
index 0000000000000..4b5890ba0fb83
--- /dev/null
+++ b/test/msan/mmap_below_shadow.cc
@@ -0,0 +1,28 @@
+// Test mmap behavior when map address is below shadow range.
+// With MAP_FIXED, we return EINVAL.
+// Without MAP_FIXED, we ignore the address hint and map somewhere in
+// application range.
+
+// RUN: %clangxx_msan -m64 -O0 -DFIXED=0 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -DFIXED=1 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -DFIXED=0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -DFIXED=1 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/mman.h>
+
+int main(void) {
+ // Hint address just below shadow.
+ uintptr_t hint = 0x4f0000000000ULL;
+ const uintptr_t app_start = 0x600000000000ULL;
+ uintptr_t p = (uintptr_t)mmap(
+ (void *)hint, 4096, PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | (FIXED ? MAP_FIXED : 0), -1, 0);
+ if (FIXED)
+ assert(p == (uintptr_t)-1 && errno == EINVAL);
+ else
+ assert(p >= app_start);
+ return 0;
+}
diff --git a/test/msan/msan_check_mem_is_initialized.cc b/test/msan/msan_check_mem_is_initialized.cc
new file mode 100644
index 0000000000000..33558cd2feb27
--- /dev/null
+++ b/test/msan/msan_check_mem_is_initialized.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_msan -m64 -O0 -g -DPOSITIVE %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK
+// RUN: MSAN_OPTIONS=verbosity=1 not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-VERBOSE
+
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ char p[32] = {};
+ __msan_poison(p + 10, 2);
+
+ __msan_check_mem_is_initialized(p, 10);
+ __msan_check_mem_is_initialized(p + 12, 30);
+#ifdef POSITIVE
+ __msan_check_mem_is_initialized(p + 5, 20);
+ // CHECK: Uninitialized bytes in __msan_check_mem_is_initialized at offset 5 inside [0x{{.*}}, 20)
+ // CHECK-VERBOSE: Shadow map of [0x{{.*}}, 0x{{.*}}), 20 bytes:
+ // CHECK-VERBOSE: 0x{{.*}}: ..000000 0000ffff 00000000 00000000
+ // CHECK-VERBOSE: 0x{{.*}}: 00000000 00...... ........ ........
+
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #0 0x{{.*}}in main{{.*}}msan_check_mem_is_initialized.cc:[[@LINE-7]]
+#endif
+ return 0;
+}
+
diff --git a/test/msan/msan_dump_shadow.cc b/test/msan/msan_dump_shadow.cc
new file mode 100644
index 0000000000000..08371e306f32a
--- /dev/null
+++ b/test/msan/msan_dump_shadow.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ char *p = new char[16];
+ __msan_dump_shadow(p, 5);
+ delete[] p;
+ const char *q = "abc";
+ __msan_dump_shadow(q, 3);
+ return 0;
+}
+
+// CHECK: ff ff ff ff ff
+// CHECK: 00 00 00
diff --git a/test/msan/msan_print_shadow.cc b/test/msan/msan_print_shadow.cc
new file mode 100644
index 0000000000000..0cc1d660be1b6
--- /dev/null
+++ b/test/msan/msan_print_shadow.cc
@@ -0,0 +1,122 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-ORIGINS < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS --check-prefix=CHECK-ORIGINS-2 < %t.out
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ char volatile x;
+ char *p = new char[320];
+ p[2] = p[5] = 1;
+ p[8] = p[9] = p[10] = p[11] = p[12] = 2;
+
+ __msan_allocated_memory(p + 4*3, 4);
+ __msan_allocated_memory(p + 4*4, 4);
+ __msan_allocated_memory(p + 4*5, 4);
+ __msan_allocated_memory(p + 4*6, 4);
+ __msan_allocated_memory(p + 4*7, 4);
+ __msan_allocated_memory(p + 4*8, 4);
+ __msan_allocated_memory(p + 4*9, 4);
+ __msan_allocated_memory(p + 4*10, 4);
+ __msan_allocated_memory(p + 4*11, 4);
+ __msan_allocated_memory(p + 4*12, 4);
+ __msan_allocated_memory(p + 4*13, 4);
+ __msan_allocated_memory(p + 4*14, 4);
+ __msan_allocated_memory(p + 4*15, 4);
+ __msan_allocated_memory(p + 4*16, 4);
+ __msan_allocated_memory(p + 4*17, 4);
+ __msan_allocated_memory(p + 4*18, 4);
+ __msan_allocated_memory(p + 4*19, 4);
+ __msan_allocated_memory(p + 4*20, 4);
+ __msan_allocated_memory(p + 4*21, 4);
+ __msan_allocated_memory(p + 4*22, 4);
+ __msan_allocated_memory(p + 4*23, 4);
+ __msan_allocated_memory(p + 4*24, 4);
+ __msan_allocated_memory(p + 4*25, 4);
+ __msan_allocated_memory(p + 4*26, 4);
+ __msan_allocated_memory(p + 4*27, 4);
+ __msan_allocated_memory(p + 4*28, 4);
+ __msan_allocated_memory(p + 4*29, 4);
+ __msan_allocated_memory(p + 4*30, 4);
+ __msan_allocated_memory(p + 4*31, 4);
+
+ p[19] = x;
+
+ __msan_print_shadow(p+5, 297);
+ delete[] p;
+ return 0;
+}
+
+// CHECK: Shadow map of [{{.*}}), 297 bytes:
+
+// CHECK-NO-ORIGINS: 0x{{.*}}: ..00ffff 00000000 ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffff.... ........
+
+// CHECK-ORIGINS: 0x{{.*}}: ..00ffff 00000000 ffffffff ffffffff |A . B C|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |D E F G|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |H I J K|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |L M N O|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |P Q R S|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |T U V W|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |X Y Z *|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |* * * A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffff.... ........ |A A A .|
+
+// CHECK-ORIGINS: Origin A (origin_id {{.*}}):
+// CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+// CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:14
+
+// CHECK-ORIGINS: Origin B (origin_id {{.*}}):
+// CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+// CHECK-ORIGINS: #0 {{.*}} in __msan_allocated_memory
+// CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:18
+
+// CHECK-ORIGINS: Origin C (origin_id {{.*}}):
+// CHECK-ORIGINS-2: Uninitialized value was stored to memory at
+// CHECK-ORIGINS-2: #0 {{.*}} in main{{.*}}msan_print_shadow.cc:48
+// CHECK-ORIGINS: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'main'
+// CHECK-ORIGINS: #0 {{.*}} in main{{.*}}msan_print_shadow.cc:12
+
+// CHECK-ORIGINS: Origin D (origin_id {{.*}}):
+// CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+// CHECK-ORIGINS: #0 {{.*}} in __msan_allocated_memory
+// CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:20
+
+// ...
+
+// CHECK-ORIGINS: Origin Z (origin_id {{.*}}):
+// CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+// CHECK-ORIGINS: #0 {{.*}} in __msan_allocated_memory
+// CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:42
diff --git a/test/msan/msan_print_shadow2.cc b/test/msan/msan_print_shadow2.cc
new file mode 100644
index 0000000000000..343ee9e5c3de3
--- /dev/null
+++ b/test/msan/msan_print_shadow2.cc
@@ -0,0 +1,49 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-ORIGINS < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS < %t.out
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ char *p = new char[16];
+ __msan_print_shadow(p, 1);
+ __msan_print_shadow(p+1, 1);
+ __msan_print_shadow(p+3, 1);
+ __msan_print_shadow(p+15, 1);
+ __msan_print_shadow(p, 0);
+ delete[] p;
+ int x = 0;
+ __msan_print_shadow(&x, 3);
+ return 0;
+}
+
+// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 1 bytes:
+// CHECK-NO-ORIGINS: 0x{{.*}}: ff...... ........ ........ ........
+// CHECK-ORIGINS: 0x{{.*}}: ff...... ........ ........ ........ |A . . .|
+// CHECK-ORIGINS: Origin A (origin_id {{.*}}):
+
+// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 1 bytes:
+// CHECK-NO-ORIGINS: 0x{{.*}}: ..ff.... ........ ........ ........
+// CHECK-ORIGINS: 0x{{.*}}: ..ff.... ........ ........ ........ |A . . .|
+// CHECK-ORIGINS: Origin A (origin_id {{.*}}):
+
+// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 1 bytes:
+// CHECK-NO-ORIGINS: 0x{{.*}}: ......ff ........ ........ ........
+// CHECK-ORIGINS: 0x{{.*}}: ......ff ........ ........ ........ |A . . .|
+// CHECK-ORIGINS: Origin A (origin_id {{.*}}):
+
+// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 1 bytes:
+// CHECK-NO-ORIGINS: 0x{{.*}}: ......ff ........ ........ ........
+// CHECK-ORIGINS: 0x{{.*}}: ......ff ........ ........ ........ |A . . .|
+// CHECK-ORIGINS: Origin A (origin_id {{.*}}):
+
+// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 0 bytes:
+
+// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 3 bytes:
+// CHECK-NO-ORIGINS: 0x{{.*}}: 000000.. ........ ........ ........
+// CHECK-ORIGINS: 0x{{.*}}: 000000.. ........ ........ ........ |. . . .|
diff --git a/test/msan/msan_print_shadow3.cc b/test/msan/msan_print_shadow3.cc
new file mode 100644
index 0000000000000..c605ef18886d1
--- /dev/null
+++ b/test/msan/msan_print_shadow3.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdint.h>
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ unsigned long long x = 0; // For 8-byte alignment.
+ uint32_t x_s = 0x12345678U;
+ __msan_partial_poison(&x, &x_s, sizeof(x_s));
+ __msan_print_shadow(&x, sizeof(x_s));
+ return 0;
+}
+
+// CHECK: Shadow map of [{{.*}}), 4 bytes:
+// CHECK: 0x{{.*}}: 87654321 ........ ........ ........
diff --git a/test/msan/mul_by_const.cc b/test/msan/mul_by_const.cc
new file mode 100644
index 0000000000000..a975bb92167ed
--- /dev/null
+++ b/test/msan/mul_by_const.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t
+
+#include <sanitizer/msan_interface.h>
+
+struct S {
+ S(int a0) : a(a0) {}
+ int a;
+ int b;
+};
+
+// Here S is passed to FooRun as a 64-bit integer.
+// This triggers an optimization where 10000 * s.a is transformed into
+// ((*(uint64_t *)&s) * (10000 * 2**32)) >> 32
+// Test that MSan understands that this kills the uninitialized high half of S
+// (i.e. S::b).
+void FooRun(S s) {
+ int64_t x = 10000 * s.a;
+ __msan_check_mem_is_initialized(&x, sizeof(x));
+}
+
+int main(void) {
+ S z(1);
+ // Take &z to ensure that it is built on stack.
+ S *volatile p = &z;
+ FooRun(z);
+ return 0;
+}
diff --git a/test/msan/no_sanitize_memory.cc b/test/msan/no_sanitize_memory.cc
new file mode 100644
index 0000000000000..c5643816c2812
--- /dev/null
+++ b/test/msan/no_sanitize_memory.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t >%t.out 2>&1
+
+// RUN: %clangxx_msan -m64 -O0 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O1 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O2 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1
+
+// Test that (no_sanitize_memory) functions
+// * don't check shadow values (-DCHECK_IN_F)
+// * treat all values loaded from memory as fully initialized (-UCHECK_IN_F)
+
+#include <stdlib.h>
+#include <stdio.h>
+
+__attribute__((noinline))
+__attribute__((no_sanitize_memory))
+int f(void) {
+ int x;
+ int * volatile p = &x;
+#ifdef CHECK_IN_F
+ if (*p)
+ exit(0);
+#endif
+ return *p;
+}
+
+int main(void) {
+ if (f())
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/no_sanitize_memory_prop.cc b/test/msan/no_sanitize_memory_prop.cc
new file mode 100644
index 0000000000000..4275ebbf78e1f
--- /dev/null
+++ b/test/msan/no_sanitize_memory_prop.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t >%t.out 2>&1
+
+// Test that (no_sanitize_memory) functions DO NOT propagate shadow.
+
+#include <stdlib.h>
+#include <stdio.h>
+
+__attribute__((noinline))
+__attribute__((no_sanitize_memory))
+int f(int x) {
+ return x;
+}
+
+int main(void) {
+ int x;
+ int * volatile p = &x;
+ int y = f(*p);
+ if (y)
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/obstack.cc b/test/msan/obstack.cc
new file mode 100644
index 0000000000000..222f43b839dc9
--- /dev/null
+++ b/test/msan/obstack.cc
@@ -0,0 +1,37 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -g -DPOSITIVE %s -o %t && not %run %t |& FileCheck %s
+
+#include <obstack.h>
+#include <sanitizer/msan_interface.h>
+#include <stdlib.h>
+
+static void *obstack_chunk_alloc(size_t sz) {
+ return malloc(sz);
+}
+
+static void obstack_chunk_free(void *p) {
+ free(p);
+}
+
+int main(void) {
+ obstack obs;
+ obstack_init(&obs);
+ for (size_t sz = 16; sz < 0xFFFF; sz *= 2) {
+ void *p = obstack_alloc(&obs, sz);
+ int data[10] = {0};
+ obstack_grow(&obs, &data, sizeof(data));
+ obstack_blank(&obs, sz);
+ obstack_grow(&obs, &data, sizeof(data));
+ obstack_int_grow(&obs, 13);
+ p = obstack_finish(&obs);
+#ifdef POSITIVE
+ if (sz == 4096) {
+ __msan_check_mem_is_initialized(p, sizeof(data));
+ __msan_check_mem_is_initialized(p, sizeof(data) + 1);
+ }
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #0 0x{{.*}} in main{{.*}}obstack.cc:[[@LINE-30]]
+#endif
+ }
+ obstack_free(&obs, 0);
+}
diff --git a/test/msan/param_tls_limit.cc b/test/msan/param_tls_limit.cc
new file mode 100644
index 0000000000000..869afc9357737
--- /dev/null
+++ b/test/msan/param_tls_limit.cc
@@ -0,0 +1,74 @@
+// ParamTLS has limited size. Everything that does not fit is considered fully
+// initialized.
+
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && %run %t
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 %s -o %t && %run %t
+
+#include <sanitizer/msan_interface.h>
+#include <assert.h>
+
+// This test assumes that ParamTLS size is 800 bytes.
+
+// This test passes poisoned values through function argument list.
+// In case of overflow, argument is unpoisoned.
+#define OVERFLOW(x) assert(__msan_test_shadow(&x, sizeof(x)) == -1)
+// In case of no overflow, it is still poisoned.
+#define NO_OVERFLOW(x) assert(__msan_test_shadow(&x, sizeof(x)) == 0)
+
+template<int N>
+struct S {
+ char x[N];
+};
+
+void f100(S<100> s) {
+ NO_OVERFLOW(s);
+}
+
+void f800(S<800> s) {
+ NO_OVERFLOW(s);
+}
+
+void f801(S<801> s) {
+ OVERFLOW(s);
+}
+
+void f1000(S<1000> s) {
+ OVERFLOW(s);
+}
+
+void f_many(int a, double b, S<800> s, int c, double d) {
+ NO_OVERFLOW(a);
+ NO_OVERFLOW(b);
+ OVERFLOW(s);
+ OVERFLOW(c);
+ OVERFLOW(d);
+}
+
+// -8 bytes for "int a", aligned by 8
+// -2 to make "int c" a partial fit
+void f_many2(int a, S<800 - 8 - 2> s, int c, double d) {
+ NO_OVERFLOW(a);
+ NO_OVERFLOW(s);
+ OVERFLOW(c);
+ OVERFLOW(d);
+}
+
+int main(void) {
+ S<100> s100;
+ S<800> s800;
+ S<801> s801;
+ S<1000> s1000;
+ f100(s100);
+ f800(s800);
+ f801(s801);
+ f1000(s1000);
+
+ int i;
+ double d;
+ f_many(i, d, s800, i, d);
+
+ S<800 - 8 - 2> s788;
+ f_many2(i, s788, i, d);
+ return 0;
+}
diff --git a/test/msan/poison_in_free.cc b/test/msan/poison_in_free.cc
new file mode 100644
index 0000000000000..16e2124c3d515
--- /dev/null
+++ b/test/msan/poison_in_free.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_msan -O0 %s -o %t && not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -O0 %s -o %t && MSAN_OPTIONS=poison_in_free=0 %run %t >%t.out 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ char *volatile x = (char*)malloc(50 * sizeof(char));
+ memset(x, 0, 50);
+ free(x);
+ return x[25];
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #0 {{.*}} in main{{.*}}poison_in_free.cc:[[@LINE-2]]
+}
diff --git a/test/msan/print_stats.cc b/test/msan/print_stats.cc
new file mode 100644
index 0000000000000..74943835b367d
--- /dev/null
+++ b/test/msan/print_stats.cc
@@ -0,0 +1,45 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -g %s -o %t
+// RUN: %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS %s
+// RUN: MSAN_OPTIONS=print_stats=1 %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS %s
+// RUN: MSAN_OPTIONS=print_stats=1,atexit=1 %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-STATS %s
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -g -DPOSITIVE=1 %s -o %t
+// RUN: not %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS %s
+// RUN: MSAN_OPTIONS=print_stats=1 not %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-STATS %s
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -g -DPOSITIVE=1 -mllvm -msan-keep-going=1 %s -o %t
+// RUN: not %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS --check-prefix=CHECK-KEEPGOING %s
+// RUN: MSAN_OPTIONS=print_stats=1 not %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-STATS --check-prefix=CHECK-KEEPGOING %s
+
+#include <stdio.h>
+int main(int argc, char **argv) {
+ int x;
+ int *volatile p = &x;
+ fprintf(stderr, "TEST\n");
+#ifdef POSITIVE
+ return *p;
+#else
+ return 0;
+#endif
+}
+
+// CHECK: TEST
+
+// CHECK-STATS: Unique heap origins:
+// CHECK-STATS: Stack depot allocated bytes:
+// CHECK-STATS: Unique origin histories:
+// CHECK-STATS: History depot allocated bytes:
+
+// CHECK-NOSTATS-NOT: Unique heap origins:
+// CHECK-NOSTATS-NOT: Stack depot allocated bytes:
+// CHECK-NOSTATS-NOT: Unique origin histories:
+// CHECK-NOSTATS-NOT: History depot allocated bytes:
+
+// CHECK-KEEPGOING: MemorySanitizer: 1 warnings reported.
diff --git a/test/msan/pthread_getattr_np_deadlock.cc b/test/msan/pthread_getattr_np_deadlock.cc
new file mode 100644
index 0000000000000..07f19cb61b6ce
--- /dev/null
+++ b/test/msan/pthread_getattr_np_deadlock.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_msan -m64 -fsanitize-memory-track-origins -O0 %s -o %t && %run %t
+
+// Regression test for a deadlock in pthread_getattr_np
+
+#include <assert.h>
+#include <pthread.h>
+
+void *ThreadFn(void *) {
+ pthread_attr_t attr;
+ int res = pthread_getattr_np(pthread_self(), &attr);
+ assert(!res);
+ return 0;
+}
+
+int main(void) {
+ pthread_t t;
+ int res = pthread_create(&t, 0, ThreadFn, 0);
+ assert(!res);
+ res = pthread_join(t, 0);
+ assert(!res);
+ return 0;
+}
diff --git a/test/msan/rand_r.cc b/test/msan/rand_r.cc
new file mode 100644
index 0000000000000..d6bdb1deaa686
--- /dev/null
+++ b/test/msan/rand_r.cc
@@ -0,0 +1,18 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -g -DUNINIT %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void) {
+ unsigned seed;
+#ifndef UNINIT
+ seed = 42;
+#endif
+ int v = rand_r(&seed);
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: in main{{.*}}rand_r.cc:[[@LINE-2]]
+ if (v) printf(".\n");
+ return 0;
+}
diff --git a/test/msan/readdir64.cc b/test/msan/readdir64.cc
new file mode 100644
index 0000000000000..4f00d18387942
--- /dev/null
+++ b/test/msan/readdir64.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t
+
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O1 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O2 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O3 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t
+
+// Test that readdir64 is intercepted as well as readdir.
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdlib.h>
+
+
+int main(void) {
+ DIR *dir = opendir(".");
+ struct dirent *d = readdir(dir);
+ if (d->d_name[0]) {
+ closedir(dir);
+ exit(0);
+ }
+ closedir(dir);
+ return 0;
+}
diff --git a/test/msan/report-demangling.cc b/test/msan/report-demangling.cc
new file mode 100644
index 0000000000000..e6d5c27ec85de
--- /dev/null
+++ b/test/msan/report-demangling.cc
@@ -0,0 +1,19 @@
+// Test that function name is mangled in the "created by an allocation" line,
+// and demangled in the single-frame "stack trace" that follows.
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
+
+__attribute__((noinline))
+int f() {
+ int x;
+ int *volatile p = &x;
+ return *p;
+}
+
+int main(int argc, char **argv) {
+ return f();
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: Uninitialized value was created by an allocation of 'x' in the stack frame of function '_Z1fv'
+ // CHECK: #0 {{.*}} in f() {{.*}}report-demangling.cc:[[@LINE-10]]
+}
diff --git a/test/msan/scandir.cc b/test/msan/scandir.cc
new file mode 100644
index 0000000000000..571ba4f603d2c
--- /dev/null
+++ b/test/msan/scandir.cc
@@ -0,0 +1,56 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+
+static int my_filter(const struct dirent *a) {
+ assert(__msan_test_shadow(&a, sizeof(a)) == (size_t)-1);
+ printf("%s\n", a->d_name);
+ __msan_print_shadow(a, a->d_reclen);
+ assert(__msan_test_shadow(a, a->d_reclen) == (size_t)-1);
+ printf("%s\n", a->d_name);
+ return strlen(a->d_name) == 3 && a->d_name[2] == 'b';
+}
+
+static int my_compar(const struct dirent **a, const struct dirent **b) {
+ assert(__msan_test_shadow(a, sizeof(*a)) == (size_t)-1);
+ assert(__msan_test_shadow(*a, (*a)->d_reclen) == (size_t)-1);
+ assert(__msan_test_shadow(b, sizeof(*b)) == (size_t)-1);
+ assert(__msan_test_shadow(*b, (*b)->d_reclen) == (size_t)-1);
+ if ((*a)->d_name[1] == (*b)->d_name[1])
+ return 0;
+ return ((*a)->d_name[1] < (*b)->d_name[1]) ? 1 : -1;
+}
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", argv[1], "scandir_test_root/");
+
+ struct dirent **d;
+ int res = scandir(buf, &d, my_filter, my_compar);
+ assert(res == 2);
+ assert(__msan_test_shadow(&d, sizeof(*d)) == (size_t)-1);
+ for (int i = 0; i < res; ++i) {
+ assert(__msan_test_shadow(&d[i], sizeof(d[i])) == (size_t)-1);
+ assert(__msan_test_shadow(d[i], d[i]->d_reclen) == (size_t)-1);
+ }
+
+ assert(strcmp(d[0]->d_name, "bbb") == 0);
+ assert(strcmp(d[1]->d_name, "aab") == 0);
+ return 0;
+}
diff --git a/test/msan/scandir_null.cc b/test/msan/scandir_null.cc
new file mode 100644
index 0000000000000..e7663dc43a741
--- /dev/null
+++ b/test/msan/scandir_null.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", argv[1], "scandir_test_root/");
+
+ struct dirent **d;
+ int res = scandir(buf, &d, NULL, NULL);
+ assert(res >= 3);
+ assert(__msan_test_shadow(&d, sizeof(*d)) == (size_t)-1);
+ for (int i = 0; i < res; ++i) {
+ assert(__msan_test_shadow(&d[i], sizeof(d[i])) == (size_t)-1);
+ assert(__msan_test_shadow(d[i], d[i]->d_reclen) == (size_t)-1);
+ }
+ return 0;
+}
diff --git a/test/msan/scandir_test_root/aaa b/test/msan/scandir_test_root/aaa
new file mode 100644
index 0000000000000..e69de29bb2d1d
--- /dev/null
+++ b/test/msan/scandir_test_root/aaa
diff --git a/test/msan/scandir_test_root/aab b/test/msan/scandir_test_root/aab
new file mode 100644
index 0000000000000..e69de29bb2d1d
--- /dev/null
+++ b/test/msan/scandir_test_root/aab
diff --git a/test/msan/scandir_test_root/bbb b/test/msan/scandir_test_root/bbb
new file mode 100644
index 0000000000000..e69de29bb2d1d
--- /dev/null
+++ b/test/msan/scandir_test_root/bbb
diff --git a/test/msan/select.cc b/test/msan/select.cc
new file mode 100644
index 0000000000000..89de75ebaaefa
--- /dev/null
+++ b/test/msan/select.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdlib.h>
+int main(int argc, char **argv) {
+ int x;
+ int *volatile p = &x;
+ int z = *p ? 1 : 0;
+ if (z)
+ exit(0);
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*select.cc:}}[[@LINE-3]]
+
+ // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*select.cc:.* main}}
+ return 0;
+}
diff --git a/test/msan/select_float_origin.cc b/test/msan/select_float_origin.cc
new file mode 100644
index 0000000000000..ca8f3a83b0ed5
--- /dev/null
+++ b/test/msan/select_float_origin.cc
@@ -0,0 +1,24 @@
+// Regression test for origin propagation in "select i1, float, float".
+// https://code.google.com/p/memory-sanitizer/issues/detail?id=78
+
+// RUN: %clangxx_msan -O2 -fsanitize-memory-track-origins %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -O2 -fsanitize-memory-track-origins=2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdio.h>
+#include <sanitizer/msan_interface.h>
+
+int main() {
+ volatile bool b = true;
+ float x, y;
+ __msan_allocated_memory(&x, sizeof(x));
+ __msan_allocated_memory(&y, sizeof(y));
+ float z = b ? x : y;
+ if (z > 0) printf(".\n");
+ // CHECK: Uninitialized value was created by a heap allocation
+ // CHECK: {{#0 0x.* in .*__msan_allocated_memory}}
+ // CHECK: {{#1 0x.* in main .*select_float_origin.cc:}}[[@LINE-6]]
+ return 0;
+}
diff --git a/test/msan/select_origin.cc b/test/msan/select_origin.cc
new file mode 100644
index 0000000000000..e832c02e99ced
--- /dev/null
+++ b/test/msan/select_origin.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// Test condition origin propagation through "select" IR instruction.
+
+#include <stdio.h>
+#include <stdint.h>
+
+__attribute__((noinline))
+int *max_by_ptr(int *a, int *b) {
+ return *a < *b ? b : a;
+}
+
+int main(void) {
+ int x;
+ int *volatile px = &x;
+ int y = 43;
+ int *p = max_by_ptr(px, &y);
+ // CHECK: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'main'
+ return *p;
+}
diff --git a/test/msan/setlocale.cc b/test/msan/setlocale.cc
new file mode 100644
index 0000000000000..b7007f78da7cd
--- /dev/null
+++ b/test/msan/setlocale.cc
@@ -0,0 +1,13 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <assert.h>
+#include <locale.h>
+#include <stdlib.h>
+
+int main(void) {
+ char *locale = setlocale (LC_ALL, "");
+ assert(locale);
+ if (locale[0])
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/signal_stress_test.cc b/test/msan/signal_stress_test.cc
new file mode 100644
index 0000000000000..654b9676f4abd
--- /dev/null
+++ b/test/msan/signal_stress_test.cc
@@ -0,0 +1,71 @@
+// 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>
+#include <stdarg.h>
+#include <sanitizer/msan_interface.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+const int kSigCnt = 200;
+
+void f(bool poisoned, int n, ...) {
+ va_list vl;
+ va_start(vl, n);
+ for (int i = 0; i < n; ++i) {
+ void *p = va_arg(vl, void *);
+ if (!poisoned)
+ assert(__msan_test_shadow(&p, sizeof(p)) == -1);
+ }
+ va_end(vl);
+}
+
+int sigcnt;
+
+void SignalHandler(int signo) {
+ assert(signo == SIGPROF);
+ void *p;
+ void **volatile q = &p;
+ f(true, 10,
+ *q, *q, *q, *q, *q,
+ *q, *q, *q, *q, *q);
+ ++sigcnt;
+}
+
+int main() {
+ signal(SIGPROF, SignalHandler);
+
+ itimerval itv;
+ itv.it_interval.tv_sec = 0;
+ itv.it_interval.tv_usec = 100;
+ itv.it_value.tv_sec = 0;
+ itv.it_value.tv_usec = 100;
+ setitimer(ITIMER_PROF, &itv, NULL);
+
+ void *p;
+ void **volatile q = &p;
+
+ do {
+ f(false, 20,
+ nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr);
+ f(true, 20,
+ *q, *q, *q, *q, *q,
+ *q, *q, *q, *q, *q,
+ *q, *q, *q, *q, *q,
+ *q, *q, *q, *q, *q);
+ } while (sigcnt < kSigCnt);
+
+ itv.it_interval.tv_sec = 0;
+ itv.it_interval.tv_usec = 0;
+ itv.it_value.tv_sec = 0;
+ itv.it_value.tv_usec = 0;
+ setitimer(ITIMER_PROF, &itv, NULL);
+
+ signal(SIGPROF, SIG_DFL);
+ return 0;
+}
diff --git a/test/msan/sigwait.cc b/test/msan/sigwait.cc
new file mode 100644
index 0000000000000..f2e77cfd64071
--- /dev/null
+++ b/test/msan/sigwait.cc
@@ -0,0 +1,30 @@
+// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <sanitizer/msan_interface.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+void test_sigwait() {
+ sigset_t s;
+ sigemptyset(&s);
+ sigaddset(&s, SIGUSR1);
+ sigprocmask(SIG_BLOCK, &s, 0);
+
+ if (pid_t pid = fork()) {
+ kill(pid, SIGUSR1);
+ _exit(0);
+ } else {
+ int sig;
+ int res = sigwait(&s, &sig);
+ assert(!res);
+ // The following checks that sig is initialized.
+ assert(sig == SIGUSR1);
+ }
+}
+
+int main(void) {
+ test_sigwait();
+ return 0;
+}
diff --git a/test/msan/sigwaitinfo.cc b/test/msan/sigwaitinfo.cc
new file mode 100644
index 0000000000000..be7a2c009e0e5
--- /dev/null
+++ b/test/msan/sigwaitinfo.cc
@@ -0,0 +1,31 @@
+// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <sanitizer/msan_interface.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+void test_sigwaitinfo() {
+ sigset_t s;
+ sigemptyset(&s);
+ sigaddset(&s, SIGUSR1);
+ sigprocmask(SIG_BLOCK, &s, 0);
+
+ if (pid_t pid = fork()) {
+ kill(pid, SIGUSR1);
+ _exit(0);
+ } else {
+ siginfo_t info;
+ int res = sigwaitinfo(&s, &info);
+ assert(!res);
+ // The following checks that sig is initialized.
+ assert(info.si_signo == SIGUSR1);
+ assert(-1 == __msan_test_shadow(&info, sizeof(info)));
+ }
+}
+
+int main(void) {
+ test_sigwaitinfo();
+ return 0;
+}
diff --git a/test/msan/stack-origin.cc b/test/msan/stack-origin.cc
new file mode 100644
index 0000000000000..c39c3a8cf6d05
--- /dev/null
+++ b/test/msan/stack-origin.cc
@@ -0,0 +1,31 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+
+#include <stdlib.h>
+int main(int argc, char **argv) {
+ int x;
+ int *volatile p = &x;
+ return *p;
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*stack-origin.cc:}}[[@LINE-2]]
+
+ // CHECK-ORIGINS: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'main'
+ // CHECK-ORIGINS: {{#0 0x.* in main .*stack-origin.cc:}}[[@LINE-8]]
+
+ // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*stack-origin.cc:.* main}}
+}
diff --git a/test/msan/stack-origin2.cc b/test/msan/stack-origin2.cc
new file mode 100644
index 0000000000000..0ba57607dadb5
--- /dev/null
+++ b/test/msan/stack-origin2.cc
@@ -0,0 +1,41 @@
+// Test that on the second entry to a function the origins are still right.
+
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+
+#include <stdlib.h>
+
+extern "C"
+int f(int depth) {
+ if (depth) return f(depth - 1);
+
+ int x;
+ int *volatile p = &x;
+ return *p;
+}
+
+int main(int argc, char **argv) {
+ return f(1);
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*stack-origin2.cc:}}[[@LINE-2]]
+
+ // CHECK-ORIGINS: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'f'
+ // CHECK-ORIGINS: {{#0 0x.* in f .*stack-origin2.cc:}}[[@LINE-14]]
+
+ // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*stack-origin2.cc:.* main}}
+}
diff --git a/test/msan/strerror_r-non-gnu.c b/test/msan/strerror_r-non-gnu.c
new file mode 100644
index 0000000000000..d55bf42ef11ee
--- /dev/null
+++ b/test/msan/strerror_r-non-gnu.c
@@ -0,0 +1,18 @@
+// RUN: %clang_msan -std=c99 -O0 -g %s -o %t && %run %t
+
+// strerror_r under a weird set of circumstances can be redirected to
+// __xpg_strerror_r. Test that MSan handles this correctly.
+
+#define _POSIX_C_SOURCE 200112
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+int main() {
+ char buf[1000];
+ int res = strerror_r(EINVAL, buf, sizeof(buf));
+ assert(!res);
+ volatile int z = strlen(buf);
+ return 0;
+}
diff --git a/test/msan/strlen_of_shadow.cc b/test/msan/strlen_of_shadow.cc
new file mode 100644
index 0000000000000..bb9fe17d41cdb
--- /dev/null
+++ b/test/msan/strlen_of_shadow.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+// Check that strlen() and similar intercepted functions can be called on shadow
+// memory.
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+const char *mem_to_shadow(const char *p) {
+ return (char *)((uintptr_t)p & ~0x400000000000ULL);
+}
+
+int main(void) {
+ const char *s = "abcdef";
+ assert(strlen(s) == 6);
+ assert(strlen(mem_to_shadow(s)) == 0);
+
+ char *t = new char[42];
+ t[41] = 0;
+ assert(strlen(mem_to_shadow(t)) == 41);
+ return 0;
+}
diff --git a/test/msan/strxfrm.cc b/test/msan/strxfrm.cc
new file mode 100644
index 0000000000000..b930a6af69c4d
--- /dev/null
+++ b/test/msan/strxfrm.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <sanitizer/msan_interface.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(void) {
+ const char *p = "abcdef";
+ char q[10];
+ size_t n = strxfrm(q, p, sizeof(q));
+ assert(n < sizeof(q));
+ __msan_check_mem_is_initialized(q, n + 1);
+ return 0;
+}
diff --git a/test/msan/sync_lock_set_and_test.cc b/test/msan/sync_lock_set_and_test.cc
new file mode 100644
index 0000000000000..b6d344a613403
--- /dev/null
+++ b/test/msan/sync_lock_set_and_test.cc
@@ -0,0 +1,7 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+int main(void) {
+ int i;
+ __sync_lock_test_and_set(&i, 0);
+ return i;
+}
diff --git a/test/msan/textdomain.cc b/test/msan/textdomain.cc
new file mode 100644
index 0000000000000..47e991e8c16b7
--- /dev/null
+++ b/test/msan/textdomain.cc
@@ -0,0 +1,12 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+
+#include <libintl.h>
+#include <stdio.h>
+
+int main() {
+ const char *td = textdomain("abcd");
+ if (td[0] == 0) {
+ printf("Try read");
+ }
+ return 0;
+}
diff --git a/test/msan/times.cc b/test/msan/times.cc
new file mode 100644
index 0000000000000..a042f548dc0c6
--- /dev/null
+++ b/test/msan/times.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/times.h>
+
+
+int main(void) {
+ struct tms t;
+ clock_t res = times(&t);
+ assert(res != (clock_t)-1);
+
+ if (t.tms_utime) printf("1\n");
+ if (t.tms_stime) printf("2\n");
+ if (t.tms_cutime) printf("3\n");
+ if (t.tms_cstime) printf("4\n");
+
+ return 0;
+}
diff --git a/test/msan/tls_reuse.cc b/test/msan/tls_reuse.cc
new file mode 100644
index 0000000000000..e024a5a8d13f5
--- /dev/null
+++ b/test/msan/tls_reuse.cc
@@ -0,0 +1,26 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+// Check that when TLS block is reused between threads, its shadow is cleaned.
+
+#include <pthread.h>
+#include <stdio.h>
+
+int __thread x;
+
+void *ThreadFn(void *) {
+ if (!x)
+ printf("zzz\n");
+ int y;
+ int * volatile p = &y;
+ x = *p;
+ return 0;
+}
+
+int main(void) {
+ pthread_t t;
+ for (int i = 0; i < 100; ++i) {
+ pthread_create(&t, 0, ThreadFn, 0);
+ pthread_join(t, 0);
+ }
+ return 0;
+}
diff --git a/test/msan/tsearch.cc b/test/msan/tsearch.cc
new file mode 100644
index 0000000000000..653dc60371cd5
--- /dev/null
+++ b/test/msan/tsearch.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <search.h>
+#include <stdlib.h>
+
+int compare(const void *pa, const void *pb) {
+ int a = *(const int *)pa;
+ int b = *(const int *)pb;
+ if (a < b)
+ return -1;
+ else if (a > b)
+ return 1;
+ else
+ return 0;
+}
+
+void myfreenode(void *p) {
+ delete (int *)p;
+}
+
+int main(void) {
+ void *root = NULL;
+ for (int i = 0; i < 5; ++i) {
+ int *p = new int(i);
+ void *q = tsearch(p, &root, compare);
+ if (q == NULL)
+ exit(1);
+ if (*(int **)q != p)
+ delete p;
+ }
+
+ tdestroy(root, myfreenode);
+
+ return 0;
+}
diff --git a/test/msan/tzset.cc b/test/msan/tzset.cc
new file mode 100644
index 0000000000000..ed61d7bcc4497
--- /dev/null
+++ b/test/msan/tzset.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+extern char *tzname[2];
+
+int main(void) {
+ if (!strlen(tzname[0]) || !strlen(tzname[1]))
+ exit(1);
+ tzset();
+ if (!strlen(tzname[0]) || !strlen(tzname[1]))
+ exit(1);
+ return 0;
+}
diff --git a/test/msan/unaligned_read_origin.cc b/test/msan/unaligned_read_origin.cc
new file mode 100644
index 0000000000000..e5618efbde24a
--- /dev/null
+++ b/test/msan/unaligned_read_origin.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char **argv) {
+ int x;
+ int *volatile p = &x;
+ return __sanitizer_unaligned_load32(p);
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*unaligned_read_origin.cc:}}[[@LINE-2]]
+ // CHECK: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'main'
+ // CHECK: {{#0 0x.* in main .*unaligned_read_origin.cc:}}[[@LINE-7]]
+}
diff --git a/test/msan/unpoison_string.cc b/test/msan/unpoison_string.cc
new file mode 100644
index 0000000000000..ac947b9cf6fde
--- /dev/null
+++ b/test/msan/unpoison_string.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t
+// RUN: %run %t
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t
+// RUN: %run %t
+
+#include <assert.h>
+#include <string.h>
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char **argv) {
+ char s[20] = "string";
+ __msan_poison(s, sizeof(s));
+ __msan_unpoison_string(s);
+ assert(__msan_test_shadow(s, sizeof(s)) == strlen("string") + 1);
+ return 0;
+}
diff --git a/test/msan/use-after-free.cc b/test/msan/use-after-free.cc
new file mode 100644
index 0000000000000..5b408c5364959
--- /dev/null
+++ b/test/msan/use-after-free.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+
+#include <stdlib.h>
+int main(int argc, char **argv) {
+ int *volatile p = (int *)malloc(sizeof(int));
+ *p = 42;
+ free(p);
+
+ if (*p)
+ exit(0);
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*use-after-free.cc:}}[[@LINE-3]]
+
+ // CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+ // CHECK-ORIGINS: {{#0 0x.* in .*free}}
+ // CHECK-ORIGINS: {{#1 0x.* in main .*use-after-free.cc:}}[[@LINE-9]]
+ return 0;
+}
diff --git a/test/msan/vector_cvt.cc b/test/msan/vector_cvt.cc
new file mode 100644
index 0000000000000..bd9b6a8b80002
--- /dev/null
+++ b/test/msan/vector_cvt.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+// RUN: %clangxx_msan -DPOSITIVE -m64 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <emmintrin.h>
+
+int to_int(double v) {
+ __m128d t = _mm_set_sd(v);
+ int x = _mm_cvtsd_si32(t);
+ return x;
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #{{.*}} in to_int{{.*}}vector_cvt.cc:[[@LINE-3]]
+}
+
+int main() {
+#ifdef POSITIVE
+ double v;
+#else
+ double v = 1.1;
+#endif
+ double* volatile p = &v;
+ int x = to_int(*p);
+ return !x;
+}
diff --git a/test/msan/vector_select.cc b/test/msan/vector_select.cc
new file mode 100644
index 0000000000000..e8d55423293c4
--- /dev/null
+++ b/test/msan/vector_select.cc
@@ -0,0 +1,13 @@
+// RUN: %clangxx_msan -m64 -O0 %s -c -o %t
+// RUN: %clangxx_msan -m64 -O3 %s -c -o %t
+
+// Regression test for MemorySanitizer instrumentation of a select instruction
+// with vector arguments.
+
+#include <emmintrin.h>
+
+__m128d select(bool b, __m128d c, __m128d d)
+{
+ return b ? c : d;
+}
+