Update compiler-rt aosp/master for 3.5 (r209699) rebase.

Change-Id: I158a30186f0faea2e2400e9dfdd878db2eb40e90
diff --git a/test/msan/CMakeLists.txt b/test/msan/CMakeLists.txt
new file mode 100644
index 0000000..08786ee
--- /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 0000000..385351d
--- /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 0000000..8604e4d
--- /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 0000000..2c02e73
--- /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 0000000..bc35c30
--- /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 0000000..e69de29
--- /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 0000000..e69de29
--- /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 0000000..e69de29
--- /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 0000000..57271b8
--- /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 0000000..78645a7
--- /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 0000000..f0c3574
--- /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 0000000..3f44a96
--- /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 0000000..39b893b
--- /dev/null
+++ b/test/msan/Linux/syscalls.cc
@@ -0,0 +1,107 @@
+// 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 <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[2];
+  struct iocb *iocbp[2] = { &iocb[0], &iocb[1] };
+  memset(iocb, 0, sizeof(iocb));
+  iocb[0].aio_lio_opcode = IOCB_CMD_PREAD;
+  iocb[0].aio_buf = (__u64)buf;
+  iocb[0].aio_nbytes = kFortyTwo;
+  iocb[1].aio_lio_opcode = IOCB_CMD_PREAD;
+  iocb[1].aio_buf = (__u64)(&buf[kFortyTwo]);
+  iocb[1].aio_nbytes = kFortyTwo;
+  __sanitizer_syscall_pre_io_submit(0, 2, &iocbp);
+  assert(__msan_test_shadow(buf, sizeof(buf)) == 2 * kFortyTwo);
+
+  __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 0000000..e1425b8
--- /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 0000000..1beba11
--- /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 0000000..e69de29
--- /dev/null
+++ b/test/msan/Linux/xattr_test_root/a
diff --git a/test/msan/SharedLibs/dso-origin-so.cc b/test/msan/SharedLibs/dso-origin-so.cc
new file mode 100644
index 0000000..8930a71
--- /dev/null
+++ b/test/msan/SharedLibs/dso-origin-so.cc
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+
+#include "dso-origin.h"
+
+void my_access(int *p) {
+  volatile int tmp;
+  // Force initialize-ness check.
+  if (*p)
+    tmp = 1;
+}
+
+void *my_alloc(unsigned sz) {
+  return malloc(sz);
+}
diff --git a/test/msan/SharedLibs/dso-origin.h b/test/msan/SharedLibs/dso-origin.h
new file mode 100644
index 0000000..ff926b3
--- /dev/null
+++ b/test/msan/SharedLibs/dso-origin.h
@@ -0,0 +1,4 @@
+extern "C" {
+void my_access(int *p);
+void *my_alloc(unsigned sz);
+}
diff --git a/test/msan/SharedLibs/lit.local.cfg b/test/msan/SharedLibs/lit.local.cfg
new file mode 100644
index 0000000..b3677c1
--- /dev/null
+++ b/test/msan/SharedLibs/lit.local.cfg
@@ -0,0 +1,4 @@
+# Sources in this directory are compiled as shared libraries and used by
+# tests in parent directory.
+
+config.suffixes = []
diff --git a/test/msan/Unit/lit.site.cfg.in b/test/msan/Unit/lit.site.cfg.in
new file mode 100644
index 0000000..dc0e961
--- /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 0000000..f4ea51d
--- /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 0000000..473e0ae
--- /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 0000000..059300e
--- /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 0000000..f69de9a
--- /dev/null
+++ b/test/msan/chained_origin.cc
@@ -0,0 +1,56 @@
+// 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
+
+#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:37}}
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: {{#0 .* in fn_h.*chained_origin.cc:25}}
+// CHECK: {{#1 .* in main.*chained_origin.cc:36}}
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: {{#0 .* in fn_g.*chained_origin.cc:15}}
+// CHECK: {{#1 .* in fn_f.*chained_origin.cc:20}}
+// CHECK: {{#2 .* in main.*chained_origin.cc:35}}
+
+// 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:28}}
+
+// CHECK-HEAP: Uninitialized value was created by a heap allocation
+// CHECK-HEAP: {{#1 .* in main.*chained_origin.cc:30}}
diff --git a/test/msan/chained_origin_limits.cc b/test/msan/chained_origin_limits.cc
new file mode 100644
index 0000000..c6f8b62
--- /dev/null
+++ b/test/msan/chained_origin_limits.cc
@@ -0,0 +1,101 @@
+// This test program creates a very large number of unique histories.
+
+// 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
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static char *buf, *cur, *end;
+void init() {
+  buf = new char[1000];
+  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 by a heap allocation
+
+// 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 by a heap allocation
+
+// 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 by a heap allocation
diff --git a/test/msan/chained_origin_memcpy.cc b/test/msan/chained_origin_memcpy.cc
new file mode 100644
index 0000000..e56db9c
--- /dev/null
+++ b/test/msan/chained_origin_memcpy.cc
@@ -0,0 +1,51 @@
+// 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
+
+#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:36}}
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: {{#1 .* in fn_h.*chained_origin_memcpy.cc:28}}
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: {{#0 .* in fn_g.*chained_origin_memcpy.cc:18}}
+// CHECK: {{#1 .* in fn_f.*chained_origin_memcpy.cc:23}}
+
+// 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:31}}
diff --git a/test/msan/chained_origin_with_signals.cc b/test/msan/chained_origin_with_signals.cc
new file mode 100644
index 0000000..5fd497e
--- /dev/null
+++ b/test/msan/chained_origin_with_signals.cc
@@ -0,0 +1,32 @@
+// 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
+
+#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(SIGUSR1, SignalHandler);
+  kill(getpid(), SIGUSR1);
+  signal(SIGUSR1, 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 0000000..7d23288
--- /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/cxa_atexit.cc b/test/msan/cxa_atexit.cc
new file mode 100644
index 0000000..0aa36ec
--- /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 0000000..6d04883
--- /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 0000000..32cc022
--- /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 0000000..2c726d3
--- /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 0000000..9bde029
--- /dev/null
+++ b/test/msan/dso-origin.cc
@@ -0,0 +1,25 @@
+// 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 %p/SharedLibs/dso-origin-so.cc \
+// RUN:     -fPIC -shared -o %t-so.so
+// RUN: %clangxx_msan -m64 -O0 %s %t-so.so -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+
+#include "SharedLibs/dso-origin.h"
+
+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-so.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-so.cc:}}
+  // CHECK: {{#2 0x.* in main .*dso-origin.cc:}}[[@LINE-10]]
+  // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*dso-origin-so.cc:.* my_access}}
+  return 0;
+}
diff --git a/test/msan/dtls_test.c b/test/msan/dtls_test.c
new file mode 100644
index 0000000..5086389
--- /dev/null
+++ b/test/msan/dtls_test.c
@@ -0,0 +1,60 @@
+/* RUN: %clang_msan -m64 %s -o %t
+   RUN: %clang_msan -m64 %s -DBUILD_SO -fPIC -o %t-so.so -shared
+   RUN: not %run %t 2>&1 | FileCheck %s
+   CHECK: MemorySanitizer: use-of-uninitialized-value
+
+   This is an actual bug in msan/glibc integration,
+   see https://sourceware.org/bugzilla/show_bug.cgi?id=16291
+*/
+
+#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 0000000..8af8eb5
--- /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/ftime.cc b/test/msan/ftime.cc
new file mode 100644
index 0000000..2d0935d
--- /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 0000000..7658cd5
--- /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 0000000..abab8bd
--- /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 0000000..7df958a
--- /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 0000000..086d0b9
--- /dev/null
+++ b/test/msan/getline.cc
@@ -0,0 +1,30 @@
+// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+  assert(argc == 2);
+  char buf[1024];
+  snprintf(buf, sizeof(buf), "%s/%s", argv[1], "getline_test_data");
+
+  FILE *fp = fopen(buf, "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/getline_test_data b/test/msan/getline_test_data
new file mode 100644
index 0000000..5ba1d4c
--- /dev/null
+++ b/test/msan/getline_test_data
@@ -0,0 +1,2 @@
+abcde
+12345
diff --git a/test/msan/heap-origin.cc b/test/msan/heap-origin.cc
new file mode 100644
index 0000000..0920001
--- /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 0000000..ea6958b
--- /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 0000000..b74aec1
--- /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 0000000..6a0db3a
--- /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 0000000..94f6cd8
--- /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 0000000..b2fa961
--- /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 0000000..545debf
--- /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 0000000..caa5c27
--- /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 0000000..7c7fde4
--- /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 0000000..ed896f7
--- /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 0000000..7975306
--- /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 0000000..6426574
--- /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 0000000..3143608
--- /dev/null
+++ b/test/msan/lit.cfg
@@ -0,0 +1,31 @@
+# -*- 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",
+                     "-g",
+                     "-m64"]
+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 0000000..fb22a57
--- /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 0000000..3f30868
--- /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/malloc_hook.cc b/test/msan/malloc_hook.cc
new file mode 100644
index 0000000..5393080
--- /dev/null
+++ b/test/msan/malloc_hook.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_msan -O2 %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <unistd.h>
+
+extern "C" {
+int __msan_get_ownership(const void *p);
+
+void *global_ptr;
+
+// Note: avoid calling functions that allocate memory in malloc/free
+// to avoid infinite recursion.
+void __msan_malloc_hook(void *ptr, size_t sz) {
+  if (__msan_get_ownership(ptr)) {
+    write(1, "MallocHook\n", sizeof("MallocHook\n"));
+    global_ptr = ptr;
+  }
+}
+void __msan_free_hook(void *ptr) {
+  if (__msan_get_ownership(ptr) && ptr == global_ptr)
+    write(1, "FreeHook\n", sizeof("FreeHook\n"));
+}
+}  // extern "C"
+
+int main() {
+  volatile int *x = new int;
+  // CHECK: MallocHook
+  // Check that malloc hook was called with correct argument.
+  if (global_ptr != (void*)x) {
+    _exit(1);
+  }
+  *x = 0;
+  delete x;
+  // CHECK: FreeHook
+  return 0;
+}
diff --git a/test/msan/mktime.cc b/test/msan/mktime.cc
new file mode 100644
index 0000000..c419057
--- /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 0000000..4b5890b
--- /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 0000000..33558cd
--- /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 0000000..08371e3
--- /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 0000000..0cc1d66
--- /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 0000000..343ee9e
--- /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/no_sanitize_memory.cc b/test/msan/no_sanitize_memory.cc
new file mode 100644
index 0000000..c564381
--- /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 0000000..b41e8a1
--- /dev/null
+++ b/test/msan/no_sanitize_memory_prop.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t >%t.out 2>&1
+// 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
+
+// Test that (no_sanitize_memory) functions propagate shadow.
+
+// Note that at -O0 there is no report, because 'x' in 'f' is spilled to the
+// stack, and then loaded back as a fully initialiazed value (due to
+// no_sanitize_memory attribute).
+
+#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);
+  // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+  // CHECK: {{#0 0x.* in main .*no_sanitize_memory_prop.cc:}}[[@LINE+1]]
+  if (y)
+    exit(0);
+  return 0;
+}
diff --git a/test/msan/obstack.cc b/test/msan/obstack.cc
new file mode 100644
index 0000000..222f43b
--- /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/poison_in_free.cc b/test/msan/poison_in_free.cc
new file mode 100644
index 0000000..16e2124
--- /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 0000000..bee364b
--- /dev/null
+++ b/test/msan/print_stats.cc
@@ -0,0 +1,43 @@
+// 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: %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-KEEPGOING: MemorySanitizer: 1 warnings reported.
+
+// 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:
diff --git a/test/msan/pthread_getattr_np_deadlock.cc b/test/msan/pthread_getattr_np_deadlock.cc
new file mode 100644
index 0000000..07f19cb
--- /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 0000000..d6bdb1d
--- /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 0000000..4f00d18
--- /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/scandir.cc b/test/msan/scandir.cc
new file mode 100644
index 0000000..571ba4f
--- /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 0000000..e7663dc
--- /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 0000000..e69de29
--- /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 0000000..e69de29
--- /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 0000000..e69de29
--- /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 0000000..89de75e
--- /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_origin.cc b/test/msan/select_origin.cc
new file mode 100644
index 0000000..e832c02
--- /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 0000000..b7007f7
--- /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 0000000..654b967
--- /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 0000000..f2e77cf
--- /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 0000000..be7a2c0
--- /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 0000000..c39c3a8
--- /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/strerror_r-non-gnu.c b/test/msan/strerror_r-non-gnu.c
new file mode 100644
index 0000000..d55bf42
--- /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 0000000..bb9fe17
--- /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 0000000..b930a6a
--- /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 0000000..b6d344a
--- /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 0000000..47e991e
--- /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 0000000..a042f54
--- /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 0000000..e024a5a
--- /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 0000000..653dc60
--- /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 0000000..ed61d7b
--- /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 0000000..e5618ef
--- /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 0000000..ac947b9
--- /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 0000000..5b408c5
--- /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 0000000..6393339
--- /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-4]]
+}
+
+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 0000000..e8d5542
--- /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;
+}
+
diff --git a/test/msan/wrap_indirect_calls.cc b/test/msan/wrap_indirect_calls.cc
new file mode 100644
index 0000000..be17bd8
--- /dev/null
+++ b/test/msan/wrap_indirect_calls.cc
@@ -0,0 +1,64 @@
+// Test indirect call wrapping in MemorySanitizer.
+
+// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/two.cc -fPIC -shared -o %t-two-so.so
+// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/wrapper.cc -fPIC -shared -o %t-wrapper-so.so
+
+// Disable fast path.
+
+// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc %s \
+// RUN:     %t-two-so.so %t-wrapper-so.so \
+// RUN:     -mllvm -msan-wrap-indirect-calls=wrapper \
+// RUN:     -mllvm -msan-wrap-indirect-calls-fast=0 \
+// RUN:     -DSLOW=1 \
+// RUN:     -Wl,--defsym=__executable_start=0 -o %t
+// RUN: %run %t
+
+// Enable fast path, call from executable, -O0.
+
+// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc %s \
+// RUN:     %t-two-so.so %t-wrapper-so.so \
+// RUN:     -mllvm -msan-wrap-indirect-calls=wrapper \
+// RUN:     -mllvm -msan-wrap-indirect-calls-fast=1 \
+// RUN:     -DSLOW=0 \
+// RUN:     -Wl,--defsym=__executable_start=0 -o %t
+// RUN: %run %t
+
+// Enable fast path, call from executable, -O3.
+
+// RUN: %clangxx_msan -O3 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc %s \
+// RUN:     %t-two-so.so %t-wrapper-so.so \
+// RUN:     -mllvm -msan-wrap-indirect-calls=wrapper \
+// RUN:     -mllvm -msan-wrap-indirect-calls-fast=1 \
+// RUN:     -DSLOW=0 \
+// RUN:     -Wl,--defsym=__executable_start=0 -o %t
+// RUN: %run %t
+
+// Enable fast path, call from DSO, -O0.
+
+// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc -shared \
+// RUN:     %t-two-so.so %t-wrapper-so.so \
+// RUN:     -mllvm -msan-wrap-indirect-calls=wrapper \
+// RUN:     -mllvm -msan-wrap-indirect-calls-fast=1 \
+// RUN:     -DSLOW=0 \
+// RUN:     -Wl,--defsym=__executable_start=0 -o %t-caller-so.so
+// RUN: %clangxx_msan -O0 %s %t-caller-so.so %t-two-so.so %t-wrapper-so.so -o %t
+// RUN: %run %t
+
+// Enable fast path, call from DSO, -O3.
+
+// RUN: %clangxx_msan -O3 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc -shared \
+// RUN:     %t-two-so.so %t-wrapper-so.so \
+// RUN:     -mllvm -msan-wrap-indirect-calls=wrapper \
+// RUN:     -mllvm -msan-wrap-indirect-calls-fast=1 \
+// RUN:     -DSLOW=0 \
+// RUN:     -Wl,--defsym=__executable_start=0 -o %t-caller-so.so
+// RUN: %clangxx_msan -O3 %s %t-caller-so.so %t-two-so.so %t-wrapper-so.so -o %t
+// RUN: %run %t
+
+// The actual test is in multiple files in wrap_indirect_calls/ directory.
+void run_test();
+
+int main() {
+  run_test();
+  return 0;
+}
diff --git a/test/msan/wrap_indirect_calls/caller.cc b/test/msan/wrap_indirect_calls/caller.cc
new file mode 100644
index 0000000..a0af8b7
--- /dev/null
+++ b/test/msan/wrap_indirect_calls/caller.cc
@@ -0,0 +1,51 @@
+// Indirectly call a bunch of functions.
+
+#include <assert.h>
+
+extern int cnt;
+
+typedef int (*F)(int, int);
+
+// A function in the same object.
+int f_local(int x, int y) {
+  return x + y;
+}
+
+// A function in another object.
+int f_other_object(int x, int y);
+
+// A function in another DSO.
+int f_dso(int x, int y);
+
+// A function in another DSO that is replaced by the wrapper.
+int f_replaced(int x, int y);
+
+void run_test(void) {
+  int x;
+  int expected_cnt = 0;
+  volatile F f;
+
+  if (SLOW) ++expected_cnt;
+  f = &f_local;
+  x = f(1, 2);
+  assert(x == 3);
+  assert(cnt == expected_cnt);
+
+  if (SLOW) ++expected_cnt;
+  f = &f_other_object;
+  x = f(2, 3);
+  assert(x == 6);
+  assert(cnt == expected_cnt);
+
+  ++expected_cnt;
+  f = &f_dso;
+  x = f(2, 3);
+  assert(x == 7);
+  assert(cnt == expected_cnt);
+
+  ++expected_cnt;
+  f = &f_replaced;
+  x = f(2, 3);
+  assert(x == 11);
+  assert(cnt == expected_cnt);
+}
diff --git a/test/msan/wrap_indirect_calls/lit.local.cfg b/test/msan/wrap_indirect_calls/lit.local.cfg
new file mode 100644
index 0000000..5e01230
--- /dev/null
+++ b/test/msan/wrap_indirect_calls/lit.local.cfg
@@ -0,0 +1,3 @@
+# Sources in this directory are used by tests in parent directory.
+
+config.suffixes = []
diff --git a/test/msan/wrap_indirect_calls/one.cc b/test/msan/wrap_indirect_calls/one.cc
new file mode 100644
index 0000000..ab7bf41
--- /dev/null
+++ b/test/msan/wrap_indirect_calls/one.cc
@@ -0,0 +1,3 @@
+int f_other_object(int x, int y) {
+  return x * y;
+}
diff --git a/test/msan/wrap_indirect_calls/two.cc b/test/msan/wrap_indirect_calls/two.cc
new file mode 100644
index 0000000..c939a99
--- /dev/null
+++ b/test/msan/wrap_indirect_calls/two.cc
@@ -0,0 +1,11 @@
+int f_dso(int x, int y) {
+  return 2 * x + y;
+}
+
+int f_replaced(int x, int y) {
+  return x + y + 5;
+}
+
+int f_replacement(int x, int y) {
+  return x + y + 6;
+}
diff --git a/test/msan/wrap_indirect_calls/wrapper.cc b/test/msan/wrap_indirect_calls/wrapper.cc
new file mode 100644
index 0000000..8fcd0c6
--- /dev/null
+++ b/test/msan/wrap_indirect_calls/wrapper.cc
@@ -0,0 +1,11 @@
+int f_replaced(int x, int y);
+int f_replacement(int x, int y);
+
+int cnt;
+
+extern "C" void *wrapper(void *p) {
+  ++cnt;
+  if (p == (void *)f_replaced)
+    return (void *)f_replacement;
+  return p;
+}
diff --git a/test/msan/wrap_indirect_calls2.cc b/test/msan/wrap_indirect_calls2.cc
new file mode 100644
index 0000000..fb4e6c7
--- /dev/null
+++ b/test/msan/wrap_indirect_calls2.cc
@@ -0,0 +1,42 @@
+// Test __msan_set_indirect_call_wrapper.
+
+// RUN: %clangxx_msan -mllvm -msan-wrap-indirect-calls=__msan_wrap_indirect_call \
+// RUN:     -mllvm -msan-wrap-indirect-calls-fast=0 \
+// RUN:     -O0 -g -rdynamic -Wl,--defsym=__executable_start=0 %s -o %t && %run %t
+
+// This test disables -msan-wrap-indirect-calls-fast, otherwise indirect calls
+// inside the same module are short-circuited and are never seen by the wrapper.
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+
+extern "C" void __msan_set_indirect_call_wrapper(uintptr_t);
+
+bool done_f, done_g;
+
+void f(void) {
+  assert(!done_g);
+  done_f = true;
+}
+
+void g(void) {
+  assert(done_f);
+  done_g = true;
+}
+
+typedef void (*Fn)(void);
+extern "C" Fn my_wrapper(Fn target) {
+  if (target == f) return g;
+  return target;
+}
+
+int main(void) {
+  volatile Fn fp;
+  fp = &f;
+  fp();
+  __msan_set_indirect_call_wrapper((uintptr_t)my_wrapper);
+  fp();
+  return !(done_f && done_g);
+}
diff --git a/test/msan/wrap_indirect_calls_in_rtl.cc b/test/msan/wrap_indirect_calls_in_rtl.cc
new file mode 100644
index 0000000..040ff13
--- /dev/null
+++ b/test/msan/wrap_indirect_calls_in_rtl.cc
@@ -0,0 +1,79 @@
+// Test indirect call wrapping in MemorySanitizer runtime.
+
+// RUN: %clangxx_msan -O0 -g -rdynamic %s -o %t && %run %t
+
+#include <assert.h>
+#include <math.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/time.h>
+
+extern "C" void __msan_set_indirect_call_wrapper(uintptr_t);
+
+bool pthread_create_done;
+
+void *ThreadFn(void *) {
+  printf("bad threadfn\n");
+  return 0;
+}
+
+void *ThreadFn2(void *) {
+  printf("good threadfn\n");
+  pthread_create_done = true;
+  return 0;
+}
+
+bool in_gettimeofday;
+bool in_lgamma;
+
+int my_gettimeofday(struct timeval *p, void *q) {
+  p->tv_sec = 1;
+  p->tv_usec = 2;
+  return 42;
+}
+
+double my_lgamma(double x) {
+  return x;
+}
+
+extern "C" uintptr_t my_wrapper(uintptr_t f) {
+  if (f == (uintptr_t)ThreadFn)
+    return (uintptr_t)&ThreadFn2;
+  if (in_gettimeofday)
+    return (uintptr_t)my_gettimeofday;
+  if (in_lgamma)
+    return (uintptr_t)my_lgamma;
+  return f;
+}
+
+int main(void) {
+  __msan_set_indirect_call_wrapper((uintptr_t)my_wrapper);
+
+  // ThreadFn is called indirectly from a wrapper function in MSan rtl and
+  // is subject to indirect call wrapping (it could be an native-to-translated
+  // edge).
+  pthread_t t;
+  pthread_create(&t, 0, ThreadFn, 0);
+  pthread_join(t, 0);
+  assert(pthread_create_done);
+
+  // gettimeofday is intercepted in msan_interceptors.cc and the real one (from
+  // libc) is called indirectly.
+  struct timeval tv;
+  in_gettimeofday = true;
+  int res = gettimeofday(&tv, NULL);
+  in_gettimeofday = false;
+  assert(tv.tv_sec == 1);
+  assert(tv.tv_usec == 2);
+  assert(res == 42);
+
+  // lgamma is intercepted in sanitizer_common_interceptors.inc and is also
+  // called indirectly.
+  in_lgamma = true;
+  double dres = lgamma(1.1);
+  in_lgamma = false;
+  assert(dres == 1.1);
+  
+  return 0;
+}