summaryrefslogtreecommitdiff
path: root/lib/msan
diff options
context:
space:
mode:
Diffstat (limited to 'lib/msan')
-rw-r--r--lib/msan/CMakeLists.txt42
-rw-r--r--lib/msan/lit_tests/CMakeLists.txt31
-rw-r--r--lib/msan/lit_tests/Linux/glob.cc27
-rw-r--r--lib/msan/lit_tests/Linux/glob_altdirfunc.cc78
-rw-r--r--lib/msan/lit_tests/Linux/glob_nomatch.cc21
-rw-r--r--lib/msan/lit_tests/Linux/glob_test_root/aa0
-rw-r--r--lib/msan/lit_tests/Linux/glob_test_root/ab0
-rw-r--r--lib/msan/lit_tests/Linux/glob_test_root/ba0
-rw-r--r--lib/msan/lit_tests/Linux/lit.local.cfg9
-rw-r--r--lib/msan/lit_tests/Linux/syscalls.cc100
-rw-r--r--lib/msan/lit_tests/Linux/tcgetattr.cc21
-rw-r--r--lib/msan/lit_tests/SharedLibs/dso-origin-so.cc14
-rw-r--r--lib/msan/lit_tests/SharedLibs/dso-origin.h4
-rw-r--r--lib/msan/lit_tests/SharedLibs/lit.local.cfg4
-rw-r--r--lib/msan/lit_tests/Unit/lit.site.cfg.in13
-rw-r--r--lib/msan/lit_tests/allocator_returns_null.cc81
-rw-r--r--lib/msan/lit_tests/backtrace.cc26
-rw-r--r--lib/msan/lit_tests/c-strdup.c17
-rw-r--r--lib/msan/lit_tests/cxa_atexit.cc28
-rw-r--r--lib/msan/lit_tests/default_blacklist.cc3
-rw-r--r--lib/msan/lit_tests/dlerror.cc14
-rw-r--r--lib/msan/lit_tests/dso-origin.cc25
-rw-r--r--lib/msan/lit_tests/errno.cc17
-rw-r--r--lib/msan/lit_tests/getaddrinfo-positive.cc23
-rw-r--r--lib/msan/lit_tests/getaddrinfo.cc24
-rw-r--r--lib/msan/lit_tests/getline.cc30
-rw-r--r--lib/msan/lit_tests/getline_test_data2
-rw-r--r--lib/msan/lit_tests/heap-origin.cc31
-rw-r--r--lib/msan/lit_tests/initgroups.cc11
-rw-r--r--lib/msan/lit_tests/inline.cc20
-rw-r--r--lib/msan/lit_tests/insertvalue_origin.cc35
-rw-r--r--lib/msan/lit_tests/ioctl.cc20
-rw-r--r--lib/msan/lit_tests/ioctl_custom.cc33
-rw-r--r--lib/msan/lit_tests/keep-going-dso.cc33
-rw-r--r--lib/msan/lit_tests/keep-going.cc34
-rw-r--r--lib/msan/lit_tests/lit.cfg74
-rw-r--r--lib/msan/lit_tests/lit.site.cfg.in5
-rw-r--r--lib/msan/lit_tests/malloc_hook.cc36
-rw-r--r--lib/msan/lit_tests/no_sanitize_memory.cc34
-rw-r--r--lib/msan/lit_tests/no_sanitize_memory_prop.cc33
-rw-r--r--lib/msan/lit_tests/poison_in_free.cc16
-rw-r--r--lib/msan/lit_tests/ptrace.cc36
-rw-r--r--lib/msan/lit_tests/readdir64.cc27
-rw-r--r--lib/msan/lit_tests/scandir.cc56
-rw-r--r--lib/msan/lit_tests/scandir_null.cc34
-rw-r--r--lib/msan/lit_tests/scandir_test_root/aaa0
-rw-r--r--lib/msan/lit_tests/scandir_test_root/aab0
-rw-r--r--lib/msan/lit_tests/scandir_test_root/bbb0
-rw-r--r--lib/msan/lit_tests/select.cc22
-rw-r--r--lib/msan/lit_tests/setlocale.cc13
-rw-r--r--lib/msan/lit_tests/signal_stress_test.cc71
-rw-r--r--lib/msan/lit_tests/sigwait.cc30
-rw-r--r--lib/msan/lit_tests/sigwaitinfo.cc31
-rw-r--r--lib/msan/lit_tests/stack-origin.cc31
-rw-r--r--lib/msan/lit_tests/sync_lock_set_and_test.cc7
-rw-r--r--lib/msan/lit_tests/tzset.cc16
-rw-r--r--lib/msan/lit_tests/unaligned_read_origin.cc16
-rw-r--r--lib/msan/lit_tests/use-after-free.cc34
-rw-r--r--lib/msan/lit_tests/vector_cvt.cc23
-rw-r--r--lib/msan/lit_tests/vector_select.cc13
-rw-r--r--lib/msan/lit_tests/wrap_indirect_calls.cc64
-rw-r--r--lib/msan/lit_tests/wrap_indirect_calls/caller.cc51
-rw-r--r--lib/msan/lit_tests/wrap_indirect_calls/lit.local.cfg3
-rw-r--r--lib/msan/lit_tests/wrap_indirect_calls/one.cc3
-rw-r--r--lib/msan/lit_tests/wrap_indirect_calls/two.cc11
-rw-r--r--lib/msan/lit_tests/wrap_indirect_calls/wrapper.cc11
-rw-r--r--lib/msan/msan.cc394
-rw-r--r--lib/msan/msan.h156
-rw-r--r--lib/msan/msan_allocator.cc154
-rw-r--r--lib/msan/msan_allocator.h33
-rw-r--r--lib/msan/msan_chained_origin_depot.cc126
-rw-r--r--lib/msan/msan_chained_origin_depot.h29
-rw-r--r--lib/msan/msan_flags.h5
-rw-r--r--lib/msan/msan_interceptors.cc1030
-rw-r--r--lib/msan/msan_interface_internal.h75
-rw-r--r--lib/msan/msan_linux.cc156
-rw-r--r--lib/msan/msan_new_delete.cc13
-rw-r--r--lib/msan/msan_origin.h169
-rw-r--r--lib/msan/msan_report.cc221
-rw-r--r--lib/msan/msan_thread.cc93
-rw-r--r--lib/msan/msan_thread.h71
-rw-r--r--lib/msan/tests/CMakeLists.txt137
-rw-r--r--lib/msan/tests/msan_loadable.cc18
-rw-r--r--lib/msan/tests/msan_test.cc1322
-rw-r--r--lib/msan/tests/msandr_test_so.cc38
-rw-r--r--lib/msan/tests/msandr_test_so.h24
86 files changed, 2923 insertions, 3013 deletions
diff --git a/lib/msan/CMakeLists.txt b/lib/msan/CMakeLists.txt
index 06f3f65d8e38e..90d9face17311 100644
--- a/lib/msan/CMakeLists.txt
+++ b/lib/msan/CMakeLists.txt
@@ -4,47 +4,43 @@ include_directories(..)
set(MSAN_RTL_SOURCES
msan.cc
msan_allocator.cc
+ msan_chained_origin_depot.cc
msan_interceptors.cc
msan_linux.cc
msan_new_delete.cc
msan_report.cc
+ msan_thread.cc
)
-set(MSAN_RTL_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- -fno-rtti
- -fPIE
- # Prevent clang from generating libc calls.
- -ffreestanding)
-# Static runtime library.
+set(MSAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(MSAN_RTL_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE MSAN_RTL_CFLAGS)
+# Prevent clang from generating libc calls.
+append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding MSAN_RTL_CFLAGS)
+
set(MSAN_RUNTIME_LIBRARIES)
-set(arch "x86_64")
-if(CAN_TARGET_${arch})
- add_compiler_rt_static_runtime(clang_rt.msan-${arch} ${arch}
+
+# Static runtime library.
+add_custom_target(msan)
+foreach(arch ${MSAN_SUPPORTED_ARCH})
+ add_compiler_rt_runtime(clang_rt.msan-${arch} ${arch} STATIC
SOURCES ${MSAN_RTL_SOURCES}
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
CFLAGS ${MSAN_RTL_CFLAGS})
+ add_dependencies(msan clang_rt.msan-${arch})
list(APPEND MSAN_RUNTIME_LIBRARIES clang_rt.msan-${arch})
if(UNIX)
add_sanitizer_rt_symbols(clang_rt.msan-${arch} msan.syms.extra)
- list(APPEND MSAN_RUNTIME_LIBRARIES clang_rt.msan-${arch}-symbols)
+ add_dependencies(msan clang_rt.msan-${arch}-symbols)
endif()
-endif()
+endforeach()
add_compiler_rt_resource_file(msan_blacklist msan_blacklist.txt)
+add_dependencies(msan msan_blacklist)
+add_dependencies(compiler-rt msan)
-# We should only build MSan unit tests if we can build instrumented libcxx.
-set(MSAN_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/projects/libcxx)
-if(EXISTS ${MSAN_LIBCXX_PATH}/)
- set(MSAN_CAN_INSTRUMENT_LIBCXX TRUE)
-else()
- set(MSAN_CAN_INSTRUMENT_LIBCXX FALSE)
-endif()
-
-if(LLVM_INCLUDE_TESTS)
+if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)
endif()
-
-add_subdirectory(lit_tests)
diff --git a/lib/msan/lit_tests/CMakeLists.txt b/lib/msan/lit_tests/CMakeLists.txt
deleted file mode 100644
index 38d1e59e709e2..0000000000000
--- a/lib/msan/lit_tests/CMakeLists.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-set(MSAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
-set(MSAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..)
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
-
-if(MSAN_CAN_INSTRUMENT_LIBCXX)
- configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg)
-endif()
-
-if(COMPILER_RT_CAN_EXECUTE_TESTS AND CAN_TARGET_x86_64)
- # Run MSan tests only if we're sure we may produce working binaries.
- set(MSAN_TEST_DEPS
- ${SANITIZER_COMMON_LIT_TEST_DEPS}
- ${MSAN_RUNTIME_LIBRARIES}
- msan_blacklist)
- set(MSAN_TEST_PARAMS
- msan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
- if(LLVM_INCLUDE_TESTS AND MSAN_CAN_INSTRUMENT_LIBCXX)
- list(APPEND MSAN_TEST_DEPS MsanUnitTests)
- endif()
- add_lit_testsuite(check-msan "Running the MemorySanitizer tests"
- ${CMAKE_CURRENT_BINARY_DIR}
- PARAMS ${MSAN_TEST_PARAMS}
- DEPENDS ${MSAN_TEST_DEPS}
- )
- set_target_properties(check-msan PROPERTIES FOLDER "MSan tests")
-endif()
diff --git a/lib/msan/lit_tests/Linux/glob.cc b/lib/msan/lit_tests/Linux/glob.cc
deleted file mode 100644
index 387ce3cf5f1ae..0000000000000
--- a/lib/msan/lit_tests/Linux/glob.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %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/lib/msan/lit_tests/Linux/glob_altdirfunc.cc b/lib/msan/lit_tests/Linux/glob_altdirfunc.cc
deleted file mode 100644
index b8200c3ee8996..0000000000000
--- a/lib/msan/lit_tests/Linux/glob_altdirfunc.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %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/lib/msan/lit_tests/Linux/glob_nomatch.cc b/lib/msan/lit_tests/Linux/glob_nomatch.cc
deleted file mode 100644
index 0262034aec5bd..0000000000000
--- a/lib/msan/lit_tests/Linux/glob_nomatch.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %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/lib/msan/lit_tests/Linux/glob_test_root/aa b/lib/msan/lit_tests/Linux/glob_test_root/aa
deleted file mode 100644
index e69de29bb2d1d..0000000000000
--- a/lib/msan/lit_tests/Linux/glob_test_root/aa
+++ /dev/null
diff --git a/lib/msan/lit_tests/Linux/glob_test_root/ab b/lib/msan/lit_tests/Linux/glob_test_root/ab
deleted file mode 100644
index e69de29bb2d1d..0000000000000
--- a/lib/msan/lit_tests/Linux/glob_test_root/ab
+++ /dev/null
diff --git a/lib/msan/lit_tests/Linux/glob_test_root/ba b/lib/msan/lit_tests/Linux/glob_test_root/ba
deleted file mode 100644
index e69de29bb2d1d..0000000000000
--- a/lib/msan/lit_tests/Linux/glob_test_root/ba
+++ /dev/null
diff --git a/lib/msan/lit_tests/Linux/lit.local.cfg b/lib/msan/lit_tests/Linux/lit.local.cfg
deleted file mode 100644
index 57271b8078a49..0000000000000
--- a/lib/msan/lit_tests/Linux/lit.local.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-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/lib/msan/lit_tests/Linux/syscalls.cc b/lib/msan/lit_tests/Linux/syscalls.cc
deleted file mode 100644
index ec308bfe30caf..0000000000000
--- a/lib/msan/lit_tests/Linux/syscalls.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t 2>&1
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %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_post_io_submit(1, 0, 2, &iocbp);
- assert(__msan_test_shadow(buf, sizeof(buf)) == kFortyTwo);
-
- return 0;
-}
diff --git a/lib/msan/lit_tests/Linux/tcgetattr.cc b/lib/msan/lit_tests/Linux/tcgetattr.cc
deleted file mode 100644
index e6e101db884f5..0000000000000
--- a/lib/msan/lit_tests/Linux/tcgetattr.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %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/lib/msan/lit_tests/SharedLibs/dso-origin-so.cc b/lib/msan/lit_tests/SharedLibs/dso-origin-so.cc
deleted file mode 100644
index 8930a7159246b..0000000000000
--- a/lib/msan/lit_tests/SharedLibs/dso-origin-so.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-#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/lib/msan/lit_tests/SharedLibs/dso-origin.h b/lib/msan/lit_tests/SharedLibs/dso-origin.h
deleted file mode 100644
index ff926b3f61c88..0000000000000
--- a/lib/msan/lit_tests/SharedLibs/dso-origin.h
+++ /dev/null
@@ -1,4 +0,0 @@
-extern "C" {
-void my_access(int *p);
-void *my_alloc(unsigned sz);
-}
diff --git a/lib/msan/lit_tests/SharedLibs/lit.local.cfg b/lib/msan/lit_tests/SharedLibs/lit.local.cfg
deleted file mode 100644
index b3677c17a0f2a..0000000000000
--- a/lib/msan/lit_tests/SharedLibs/lit.local.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-# Sources in this directory are compiled as shared libraries and used by
-# tests in parent directory.
-
-config.suffixes = []
diff --git a/lib/msan/lit_tests/Unit/lit.site.cfg.in b/lib/msan/lit_tests/Unit/lit.site.cfg.in
deleted file mode 100644
index 8e67f557d7fde..0000000000000
--- a/lib/msan/lit_tests/Unit/lit.site.cfg.in
+++ /dev/null
@@ -1,13 +0,0 @@
-## 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@/lib/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.
-config.test_exec_root = "@MSAN_BINARY_DIR@/tests"
-config.test_source_root = config.test_exec_root
diff --git a/lib/msan/lit_tests/allocator_returns_null.cc b/lib/msan/lit_tests/allocator_returns_null.cc
deleted file mode 100644
index aaa85cce71134..0000000000000
--- a/lib/msan/lit_tests/allocator_returns_null.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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 %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %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/lib/msan/lit_tests/backtrace.cc b/lib/msan/lit_tests/backtrace.cc
deleted file mode 100644
index 48684c29c60d6..0000000000000
--- a/lib/msan/lit_tests/backtrace.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %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/lib/msan/lit_tests/c-strdup.c b/lib/msan/lit_tests/c-strdup.c
deleted file mode 100644
index 7772f0f307b72..0000000000000
--- a/lib/msan/lit_tests/c-strdup.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_msan -m64 -O0 %s -o %t && %t >%t.out 2>&1
-// RUN: %clang_msan -m64 -O1 %s -o %t && %t >%t.out 2>&1
-// RUN: %clang_msan -m64 -O2 %s -o %t && %t >%t.out 2>&1
-// RUN: %clang_msan -m64 -O3 %s -o %t && %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/lib/msan/lit_tests/cxa_atexit.cc b/lib/msan/lit_tests/cxa_atexit.cc
deleted file mode 100644
index f3641aadce03b..0000000000000
--- a/lib/msan/lit_tests/cxa_atexit.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %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/lib/msan/lit_tests/default_blacklist.cc b/lib/msan/lit_tests/default_blacklist.cc
deleted file mode 100644
index 32cc02257cb09..0000000000000
--- a/lib/msan/lit_tests/default_blacklist.cc
+++ /dev/null
@@ -1,3 +0,0 @@
-// 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/lib/msan/lit_tests/dlerror.cc b/lib/msan/lit_tests/dlerror.cc
deleted file mode 100644
index 281b3164fd7e9..0000000000000
--- a/lib/msan/lit_tests/dlerror.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %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/lib/msan/lit_tests/dso-origin.cc b/lib/msan/lit_tests/dso-origin.cc
deleted file mode 100644
index 13661c65e744b..0000000000000
--- a/lib/msan/lit_tests/dso-origin.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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 %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/lib/msan/lit_tests/errno.cc b/lib/msan/lit_tests/errno.cc
deleted file mode 100644
index af27ad0b03298..0000000000000
--- a/lib/msan/lit_tests/errno.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %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/lib/msan/lit_tests/getaddrinfo-positive.cc b/lib/msan/lit_tests/getaddrinfo-positive.cc
deleted file mode 100644
index 7fde1fdfab937..0000000000000
--- a/lib/msan/lit_tests/getaddrinfo-positive.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %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: UMR in __interceptor_getaddrinfo at offset 0 inside
- // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
- // CHECK: #0 {{.*}} in main {{.*}}getaddrinfo-positive.cc:[[@LINE-3]]
- return 0;
-}
diff --git a/lib/msan/lit_tests/getaddrinfo.cc b/lib/msan/lit_tests/getaddrinfo.cc
deleted file mode 100644
index 0518cf4733d0f..0000000000000
--- a/lib/msan/lit_tests/getaddrinfo.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %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/lib/msan/lit_tests/getline.cc b/lib/msan/lit_tests/getline.cc
deleted file mode 100644
index 27168a8856066..0000000000000
--- a/lib/msan/lit_tests/getline.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// RUN: %clangxx_msan -O0 %s -o %t && %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/lib/msan/lit_tests/getline_test_data b/lib/msan/lit_tests/getline_test_data
deleted file mode 100644
index 5ba1d4cec0dd2..0000000000000
--- a/lib/msan/lit_tests/getline_test_data
+++ /dev/null
@@ -1,2 +0,0 @@
-abcde
-12345
diff --git a/lib/msan/lit_tests/heap-origin.cc b/lib/msan/lit_tests/heap-origin.cc
deleted file mode 100644
index dfe7edd27e820..0000000000000
--- a/lib/msan/lit_tests/heap-origin.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %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 %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 %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 %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/lib/msan/lit_tests/initgroups.cc b/lib/msan/lit_tests/initgroups.cc
deleted file mode 100644
index adba5369579ac..0000000000000
--- a/lib/msan/lit_tests/initgroups.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %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/lib/msan/lit_tests/inline.cc b/lib/msan/lit_tests/inline.cc
deleted file mode 100644
index 4aeb15583f848..0000000000000
--- a/lib/msan/lit_tests/inline.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clangxx_msan -O3 %s -o %t && %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/lib/msan/lit_tests/insertvalue_origin.cc b/lib/msan/lit_tests/insertvalue_origin.cc
deleted file mode 100644
index 769ea45f8c4db..0000000000000
--- a/lib/msan/lit_tests/insertvalue_origin.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %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 %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/lib/msan/lit_tests/ioctl.cc b/lib/msan/lit_tests/ioctl.cc
deleted file mode 100644
index caff80c2e5d74..0000000000000
--- a/lib/msan/lit_tests/ioctl.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %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/lib/msan/lit_tests/ioctl_custom.cc b/lib/msan/lit_tests/ioctl_custom.cc
deleted file mode 100644
index 94ed528c70b91..0000000000000
--- a/lib/msan/lit_tests/ioctl_custom.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %t
-
-// RUN: %clangxx_msan -DPOSITIVE -m64 -O0 -g %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_msan -DPOSITIVE -m64 -O3 -g %s -o %t && not %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: UMR in ioctl{{.*}} at offset 0
- // 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/lib/msan/lit_tests/keep-going-dso.cc b/lib/msan/lit_tests/keep-going-dso.cc
deleted file mode 100644
index 6d006756a110f..0000000000000
--- a/lib/msan/lit_tests/keep-going-dso.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %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 %t >%t.out 2>&1
-// FileCheck %s <%t.out
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %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 %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 %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 %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/lib/msan/lit_tests/keep-going.cc b/lib/msan/lit_tests/keep-going.cc
deleted file mode 100644
index e33b137c76f78..0000000000000
--- a/lib/msan/lit_tests/keep-going.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// FileCheck %s <%t.out
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %t >%t.out 2>&1
-// FileCheck %s <%t.out
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %t >%t.out 2>&1
-// FileCheck %s <%t.out
-
-// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && not %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 %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 %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 %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 %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/lib/msan/lit_tests/lit.cfg b/lib/msan/lit_tests/lit.cfg
deleted file mode 100644
index da1bde6dd04ad..0000000000000
--- a/lib/msan/lit_tests/lit.cfg
+++ /dev/null
@@ -1,74 +0,0 @@
-# -*- Python -*-
-
-import os
-
-import lit.util
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-# Setup config name.
-config.name = 'MemorySanitizer'
-
-# Setup source root.
-config.test_source_root = os.path.dirname(__file__)
-
-def DisplayNoConfigMessage():
- lit_config.fatal("No site specific configuration available! " +
- "Try running your test from the build tree or running " +
- "make check-msan")
-
-# Figure out LLVM source root.
-llvm_src_root = getattr(config, 'llvm_src_root', None)
-if llvm_src_root is None:
- # We probably haven't loaded the site-specific configuration: the user
- # is likely trying to run a test file directly, and the site configuration
- # wasn't created by the build system.
- msan_site_cfg = lit_config.params.get('msan_site_config', None)
- if (msan_site_cfg) and (os.path.exists(msan_site_cfg)):
- lit_config.load_config(config, msan_site_cfg)
- raise SystemExit
-
- # Try to guess the location of site-specific configuration using llvm-config
- # util that can point where the build tree is.
- llvm_config = lit.util.which("llvm-config", config.environment["PATH"])
- if not llvm_config:
- DisplayNoConfigMessage()
-
- # Find out the presumed location of generated site config.
- llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip()
- msan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
- "lib", "msan", "lit_tests", "lit.site.cfg")
- if (not msan_site_cfg) or (not os.path.exists(msan_site_cfg)):
- DisplayNoConfigMessage()
-
- lit_config.load_config(config, msan_site_cfg)
- raise SystemExit
-
-# 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 = ["--driver-mode=g++ "] + clang_msan_cflags
-config.substitutions.append( ("%clang_msan ",
- " ".join([config.clang] + clang_msan_cflags) +
- " ") )
-config.substitutions.append( ("%clangxx_msan ",
- " ".join([config.clang] + 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/lib/msan/lit_tests/lit.site.cfg.in b/lib/msan/lit_tests/lit.site.cfg.in
deleted file mode 100644
index 946df778f3d39..0000000000000
--- a/lib/msan/lit_tests/lit.site.cfg.in
+++ /dev/null
@@ -1,5 +0,0 @@
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-
-# Load tool-specific config that would do the real work.
-lit_config.load_config(config, "@MSAN_SOURCE_DIR@/lit_tests/lit.cfg")
diff --git a/lib/msan/lit_tests/malloc_hook.cc b/lib/msan/lit_tests/malloc_hook.cc
deleted file mode 100644
index fc68fbc35fbb0..0000000000000
--- a/lib/msan/lit_tests/malloc_hook.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clangxx_msan -O2 %s -o %t
-// 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/lib/msan/lit_tests/no_sanitize_memory.cc b/lib/msan/lit_tests/no_sanitize_memory.cc
deleted file mode 100644
index 48afc17e35e92..0000000000000
--- a/lib/msan/lit_tests/no_sanitize_memory.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t >%t.out 2>&1
-
-// RUN: %clangxx_msan -m64 -O0 %s -o %t -DCHECK_IN_F && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O1 %s -o %t -DCHECK_IN_F && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O2 %s -o %t -DCHECK_IN_F && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O3 %s -o %t -DCHECK_IN_F && %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/lib/msan/lit_tests/no_sanitize_memory_prop.cc b/lib/msan/lit_tests/no_sanitize_memory_prop.cc
deleted file mode 100644
index 3551524788523..0000000000000
--- a/lib/msan/lit_tests/no_sanitize_memory_prop.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %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/lib/msan/lit_tests/poison_in_free.cc b/lib/msan/lit_tests/poison_in_free.cc
deleted file mode 100644
index f134d05abb1ee..0000000000000
--- a/lib/msan/lit_tests/poison_in_free.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_msan -O0 %s -o %t && not %t >%t.out 2>&1
-// FileCheck %s <%t.out
-// RUN: %clangxx_msan -O0 %s -o %t && MSAN_OPTIONS=poison_in_free=0 %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/lib/msan/lit_tests/ptrace.cc b/lib/msan/lit_tests/ptrace.cc
deleted file mode 100644
index d0e83eabd6a4e..0000000000000
--- a/lib/msan/lit_tests/ptrace.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-
-#include <assert.h>
-#include <stdio.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <sys/user.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-int main(void) {
- pid_t pid;
- pid = fork();
- if (pid == 0) { // child
- ptrace(PTRACE_TRACEME, 0, NULL, NULL);
- execl("/bin/true", "true", NULL);
- } else {
- wait(NULL);
- user_regs_struct regs;
- int res;
- res = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
- assert(!res);
- if (regs.rip)
- printf("%zx\n", regs.rip);
-
- user_fpregs_struct fpregs;
- res = ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs);
- assert(!res);
- if (fpregs.mxcsr)
- printf("%x\n", fpregs.mxcsr);
-
- ptrace(PTRACE_CONT, pid, NULL, NULL);
- wait(NULL);
- }
- return 0;
-}
diff --git a/lib/msan/lit_tests/readdir64.cc b/lib/msan/lit_tests/readdir64.cc
deleted file mode 100644
index 0ec106c741f51..0000000000000
--- a/lib/msan/lit_tests/readdir64.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t
-
-// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O1 -D_FILE_OFFSET_BITS=64 %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O2 -D_FILE_OFFSET_BITS=64 %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O3 -D_FILE_OFFSET_BITS=64 %s -o %t && %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/lib/msan/lit_tests/scandir.cc b/lib/msan/lit_tests/scandir.cc
deleted file mode 100644
index 94672e1adbeef..0000000000000
--- a/lib/msan/lit_tests/scandir.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p
-// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t %p
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %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/lib/msan/lit_tests/scandir_null.cc b/lib/msan/lit_tests/scandir_null.cc
deleted file mode 100644
index 84af7f418d219..0000000000000
--- a/lib/msan/lit_tests/scandir_null.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p
-// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t %p
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %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/lib/msan/lit_tests/scandir_test_root/aaa b/lib/msan/lit_tests/scandir_test_root/aaa
deleted file mode 100644
index e69de29bb2d1d..0000000000000
--- a/lib/msan/lit_tests/scandir_test_root/aaa
+++ /dev/null
diff --git a/lib/msan/lit_tests/scandir_test_root/aab b/lib/msan/lit_tests/scandir_test_root/aab
deleted file mode 100644
index e69de29bb2d1d..0000000000000
--- a/lib/msan/lit_tests/scandir_test_root/aab
+++ /dev/null
diff --git a/lib/msan/lit_tests/scandir_test_root/bbb b/lib/msan/lit_tests/scandir_test_root/bbb
deleted file mode 100644
index e69de29bb2d1d..0000000000000
--- a/lib/msan/lit_tests/scandir_test_root/bbb
+++ /dev/null
diff --git a/lib/msan/lit_tests/select.cc b/lib/msan/lit_tests/select.cc
deleted file mode 100644
index a169a2dd9118c..0000000000000
--- a/lib/msan/lit_tests/select.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %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/lib/msan/lit_tests/setlocale.cc b/lib/msan/lit_tests/setlocale.cc
deleted file mode 100644
index a22b744d74db7..0000000000000
--- a/lib/msan/lit_tests/setlocale.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %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/lib/msan/lit_tests/signal_stress_test.cc b/lib/msan/lit_tests/signal_stress_test.cc
deleted file mode 100644
index ea75eae1bdaaf..0000000000000
--- a/lib/msan/lit_tests/signal_stress_test.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// RUN: %clangxx_msan -std=c++11 -O0 %s -o %t && %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/lib/msan/lit_tests/sigwait.cc b/lib/msan/lit_tests/sigwait.cc
deleted file mode 100644
index 29aa86c938f2a..0000000000000
--- a/lib/msan/lit_tests/sigwait.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %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/lib/msan/lit_tests/sigwaitinfo.cc b/lib/msan/lit_tests/sigwaitinfo.cc
deleted file mode 100644
index d4f004598a62f..0000000000000
--- a/lib/msan/lit_tests/sigwaitinfo.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %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/lib/msan/lit_tests/stack-origin.cc b/lib/msan/lit_tests/stack-origin.cc
deleted file mode 100644
index b0b05d9658bfb..0000000000000
--- a/lib/msan/lit_tests/stack-origin.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %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 %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 %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 %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/lib/msan/lit_tests/sync_lock_set_and_test.cc b/lib/msan/lit_tests/sync_lock_set_and_test.cc
deleted file mode 100644
index 1023b3e543681..0000000000000
--- a/lib/msan/lit_tests/sync_lock_set_and_test.cc
+++ /dev/null
@@ -1,7 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-
-int main(void) {
- int i;
- __sync_lock_test_and_set(&i, 0);
- return i;
-}
diff --git a/lib/msan/lit_tests/tzset.cc b/lib/msan/lit_tests/tzset.cc
deleted file mode 100644
index 7e1c2cfad5666..0000000000000
--- a/lib/msan/lit_tests/tzset.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %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/lib/msan/lit_tests/unaligned_read_origin.cc b/lib/msan/lit_tests/unaligned_read_origin.cc
deleted file mode 100644
index fa29ab69de1b0..0000000000000
--- a/lib/msan/lit_tests/unaligned_read_origin.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %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 %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/lib/msan/lit_tests/use-after-free.cc b/lib/msan/lit_tests/use-after-free.cc
deleted file mode 100644
index ac47c0233a10f..0000000000000
--- a/lib/msan/lit_tests/use-after-free.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %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 %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 %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 %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/lib/msan/lit_tests/vector_cvt.cc b/lib/msan/lit_tests/vector_cvt.cc
deleted file mode 100644
index c200c77de96a7..0000000000000
--- a/lib/msan/lit_tests/vector_cvt.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-// RUN: %clangxx_msan -DPOSITIVE -m64 -O0 %s -o %t && not %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/lib/msan/lit_tests/vector_select.cc b/lib/msan/lit_tests/vector_select.cc
deleted file mode 100644
index e8d55423293c4..0000000000000
--- a/lib/msan/lit_tests/vector_select.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// 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/lib/msan/lit_tests/wrap_indirect_calls.cc b/lib/msan/lit_tests/wrap_indirect_calls.cc
deleted file mode 100644
index b4bac1ecbd222..0000000000000
--- a/lib/msan/lit_tests/wrap_indirect_calls.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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: %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: %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: %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: %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: %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/lib/msan/lit_tests/wrap_indirect_calls/caller.cc b/lib/msan/lit_tests/wrap_indirect_calls/caller.cc
deleted file mode 100644
index a0af8b7bb0c53..0000000000000
--- a/lib/msan/lit_tests/wrap_indirect_calls/caller.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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/lib/msan/lit_tests/wrap_indirect_calls/lit.local.cfg b/lib/msan/lit_tests/wrap_indirect_calls/lit.local.cfg
deleted file mode 100644
index 5e01230c09864..0000000000000
--- a/lib/msan/lit_tests/wrap_indirect_calls/lit.local.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-# Sources in this directory are used by tests in parent directory.
-
-config.suffixes = []
diff --git a/lib/msan/lit_tests/wrap_indirect_calls/one.cc b/lib/msan/lit_tests/wrap_indirect_calls/one.cc
deleted file mode 100644
index ab7bf4125c0a3..0000000000000
--- a/lib/msan/lit_tests/wrap_indirect_calls/one.cc
+++ /dev/null
@@ -1,3 +0,0 @@
-int f_other_object(int x, int y) {
- return x * y;
-}
diff --git a/lib/msan/lit_tests/wrap_indirect_calls/two.cc b/lib/msan/lit_tests/wrap_indirect_calls/two.cc
deleted file mode 100644
index c939a993bc9a0..0000000000000
--- a/lib/msan/lit_tests/wrap_indirect_calls/two.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-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/lib/msan/lit_tests/wrap_indirect_calls/wrapper.cc b/lib/msan/lit_tests/wrap_indirect_calls/wrapper.cc
deleted file mode 100644
index 8fcd0c635d964..0000000000000
--- a/lib/msan/lit_tests/wrap_indirect_calls/wrapper.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-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/lib/msan/msan.cc b/lib/msan/msan.cc
index 83b11e5c2ff31..853e448fab8ea 100644
--- a/lib/msan/msan.cc
+++ b/lib/msan/msan.cc
@@ -13,6 +13,9 @@
//===----------------------------------------------------------------------===//
#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
+#include "msan_thread.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
@@ -20,8 +23,8 @@
#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
-#include "interception/interception.h"
// ACHTUNG! No system header includes in this file.
@@ -31,22 +34,25 @@ using namespace __sanitizer;
static THREADLOCAL int msan_expect_umr = 0;
static THREADLOCAL int msan_expected_umr_found = 0;
-static int msan_running_under_dr = 0;
-
+// Function argument shadow. Each argument starts at the next available 8-byte
+// aligned address.
SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSizeInWords];
+THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSize / sizeof(u64)];
+// Function argument origin. Each argument starts at the same offset as the
+// corresponding shadow in (__msan_param_tls). Slightly weird, but changing this
+// would break compatibility with older prebuilt binaries.
SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSizeInWords];
+THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSize / sizeof(u32)];
SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSizeInWords];
+THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSize / sizeof(u64)];
SANITIZER_INTERFACE_ATTRIBUTE
THREADLOCAL u32 __msan_retval_origin_tls;
SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSizeInWords];
+THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)];
SANITIZER_INTERFACE_ATTRIBUTE
THREADLOCAL u64 __msan_va_arg_overflow_size_tls;
@@ -54,12 +60,7 @@ THREADLOCAL u64 __msan_va_arg_overflow_size_tls;
SANITIZER_INTERFACE_ATTRIBUTE
THREADLOCAL u32 __msan_origin_tls;
-static THREADLOCAL struct {
- uptr stack_top, stack_bottom;
-} __msan_stack_bounds;
-
static THREADLOCAL int is_in_symbolizer;
-static THREADLOCAL int is_in_loader;
extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_track_origins;
@@ -71,34 +72,10 @@ extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_keep_going;
namespace __msan {
-static bool IsRunningUnderDr() {
- bool result = false;
- MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- const sptr kBufSize = 4095;
- char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
- while (proc_maps.Next(/* start */0, /* end */0, /* file_offset */0,
- filename, kBufSize, /* protection */0)) {
- if (internal_strstr(filename, "libdynamorio") != 0) {
- result = true;
- break;
- }
- }
- UnmapOrDie(filename, kBufSize);
- return result;
-}
-
void EnterSymbolizer() { ++is_in_symbolizer; }
void ExitSymbolizer() { --is_in_symbolizer; }
bool IsInSymbolizer() { return is_in_symbolizer; }
-void EnterLoader() { ++is_in_loader; }
-void ExitLoader() { --is_in_loader; }
-
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE
-bool __msan_is_in_loader() { return is_in_loader; }
-}
-
static Flags msan_flags;
Flags *flags() {
@@ -110,6 +87,8 @@ bool msan_init_is_running;
int msan_report_count = 0;
+void (*death_callback)(void);
+
// Array of stack origins.
// FIXME: make it resizable.
static const uptr kNumStackOriginDescrs = 1024 * 1024;
@@ -118,33 +97,63 @@ static uptr StackOriginPC[kNumStackOriginDescrs];
static atomic_uint32_t NumStackOriginDescrs;
static void ParseFlagsFromString(Flags *f, const char *str) {
- ParseCommonFlagsFromString(str);
- ParseFlag(str, &f->poison_heap_with_zeroes, "poison_heap_with_zeroes");
- ParseFlag(str, &f->poison_stack_with_zeroes, "poison_stack_with_zeroes");
- ParseFlag(str, &f->poison_in_malloc, "poison_in_malloc");
- ParseFlag(str, &f->poison_in_free, "poison_in_free");
- ParseFlag(str, &f->exit_code, "exit_code");
+ CommonFlags *cf = common_flags();
+ ParseCommonFlagsFromString(cf, str);
+ ParseFlag(str, &f->poison_heap_with_zeroes, "poison_heap_with_zeroes", "");
+ ParseFlag(str, &f->poison_stack_with_zeroes, "poison_stack_with_zeroes", "");
+ ParseFlag(str, &f->poison_in_malloc, "poison_in_malloc", "");
+ ParseFlag(str, &f->poison_in_free, "poison_in_free", "");
+ ParseFlag(str, &f->exit_code, "exit_code", "");
if (f->exit_code < 0 || f->exit_code > 127) {
Printf("Exit code not in [0, 128) range: %d\n", f->exit_code);
Die();
}
- ParseFlag(str, &f->report_umrs, "report_umrs");
- ParseFlag(str, &f->wrap_signals, "wrap_signals");
+ ParseFlag(str, &f->origin_history_size, "origin_history_size", "");
+ if (f->origin_history_size < 0 ||
+ f->origin_history_size > Origin::kMaxDepth) {
+ Printf(
+ "Origin history size invalid: %d. Must be 0 (unlimited) or in [1, %d] "
+ "range.\n",
+ f->origin_history_size, Origin::kMaxDepth);
+ Die();
+ }
+ ParseFlag(str, &f->origin_history_per_stack_limit,
+ "origin_history_per_stack_limit", "");
+ // Limiting to kStackDepotMaxUseCount / 2 to avoid overflow in
+ // StackDepotHandle::inc_use_count_unsafe.
+ if (f->origin_history_per_stack_limit < 0 ||
+ f->origin_history_per_stack_limit > kStackDepotMaxUseCount / 2) {
+ Printf(
+ "Origin per-stack limit invalid: %d. Must be 0 (unlimited) or in [1, "
+ "%d] range.\n",
+ f->origin_history_per_stack_limit, kStackDepotMaxUseCount / 2);
+ Die();
+ }
+
+ ParseFlag(str, &f->report_umrs, "report_umrs", "");
+ ParseFlag(str, &f->wrap_signals, "wrap_signals", "");
+ ParseFlag(str, &f->print_stats, "print_stats", "");
+ ParseFlag(str, &f->atexit, "atexit", "");
+ ParseFlag(str, &f->store_context_size, "store_context_size", "");
+ if (f->store_context_size < 1) f->store_context_size = 1;
// keep_going is an old name for halt_on_error,
// and it has inverse meaning.
f->halt_on_error = !f->halt_on_error;
- ParseFlag(str, &f->halt_on_error, "keep_going");
+ ParseFlag(str, &f->halt_on_error, "keep_going", "");
f->halt_on_error = !f->halt_on_error;
- ParseFlag(str, &f->halt_on_error, "halt_on_error");
+ ParseFlag(str, &f->halt_on_error, "halt_on_error", "");
}
static void InitializeFlags(Flags *f, const char *options) {
CommonFlags *cf = common_flags();
- SetCommonFlagDefaults();
+ SetCommonFlagsDefaults(cf);
cf->external_symbolizer_path = GetEnv("MSAN_SYMBOLIZER_PATH");
cf->malloc_context_size = 20;
cf->handle_ioctl = true;
+ // FIXME: test and enable.
+ cf->check_printf = false;
+ cf->intercept_tls_get_addr = true;
internal_memset(f, 0, sizeof(*f));
f->poison_heap_with_zeroes = false;
@@ -152,9 +161,14 @@ static void InitializeFlags(Flags *f, const char *options) {
f->poison_in_malloc = true;
f->poison_in_free = true;
f->exit_code = 77;
+ f->origin_history_size = Origin::kMaxDepth;
+ f->origin_history_per_stack_limit = 20000;
f->report_umrs = true;
f->wrap_signals = true;
+ f->print_stats = false;
+ f->atexit = false;
f->halt_on_error = !&__msan_keep_going;
+ f->store_context_size = 20;
// Override from user-specified string.
if (__msan_default_options)
@@ -162,39 +176,22 @@ static void InitializeFlags(Flags *f, const char *options) {
ParseFlagsFromString(f, options);
}
-static void GetCurrentStackBounds(uptr *stack_top, uptr *stack_bottom) {
- if (__msan_stack_bounds.stack_top == 0) {
- // Break recursion (GetStackTrace -> GetThreadStackTopAndBottom ->
- // realloc -> GetStackTrace).
- __msan_stack_bounds.stack_top = __msan_stack_bounds.stack_bottom = 1;
- GetThreadStackTopAndBottom(/* at_initialization */false,
- &__msan_stack_bounds.stack_top,
- &__msan_stack_bounds.stack_bottom);
- }
- *stack_top = __msan_stack_bounds.stack_top;
- *stack_bottom = __msan_stack_bounds.stack_bottom;
-}
-
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
bool request_fast_unwind) {
- if (!StackTrace::WillUseFastUnwind(request_fast_unwind)) {
+ MsanThread *t = GetCurrentThread();
+ if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) {
// Block reports from our interceptors during _Unwind_Backtrace.
SymbolizerScope sym_scope;
- return stack->Unwind(max_s, pc, bp, 0, 0, request_fast_unwind);
+ return stack->Unwind(max_s, pc, bp, 0, 0, 0, request_fast_unwind);
}
- uptr stack_top, stack_bottom;
- GetCurrentStackBounds(&stack_top, &stack_bottom);
- stack->Unwind(max_s, pc, bp, stack_top, stack_bottom, request_fast_unwind);
+ stack->Unwind(max_s, pc, bp, 0, t->stack_top(), t->stack_bottom(),
+ request_fast_unwind);
}
void PrintWarning(uptr pc, uptr bp) {
PrintWarningWithOrigin(pc, bp, __msan_origin_tls);
}
-bool OriginIsValid(u32 origin) {
- return origin != 0 && origin != (u32)-1;
-}
-
void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin) {
if (msan_expect_umr) {
// Printf("Expected UMR\n");
@@ -205,15 +202,13 @@ void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin) {
++msan_report_count;
- StackTrace stack;
- GetStackTrace(&stack, kStackTraceMax, pc, bp,
- common_flags()->fast_unwind_on_fatal);
+ GET_FATAL_STACK_TRACE_PC_BP(pc, bp);
u32 report_origin =
- (__msan_get_track_origins() && OriginIsValid(origin)) ? origin : 0;
+ (__msan_get_track_origins() && Origin::isValidId(origin)) ? origin : 0;
ReportUMR(&stack, report_origin);
- if (__msan_get_track_origins() && !OriginIsValid(origin)) {
+ if (__msan_get_track_origins() && !Origin::isValidId(origin)) {
Printf(
" ORIGIN: invalid (%x). Might be a bug in MemorySanitizer origin "
"tracking.\n This could still be a bug in your code, too!\n",
@@ -242,7 +237,8 @@ void ScopedThreadLocalStateBackup::Restore() {
internal_memset(__msan_va_arg_tls, 0, sizeof(__msan_va_arg_tls));
if (__msan_get_track_origins()) {
- internal_memset(&__msan_retval_origin_tls, 0, sizeof(__msan_retval_tls));
+ internal_memset(&__msan_retval_origin_tls, 0,
+ sizeof(__msan_retval_origin_tls));
internal_memset(__msan_param_origin_tls, 0,
sizeof(__msan_param_origin_tls));
}
@@ -251,25 +247,71 @@ void ScopedThreadLocalStateBackup::Restore() {
void UnpoisonThreadLocalState() {
}
-const char *GetOriginDescrIfStack(u32 id, uptr *pc) {
- if ((id >> 31) == 0) return 0;
- id &= (1U << 31) - 1;
+const char *GetStackOriginDescr(u32 id, uptr *pc) {
CHECK_LT(id, kNumStackOriginDescrs);
if (pc) *pc = StackOriginPC[id];
return StackOriginDescr[id];
}
+u32 ChainOrigin(u32 id, StackTrace *stack) {
+ MsanThread *t = GetCurrentThread();
+ if (t && t->InSignalHandler())
+ return id;
+
+ Origin o = Origin::FromRawId(id);
+ Origin chained = Origin::CreateChainedOrigin(o, stack);
+ return chained.raw_id();
+}
+
} // namespace __msan
// Interface.
using namespace __msan;
+#define MSAN_MAYBE_WARNING(type, size) \
+ void __msan_maybe_warning_##size(type s, u32 o) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ if (UNLIKELY(s)) { \
+ PrintWarningWithOrigin(pc, bp, o); \
+ if (__msan::flags()->halt_on_error) { \
+ Printf("Exiting\n"); \
+ Die(); \
+ } \
+ } \
+ }
+
+MSAN_MAYBE_WARNING(u8, 1)
+MSAN_MAYBE_WARNING(u16, 2)
+MSAN_MAYBE_WARNING(u32, 4)
+MSAN_MAYBE_WARNING(u64, 8)
+
+#define MSAN_MAYBE_STORE_ORIGIN(type, size) \
+ void __msan_maybe_store_origin_##size(type s, void *p, u32 o) { \
+ if (UNLIKELY(s)) { \
+ if (__msan_get_track_origins() > 1) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ GET_STORE_STACK_TRACE_PC_BP(pc, bp); \
+ o = ChainOrigin(o, &stack); \
+ } \
+ *(u32 *)MEM_TO_ORIGIN((uptr)p & ~3UL) = o; \
+ } \
+ }
+
+MSAN_MAYBE_STORE_ORIGIN(u8, 1)
+MSAN_MAYBE_STORE_ORIGIN(u16, 2)
+MSAN_MAYBE_STORE_ORIGIN(u32, 4)
+MSAN_MAYBE_STORE_ORIGIN(u64, 8)
+
void __msan_warning() {
GET_CALLER_PC_BP_SP;
(void)sp;
PrintWarning(pc, bp);
if (__msan::flags()->halt_on_error) {
+ if (__msan::flags()->print_stats)
+ ReportStats();
Printf("Exiting\n");
Die();
}
@@ -279,11 +321,14 @@ void __msan_warning_noreturn() {
GET_CALLER_PC_BP_SP;
(void)sp;
PrintWarning(pc, bp);
+ if (__msan::flags()->print_stats)
+ ReportStats();
Printf("Exiting\n");
Die();
}
void __msan_init() {
+ CHECK(!msan_init_is_running);
if (msan_inited) return;
msan_init_is_running = 1;
SanitizerToolName = "MemorySanitizer";
@@ -293,6 +338,7 @@ void __msan_init() {
const char *msan_options = GetEnv("MSAN_OPTIONS");
InitializeFlags(&msan_flags, msan_options);
+ if (common_flags()->help) PrintFlagDescriptions();
__sanitizer_set_report_path(common_flags()->log_path);
InitializeInterceptors();
@@ -300,25 +346,21 @@ void __msan_init() {
if (MSAN_REPLACE_OPERATORS_NEW_AND_DELETE)
ReplaceOperatorsNewAndDelete();
+ DisableCoreDumperIfNecessary();
if (StackSizeIsUnlimited()) {
- if (common_flags()->verbosity)
- Printf("Unlimited stack, doing reexec\n");
+ VPrintf(1, "Unlimited stack, doing reexec\n");
// A reasonably large stack size. It is bigger than the usual 8Mb, because,
// well, the program could have been run with unlimited stack for a reason.
SetStackSizeLimitInBytes(32 * 1024 * 1024);
ReExec();
}
- if (common_flags()->verbosity)
- Printf("MSAN_OPTIONS: %s\n", msan_options ? msan_options : "<empty>");
+ VPrintf(1, "MSAN_OPTIONS: %s\n", msan_options ? msan_options : "<empty>");
- msan_running_under_dr = IsRunningUnderDr();
__msan_clear_on_return();
- if (__msan_get_track_origins() && common_flags()->verbosity > 0)
- Printf("msan_track_origins\n");
- if (!InitShadow(/* prot1 */ false, /* prot2 */ true, /* map_shadow */ true,
- __msan_get_track_origins())) {
- // FIXME: prot1 = false is only required when running under DR.
+ if (__msan_get_track_origins())
+ VPrintf(1, "msan_track_origins\n");
+ if (!InitShadow(/* map_shadow */ true, __msan_get_track_origins())) {
Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
Printf("FATAL: Disabling ASLR is known to cause this error.\n");
@@ -328,19 +370,21 @@ void __msan_init() {
Die();
}
- const char *external_symbolizer = common_flags()->external_symbolizer_path;
- bool external_symbolizer_started =
- Symbolizer::Init(external_symbolizer)->IsExternalAvailable();
- if (external_symbolizer && external_symbolizer[0]) {
- CHECK(external_symbolizer_started);
+ Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer);
+
+ if (common_flags()->coverage) {
+ __sanitizer_cov_init();
+ Atexit(__sanitizer_cov_dump);
}
- Symbolizer::Get()->AddHooks(EnterSymbolizer, ExitSymbolizer);
- GetThreadStackTopAndBottom(/* at_initialization */true,
- &__msan_stack_bounds.stack_top,
- &__msan_stack_bounds.stack_bottom);
- if (common_flags()->verbosity)
- Printf("MemorySanitizer init done\n");
+ MsanTSDInit(MsanTSDDtor);
+
+ MsanThread *main_thread = MsanThread::Create(0, 0);
+ SetCurrentThread(main_thread);
+ main_thread->ThreadStart();
+
+ VPrintf(1, "MemorySanitizer init done\n");
+
msan_init_is_running = 0;
msan_inited = 1;
}
@@ -359,9 +403,7 @@ void __msan_set_expect_umr(int expect_umr) {
} else if (!msan_expected_umr_found) {
GET_CALLER_PC_BP_SP;
(void)sp;
- StackTrace stack;
- GetStackTrace(&stack, kStackTraceMax, pc, bp,
- common_flags()->fast_unwind_on_fatal);
+ GET_FATAL_STACK_TRACE_PC_BP(pc, bp);
ReportExpectedUMRNotFound(&stack);
Die();
}
@@ -373,75 +415,66 @@ void __msan_print_shadow(const void *x, uptr size) {
Printf("Not a valid application address: %p\n", x);
return;
}
+
+ DescribeMemoryRange(x, size);
+}
+
+void __msan_dump_shadow(const void *x, uptr size) {
+ if (!MEM_IS_APP(x)) {
+ Printf("Not a valid application address: %p\n", x);
+ return;
+ }
+
unsigned char *s = (unsigned char*)MEM_TO_SHADOW(x);
- u32 *o = (u32*)MEM_TO_ORIGIN(x);
for (uptr i = 0; i < size; i++) {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ Printf("%x%x ", s[i] & 0xf, s[i] >> 4);
+#else
Printf("%x%x ", s[i] >> 4, s[i] & 0xf);
- }
- Printf("\n");
- if (__msan_get_track_origins()) {
- for (uptr i = 0; i < size / 4; i++) {
- Printf(" o: %x ", o[i]);
- }
- Printf("\n");
- }
-}
-
-void __msan_print_param_shadow() {
- for (int i = 0; i < 16; i++) {
- Printf("#%d:%zx ", i, __msan_param_tls[i]);
+#endif
}
Printf("\n");
}
sptr __msan_test_shadow(const void *x, uptr size) {
- unsigned char *s = (unsigned char*)MEM_TO_SHADOW((uptr)x);
+ if (!MEM_IS_APP(x)) return -1;
+ unsigned char *s = (unsigned char *)MEM_TO_SHADOW((uptr)x);
for (uptr i = 0; i < size; ++i)
if (s[i])
return i;
return -1;
}
+void __msan_check_mem_is_initialized(const void *x, uptr size) {
+ if (!__msan::flags()->report_umrs) return;
+ sptr offset = __msan_test_shadow(x, size);
+ if (offset < 0)
+ return;
+
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ ReportUMRInsideAddressRange(__func__, x, size, offset);
+ __msan::PrintWarningWithOrigin(pc, bp,
+ __msan_get_origin(((const char *)x) + offset));
+ if (__msan::flags()->halt_on_error) {
+ Printf("Exiting\n");
+ Die();
+ }
+}
+
int __msan_set_poison_in_malloc(int do_poison) {
int old = flags()->poison_in_malloc;
flags()->poison_in_malloc = do_poison;
return old;
}
-int __msan_has_dynamic_component() {
- return msan_running_under_dr;
-}
+int __msan_has_dynamic_component() { return false; }
NOINLINE
void __msan_clear_on_return() {
__msan_param_tls[0] = 0;
}
-static void* get_tls_base() {
- u64 p;
- asm("mov %%fs:0, %0"
- : "=r"(p) ::);
- return (void*)p;
-}
-
-int __msan_get_retval_tls_offset() {
- // volatile here is needed to avoid UB, because the compiler thinks that we
- // are doing address arithmetics on unrelated pointers, and takes some
- // shortcuts
- volatile sptr retval_tls_p = (sptr)&__msan_retval_tls;
- volatile sptr tls_base_p = (sptr)get_tls_base();
- return retval_tls_p - tls_base_p;
-}
-
-int __msan_get_param_tls_offset() {
- // volatile here is needed to avoid UB, because the compiler thinks that we
- // are doing address arithmetics on unrelated pointers, and takes some
- // shortcuts
- volatile sptr param_tls_p = (sptr)&__msan_param_tls;
- volatile sptr tls_base_p = (sptr)get_tls_base();
- return param_tls_p - tls_base_p;
-}
-
void __msan_partial_poison(const void* data, void* shadow, uptr size) {
internal_memcpy((void*)MEM_TO_SHADOW((uptr)data), shadow, size);
}
@@ -460,8 +493,8 @@ void __msan_set_origin(const void *a, uptr size, u32 origin) {
uptr beg = x & ~3UL; // align down.
uptr end = (x + size + 3) & ~3UL; // align up.
u64 origin64 = ((u64)origin << 32) | origin;
- // This is like memset, but the value is 32-bit. We unroll by 2 two write
- // 64-bits at once. May want to unroll further to get 128-bit stores.
+ // This is like memset, but the value is 32-bit. We unroll by 2 to write
+ // 64 bits at once. May want to unroll further to get 128-bit stores.
if (beg & 7ULL) {
*(u32*)beg = origin;
beg += 4;
@@ -475,11 +508,11 @@ void __msan_set_origin(const void *a, uptr size, u32 origin) {
// 'descr' is created at compile time and contains '----' in the beginning.
// When we see descr for the first time we replace '----' with a uniq id
// and set the origin to (id | (31-th bit)).
-void __msan_set_alloca_origin(void *a, uptr size, const char *descr) {
+void __msan_set_alloca_origin(void *a, uptr size, char *descr) {
__msan_set_alloca_origin4(a, size, descr, 0);
}
-void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc) {
+void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc) {
static const u32 dash = '-';
static const u32 first_timer =
dash + (dash << 8) + (dash << 16) + (dash << 24);
@@ -487,23 +520,25 @@ void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc) {
bool print = false; // internal_strstr(descr + 4, "AllocaTOTest") != 0;
u32 id = *id_ptr;
if (id == first_timer) {
- id = atomic_fetch_add(&NumStackOriginDescrs,
- 1, memory_order_relaxed);
+ u32 idx = atomic_fetch_add(&NumStackOriginDescrs, 1, memory_order_relaxed);
+ CHECK_LT(idx, kNumStackOriginDescrs);
+ StackOriginDescr[idx] = descr + 4;
+ StackOriginPC[idx] = pc;
+ id = Origin::CreateStackOrigin(idx).raw_id();
*id_ptr = id;
- CHECK_LT(id, kNumStackOriginDescrs);
- StackOriginDescr[id] = descr + 4;
- StackOriginPC[id] = pc;
if (print)
- Printf("First time: id=%d %s %p \n", id, descr + 4, pc);
+ Printf("First time: idx=%d id=%d %s %p \n", idx, id, descr + 4, pc);
}
- id |= 1U << 31;
if (print)
Printf("__msan_set_alloca_origin: descr=%s id=%x\n", descr + 4, id);
__msan_set_origin(a, size, id);
}
-const char *__msan_get_origin_descr_if_stack(u32 id) {
- return GetOriginDescrIfStack(id, 0);
+u32 __msan_chain_origin(u32 id) {
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ GET_STORE_STACK_TRACE_PC_BP(pc, bp);
+ return ChainOrigin(id, &stack);
}
u32 __msan_get_origin(const void *a) {
@@ -521,40 +556,50 @@ u32 __msan_get_umr_origin() {
u16 __sanitizer_unaligned_load16(const uu16 *p) {
__msan_retval_tls[0] = *(uu16 *)MEM_TO_SHADOW((uptr)p);
if (__msan_get_track_origins())
- __msan_retval_origin_tls = *(uu32 *)MEM_TO_ORIGIN((uptr)p);
+ __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p));
return *p;
}
u32 __sanitizer_unaligned_load32(const uu32 *p) {
__msan_retval_tls[0] = *(uu32 *)MEM_TO_SHADOW((uptr)p);
if (__msan_get_track_origins())
- __msan_retval_origin_tls = *(uu32 *)MEM_TO_ORIGIN((uptr)p);
+ __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p));
return *p;
}
u64 __sanitizer_unaligned_load64(const uu64 *p) {
__msan_retval_tls[0] = *(uu64 *)MEM_TO_SHADOW((uptr)p);
if (__msan_get_track_origins())
- __msan_retval_origin_tls = *(uu32 *)MEM_TO_ORIGIN((uptr)p);
+ __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p));
return *p;
}
void __sanitizer_unaligned_store16(uu16 *p, u16 x) {
- *(uu16 *)MEM_TO_SHADOW((uptr)p) = __msan_param_tls[1];
- if (__msan_get_track_origins())
- *(uu32 *)MEM_TO_ORIGIN((uptr)p) = __msan_param_origin_tls[1];
+ u16 s = __msan_param_tls[1];
+ *(uu16 *)MEM_TO_SHADOW((uptr)p) = s;
+ if (s && __msan_get_track_origins())
+ if (uu32 o = __msan_param_origin_tls[2])
+ SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o);
*p = x;
}
void __sanitizer_unaligned_store32(uu32 *p, u32 x) {
- *(uu32 *)MEM_TO_SHADOW((uptr)p) = __msan_param_tls[1];
- if (__msan_get_track_origins())
- *(uu32 *)MEM_TO_ORIGIN((uptr)p) = __msan_param_origin_tls[1];
+ u32 s = __msan_param_tls[1];
+ *(uu32 *)MEM_TO_SHADOW((uptr)p) = s;
+ if (s && __msan_get_track_origins())
+ if (uu32 o = __msan_param_origin_tls[2])
+ SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o);
*p = x;
}
void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
- *(uu64 *)MEM_TO_SHADOW((uptr)p) = __msan_param_tls[1];
- if (__msan_get_track_origins())
- *(uu32 *)MEM_TO_ORIGIN((uptr)p) = __msan_param_origin_tls[1];
+ u64 s = __msan_param_tls[1];
+ *(uu64 *)MEM_TO_SHADOW((uptr)p) = s;
+ if (s && __msan_get_track_origins())
+ if (uu32 o = __msan_param_origin_tls[2])
+ SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o);
*p = x;
}
+void __msan_set_death_callback(void (*callback)(void)) {
+ death_callback = callback;
+}
+
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
@@ -562,3 +607,10 @@ const char* __msan_default_options() { return ""; }
} // extern "C"
#endif
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME());
+ stack.Print();
+}
+} // extern "C"
diff --git a/lib/msan/msan.h b/lib/msan/msan.h
index 4e6c6194505e4..9bc1e4c6a4473 100644
--- a/lib/msan/msan.h
+++ b/lib/msan/msan.h
@@ -25,15 +25,94 @@
# define MSAN_REPLACE_OPERATORS_NEW_AND_DELETE 1
#endif
-#define MEM_TO_SHADOW(mem) (((uptr)mem) & ~0x400000000000ULL)
-#define SHADOW_TO_ORIGIN(shadow) (((uptr)shadow) + 0x200000000000ULL)
-#define MEM_TO_ORIGIN(mem) (SHADOW_TO_ORIGIN(MEM_TO_SHADOW(mem)))
-#define MEM_IS_APP(mem) ((uptr)mem >= 0x600000000000ULL)
+/*
+C/C++ on FreeBSD
+0000 0000 0000 - 00ff ffff ffff: Low memory: main binary, MAP_32BIT mappings and modules
+0100 0000 0000 - 0fff ffff ffff: Bad1
+1000 0000 0000 - 30ff ffff ffff: Shadow
+3100 0000 0000 - 37ff ffff ffff: Bad2
+3800 0000 0000 - 58ff ffff ffff: Origins
+5900 0000 0000 - 5fff ffff ffff: Bad3
+6000 0000 0000 - 7fff ffff ffff: High memory: heap, modules and main thread stack
+
+C/C++ on Linux/PIE
+0000 0000 0000 - 1fff ffff ffff: Bad1
+2000 0000 0000 - 3fff ffff ffff: Shadow
+4000 0000 0000 - 5fff ffff ffff: Origins
+6000 0000 0000 - 7fff ffff ffff: Main memory
+
+C/C++ on Mips
+0000 0000 0000 - 009f ffff ffff: Bad1
+00a0 0000 0000 - 00bf ffff ffff: Shadow
+00c0 0000 0000 - 00df ffff ffff: Origins
+00e0 0000 0000 - 00ff ffff ffff: Main memory
+*/
+
+#if SANITIZER_LINUX && defined(__mips64)
+const uptr kLowMemBeg = 0;
+const uptr kLowMemSize = 0;
+const uptr kHighMemBeg = 0x00e000000000;
+const uptr kHighMemSize = 0x002000000000;
+const uptr kShadowBeg = 0x00a000000000;
+const uptr kShadowSize = 0x002000000000;
+const uptr kOriginsBeg = 0x00c000000000;
+# define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x4000000000ULL)
+#elif SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 64
+const uptr kLowMemBeg = 0x000000000000;
+const uptr kLowMemSize = 0x010000000000;
+const uptr kHighMemBeg = 0x600000000000;
+const uptr kHighMemSize = 0x200000000000;
+const uptr kShadowBeg = 0x100000000000;
+const uptr kShadowSize = 0x210000000000;
+const uptr kOriginsBeg = 0x380000000000;
+// Maps low and high app ranges to contiguous space with zero base:
+// Low: 0000 0000 0000 - 00ff ffff ffff -> 2000 0000 0000 - 20ff ffff ffff
+// High: 6000 0000 0000 - 7fff ffff ffff -> 0000 0000 0000 - 1fff ffff ffff
+# define LINEARIZE_MEM(mem) \
+ (((uptr)(mem) & ~0xc00000000000ULL) ^ 0x200000000000ULL)
+# define MEM_TO_SHADOW(mem) (LINEARIZE_MEM((mem)) + 0x100000000000ULL)
+#elif SANITIZER_LINUX && SANITIZER_WORDSIZE == 64
+const uptr kLowMemBeg = 0;
+const uptr kLowMemSize = 0;
+const uptr kHighMemBeg = 0x600000000000;
+const uptr kHighMemSize = 0x200000000000;
+const uptr kShadowBeg = 0x200000000000;
+const uptr kShadowSize = 0x200000000000;
+const uptr kOriginsBeg = 0x400000000000;
+# define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x400000000000ULL)
+#else
+#error "Unsupported platform"
+#endif
+
+const uptr kBad1Beg = kLowMemBeg + kLowMemSize;
+const uptr kBad1Size = kShadowBeg - kBad1Beg;
+
+const uptr kBad2Beg = kShadowBeg + kShadowSize;
+const uptr kBad2Size = kOriginsBeg - kBad2Beg;
+
+const uptr kOriginsSize = kShadowSize;
+
+const uptr kBad3Beg = kOriginsBeg + kOriginsSize;
+const uptr kBad3Size = kHighMemBeg - kBad3Beg;
+
+#define SHADOW_TO_ORIGIN(shadow) \
+ (((uptr)(shadow)) + (kOriginsBeg - kShadowBeg))
+
+#define MEM_TO_ORIGIN(mem) (SHADOW_TO_ORIGIN(MEM_TO_SHADOW((mem))))
+
+#define MEM_IS_APP(mem) \
+ ((kLowMemSize > 0 && (uptr)(mem) < kLowMemSize) || \
+ (uptr)(mem) >= kHighMemBeg)
+
#define MEM_IS_SHADOW(mem) \
- ((uptr)mem >= 0x200000000000ULL && (uptr)mem <= 0x400000000000ULL)
+ ((uptr)(mem) >= kShadowBeg && (uptr)(mem) < kShadowBeg + kShadowSize)
-const int kMsanParamTlsSizeInWords = 100;
-const int kMsanRetvalTlsSizeInWords = 100;
+#define MEM_IS_ORIGIN(mem) \
+ ((uptr)(mem) >= kOriginsBeg && (uptr)(mem) < kOriginsBeg + kOriginsSize)
+
+// These constants must be kept in sync with the ones in MemorySanitizer.cc.
+const int kMsanParamTlsSize = 800;
+const int kMsanRetvalTlsSize = 800;
namespace __msan {
extern int msan_inited;
@@ -41,7 +120,7 @@ extern bool msan_init_is_running;
extern int msan_report_count;
bool ProtectRange(uptr beg, uptr end);
-bool InitShadow(bool prot1, bool prot2, bool map_shadow, bool init_origins);
+bool InitShadow(bool map_shadow, bool init_origins);
char *GetProcSelfMaps();
void InitializeInterceptors();
@@ -53,7 +132,7 @@ void InstallTrapHandler();
void InstallAtExitHandler();
void ReplaceOperatorsNewAndDelete();
-const char *GetOriginDescrIfStack(u32 id, uptr *pc);
+const char *GetStackOriginDescr(u32 id, uptr *pc);
void EnterSymbolizer();
void ExitSymbolizer();
@@ -64,31 +143,56 @@ struct SymbolizerScope {
~SymbolizerScope() { ExitSymbolizer(); }
};
-void EnterLoader();
-void ExitLoader();
-
void MsanDie();
void PrintWarning(uptr pc, uptr bp);
void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin);
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
bool request_fast_unwind);
void ReportUMR(StackTrace *stack, u32 origin);
void ReportExpectedUMRNotFound(StackTrace *stack);
+void ReportStats();
void ReportAtExitStatistics();
+void DescribeMemoryRange(const void *x, uptr size);
+void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size,
+ uptr offset);
// Unpoison first n function arguments.
void UnpoisonParam(uptr n);
void UnpoisonThreadLocalState();
-#define GET_MALLOC_STACK_TRACE \
- StackTrace stack; \
- stack.size = 0; \
- if (__msan_get_track_origins() && msan_inited) \
- GetStackTrace(&stack, common_flags()->malloc_context_size, \
- StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
- common_flags()->fast_unwind_on_malloc)
+u32 GetOriginIfPoisoned(uptr a, uptr size);
+void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size, u32 src_origin);
+void CopyOrigin(void *dst, const void *src, uptr size, StackTrace *stack);
+void MovePoison(void *dst, const void *src, uptr size, StackTrace *stack);
+void CopyPoison(void *dst, const void *src, uptr size, StackTrace *stack);
+
+// Returns a "chained" origin id, pointing to the given stack trace followed by
+// the previous origin id.
+u32 ChainOrigin(u32 id, StackTrace *stack);
+
+#define GET_MALLOC_STACK_TRACE \
+ BufferedStackTrace stack; \
+ if (__msan_get_track_origins() && msan_inited) \
+ GetStackTrace(&stack, common_flags()->malloc_context_size, \
+ StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
+ common_flags()->fast_unwind_on_malloc)
+
+#define GET_STORE_STACK_TRACE_PC_BP(pc, bp) \
+ BufferedStackTrace stack; \
+ if (__msan_get_track_origins() > 1 && msan_inited) \
+ GetStackTrace(&stack, flags()->store_context_size, pc, bp, \
+ common_flags()->fast_unwind_on_malloc)
+
+#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp) \
+ BufferedStackTrace stack; \
+ if (msan_inited) \
+ GetStackTrace(&stack, kStackTraceMax, pc, bp, \
+ common_flags()->fast_unwind_on_fatal)
+
+#define GET_STORE_STACK_TRACE \
+ GET_STORE_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
class ScopedThreadLocalStateBackup {
public:
@@ -99,11 +203,19 @@ class ScopedThreadLocalStateBackup {
private:
u64 va_arg_overflow_size_tls;
};
+
+extern void (*death_callback)(void);
+
+void MsanTSDInit(void (*destructor)(void *tsd));
+void *MsanTSDGet();
+void MsanTSDSet(void *tsd);
+void MsanTSDDtor(void *tsd);
+
} // namespace __msan
#define MSAN_MALLOC_HOOK(ptr, size) \
- if (&__msan_malloc_hook) __msan_malloc_hook(ptr, size)
+ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
#define MSAN_FREE_HOOK(ptr) \
- if (&__msan_free_hook) __msan_free_hook(ptr)
+ if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
#endif // MSAN_H
diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc
index 2badf712188b8..f21d71409ce21 100644
--- a/lib/msan/msan_allocator.cc
+++ b/lib/msan/msan_allocator.cc
@@ -13,8 +13,11 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_allocator.h"
-#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "msan.h"
+#include "msan_allocator.h"
+#include "msan_origin.h"
+#include "msan_thread.h"
namespace __msan {
@@ -22,20 +25,47 @@ struct Metadata {
uptr requested_size;
};
-static const uptr kAllocatorSpace = 0x600000000000ULL;
-static const uptr kAllocatorSize = 0x80000000000; // 8T.
-static const uptr kMetadataSize = sizeof(Metadata);
-static const uptr kMaxAllowedMallocSize = 8UL << 30;
+struct MsanMapUnmapCallback {
+ void OnMap(uptr p, uptr size) const {}
+ void OnUnmap(uptr p, uptr size) const {
+ __msan_unpoison((void *)p, size);
-typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
- DefaultSizeClassMap> PrimaryAllocator;
+ // We are about to unmap a chunk of user memory.
+ // Mark the corresponding shadow memory as not needed.
+ FlushUnneededShadowMemory(MEM_TO_SHADOW(p), size);
+ if (__msan_get_track_origins())
+ FlushUnneededShadowMemory(MEM_TO_ORIGIN(p), size);
+ }
+};
+
+#if defined(__mips64)
+ static const uptr kMaxAllowedMallocSize = 2UL << 30;
+ static const uptr kRegionSizeLog = 20;
+ static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+ typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+ typedef CompactSizeClassMap SizeClassMap;
+
+ typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata),
+ SizeClassMap, kRegionSizeLog, ByteMap,
+ MsanMapUnmapCallback> PrimaryAllocator;
+#elif defined(__x86_64__)
+ static const uptr kAllocatorSpace = 0x600000000000ULL;
+ static const uptr kAllocatorSize = 0x80000000000; // 8T.
+ static const uptr kMetadataSize = sizeof(Metadata);
+ static const uptr kMaxAllowedMallocSize = 8UL << 30;
+
+ typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
+ DefaultSizeClassMap,
+ MsanMapUnmapCallback> PrimaryAllocator;
+#endif
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
-typedef LargeMmapAllocator<> SecondaryAllocator;
+typedef LargeMmapAllocator<MsanMapUnmapCallback> SecondaryAllocator;
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
SecondaryAllocator> Allocator;
-static THREADLOCAL AllocatorCache cache;
static Allocator allocator;
+static AllocatorCache fallback_allocator_cache;
+static SpinMutex fallback_mutex;
static int inited = 0;
@@ -46,42 +76,55 @@ static inline void Init() {
allocator.Init();
}
-void MsanAllocatorThreadFinish() {
- allocator.SwallowCache(&cache);
+AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) {
+ CHECK(ms);
+ CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache));
+ return reinterpret_cast<AllocatorCache *>(ms->allocator_cache);
}
-static void *MsanAllocate(StackTrace *stack, uptr size,
- uptr alignment, bool zeroise) {
+void MsanThreadLocalMallocStorage::CommitBack() {
+ allocator.SwallowCache(GetAllocatorCache(this));
+}
+
+static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
+ bool zeroise) {
Init();
if (size > kMaxAllowedMallocSize) {
Report("WARNING: MemorySanitizer failed to allocate %p bytes\n",
(void *)size);
return AllocatorReturnNull();
}
- void *res = allocator.Allocate(&cache, size, alignment, false);
- Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(res));
+ MsanThread *t = GetCurrentThread();
+ void *allocated;
+ if (t) {
+ AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
+ allocated = allocator.Allocate(cache, size, alignment, false);
+ } else {
+ SpinMutexLock l(&fallback_mutex);
+ AllocatorCache *cache = &fallback_allocator_cache;
+ allocated = allocator.Allocate(cache, size, alignment, false);
+ }
+ Metadata *meta =
+ reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
meta->requested_size = size;
if (zeroise) {
- __msan_clear_and_unpoison(res, size);
+ __msan_clear_and_unpoison(allocated, size);
} else if (flags()->poison_in_malloc) {
- __msan_poison(res, size);
+ __msan_poison(allocated, size);
if (__msan_get_track_origins()) {
- u32 stack_id = StackDepotPut(stack->trace, stack->size);
- CHECK(stack_id);
- CHECK_EQ((stack_id >> 31),
- 0); // Higher bit is occupied by stack origins.
- __msan_set_origin(res, size, stack_id);
+ Origin o = Origin::CreateHeapOrigin(stack);
+ __msan_set_origin(allocated, size, o.raw_id());
}
}
- MSAN_MALLOC_HOOK(res, size);
- return res;
+ MSAN_MALLOC_HOOK(allocated, size);
+ return allocated;
}
void MsanDeallocate(StackTrace *stack, void *p) {
CHECK(p);
Init();
MSAN_FREE_HOOK(p);
- Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(p));
+ Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p));
uptr size = meta->requested_size;
meta->requested_size = 0;
// This memory will not be reused by anyone else, so we are free to keep it
@@ -89,14 +132,19 @@ void MsanDeallocate(StackTrace *stack, void *p) {
if (flags()->poison_in_free) {
__msan_poison(p, size);
if (__msan_get_track_origins()) {
- u32 stack_id = StackDepotPut(stack->trace, stack->size);
- CHECK(stack_id);
- CHECK_EQ((stack_id >> 31),
- 0); // Higher bit is occupied by stack origins.
- __msan_set_origin(p, size, stack_id);
+ Origin o = Origin::CreateHeapOrigin(stack);
+ __msan_set_origin(p, size, o.raw_id());
}
}
- allocator.Deallocate(&cache, p);
+ MsanThread *t = GetCurrentThread();
+ if (t) {
+ AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
+ allocator.Deallocate(cache, p);
+ } else {
+ SpinMutexLock l(&fallback_mutex);
+ AllocatorCache *cache = &fallback_allocator_cache;
+ allocator.Deallocate(cache, p);
+ }
}
void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
@@ -128,12 +176,10 @@ void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
}
static uptr AllocationSize(const void *p) {
- if (p == 0)
- return 0;
+ if (p == 0) return 0;
const void *beg = allocator.GetBlockBegin(p);
- if (beg != p)
- return 0;
- Metadata *b = (Metadata*)allocator.GetMetaData(p);
+ if (beg != p) return 0;
+ Metadata *b = (Metadata *)allocator.GetMetaData(p);
return b->requested_size;
}
@@ -141,38 +187,24 @@ static uptr AllocationSize(const void *p) {
using namespace __msan;
-uptr __msan_get_current_allocated_bytes() {
- u64 stats[AllocatorStatCount];
+uptr __sanitizer_get_current_allocated_bytes() {
+ uptr stats[AllocatorStatCount];
allocator.GetStats(stats);
- u64 m = stats[AllocatorStatMalloced];
- u64 f = stats[AllocatorStatFreed];
- return m >= f ? m - f : 1;
+ return stats[AllocatorStatAllocated];
}
-uptr __msan_get_heap_size() {
- u64 stats[AllocatorStatCount];
+uptr __sanitizer_get_heap_size() {
+ uptr stats[AllocatorStatCount];
allocator.GetStats(stats);
- u64 m = stats[AllocatorStatMmapped];
- u64 f = stats[AllocatorStatUnmapped];
- return m >= f ? m - f : 1;
+ return stats[AllocatorStatMapped];
}
-uptr __msan_get_free_bytes() {
- return 1;
-}
+uptr __sanitizer_get_free_bytes() { return 1; }
-uptr __msan_get_unmapped_bytes() {
- return 1;
-}
+uptr __sanitizer_get_unmapped_bytes() { return 1; }
-uptr __msan_get_estimated_allocated_size(uptr size) {
- return size;
-}
+uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
-int __msan_get_ownership(const void *p) {
- return AllocationSize(p) != 0;
-}
+int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
-uptr __msan_get_allocated_size(const void *p) {
- return AllocationSize(p);
-}
+uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
diff --git a/lib/msan/msan_allocator.h b/lib/msan/msan_allocator.h
new file mode 100644
index 0000000000000..407942e54c1a9
--- /dev/null
+++ b/lib/msan/msan_allocator.h
@@ -0,0 +1,33 @@
+//===-- msan_allocator.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_ALLOCATOR_H
+#define MSAN_ALLOCATOR_H
+
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+struct MsanThreadLocalMallocStorage {
+ uptr quarantine_cache[16];
+ // Allocator cache contains atomic_uint64_t which must be 8-byte aligned.
+ ALIGNED(8) uptr allocator_cache[96 * (512 * 8 + 16)]; // Opaque.
+ void CommitBack();
+
+ private:
+ // These objects are allocated via mmap() and are zero-initialized.
+ MsanThreadLocalMallocStorage() {}
+};
+
+} // namespace __msan
+#endif // MSAN_ALLOCATOR_H
diff --git a/lib/msan/msan_chained_origin_depot.cc b/lib/msan/msan_chained_origin_depot.cc
new file mode 100644
index 0000000000000..c21e8e82746aa
--- /dev/null
+++ b/lib/msan/msan_chained_origin_depot.cc
@@ -0,0 +1,126 @@
+//===-- msan_chained_origin_depot.cc -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A storage for chained origins.
+//===----------------------------------------------------------------------===//
+
+#include "msan_chained_origin_depot.h"
+
+#include "sanitizer_common/sanitizer_stackdepotbase.h"
+
+namespace __msan {
+
+struct ChainedOriginDepotDesc {
+ u32 here_id;
+ u32 prev_id;
+};
+
+struct ChainedOriginDepotNode {
+ ChainedOriginDepotNode *link;
+ u32 id;
+ u32 here_id;
+ u32 prev_id;
+
+ typedef ChainedOriginDepotDesc args_type;
+ bool eq(u32 hash, const args_type &args) const {
+ return here_id == args.here_id && prev_id == args.prev_id;
+ }
+ static uptr storage_size(const args_type &args) {
+ return sizeof(ChainedOriginDepotNode);
+ }
+ /* This is murmur2 hash for the 64->32 bit case.
+ It does not behave all that well because the keys have a very biased
+ distribution (I've seen 7-element buckets with the table only 14% full).
+
+ here_id is built of
+ * (1 bits) Reserved, zero.
+ * (8 bits) Part id = bits 13..20 of the hash value of here_id's key.
+ * (23 bits) Sequential number (each part has each own sequence).
+
+ prev_id has either the same distribution as here_id (but with 3:8:21)
+ split, or one of two reserved values (-1) or (-2). Either case can
+ dominate depending on the workload.
+ */
+ static u32 hash(const args_type &args) {
+ const u32 m = 0x5bd1e995;
+ const u32 seed = 0x9747b28c;
+ const u32 r = 24;
+ u32 h = seed;
+ u32 k = args.here_id;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+
+ k = args.prev_id;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+ return h;
+ }
+ static bool is_valid(const args_type &args) { return true; }
+ void store(const args_type &args, u32 other_hash) {
+ here_id = args.here_id;
+ prev_id = args.prev_id;
+ }
+ args_type load() const {
+ args_type ret = {here_id, prev_id};
+ return ret;
+ }
+ struct Handle {
+ ChainedOriginDepotNode *node_;
+ Handle() : node_(0) {}
+ explicit Handle(ChainedOriginDepotNode *node) : node_(node) {}
+ bool valid() { return node_; }
+ u32 id() { return node_->id; }
+ int here_id() { return node_->here_id; }
+ int prev_id() { return node_->prev_id; }
+ };
+ Handle get_handle() { return Handle(this); }
+
+ typedef Handle handle_type;
+};
+
+static StackDepotBase<ChainedOriginDepotNode, 4, 20> chainedOriginDepot;
+
+StackDepotStats *ChainedOriginDepotGetStats() {
+ return chainedOriginDepot.GetStats();
+}
+
+bool ChainedOriginDepotPut(u32 here_id, u32 prev_id, u32 *new_id) {
+ ChainedOriginDepotDesc desc = {here_id, prev_id};
+ bool inserted;
+ ChainedOriginDepotNode::Handle h = chainedOriginDepot.Put(desc, &inserted);
+ *new_id = h.valid() ? h.id() : 0;
+ return inserted;
+}
+
+// Retrieves a stored stack trace by the id.
+u32 ChainedOriginDepotGet(u32 id, u32 *other) {
+ ChainedOriginDepotDesc desc = chainedOriginDepot.Get(id);
+ *other = desc.prev_id;
+ return desc.here_id;
+}
+
+void ChainedOriginDepotLockAll() {
+ chainedOriginDepot.LockAll();
+}
+
+void ChainedOriginDepotUnlockAll() {
+ chainedOriginDepot.UnlockAll();
+}
+
+} // namespace __msan
diff --git a/lib/msan/msan_chained_origin_depot.h b/lib/msan/msan_chained_origin_depot.h
new file mode 100644
index 0000000000000..f7a71cef205ff
--- /dev/null
+++ b/lib/msan/msan_chained_origin_depot.h
@@ -0,0 +1,29 @@
+//===-- msan_chained_origin_depot.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A storage for chained origins.
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_CHAINED_ORIGIN_DEPOT_H
+#define MSAN_CHAINED_ORIGIN_DEPOT_H
+
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+StackDepotStats *ChainedOriginDepotGetStats();
+bool ChainedOriginDepotPut(u32 here_id, u32 prev_id, u32 *new_id);
+// Retrieves a stored stack trace by the id.
+u32 ChainedOriginDepotGet(u32 id, u32 *other);
+
+void ChainedOriginDepotLockAll();
+void ChainedOriginDepotUnlockAll();
+
+} // namespace __msan
+
+#endif // MSAN_CHAINED_ORIGIN_DEPOT_H
diff --git a/lib/msan/msan_flags.h b/lib/msan/msan_flags.h
index 93fa8a60dba00..9b93f118a9856 100644
--- a/lib/msan/msan_flags.h
+++ b/lib/msan/msan_flags.h
@@ -19,13 +19,18 @@ namespace __msan {
// Flags.
struct Flags {
int exit_code;
+ int origin_history_size;
+ int origin_history_per_stack_limit;
bool poison_heap_with_zeroes; // default: false
bool poison_stack_with_zeroes; // default: false
bool poison_in_malloc; // default: true
bool poison_in_free; // default: true
bool report_umrs;
bool wrap_signals;
+ bool print_stats;
bool halt_on_error;
+ bool atexit;
+ int store_context_size; // like malloc_context_size, but for uninit stores
};
Flags *flags();
diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index 15a8bec12f319..bbdf18e162a38 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/lib/msan/msan_interceptors.cc
@@ -17,14 +17,19 @@
#include "interception/interception.h"
#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
+#include "msan_thread.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include <stdarg.h>
// ACHTUNG! No other system header includes in this file.
@@ -37,11 +42,15 @@ using __sanitizer::atomic_load;
using __sanitizer::atomic_store;
using __sanitizer::atomic_uintptr_t;
-static unsigned g_thread_finalize_key;
+#if SANITIZER_FREEBSD
+#define __errno_location __error
+#endif
// True if this is a nested interceptor.
static THREADLOCAL int in_interceptor_scope;
+extern "C" int *__errno_location(void);
+
struct InterceptorScope {
InterceptorScope() { ++in_interceptor_scope; }
~InterceptorScope() { --in_interceptor_scope; }
@@ -59,22 +68,22 @@ bool IsInInterceptorScope() {
} while (0)
// Check that [x, x+n) range is unpoisoned.
-#define CHECK_UNPOISONED_0(x, n) \
- do { \
- sptr offset = __msan_test_shadow(x, n); \
- if (__msan::IsInSymbolizer()) break; \
- if (offset >= 0 && __msan::flags()->report_umrs) { \
- GET_CALLER_PC_BP_SP; \
- (void) sp; \
- Printf("UMR in %s at offset %d inside [%p, +%d) \n", __FUNCTION__, \
- offset, x, n); \
- __msan::PrintWarningWithOrigin(pc, bp, \
- __msan_get_origin((char *)x + offset)); \
- if (__msan::flags()->halt_on_error) { \
- Printf("Exiting\n"); \
- Die(); \
- } \
- } \
+#define CHECK_UNPOISONED_0(x, n) \
+ do { \
+ sptr offset = __msan_test_shadow(x, n); \
+ if (__msan::IsInSymbolizer()) \
+ break; \
+ if (offset >= 0 && __msan::flags()->report_umrs) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ ReportUMRInsideAddressRange(__func__, x, n, offset); \
+ __msan::PrintWarningWithOrigin( \
+ pc, bp, __msan_get_origin((const char *)x + offset)); \
+ if (__msan::flags()->halt_on_error) { \
+ Printf("Exiting\n"); \
+ Die(); \
+ } \
+ } \
} while (0)
// Check that [x, x+n) range is unpoisoned unless we are in a nested
@@ -84,9 +93,6 @@ bool IsInInterceptorScope() {
if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
} while (0);
-static void *fast_memset(void *ptr, int c, SIZE_T n);
-static void *fast_memcpy(void *dst, const void *src, SIZE_T n);
-
INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
ENSURE_MSAN_INITED();
SIZE_T res = REAL(fread)(ptr, size, nmemb, file);
@@ -95,6 +101,7 @@ INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb,
void *file) {
ENSURE_MSAN_INITED();
@@ -103,6 +110,10 @@ INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb,
__msan_unpoison(ptr, res *size);
return res;
}
+#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED INTERCEPT_FUNCTION(fread_unlocked)
+#else
+#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED
+#endif
INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) {
ENSURE_MSAN_INITED();
@@ -152,12 +163,32 @@ INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
return 0;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(void *, memalign, SIZE_T boundary, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
CHECK_EQ(boundary & (boundary - 1), 0);
void *ptr = MsanReallocate(&stack, 0, size, boundary, false);
return ptr;
}
+#define MSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
+#else
+#define MSAN_MAYBE_INTERCEPT_MEMALIGN
+#endif
+
+INTERCEPTOR(void *, aligned_alloc, SIZE_T boundary, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ CHECK_EQ(boundary & (boundary - 1), 0);
+ void *ptr = MsanReallocate(&stack, 0, size, boundary, false);
+ return ptr;
+}
+
+INTERCEPTOR(void *, __libc_memalign, SIZE_T boundary, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ CHECK_EQ(boundary & (boundary - 1), 0);
+ void *ptr = MsanReallocate(&stack, 0, size, boundary, false);
+ DTLS_on_libc_memalign(ptr, size * boundary);
+ return ptr;
+}
INTERCEPTOR(void *, valloc, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
@@ -165,6 +196,7 @@ INTERCEPTOR(void *, valloc, SIZE_T size) {
return ptr;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(void *, pvalloc, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
uptr PageSize = GetPageSizeCached();
@@ -176,6 +208,10 @@ INTERCEPTOR(void *, pvalloc, SIZE_T size) {
void *ptr = MsanReallocate(&stack, 0, size, PageSize, false);
return ptr;
}
+#define MSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
+#else
+#define MSAN_MAYBE_INTERCEPT_PVALLOC
+#endif
INTERCEPTOR(void, free, void *ptr) {
GET_MALLOC_STACK_TRACE;
@@ -183,7 +219,55 @@ INTERCEPTOR(void, free, void *ptr) {
MsanDeallocate(&stack, ptr);
}
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void, cfree, void *ptr) {
+ GET_MALLOC_STACK_TRACE;
+ if (ptr == 0) return;
+ MsanDeallocate(&stack, ptr);
+}
+#define MSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
+#else
+#define MSAN_MAYBE_INTERCEPT_CFREE
+#endif
+
+INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
+ return __sanitizer_get_allocated_size(ptr);
+}
+
+#if !SANITIZER_FREEBSD
+// This function actually returns a struct by value, but we can't unpoison a
+// temporary! The following is equivalent on all supported platforms, and we
+// have a test to confirm that.
+INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) {
+ REAL(memset)(sret, 0, sizeof(*sret));
+ __msan_unpoison(sret, sizeof(*sret));
+}
+#define MSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
+#else
+#define MSAN_MAYBE_INTERCEPT_MALLINFO
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, mallopt, int cmd, int value) {
+ return -1;
+}
+#define MSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
+#else
+#define MSAN_MAYBE_INTERCEPT_MALLOPT
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void, malloc_stats, void) {
+ // FIXME: implement, but don't call REAL(malloc_stats)!
+}
+#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS INTERCEPT_FUNCTION(malloc_stats)
+#else
+#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS
+#endif
+
INTERCEPTOR(SIZE_T, strlen, const char *s) {
+ if (msan_init_is_running)
+ return REAL(strlen)(s);
ENSURE_MSAN_INITED();
SIZE_T res = REAL(strlen)(s);
CHECK_UNPOISONED(s, res + 1);
@@ -203,304 +287,261 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T n) {
INTERCEPTOR(char *, strcpy, char *dest, const char *src) { // NOLINT
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T n = REAL(strlen)(src);
char *res = REAL(strcpy)(dest, src); // NOLINT
- __msan_copy_poison(dest, src, n + 1);
+ CopyPoison(dest, src, n + 1, &stack);
return res;
}
INTERCEPTOR(char *, strncpy, char *dest, const char *src, SIZE_T n) { // NOLINT
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T copy_size = REAL(strnlen)(src, n);
if (copy_size < n)
copy_size++; // trailing \0
char *res = REAL(strncpy)(dest, src, n); // NOLINT
- __msan_copy_poison(dest, src, copy_size);
+ CopyPoison(dest, src, copy_size, &stack);
+ __msan_unpoison(dest + copy_size, n - copy_size);
return res;
}
INTERCEPTOR(char *, stpcpy, char *dest, const char *src) { // NOLINT
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T n = REAL(strlen)(src);
char *res = REAL(stpcpy)(dest, src); // NOLINT
- __msan_copy_poison(dest, src, n + 1);
+ CopyPoison(dest, src, n + 1, &stack);
return res;
}
INTERCEPTOR(char *, strdup, char *src) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T n = REAL(strlen)(src);
char *res = REAL(strdup)(src);
- __msan_copy_poison(res, src, n + 1);
+ CopyPoison(res, src, n + 1, &stack);
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(char *, __strdup, char *src) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T n = REAL(strlen)(src);
char *res = REAL(__strdup)(src);
- __msan_copy_poison(res, src, n + 1);
+ CopyPoison(res, src, n + 1, &stack);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___STRDUP INTERCEPT_FUNCTION(__strdup)
+#else
+#define MSAN_MAYBE_INTERCEPT___STRDUP
+#endif
INTERCEPTOR(char *, strndup, char *src, SIZE_T n) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T copy_size = REAL(strnlen)(src, n);
char *res = REAL(strndup)(src, n);
- __msan_copy_poison(res, src, copy_size);
+ CopyPoison(res, src, copy_size, &stack);
__msan_unpoison(res + copy_size, 1); // \0
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(char *, __strndup, char *src, SIZE_T n) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T copy_size = REAL(strnlen)(src, n);
char *res = REAL(__strndup)(src, n);
- __msan_copy_poison(res, src, copy_size);
+ CopyPoison(res, src, copy_size, &stack);
__msan_unpoison(res + copy_size, 1); // \0
return res;
}
+#define MSAN_MAYBE_INTERCEPT___STRNDUP INTERCEPT_FUNCTION(__strndup)
+#else
+#define MSAN_MAYBE_INTERCEPT___STRNDUP
+#endif
INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) {
ENSURE_MSAN_INITED();
char *res = REAL(gcvt)(number, ndigit, buf);
- // DynamoRio tool will take care of unpoisoning gcvt result for us.
- if (!__msan_has_dynamic_component()) {
- SIZE_T n = REAL(strlen)(buf);
- __msan_unpoison(buf, n + 1);
- }
+ SIZE_T n = REAL(strlen)(buf);
+ __msan_unpoison(buf, n + 1);
return res;
}
INTERCEPTOR(char *, strcat, char *dest, const char *src) { // NOLINT
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T src_size = REAL(strlen)(src);
SIZE_T dest_size = REAL(strlen)(dest);
char *res = REAL(strcat)(dest, src); // NOLINT
- __msan_copy_poison(dest + dest_size, src, src_size + 1);
+ CopyPoison(dest + dest_size, src, src_size + 1, &stack);
return res;
}
INTERCEPTOR(char *, strncat, char *dest, const char *src, SIZE_T n) { // NOLINT
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T dest_size = REAL(strlen)(dest);
- SIZE_T copy_size = REAL(strlen)(src);
- if (copy_size < n)
- copy_size++; // trailing \0
+ SIZE_T copy_size = REAL(strnlen)(src, n);
char *res = REAL(strncat)(dest, src, n); // NOLINT
- __msan_copy_poison(dest + dest_size, src, copy_size);
- return res;
-}
-
-INTERCEPTOR(long, strtol, const char *nptr, char **endptr, // NOLINT
- int base) {
- ENSURE_MSAN_INITED();
- long res = REAL(strtol)(nptr, endptr, base); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(long long, strtoll, const char *nptr, char **endptr, // NOLINT
- int base) {
- ENSURE_MSAN_INITED();
- long res = REAL(strtoll)(nptr, endptr, base); //NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(unsigned long, strtoul, const char *nptr, char **endptr, // NOLINT
- int base) {
- ENSURE_MSAN_INITED();
- unsigned long res = REAL(strtoul)(nptr, endptr, base); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(unsigned long long, strtoull, const char *nptr, // NOLINT
- char **endptr, int base) {
- ENSURE_MSAN_INITED();
- unsigned long res = REAL(strtoull)(nptr, endptr, base); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(double, strtod, const char *nptr, char **endptr) { // NOLINT
- ENSURE_MSAN_INITED();
- double res = REAL(strtod)(nptr, endptr); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(double, strtod_l, const char *nptr, char **endptr,
- void *loc) { // NOLINT
- ENSURE_MSAN_INITED();
- double res = REAL(strtod_l)(nptr, endptr, loc); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(double, __strtod_l, const char *nptr, char **endptr,
- void *loc) { // NOLINT
- ENSURE_MSAN_INITED();
- double res = REAL(__strtod_l)(nptr, endptr, loc); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(float, strtof, const char *nptr, char **endptr) { // NOLINT
- ENSURE_MSAN_INITED();
- float res = REAL(strtof)(nptr, endptr); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
+ CopyPoison(dest + dest_size, src, copy_size, &stack);
+ __msan_unpoison(dest + dest_size + copy_size, 1); // \0
return res;
}
-INTERCEPTOR(float, strtof_l, const char *nptr, char **endptr,
- void *loc) { // NOLINT
- ENSURE_MSAN_INITED();
- float res = REAL(strtof_l)(nptr, endptr, loc); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
+// Hack: always pass nptr and endptr as part of __VA_ARGS_ to avoid having to
+// deal with empty __VA_ARGS__ in the case of INTERCEPTOR_STRTO.
+#define INTERCEPTOR_STRTO_BODY(ret_type, func, ...) \
+ ENSURE_MSAN_INITED(); \
+ ret_type res = REAL(func)(__VA_ARGS__); \
+ __msan_unpoison(endptr, sizeof(*endptr)); \
return res;
-}
-INTERCEPTOR(float, __strtof_l, const char *nptr, char **endptr,
- void *loc) { // NOLINT
- ENSURE_MSAN_INITED();
- float res = REAL(__strtof_l)(nptr, endptr, loc); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
+#define INTERCEPTOR_STRTO(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr); \
}
- return res;
-}
-INTERCEPTOR(long double, strtold, const char *nptr, char **endptr) { // NOLINT
- ENSURE_MSAN_INITED();
- long double res = REAL(strtold)(nptr, endptr); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
+#define INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
+ int base) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base); \
}
- return res;
-}
-INTERCEPTOR(long double, strtold_l, const char *nptr, char **endptr,
- void *loc) { // NOLINT
- ENSURE_MSAN_INITED();
- long double res = REAL(strtold_l)(nptr, endptr, loc); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
+#define INTERCEPTOR_STRTO_LOC(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
+ void *loc) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, loc); \
}
- return res;
-}
-INTERCEPTOR(long double, __strtold_l, const char *nptr, char **endptr,
- void *loc) { // NOLINT
- ENSURE_MSAN_INITED();
- long double res = REAL(__strtold_l)(nptr, endptr, loc); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
+#define INTERCEPTOR_STRTO_BASE_LOC(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
+ int base, void *loc) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base, loc); \
}
- return res;
-}
-INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap) {
+#define INTERCEPTORS_STRTO(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type) \
+ INTERCEPTOR_STRTO_LOC(ret_type, __##func##_l, char_type) \
+ INTERCEPTOR_STRTO_LOC(ret_type, __##func##_internal, char_type)
+
+#define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type) \
+ INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_l, char_type) \
+ INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_internal, char_type)
+
+INTERCEPTORS_STRTO(double, strtod, char) // NOLINT
+INTERCEPTORS_STRTO(float, strtof, char) // NOLINT
+INTERCEPTORS_STRTO(long double, strtold, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(long, strtol, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(long long, strtoll, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long, strtoul, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long long, strtoull, char) // NOLINT
+
+INTERCEPTORS_STRTO(double, wcstod, wchar_t) // NOLINT
+INTERCEPTORS_STRTO(float, wcstof, wchar_t) // NOLINT
+INTERCEPTORS_STRTO(long double, wcstold, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(long, wcstol, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(long long, wcstoll, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long, wcstoul, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long long, wcstoull, wchar_t) // NOLINT
+
+#define INTERCEPT_STRTO(func) \
+ INTERCEPT_FUNCTION(func); \
+ INTERCEPT_FUNCTION(func##_l); \
+ INTERCEPT_FUNCTION(__##func##_l); \
+ INTERCEPT_FUNCTION(__##func##_internal);
+
+
+// FIXME: support *wprintf in common format interceptors.
+INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
ENSURE_MSAN_INITED();
- int res = REAL(vasprintf)(strp, format, ap);
- if (res >= 0 && !__msan_has_dynamic_component()) {
- __msan_unpoison(strp, sizeof(*strp));
- __msan_unpoison(*strp, res + 1);
+ int res = REAL(vswprintf)(str, size, format, ap);
+ if (res >= 0) {
+ __msan_unpoison(str, 4 * (res + 1));
}
return res;
}
-INTERCEPTOR(int, asprintf, char **strp, const char *format, ...) { // NOLINT
+INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {
ENSURE_MSAN_INITED();
va_list ap;
va_start(ap, format);
- int res = vasprintf(strp, format, ap); // NOLINT
+ int res = vswprintf(str, size, format, ap);
va_end(ap);
return res;
}
-INTERCEPTOR(int, vsnprintf, char *str, uptr size,
- const char *format, va_list ap) {
+INTERCEPTOR(SIZE_T, strxfrm, char *dest, const char *src, SIZE_T n) {
ENSURE_MSAN_INITED();
- int res = REAL(vsnprintf)(str, size, format, ap);
- if (res >= 0 && !__msan_has_dynamic_component()) {
- __msan_unpoison(str, res + 1);
- }
+ CHECK_UNPOISONED(src, REAL(strlen)(src) + 1);
+ SIZE_T res = REAL(strxfrm)(dest, src, n);
+ if (res < n) __msan_unpoison(dest, res + 1);
return res;
}
-INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap) {
+INTERCEPTOR(SIZE_T, strxfrm_l, char *dest, const char *src, SIZE_T n,
+ void *loc) {
ENSURE_MSAN_INITED();
- int res = REAL(vsprintf)(str, format, ap);
- if (res >= 0 && !__msan_has_dynamic_component()) {
- __msan_unpoison(str, res + 1);
- }
+ CHECK_UNPOISONED(src, REAL(strlen)(src) + 1);
+ SIZE_T res = REAL(strxfrm_l)(dest, src, n, loc);
+ if (res < n) __msan_unpoison(dest, res + 1);
return res;
}
-INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
- ENSURE_MSAN_INITED();
- int res = REAL(vswprintf)(str, size, format, ap);
- if (res >= 0 && !__msan_has_dynamic_component()) {
- __msan_unpoison(str, 4 * (res + 1));
- }
+#define INTERCEPTOR_STRFTIME_BODY(char_type, ret_type, func, s, ...) \
+ ENSURE_MSAN_INITED(); \
+ ret_type res = REAL(func)(s, __VA_ARGS__); \
+ if (s) __msan_unpoison(s, sizeof(char_type) * (res + 1)); \
return res;
-}
-INTERCEPTOR(int, sprintf, char *str, const char *format, ...) { // NOLINT
- ENSURE_MSAN_INITED();
- va_list ap;
- va_start(ap, format);
- int res = vsprintf(str, format, ap); // NOLINT
- va_end(ap);
- return res;
+INTERCEPTOR(SIZE_T, strftime, char *s, SIZE_T max, const char *format,
+ __sanitizer_tm *tm) {
+ INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime, s, max, format, tm);
}
-INTERCEPTOR(int, snprintf, char *str, uptr size, const char *format, ...) {
- ENSURE_MSAN_INITED();
- va_list ap;
- va_start(ap, format);
- int res = vsnprintf(str, size, format, ap);
- va_end(ap);
- return res;
+INTERCEPTOR(SIZE_T, strftime_l, char *s, SIZE_T max, const char *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime_l, s, max, format, tm, loc);
}
-INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {
- ENSURE_MSAN_INITED();
- va_list ap;
- va_start(ap, format);
- int res = vswprintf(str, size, format, ap);
- va_end(ap);
- return res;
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(SIZE_T, __strftime_l, char *s, SIZE_T max, const char *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, __strftime_l, s, max, format, tm,
+ loc);
}
+#define MSAN_MAYBE_INTERCEPT___STRFTIME_L INTERCEPT_FUNCTION(__strftime_l)
+#else
+#define MSAN_MAYBE_INTERCEPT___STRFTIME_L
+#endif
-// SIZE_T strftime(char *s, SIZE_T max, const char *format,const struct tm *tm);
-INTERCEPTOR(SIZE_T, strftime, char *s, SIZE_T max, const char *format,
+INTERCEPTOR(SIZE_T, wcsftime, wchar_t *s, SIZE_T max, const wchar_t *format,
__sanitizer_tm *tm) {
- ENSURE_MSAN_INITED();
- SIZE_T res = REAL(strftime)(s, max, format, tm);
- if (res) __msan_unpoison(s, res + 1);
- return res;
+ INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime, s, max, format, tm);
+}
+
+INTERCEPTOR(SIZE_T, wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime_l, s, max, format, tm,
+ loc);
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(SIZE_T, __wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, __wcsftime_l, s, max, format, tm,
+ loc);
}
+#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L INTERCEPT_FUNCTION(__wcsftime_l)
+#else
+#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L
+#endif
INTERCEPTOR(int, mbtowc, wchar_t *dest, const char *src, SIZE_T n) {
ENSURE_MSAN_INITED();
@@ -533,38 +574,42 @@ INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) {
// wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
wchar_t *res = REAL(wcscpy)(dest, src);
- __msan_copy_poison(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1));
+ CopyPoison(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1), &stack);
return res;
}
// wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n);
INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
wchar_t *res = REAL(wmemcpy)(dest, src, n);
- __msan_copy_poison(dest, src, n * sizeof(wchar_t));
+ CopyPoison(dest, src, n * sizeof(wchar_t), &stack);
return res;
}
INTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
wchar_t *res = REAL(wmempcpy)(dest, src, n);
- __msan_copy_poison(dest, src, n * sizeof(wchar_t));
+ CopyPoison(dest, src, n * sizeof(wchar_t), &stack);
return res;
}
INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) {
CHECK(MEM_IS_APP(s));
ENSURE_MSAN_INITED();
- wchar_t *res = (wchar_t *)fast_memset(s, c, n * sizeof(wchar_t));
+ wchar_t *res = REAL(wmemset)(s, c, n);
__msan_unpoison(s, n * sizeof(wchar_t));
return res;
}
INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dest, const wchar_t *src, SIZE_T n) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
wchar_t *res = REAL(wmemmove)(dest, src, n);
- __msan_move_poison(dest, src, n * sizeof(wchar_t));
+ MovePoison(dest, src, n * sizeof(wchar_t), &stack);
return res;
}
@@ -574,13 +619,6 @@ INTERCEPTOR(int, wcscmp, const wchar_t *s1, const wchar_t *s2) {
return res;
}
-INTERCEPTOR(double, wcstod, const wchar_t *nptr, wchar_t **endptr) {
- ENSURE_MSAN_INITED();
- double res = REAL(wcstod)(nptr, endptr);
- __msan_unpoison(endptr, sizeof(*endptr));
- return res;
-}
-
INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
ENSURE_MSAN_INITED();
int res = REAL(gettimeofday)(tv, tz);
@@ -594,20 +632,18 @@ INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
INTERCEPTOR(char *, fcvt, double x, int a, int *b, int *c) {
ENSURE_MSAN_INITED();
char *res = REAL(fcvt)(x, a, b, c);
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(b, sizeof(*b));
- __msan_unpoison(c, sizeof(*c));
- }
+ __msan_unpoison(b, sizeof(*b));
+ __msan_unpoison(c, sizeof(*c));
+ if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
return res;
}
INTERCEPTOR(char *, getenv, char *name) {
+ if (msan_init_is_running)
+ return REAL(getenv)(name);
ENSURE_MSAN_INITED();
char *res = REAL(getenv)(name);
- if (!__msan_has_dynamic_component()) {
- if (res)
- __msan_unpoison(res, REAL(strlen)(res) + 1);
- }
+ if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
return res;
}
@@ -637,6 +673,7 @@ INTERCEPTOR(int, putenv, char *string) {
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__fxstat)(magic, fd, buf);
@@ -644,7 +681,12 @@ INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
__msan_unpoison(buf, __sanitizer::struct_stat_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___FXSTAT INTERCEPT_FUNCTION(__fxstat)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTAT
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__fxstat64)(magic, fd, buf);
@@ -652,7 +694,12 @@ INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) {
__msan_unpoison(buf, __sanitizer::struct_stat64_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___FXSTAT64 INTERCEPT_FUNCTION(__fxstat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTAT64
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf,
int flags) {
ENSURE_MSAN_INITED();
@@ -660,7 +707,12 @@ INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf,
if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___FXSTATAT INTERCEPT_FUNCTION(__fxstatat)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTATAT
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf,
int flags) {
ENSURE_MSAN_INITED();
@@ -668,7 +720,12 @@ INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf,
if (!res) __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___FXSTATAT64 INTERCEPT_FUNCTION(__fxstatat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTATAT64
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __xstat, int magic, char *path, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__xstat)(magic, path, buf);
@@ -676,7 +733,12 @@ INTERCEPTOR(int, __xstat, int magic, char *path, void *buf) {
__msan_unpoison(buf, __sanitizer::struct_stat_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___XSTAT INTERCEPT_FUNCTION(__xstat)
+#else
+#define MSAN_MAYBE_INTERCEPT___XSTAT
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __xstat64, int magic, char *path, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__xstat64)(magic, path, buf);
@@ -684,7 +746,12 @@ INTERCEPTOR(int, __xstat64, int magic, char *path, void *buf) {
__msan_unpoison(buf, __sanitizer::struct_stat64_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___XSTAT64 INTERCEPT_FUNCTION(__xstat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___XSTAT64
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __lxstat, int magic, char *path, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__lxstat)(magic, path, buf);
@@ -692,7 +759,12 @@ INTERCEPTOR(int, __lxstat, int magic, char *path, void *buf) {
__msan_unpoison(buf, __sanitizer::struct_stat_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___LXSTAT INTERCEPT_FUNCTION(__lxstat)
+#else
+#define MSAN_MAYBE_INTERCEPT___LXSTAT
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __lxstat64, int magic, char *path, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__lxstat64)(magic, path, buf);
@@ -700,6 +772,10 @@ INTERCEPTOR(int, __lxstat64, int magic, char *path, void *buf) {
__msan_unpoison(buf, __sanitizer::struct_stat64_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___LXSTAT64 INTERCEPT_FUNCTION(__lxstat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___LXSTAT64
+#endif
INTERCEPTOR(int, pipe, int pipefd[2]) {
if (msan_init_is_running)
@@ -735,6 +811,7 @@ INTERCEPTOR(char *, fgets, char *s, int size, void *stream) {
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {
ENSURE_MSAN_INITED();
char *res = REAL(fgets_unlocked)(s, size, stream);
@@ -742,6 +819,10 @@ INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {
__msan_unpoison(s, REAL(strlen)(s) + 1);
return res;
}
+#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED INTERCEPT_FUNCTION(fgets_unlocked)
+#else
+#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED
+#endif
INTERCEPTOR(int, getrlimit, int resource, void *rlim) {
if (msan_init_is_running)
@@ -753,6 +834,7 @@ INTERCEPTOR(int, getrlimit, int resource, void *rlim) {
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, getrlimit64, int resource, void *rlim) {
if (msan_init_is_running)
return REAL(getrlimit64)(resource, rlim);
@@ -762,6 +844,10 @@ INTERCEPTOR(int, getrlimit64, int resource, void *rlim) {
__msan_unpoison(rlim, __sanitizer::struct_rlimit64_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64 INTERCEPT_FUNCTION(getrlimit64)
+#else
+#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64
+#endif
INTERCEPTOR(int, uname, void *utsname) {
ENSURE_MSAN_INITED();
@@ -784,6 +870,7 @@ INTERCEPTOR(int, gethostname, char *name, SIZE_T len) {
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents,
int timeout) {
ENSURE_MSAN_INITED();
@@ -793,7 +880,12 @@ INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents,
}
return res;
}
+#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT INTERCEPT_FUNCTION(epoll_wait)
+#else
+#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents,
int timeout, void *sigmask) {
ENSURE_MSAN_INITED();
@@ -803,6 +895,10 @@ INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents,
}
return res;
}
+#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT INTERCEPT_FUNCTION(epoll_pwait)
+#else
+#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT
+#endif
INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) {
ENSURE_MSAN_INITED();
@@ -861,30 +957,51 @@ void __msan_allocated_memory(const void* data, uptr size) {
if (flags()->poison_in_malloc)
__msan_poison(data, size);
if (__msan_get_track_origins()) {
- u32 stack_id = StackDepotPut(stack.trace, stack.size);
- CHECK(stack_id);
- CHECK_EQ((stack_id >> 31), 0); // Higher bit is occupied by stack origins.
- __msan_set_origin(data, size, stack_id);
+ Origin o = Origin::CreateHeapOrigin(&stack);
+ __msan_set_origin(data, size, o.raw_id());
}
}
INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
int fd, OFF_T offset) {
- ENSURE_MSAN_INITED();
+ if (msan_init_is_running)
+ return REAL(mmap)(addr, length, prot, flags, fd, offset);
+ ENSURE_MSAN_INITED();
+ if (addr && !MEM_IS_APP(addr)) {
+ if (flags & map_fixed) {
+ *__errno_location() = errno_EINVAL;
+ return (void *)-1;
+ } else {
+ addr = 0;
+ }
+ }
void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
if (res != (void*)-1)
__msan_unpoison(res, RoundUpTo(length, GetPageSize()));
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
int fd, OFF64_T offset) {
ENSURE_MSAN_INITED();
+ if (addr && !MEM_IS_APP(addr)) {
+ if (flags & map_fixed) {
+ *__errno_location() = errno_EINVAL;
+ return (void *)-1;
+ } else {
+ addr = 0;
+ }
+ }
void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
if (res != (void*)-1)
__msan_unpoison(res, RoundUpTo(length, GetPageSize()));
return res;
}
+#define MSAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64)
+#else
+#define MSAN_MAYBE_INTERCEPT_MMAP64
+#endif
struct dlinfo {
char *dli_fname;
@@ -906,32 +1023,13 @@ INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) {
return res;
}
-INTERCEPTOR(char *, dlerror) {
+INTERCEPTOR(char *, dlerror, int fake) {
ENSURE_MSAN_INITED();
- char *res = REAL(dlerror)();
+ char *res = REAL(dlerror)(fake);
if (res != 0) __msan_unpoison(res, REAL(strlen)(res) + 1);
return res;
}
-// dlopen() ultimately calls mmap() down inside the loader, which generally
-// doesn't participate in dynamic symbol resolution. Therefore we won't
-// intercept its calls to mmap, and we have to hook it here. The loader
-// initializes the module before returning, so without the dynamic component, we
-// won't be able to clear the shadow before the initializers. Fixing this would
-// require putting our own initializer first to clear the shadow.
-INTERCEPTOR(void *, dlopen, const char *filename, int flag) {
- ENSURE_MSAN_INITED();
- EnterLoader();
- link_map *map = (link_map *)REAL(dlopen)(filename, flag);
- ExitLoader();
- if (!__msan_has_dynamic_component() && map) {
- // If msandr didn't clear the shadow before the initializers ran, we do it
- // ourselves afterwards.
- ForEachMappedRegion(map, __msan_unpoison);
- }
- return (void *)map;
-}
-
typedef int (*dl_iterate_phdr_cb)(__sanitizer_dl_phdr_info *info, SIZE_T size,
void *data);
struct dl_iterate_phdr_data {
@@ -953,12 +1051,10 @@ static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) {
ENSURE_MSAN_INITED();
- EnterLoader();
dl_iterate_phdr_data cbdata;
cbdata.callback = callback;
cbdata.data = data;
int res = REAL(dl_iterate_phdr)(msan_dl_iterate_phdr_cb, (void *)&cbdata);
- ExitLoader();
return res;
}
@@ -971,6 +1067,18 @@ INTERCEPTOR(int, getrusage, int who, void *usage) {
return res;
}
+class SignalHandlerScope {
+ public:
+ SignalHandlerScope() {
+ if (MsanThread *t = GetCurrentThread())
+ t->EnterSignalHandler();
+ }
+ ~SignalHandlerScope() {
+ if (MsanThread *t = GetCurrentThread())
+ t->LeaveSignalHandler();
+ }
+};
+
// sigactions_mu guarantees atomicity of sigaction() and signal() calls.
// Access to sigactions[] is gone with relaxed atomics to avoid data race with
// the signal handler.
@@ -979,6 +1087,7 @@ static atomic_uintptr_t sigactions[kMaxSignals];
static StaticSpinMutex sigactions_mu;
static void SignalHandler(int signo) {
+ SignalHandlerScope signal_handler_scope;
ScopedThreadLocalStateBackup stlsb;
UnpoisonParam(1);
@@ -989,6 +1098,7 @@ static void SignalHandler(int signo) {
}
static void SignalAction(int signo, void *si, void *uc) {
+ SignalHandlerScope signal_handler_scope;
ScopedThreadLocalStateBackup stlsb;
UnpoisonParam(3);
__msan_unpoison(si, sizeof(__sanitizer_sigaction));
@@ -1013,21 +1123,21 @@ INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
__sanitizer_sigaction new_act;
__sanitizer_sigaction *pnew_act = act ? &new_act : 0;
if (act) {
- internal_memcpy(pnew_act, act, sizeof(__sanitizer_sigaction));
- uptr cb = (uptr)pnew_act->sa_sigaction;
+ REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction));
+ uptr cb = (uptr)pnew_act->sigaction;
uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo)
? (uptr)SignalAction
: (uptr)SignalHandler;
if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
atomic_store(&sigactions[signo], cb, memory_order_relaxed);
- pnew_act->sa_sigaction = (void (*)(int, void *, void *))new_cb;
+ pnew_act->sigaction = (void (*)(int, void *, void *))new_cb;
}
}
res = REAL(sigaction)(signo, pnew_act, oldact);
if (res == 0 && oldact) {
- uptr cb = (uptr)oldact->sa_sigaction;
+ uptr cb = (uptr)oldact->sigaction;
if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
- oldact->sa_sigaction = (void (*)(int, void *, void *))old_cb;
+ oldact->sigaction = (void (*)(int, void *, void *))old_cb;
}
}
} else {
@@ -1057,38 +1167,11 @@ INTERCEPTOR(int, signal, int signo, uptr cb) {
extern "C" int pthread_attr_init(void *attr);
extern "C" int pthread_attr_destroy(void *attr);
-extern "C" int pthread_setspecific(unsigned key, const void *v);
-extern "C" int pthread_yield();
-
-static void thread_finalize(void *v) {
- uptr iter = (uptr)v;
- if (iter > 1) {
- if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
- Printf("MemorySanitizer: failed to set thread key\n");
- Die();
- }
- return;
- }
- MsanAllocatorThreadFinish();
-}
-
-struct ThreadParam {
- void* (*callback)(void *arg);
- void *param;
- atomic_uintptr_t done;
-};
static void *MsanThreadStartFunc(void *arg) {
- ThreadParam *p = (ThreadParam *)arg;
- void* (*callback)(void *arg) = p->callback;
- void *param = p->param;
- if (pthread_setspecific(g_thread_finalize_key,
- (void *)kPthreadDestructorIterations)) {
- Printf("MemorySanitizer: failed to set thread key\n");
- Die();
- }
- atomic_store(&p->done, 1, memory_order_release);
- return callback(param);
+ MsanThread *t = (MsanThread *)arg;
+ SetCurrentThread(t);
+ return t->ThreadStart();
}
INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
@@ -1100,18 +1183,11 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
attr = &myattr;
}
- AdjustStackSizeLinux(attr);
+ AdjustStackSize(attr);
- ThreadParam p;
- p.callback = callback;
- p.param = param;
- atomic_store(&p.done, 0, memory_order_relaxed);
+ MsanThread *t = MsanThread::Create(callback, param);
- int res = REAL(pthread_create)(th, attr, MsanThreadStartFunc, (void *)&p);
- if (res == 0) {
- while (atomic_load(&p.done, memory_order_acquire) != 1)
- pthread_yield();
- }
+ int res = REAL(pthread_create)(th, attr, MsanThreadStartFunc, t);
if (attr == &myattr)
pthread_attr_destroy(&myattr);
@@ -1123,6 +1199,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
INTERCEPTOR(int, pthread_key_create, __sanitizer_pthread_key_t *key,
void (*dtor)(void *value)) {
+ if (msan_init_is_running) return REAL(pthread_key_create)(key, dtor);
ENSURE_MSAN_INITED();
int res = REAL(pthread_key_create)(key, dtor);
if (!res && key)
@@ -1140,9 +1217,9 @@ INTERCEPTOR(int, pthread_join, void *th, void **retval) {
extern char *tzname[2];
-INTERCEPTOR(void, tzset) {
+INTERCEPTOR(void, tzset, int fake) {
ENSURE_MSAN_INITED();
- REAL(tzset)();
+ REAL(tzset)(fake);
if (tzname[0])
__msan_unpoison(tzname[0], REAL(strlen)(tzname[0]) + 1);
if (tzname[1])
@@ -1189,34 +1266,22 @@ INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) {
return p;
}
-// Linux kernel has a bug that leads to kernel deadlock if a process
-// maps TBs of memory and then calls mlock().
-static void MlockIsUnsupported() {
- static atomic_uint8_t printed;
- if (atomic_exchange(&printed, 1, memory_order_relaxed))
- return;
- if (common_flags()->verbosity > 0)
- Printf("INFO: MemorySanitizer ignores mlock/mlockall/munlock/munlockall\n");
-}
-
-INTERCEPTOR(int, mlock, const void *addr, uptr len) {
- MlockIsUnsupported();
- return 0;
-}
-
-INTERCEPTOR(int, munlock, const void *addr, uptr len) {
- MlockIsUnsupported();
- return 0;
+static void BeforeFork() {
+ StackDepotLockAll();
+ ChainedOriginDepotLockAll();
}
-INTERCEPTOR(int, mlockall, int flags) {
- MlockIsUnsupported();
- return 0;
+static void AfterFork() {
+ ChainedOriginDepotUnlockAll();
+ StackDepotUnlockAll();
}
-INTERCEPTOR(int, munlockall, void) {
- MlockIsUnsupported();
- return 0;
+INTERCEPTOR(int, fork, void) {
+ ENSURE_MSAN_INITED();
+ BeforeFork();
+ int pid = REAL(fork)();
+ AfterFork();
+ return pid;
}
struct MSanInterceptorContext {
@@ -1232,8 +1297,6 @@ int OnExit() {
} // namespace __msan
-extern "C" int *__errno_location(void);
-
// A version of CHECK_UNPOISONED using a saved scope value. Used in common
// interceptors.
#define CHECK_UNPOISONED_CTX(ctx, x, n) \
@@ -1242,21 +1305,20 @@ extern "C" int *__errno_location(void);
CHECK_UNPOISONED_0(x, n); \
} while (0)
-#define MSAN_INTERCEPT_FUNC(name) \
- do { \
- if ((!INTERCEPT_FUNCTION(name) || !REAL(name)) && \
- common_flags()->verbosity > 0) \
- Report("MemorySanitizer: failed to intercept '" #name "'\n"); \
+#define MSAN_INTERCEPT_FUNC(name) \
+ do { \
+ if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \
+ VReport(1, "MemorySanitizer: failed to intercept '" #name "'\n"); \
} while (0)
#define COMMON_INTERCEPT_FUNCTION(name) MSAN_INTERCEPT_FUNC(name)
-#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) \
UnpoisonParam(count)
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
__msan_unpoison(ptr, size)
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
CHECK_UNPOISONED_CTX(ctx, ptr, size)
-#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, ptr, size) \
+#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \
__msan_unpoison(ptr, size)
#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
if (msan_init_is_running) return REAL(func)(__VA_ARGS__); \
@@ -1283,6 +1345,9 @@ extern "C" int *__errno_location(void);
} while (false) // FIXME
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, map) \
+ if (map) ForEachMappedRegion((link_map *)map, __msan_unpoison);
+
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
@@ -1295,155 +1360,204 @@ extern "C" int *__errno_location(void);
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
-// static
-void *fast_memset(void *ptr, int c, SIZE_T n) {
- // hack until we have a really fast internal_memset
- if (sizeof(uptr) == 8 &&
- (n % 8) == 0 &&
- ((uptr)ptr % 8) == 0 &&
- (c == 0 || c == -1)) {
- // Printf("memset %p %zd %x\n", ptr, n, c);
- uptr to_store = c ? -1L : 0L;
- uptr *p = (uptr*)ptr;
- for (SIZE_T i = 0; i < n / 8; i++)
- p[i] = to_store;
- return ptr;
- }
- return internal_memset(ptr, c, n);
-}
-
-// static
-void *fast_memcpy(void *dst, const void *src, SIZE_T n) {
- // Same hack as in fast_memset above.
- if (sizeof(uptr) == 8 &&
- (n % 8) == 0 &&
- ((uptr)dst % 8) == 0 &&
- ((uptr)src % 8) == 0) {
- uptr *d = (uptr*)dst;
- uptr *s = (uptr*)src;
- for (SIZE_T i = 0; i < n / 8; i++)
- d[i] = s[i];
- return dst;
+static void PoisonShadow(uptr ptr, uptr size, u8 value) {
+ uptr PageSize = GetPageSizeCached();
+ uptr shadow_beg = MEM_TO_SHADOW(ptr);
+ uptr shadow_end = MEM_TO_SHADOW(ptr + size);
+ if (value ||
+ shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
+ REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+ } else {
+ uptr page_beg = RoundUpTo(shadow_beg, PageSize);
+ uptr page_end = RoundDownTo(shadow_end, PageSize);
+
+ if (page_beg >= page_end) {
+ REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
+ } else {
+ if (page_beg != shadow_beg) {
+ REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
+ }
+ if (page_end != shadow_end) {
+ REAL(memset)((void *)page_end, 0, shadow_end - page_end);
+ }
+ MmapFixedNoReserve(page_beg, page_end - page_beg);
+ }
}
- return internal_memcpy(dst, src, n);
}
// These interface functions reside here so that they can use
-// fast_memset, etc.
+// REAL(memset), etc.
void __msan_unpoison(const void *a, uptr size) {
if (!MEM_IS_APP(a)) return;
- fast_memset((void*)MEM_TO_SHADOW((uptr)a), 0, size);
+ PoisonShadow((uptr)a, size, 0);
}
void __msan_poison(const void *a, uptr size) {
if (!MEM_IS_APP(a)) return;
- fast_memset((void*)MEM_TO_SHADOW((uptr)a),
- __msan::flags()->poison_heap_with_zeroes ? 0 : -1, size);
+ PoisonShadow((uptr)a, size,
+ __msan::flags()->poison_heap_with_zeroes ? 0 : -1);
}
void __msan_poison_stack(void *a, uptr size) {
if (!MEM_IS_APP(a)) return;
- fast_memset((void*)MEM_TO_SHADOW((uptr)a),
- __msan::flags()->poison_stack_with_zeroes ? 0 : -1, size);
+ PoisonShadow((uptr)a, size,
+ __msan::flags()->poison_stack_with_zeroes ? 0 : -1);
}
void __msan_clear_and_unpoison(void *a, uptr size) {
- fast_memset(a, 0, size);
- fast_memset((void*)MEM_TO_SHADOW((uptr)a), 0, size);
+ REAL(memset)(a, 0, size);
+ PoisonShadow((uptr)a, size, 0);
+}
+
+void *__msan_memcpy(void *dest, const void *src, SIZE_T n) {
+ if (!msan_inited) return internal_memcpy(dest, src, n);
+ if (msan_init_is_running) return REAL(memcpy)(dest, src, n);
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ void *res = REAL(memcpy)(dest, src, n);
+ CopyPoison(dest, src, n, &stack);
+ return res;
+}
+
+void *__msan_memset(void *s, int c, SIZE_T n) {
+ if (!msan_inited) return internal_memset(s, c, n);
+ if (msan_init_is_running) return REAL(memset)(s, c, n);
+ ENSURE_MSAN_INITED();
+ void *res = REAL(memset)(s, c, n);
+ __msan_unpoison(s, n);
+ return res;
+}
+
+void *__msan_memmove(void *dest, const void *src, SIZE_T n) {
+ if (!msan_inited) return internal_memmove(dest, src, n);
+ if (msan_init_is_running) return REAL(memmove)(dest, src, n);
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ void *res = REAL(memmove)(dest, src, n);
+ MovePoison(dest, src, n, &stack);
+ return res;
+}
+
+void __msan_unpoison_string(const char* s) {
+ if (!MEM_IS_APP(s)) return;
+ __msan_unpoison(s, REAL(strlen)(s) + 1);
}
-u32 get_origin_if_poisoned(uptr a, uptr size) {
- unsigned char *s = (unsigned char *)MEM_TO_SHADOW(a);
+namespace __msan {
+
+u32 GetOriginIfPoisoned(uptr addr, uptr size) {
+ unsigned char *s = (unsigned char *)MEM_TO_SHADOW(addr);
for (uptr i = 0; i < size; ++i)
if (s[i])
- return *(u32 *)SHADOW_TO_ORIGIN((s + i) & ~3UL);
+ return *(u32 *)SHADOW_TO_ORIGIN(((uptr)s + i) & ~3UL);
return 0;
}
-void __msan_copy_origin(void *dst, const void *src, uptr size) {
+void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size,
+ u32 src_origin) {
+ uptr dst_s = MEM_TO_SHADOW(addr);
+ uptr src_s = src_shadow;
+ uptr src_s_end = src_s + size;
+
+ for (; src_s < src_s_end; ++dst_s, ++src_s)
+ if (*(u8 *)src_s) *(u32 *)SHADOW_TO_ORIGIN(dst_s &~3UL) = src_origin;
+}
+
+void CopyOrigin(void *dst, const void *src, uptr size, StackTrace *stack) {
if (!__msan_get_track_origins()) return;
if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return;
+
uptr d = (uptr)dst;
uptr beg = d & ~3UL;
// Copy left unaligned origin if that memory is poisoned.
if (beg < d) {
- u32 o = get_origin_if_poisoned(beg, d - beg);
- if (o)
+ u32 o = GetOriginIfPoisoned((uptr)src, d - beg);
+ if (o) {
+ if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
*(u32 *)MEM_TO_ORIGIN(beg) = o;
+ }
beg += 4;
}
- uptr end = (d + size + 3) & ~3UL;
+ uptr end = (d + size) & ~3UL;
+ // If both ends fall into the same 4-byte slot, we are done.
+ if (end < beg) return;
+
// Copy right unaligned origin if that memory is poisoned.
- if (end > d + size) {
- u32 o = get_origin_if_poisoned(d + size, end - d - size);
- if (o)
- *(u32 *)MEM_TO_ORIGIN(end - 4) = o;
- end -= 4;
+ if (end < d + size) {
+ u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end);
+ if (o) {
+ if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
+ *(u32 *)MEM_TO_ORIGIN(end) = o;
+ }
}
if (beg < end) {
// Align src up.
uptr s = ((uptr)src + 3) & ~3UL;
- fast_memcpy((void*)MEM_TO_ORIGIN(beg), (void*)MEM_TO_ORIGIN(s), end - beg);
+ // FIXME: factor out to msan_copy_origin_aligned
+ if (__msan_get_track_origins() > 1) {
+ u32 *src = (u32 *)MEM_TO_ORIGIN(s);
+ u32 *src_s = (u32 *)MEM_TO_SHADOW(s);
+ u32 *src_end = (u32 *)MEM_TO_ORIGIN(s + (end - beg));
+ u32 *dst = (u32 *)MEM_TO_ORIGIN(beg);
+ u32 src_o = 0;
+ u32 dst_o = 0;
+ for (; src < src_end; ++src, ++src_s, ++dst) {
+ if (!*src_s) continue;
+ if (*src != src_o) {
+ src_o = *src;
+ dst_o = ChainOrigin(src_o, stack);
+ }
+ *dst = dst_o;
+ }
+ } else {
+ REAL(memcpy)((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s),
+ end - beg);
+ }
}
}
-void __msan_copy_poison(void *dst, const void *src, uptr size) {
+void MovePoison(void *dst, const void *src, uptr size, StackTrace *stack) {
if (!MEM_IS_APP(dst)) return;
if (!MEM_IS_APP(src)) return;
- fast_memcpy((void*)MEM_TO_SHADOW((uptr)dst),
- (void*)MEM_TO_SHADOW((uptr)src), size);
- __msan_copy_origin(dst, src, size);
+ if (src == dst) return;
+ REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst),
+ (void *)MEM_TO_SHADOW((uptr)src), size);
+ CopyOrigin(dst, src, size, stack);
}
-void __msan_move_poison(void *dst, const void *src, uptr size) {
+void CopyPoison(void *dst, const void *src, uptr size, StackTrace *stack) {
if (!MEM_IS_APP(dst)) return;
if (!MEM_IS_APP(src)) return;
- internal_memmove((void*)MEM_TO_SHADOW((uptr)dst),
- (void*)MEM_TO_SHADOW((uptr)src), size);
- __msan_copy_origin(dst, src, size);
-}
-
-void *__msan_memcpy(void *dest, const void *src, SIZE_T n) {
- ENSURE_MSAN_INITED();
- void *res = fast_memcpy(dest, src, n);
- __msan_copy_poison(dest, src, n);
- return res;
-}
-
-void *__msan_memset(void *s, int c, SIZE_T n) {
- ENSURE_MSAN_INITED();
- void *res = fast_memset(s, c, n);
- __msan_unpoison(s, n);
- return res;
-}
-
-void *__msan_memmove(void *dest, const void *src, SIZE_T n) {
- ENSURE_MSAN_INITED();
- void *res = REAL(memmove)(dest, src, n);
- __msan_move_poison(dest, src, n);
- return res;
+ REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst),
+ (void *)MEM_TO_SHADOW((uptr)src), size);
+ CopyOrigin(dst, src, size, stack);
}
-namespace __msan {
void InitializeInterceptors() {
static int inited = 0;
CHECK_EQ(inited, 0);
- SANITIZER_COMMON_INTERCEPTORS_INIT;
+ InitializeCommonInterceptors();
INTERCEPT_FUNCTION(mmap);
- INTERCEPT_FUNCTION(mmap64);
+ MSAN_MAYBE_INTERCEPT_MMAP64;
INTERCEPT_FUNCTION(posix_memalign);
- INTERCEPT_FUNCTION(memalign);
+ MSAN_MAYBE_INTERCEPT_MEMALIGN;
+ INTERCEPT_FUNCTION(__libc_memalign);
INTERCEPT_FUNCTION(valloc);
- INTERCEPT_FUNCTION(pvalloc);
+ MSAN_MAYBE_INTERCEPT_PVALLOC;
INTERCEPT_FUNCTION(malloc);
INTERCEPT_FUNCTION(calloc);
INTERCEPT_FUNCTION(realloc);
INTERCEPT_FUNCTION(free);
+ MSAN_MAYBE_INTERCEPT_CFREE;
+ INTERCEPT_FUNCTION(malloc_usable_size);
+ MSAN_MAYBE_INTERCEPT_MALLINFO;
+ MSAN_MAYBE_INTERCEPT_MALLOPT;
+ MSAN_MAYBE_INTERCEPT_MALLOC_STATS;
INTERCEPT_FUNCTION(fread);
- INTERCEPT_FUNCTION(fread_unlocked);
+ MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED;
INTERCEPT_FUNCTION(readlink);
INTERCEPT_FUNCTION(memcpy);
INTERCEPT_FUNCTION(memccpy);
@@ -1458,73 +1572,73 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(strcpy); // NOLINT
INTERCEPT_FUNCTION(stpcpy); // NOLINT
INTERCEPT_FUNCTION(strdup);
- INTERCEPT_FUNCTION(__strdup);
+ MSAN_MAYBE_INTERCEPT___STRDUP;
INTERCEPT_FUNCTION(strndup);
- INTERCEPT_FUNCTION(__strndup);
+ MSAN_MAYBE_INTERCEPT___STRNDUP;
INTERCEPT_FUNCTION(strncpy); // NOLINT
INTERCEPT_FUNCTION(strlen);
INTERCEPT_FUNCTION(strnlen);
INTERCEPT_FUNCTION(gcvt);
INTERCEPT_FUNCTION(strcat); // NOLINT
INTERCEPT_FUNCTION(strncat); // NOLINT
- INTERCEPT_FUNCTION(strtol);
- INTERCEPT_FUNCTION(strtoll);
- INTERCEPT_FUNCTION(strtoul);
- INTERCEPT_FUNCTION(strtoull);
- INTERCEPT_FUNCTION(strtod);
- INTERCEPT_FUNCTION(strtod_l);
- INTERCEPT_FUNCTION(__strtod_l);
- INTERCEPT_FUNCTION(strtof);
- INTERCEPT_FUNCTION(strtof_l);
- INTERCEPT_FUNCTION(__strtof_l);
- INTERCEPT_FUNCTION(strtold);
- INTERCEPT_FUNCTION(strtold_l);
- INTERCEPT_FUNCTION(__strtold_l);
- INTERCEPT_FUNCTION(vasprintf);
- INTERCEPT_FUNCTION(asprintf);
- INTERCEPT_FUNCTION(vsprintf);
- INTERCEPT_FUNCTION(vsnprintf);
+ INTERCEPT_STRTO(strtod);
+ INTERCEPT_STRTO(strtof);
+ INTERCEPT_STRTO(strtold);
+ INTERCEPT_STRTO(strtol);
+ INTERCEPT_STRTO(strtoul);
+ INTERCEPT_STRTO(strtoll);
+ INTERCEPT_STRTO(strtoull);
+ INTERCEPT_STRTO(wcstod);
+ INTERCEPT_STRTO(wcstof);
+ INTERCEPT_STRTO(wcstold);
+ INTERCEPT_STRTO(wcstol);
+ INTERCEPT_STRTO(wcstoul);
+ INTERCEPT_STRTO(wcstoll);
+ INTERCEPT_STRTO(wcstoull);
INTERCEPT_FUNCTION(vswprintf);
- INTERCEPT_FUNCTION(sprintf); // NOLINT
- INTERCEPT_FUNCTION(snprintf);
INTERCEPT_FUNCTION(swprintf);
+ INTERCEPT_FUNCTION(strxfrm);
+ INTERCEPT_FUNCTION(strxfrm_l);
INTERCEPT_FUNCTION(strftime);
+ INTERCEPT_FUNCTION(strftime_l);
+ MSAN_MAYBE_INTERCEPT___STRFTIME_L;
+ INTERCEPT_FUNCTION(wcsftime);
+ INTERCEPT_FUNCTION(wcsftime_l);
+ MSAN_MAYBE_INTERCEPT___WCSFTIME_L;
INTERCEPT_FUNCTION(mbtowc);
INTERCEPT_FUNCTION(mbrtowc);
INTERCEPT_FUNCTION(wcslen);
INTERCEPT_FUNCTION(wcschr);
INTERCEPT_FUNCTION(wcscpy);
INTERCEPT_FUNCTION(wcscmp);
- INTERCEPT_FUNCTION(wcstod);
INTERCEPT_FUNCTION(getenv);
INTERCEPT_FUNCTION(setenv);
INTERCEPT_FUNCTION(putenv);
INTERCEPT_FUNCTION(gettimeofday);
INTERCEPT_FUNCTION(fcvt);
- INTERCEPT_FUNCTION(__fxstat);
- INTERCEPT_FUNCTION(__fxstatat);
- INTERCEPT_FUNCTION(__xstat);
- INTERCEPT_FUNCTION(__lxstat);
- INTERCEPT_FUNCTION(__fxstat64);
- INTERCEPT_FUNCTION(__fxstatat64);
- INTERCEPT_FUNCTION(__xstat64);
- INTERCEPT_FUNCTION(__lxstat64);
+ MSAN_MAYBE_INTERCEPT___FXSTAT;
+ MSAN_MAYBE_INTERCEPT___FXSTATAT;
+ MSAN_MAYBE_INTERCEPT___XSTAT;
+ MSAN_MAYBE_INTERCEPT___LXSTAT;
+ MSAN_MAYBE_INTERCEPT___FXSTAT64;
+ MSAN_MAYBE_INTERCEPT___FXSTATAT64;
+ MSAN_MAYBE_INTERCEPT___XSTAT64;
+ MSAN_MAYBE_INTERCEPT___LXSTAT64;
INTERCEPT_FUNCTION(pipe);
INTERCEPT_FUNCTION(pipe2);
INTERCEPT_FUNCTION(socketpair);
INTERCEPT_FUNCTION(fgets);
- INTERCEPT_FUNCTION(fgets_unlocked);
+ MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED;
INTERCEPT_FUNCTION(getrlimit);
- INTERCEPT_FUNCTION(getrlimit64);
+ MSAN_MAYBE_INTERCEPT_GETRLIMIT64;
INTERCEPT_FUNCTION(uname);
INTERCEPT_FUNCTION(gethostname);
- INTERCEPT_FUNCTION(epoll_wait);
- INTERCEPT_FUNCTION(epoll_pwait);
+ MSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
+ MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT;
INTERCEPT_FUNCTION(recv);
INTERCEPT_FUNCTION(recvfrom);
INTERCEPT_FUNCTION(dladdr);
INTERCEPT_FUNCTION(dlerror);
- INTERCEPT_FUNCTION(dlopen);
INTERCEPT_FUNCTION(dl_iterate_phdr);
INTERCEPT_FUNCTION(getrusage);
INTERCEPT_FUNCTION(sigaction);
@@ -1535,11 +1649,7 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(tzset);
INTERCEPT_FUNCTION(__cxa_atexit);
INTERCEPT_FUNCTION(shmat);
-
- if (REAL(pthread_key_create)(&g_thread_finalize_key, &thread_finalize)) {
- Printf("MemorySanitizer: failed to create thread key\n");
- Die();
- }
+ INTERCEPT_FUNCTION(fork);
inited = 1;
}
diff --git a/lib/msan/msan_interface_internal.h b/lib/msan/msan_interface_internal.h
index 794b3540f9313..8641f814bc5f8 100644
--- a/lib/msan/msan_interface_internal.h
+++ b/lib/msan/msan_interface_internal.h
@@ -38,8 +38,28 @@ SANITIZER_INTERFACE_ATTRIBUTE __attribute__((noreturn))
void __msan_warning_noreturn();
SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_1(u8 s, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_2(u16 s, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_4(u32 s, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_8(u64 s, u32 o);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_1(u8 s, void *p, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_2(u16 s, void *p, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_4(u32 s, void *p, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_8(u64 s, void *p, u32 o);
+
+SANITIZER_INTERFACE_ATTRIBUTE
void __msan_unpoison(const void *a, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_unpoison_string(const char *s);
+SANITIZER_INTERFACE_ATTRIBUTE
void __msan_clear_and_unpoison(void *a, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void* __msan_memcpy(void *dst, const void *src, uptr size);
@@ -48,12 +68,6 @@ void* __msan_memset(void *s, int c, uptr n);
SANITIZER_INTERFACE_ATTRIBUTE
void* __msan_memmove(void* dest, const void* src, uptr n);
SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_copy_poison(void *dst, const void *src, uptr size);
-SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_copy_origin(void *dst, const void *src, uptr size);
-SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_move_poison(void *dst, const void *src, uptr size);
-SANITIZER_INTERFACE_ATTRIBUTE
void __msan_poison(const void *a, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_poison_stack(void *a, uptr size);
@@ -69,11 +83,16 @@ SANITIZER_INTERFACE_ATTRIBUTE
sptr __msan_test_shadow(const void *x, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_check_mem_is_initialized(const void *x, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
void __msan_set_origin(const void *a, uptr size, u32 origin);
SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_set_alloca_origin(void *a, uptr size, const char *descr);
+void __msan_set_alloca_origin(void *a, uptr size, char *descr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc);
SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc);
+u32 __msan_chain_origin(u32 id);
SANITIZER_INTERFACE_ATTRIBUTE
u32 __msan_get_origin(const void *a);
@@ -99,26 +118,14 @@ void __msan_set_expect_umr(int expect_umr);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_print_shadow(const void *x, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_print_param_shadow();
+void __msan_dump_shadow(const void *x, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
int __msan_has_dynamic_component();
-// Returns x such that %fs:x is the first byte of __msan_retval_tls.
-SANITIZER_INTERFACE_ATTRIBUTE
-int __msan_get_retval_tls_offset();
-SANITIZER_INTERFACE_ATTRIBUTE
-int __msan_get_param_tls_offset();
-
-// For intercepting mmap from ld.so in msandr.
-SANITIZER_INTERFACE_ATTRIBUTE
-bool __msan_is_in_loader();
-
// For testing.
SANITIZER_INTERFACE_ATTRIBUTE
u32 __msan_get_umr_origin();
SANITIZER_INTERFACE_ATTRIBUTE
-const char *__msan_get_origin_descr_if_stack(u32 id);
-SANITIZER_INTERFACE_ATTRIBUTE
void __msan_partial_poison(const void* data, void* shadow, uptr size);
// Tell MSan about newly allocated memory (ex.: custom allocator).
@@ -145,31 +152,7 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_unaligned_store64(uu64 *p, u64 x);
SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_estimated_allocated_size(uptr size);
-
-SANITIZER_INTERFACE_ATTRIBUTE
-int __msan_get_ownership(const void *p);
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_allocated_size(const void *p);
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_current_allocated_bytes();
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_heap_size();
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_free_bytes();
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_unmapped_bytes();
-
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-/* OPTIONAL */ void __msan_malloc_hook(void *ptr, uptr size);
-
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-/* OPTIONAL */ void __msan_free_hook(void *ptr);
+void __msan_set_death_callback(void (*callback)(void));
} // extern "C"
#endif // MSAN_INTERFACE_INTERNAL_H
diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc
index 46f501e488c52..0b67b531d51ca 100644
--- a/lib/msan/msan_linux.cc
+++ b/lib/msan/msan_linux.cc
@@ -9,16 +9,18 @@
//
// This file is a part of MemorySanitizer.
//
-// Linux-specific code.
+// Linux- and FreeBSD-specific code.
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
#include "msan.h"
+#include "msan_thread.h"
#include <elf.h>
#include <link.h>
+#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
@@ -33,63 +35,117 @@
namespace __msan {
-static const uptr kMemBeg = 0x600000000000;
-static const uptr kMemEnd = 0x7fffffffffff;
-static const uptr kShadowBeg = MEM_TO_SHADOW(kMemBeg);
-static const uptr kShadowEnd = MEM_TO_SHADOW(kMemEnd);
-static const uptr kBad1Beg = 0x100000000; // 4G
-static const uptr kBad1End = kShadowBeg - 1;
-static const uptr kBad2Beg = kShadowEnd + 1;
-static const uptr kBad2End = kMemBeg - 1;
-static const uptr kOriginsBeg = kBad2Beg;
-static const uptr kOriginsEnd = kBad2End;
-
-bool InitShadow(bool prot1, bool prot2, bool map_shadow, bool init_origins) {
- if ((uptr) & InitShadow < kMemBeg) {
- Printf("FATAL: Code below application range: %p < %p. Non-PIE build?\n",
- &InitShadow, (void *)kMemBeg);
- return false;
+void ReportMapRange(const char *descr, uptr beg, uptr size) {
+ if (size > 0) {
+ uptr end = beg + size - 1;
+ VPrintf(1, "%s : %p - %p\n", descr, beg, end);
}
+}
- if (common_flags()->verbosity) {
- Printf("__msan_init %p\n", &__msan_init);
- Printf("Memory : %p %p\n", kMemBeg, kMemEnd);
- Printf("Bad2 : %p %p\n", kBad2Beg, kBad2End);
- Printf("Origins : %p %p\n", kOriginsBeg, kOriginsEnd);
- Printf("Shadow : %p %p\n", kShadowBeg, kShadowEnd);
- Printf("Bad1 : %p %p\n", kBad1Beg, kBad1End);
+static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
+ if (size > 0) {
+ uptr end = beg + size - 1;
+ if (!MemoryRangeIsAvailable(beg, end)) {
+ Printf("FATAL: Memory range %p - %p is not available.\n", beg, end);
+ return false;
+ }
}
+ return true;
+}
- if (!MemoryRangeIsAvailable(kShadowBeg,
- init_origins ? kOriginsEnd : kShadowEnd)) {
- Printf("FATAL: Shadow memory range is not available.\n");
+static bool ProtectMemoryRange(uptr beg, uptr size) {
+ if (size > 0) {
+ uptr end = beg + size - 1;
+ if (!Mprotect(beg, size)) {
+ Printf("FATAL: Cannot protect memory range %p - %p.\n", beg, end);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool InitShadow(bool map_shadow, bool init_origins) {
+ // Let user know mapping parameters first.
+ VPrintf(1, "__msan_init %p\n", &__msan_init);
+ ReportMapRange("Low Memory ", kLowMemBeg, kLowMemSize);
+ ReportMapRange("Bad1 ", kBad1Beg, kBad1Size);
+ ReportMapRange("Shadow ", kShadowBeg, kShadowSize);
+ ReportMapRange("Bad2 ", kBad2Beg, kBad2Size);
+ ReportMapRange("Origins ", kOriginsBeg, kOriginsSize);
+ ReportMapRange("Bad3 ", kBad3Beg, kBad3Size);
+ ReportMapRange("High Memory", kHighMemBeg, kHighMemSize);
+
+ // Check mapping sanity (the invariant).
+ CHECK_EQ(kLowMemBeg, 0);
+ CHECK_EQ(kBad1Beg, kLowMemBeg + kLowMemSize);
+ CHECK_EQ(kShadowBeg, kBad1Beg + kBad1Size);
+ CHECK_GT(kShadowSize, 0);
+ CHECK_GE(kShadowSize, kLowMemSize + kHighMemSize);
+ CHECK_EQ(kBad2Beg, kShadowBeg + kShadowSize);
+ CHECK_EQ(kOriginsBeg, kBad2Beg + kBad2Size);
+ CHECK_EQ(kOriginsSize, kShadowSize);
+ CHECK_EQ(kBad3Beg, kOriginsBeg + kOriginsSize);
+ CHECK_EQ(kHighMemBeg, kBad3Beg + kBad3Size);
+ CHECK_GT(kHighMemSize, 0);
+ CHECK_GE(kHighMemBeg + kHighMemSize, kHighMemBeg); // Tests for no overflow.
+
+ if (kLowMemSize > 0) {
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(kLowMemBeg)));
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(kLowMemBeg + kLowMemSize - 1)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(kLowMemBeg)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(kLowMemBeg + kLowMemSize - 1)));
+ }
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(kHighMemBeg)));
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(kHighMemBeg + kHighMemSize - 1)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(kHighMemBeg)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(kHighMemBeg + kHighMemSize - 1)));
+
+ if (!MEM_IS_APP(&__msan_init)) {
+ Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
+ (uptr)&__msan_init);
return false;
}
- if (prot1 && !Mprotect(kBad1Beg, kBad1End - kBad1Beg))
+ if (!CheckMemoryRangeAvailability(kShadowBeg, kShadowSize) ||
+ (init_origins &&
+ !CheckMemoryRangeAvailability(kOriginsBeg, kOriginsSize)) ||
+ !CheckMemoryRangeAvailability(kBad1Beg, kBad1Size) ||
+ !CheckMemoryRangeAvailability(kBad2Beg, kBad2Size) ||
+ !CheckMemoryRangeAvailability(kBad3Beg, kBad3Size)) {
return false;
- if (prot2 && !Mprotect(kBad2Beg, kBad2End - kBad2Beg))
+ }
+
+ if (!ProtectMemoryRange(kBad1Beg, kBad1Size) ||
+ !ProtectMemoryRange(kBad2Beg, kBad2Size) ||
+ !ProtectMemoryRange(kBad3Beg, kBad3Size)) {
return false;
+ }
+
if (map_shadow) {
- void *shadow = MmapFixedNoReserve(kShadowBeg, kShadowEnd - kShadowBeg);
+ void *shadow = MmapFixedNoReserve(kShadowBeg, kShadowSize);
if (shadow != (void*)kShadowBeg) return false;
}
if (init_origins) {
- void *origins = MmapFixedNoReserve(kOriginsBeg, kOriginsEnd - kOriginsBeg);
+ void *origins = MmapFixedNoReserve(kOriginsBeg, kOriginsSize);
if (origins != (void*)kOriginsBeg) return false;
}
return true;
}
void MsanDie() {
+ if (common_flags()->coverage)
+ __sanitizer_cov_dump();
+ if (death_callback)
+ death_callback();
_exit(flags()->exit_code);
}
static void MsanAtExit(void) {
+ if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
+ ReportStats();
if (msan_report_count > 0) {
ReportAtExitStatistics();
- if (flags()->exit_code)
- _exit(flags()->exit_code);
+ if (flags()->exit_code) _exit(flags()->exit_code);
}
}
@@ -97,6 +153,36 @@ void InstallAtExitHandler() {
atexit(MsanAtExit);
}
+// ---------------------- TSD ---------------- {{{1
+
+static pthread_key_t tsd_key;
+static bool tsd_key_inited = false;
+void MsanTSDInit(void (*destructor)(void *tsd)) {
+ CHECK(!tsd_key_inited);
+ tsd_key_inited = true;
+ CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
+}
+
+void *MsanTSDGet() {
+ CHECK(tsd_key_inited);
+ return pthread_getspecific(tsd_key);
+}
+
+void MsanTSDSet(void *tsd) {
+ CHECK(tsd_key_inited);
+ pthread_setspecific(tsd_key, tsd);
+}
+
+void MsanTSDDtor(void *tsd) {
+ MsanThread *t = (MsanThread*)tsd;
+ if (t->destructor_iterations_ > 1) {
+ t->destructor_iterations_--;
+ CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
+ return;
+ }
+ MsanThread::TSDDtor(tsd);
+}
+
} // namespace __msan
-#endif // __linux__
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/msan/msan_new_delete.cc b/lib/msan/msan_new_delete.cc
index 17687ddfc2130..9a8e56e4a28ad 100644
--- a/lib/msan/msan_new_delete.cc
+++ b/lib/msan/msan_new_delete.cc
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "msan.h"
+#include "interception/interception.h"
#if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
@@ -37,18 +38,26 @@ namespace std {
GET_MALLOC_STACK_TRACE; \
return MsanReallocate(&stack, 0, size, sizeof(u64), false)
+INTERCEPTOR_ATTRIBUTE
void *operator new(size_t size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
#define OPERATOR_DELETE_BODY \
GET_MALLOC_STACK_TRACE; \
if (ptr) MsanDeallocate(&stack, ptr)
-void operator delete(void *ptr) { OPERATOR_DELETE_BODY; }
-void operator delete[](void *ptr) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
void operator delete[](void *ptr, std::nothrow_t const&) {
OPERATOR_DELETE_BODY;
}
diff --git a/lib/msan/msan_origin.h b/lib/msan/msan_origin.h
new file mode 100644
index 0000000000000..1284c01bf2af4
--- /dev/null
+++ b/lib/msan/msan_origin.h
@@ -0,0 +1,169 @@
+//===-- msan_origin.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Origin id utils.
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_ORIGIN_H
+#define MSAN_ORIGIN_H
+
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "msan_chained_origin_depot.h"
+
+namespace __msan {
+
+// Origin handling.
+//
+// Origin is a 32-bit identifier that is attached to any uninitialized value in
+// the program and describes, more or less exactly, how this memory came to be
+// uninitialized.
+//
+// There are 3 kinds of origin ids:
+// 1xxx xxxx xxxx xxxx heap origin id
+// 0000 xxxx xxxx xxxx stack origin id
+// 0zzz xxxx xxxx xxxx chained origin id
+//
+// Heap origin id describes a heap memory allocation and contains (in the xxx
+// part) a value of StackDepot.
+//
+// Stack origin id describes a stack memory allocation and contains (in the xxx
+// part) an index into StackOriginDescr and StackOriginPC. We don't store a
+// stack trace for such origins for performance reasons.
+//
+// Chained origin id describes an event of storing an uninitialized value to
+// memory. The xxx part is a value of ChainedOriginDepot, which is a mapping of
+// (stack_id, prev_id) -> id, where
+// * stack_id describes the event.
+// StackDepot keeps a mapping between those and corresponding stack traces.
+// * prev_id is another origin id that describes the earlier part of the
+// uninitialized value history.
+// Following a chain of prev_id provides the full recorded history of an
+// uninitialized value.
+//
+// This, effectively, defines a tree (or 2 trees, see below) where nodes are
+// points in value history marked with origin ids, and edges are events that are
+// marked with stack_id.
+//
+// The "zzz" bits of chained origin id are used to store the length (or depth)
+// of the origin chain.
+
+class Origin {
+ public:
+ static bool isValidId(u32 id) { return id != 0 && id != (u32)-1; }
+
+ u32 raw_id() const { return raw_id_; }
+ bool isHeapOrigin() const {
+ // 1xxx xxxx xxxx xxxx
+ return raw_id_ >> kHeapShift == 0;
+ }
+ bool isStackOrigin() const {
+ // 1000 xxxx xxxx xxxx
+ return (raw_id_ >> kDepthShift) == (1 << kDepthBits);
+ }
+ bool isChainedOrigin() const {
+ // 1zzz xxxx xxxx xxxx, zzz != 000
+ return (raw_id_ >> kDepthShift) > (1 << kDepthBits);
+ }
+ u32 getChainedId() const {
+ CHECK(isChainedOrigin());
+ return raw_id_ & kChainedIdMask;
+ }
+ u32 getStackId() const {
+ CHECK(isStackOrigin());
+ return raw_id_ & kChainedIdMask;
+ }
+ u32 getHeapId() const {
+ CHECK(isHeapOrigin());
+ return raw_id_ & kHeapIdMask;
+ }
+
+ // Returns the next origin in the chain and the current stack trace.
+ Origin getNextChainedOrigin(StackTrace *stack) const {
+ CHECK(isChainedOrigin());
+ u32 prev_id;
+ u32 stack_id = ChainedOriginDepotGet(getChainedId(), &prev_id);
+ *stack = StackDepotGet(stack_id);
+ return Origin(prev_id);
+ }
+
+ StackTrace getStackTraceForHeapOrigin() const {
+ return StackDepotGet(getHeapId());
+ }
+
+ static Origin CreateStackOrigin(u32 id) {
+ CHECK((id & kStackIdMask) == id);
+ return Origin((1 << kHeapShift) | id);
+ }
+
+ static Origin CreateHeapOrigin(StackTrace *stack) {
+ u32 stack_id = StackDepotPut(*stack);
+ CHECK(stack_id);
+ CHECK((stack_id & kHeapIdMask) == stack_id);
+ return Origin(stack_id);
+ }
+
+ static Origin CreateChainedOrigin(Origin prev, StackTrace *stack) {
+ int depth = prev.isChainedOrigin() ? prev.depth() : 0;
+ // depth is the length of the chain minus 1.
+ // origin_history_size of 0 means unlimited depth.
+ if (flags()->origin_history_size > 0) {
+ if (depth + 1 >= flags()->origin_history_size) {
+ return prev;
+ } else {
+ ++depth;
+ CHECK(depth < (1 << kDepthBits));
+ }
+ }
+
+ StackDepotHandle h = StackDepotPut_WithHandle(*stack);
+ if (!h.valid()) return prev;
+
+ if (flags()->origin_history_per_stack_limit > 0) {
+ int use_count = h.use_count();
+ if (use_count > flags()->origin_history_per_stack_limit) return prev;
+ }
+
+ u32 chained_id;
+ bool inserted = ChainedOriginDepotPut(h.id(), prev.raw_id(), &chained_id);
+ CHECK((chained_id & kChainedIdMask) == chained_id);
+
+ if (inserted && flags()->origin_history_per_stack_limit > 0)
+ h.inc_use_count_unsafe();
+
+ return Origin((1 << kHeapShift) | (depth << kDepthShift) | chained_id);
+ }
+
+ static Origin FromRawId(u32 id) {
+ return Origin(id);
+ }
+
+ private:
+ static const int kDepthBits = 3;
+ static const int kDepthShift = 32 - kDepthBits - 1;
+
+ static const int kHeapShift = 31;
+ static const u32 kChainedIdMask = ((u32)-1) >> (32 - kDepthShift);
+ static const u32 kStackIdMask = ((u32)-1) >> (32 - kDepthShift);
+ static const u32 kHeapIdMask = ((u32)-1) >> (32 - kHeapShift);
+
+ u32 raw_id_;
+
+ explicit Origin(u32 raw_id) : raw_id_(raw_id) {}
+
+ int depth() const {
+ CHECK(isChainedOrigin());
+ return (raw_id_ >> kDepthShift) & ((1 << kDepthBits) - 1);
+ }
+
+ public:
+ static const int kMaxDepth = (1 << kDepthBits) - 1;
+};
+
+} // namespace __msan
+
+#endif // MSAN_ORIGIN_H
diff --git a/lib/msan/msan_report.cc b/lib/msan/msan_report.cc
index e3ef99307940a..717c4a958c8f4 100644
--- a/lib/msan/msan_report.cc
+++ b/lib/msan/msan_report.cc
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
@@ -25,44 +27,57 @@ using namespace __sanitizer;
namespace __msan {
-class Decorator: private __sanitizer::AnsiColorDecorator {
+class Decorator: public __sanitizer::SanitizerCommonDecorator {
public:
- Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
+ Decorator() : SanitizerCommonDecorator() { }
const char *Warning() { return Red(); }
const char *Origin() { return Magenta(); }
const char *Name() { return Green(); }
const char *End() { return Default(); }
};
-static void DescribeOrigin(u32 origin) {
+static void DescribeStackOrigin(const char *so, uptr pc) {
Decorator d;
- if (common_flags()->verbosity)
- Printf(" raw origin id: %d\n", origin);
- uptr pc;
- if (const char *so = GetOriginDescrIfStack(origin, &pc)) {
- char* s = internal_strdup(so);
- char* sep = internal_strchr(s, '@');
- CHECK(sep);
- *sep = '\0';
- Printf("%s", d.Origin());
- Printf(" %sUninitialized value was created by an allocation of '%s%s%s'"
- " in the stack frame of function '%s%s%s'%s\n",
- d.Origin(), d.Name(), s, d.Origin(), d.Name(),
- Symbolizer::Get()->Demangle(sep + 1), d.Origin(), d.End());
- InternalFree(s);
-
- if (pc) {
- // For some reason function address in LLVM IR is 1 less then the address
- // of the first instruction.
- pc += 1;
- StackTrace::PrintStack(&pc, 1);
- }
+ char *s = internal_strdup(so);
+ char *sep = internal_strchr(s, '@');
+ CHECK(sep);
+ *sep = '\0';
+ Printf("%s", d.Origin());
+ Printf(
+ " %sUninitialized value was created by an allocation of '%s%s%s'"
+ " in the stack frame of function '%s%s%s'%s\n",
+ d.Origin(), d.Name(), s, d.Origin(), d.Name(), sep + 1, d.Origin(),
+ d.End());
+ InternalFree(s);
+
+ if (pc) {
+ // For some reason function address in LLVM IR is 1 less then the address
+ // of the first instruction.
+ pc = StackTrace::GetNextInstructionPc(pc);
+ StackTrace(&pc, 1).Print();
+ }
+}
+
+static void DescribeOrigin(u32 id) {
+ VPrintf(1, " raw origin id: %d\n", id);
+ Decorator d;
+ Origin o = Origin::FromRawId(id);
+ while (o.isChainedOrigin()) {
+ StackTrace stack;
+ o = o.getNextChainedOrigin(&stack);
+ Printf(" %sUninitialized value was stored to memory at%s\n", d.Origin(),
+ d.End());
+ stack.Print();
+ }
+ if (o.isStackOrigin()) {
+ uptr pc;
+ const char *so = GetStackOriginDescr(o.getStackId(), &pc);
+ DescribeStackOrigin(so, pc);
} else {
- uptr size = 0;
- const uptr *trace = StackDepotGet(origin, &size);
+ StackTrace stack = o.getStackTraceForHeapOrigin();
Printf(" %sUninitialized value was created by a heap allocation%s\n",
d.Origin(), d.End());
- StackTrace::PrintStack(trace, size);
+ stack.Print();
}
}
@@ -75,7 +90,7 @@ void ReportUMR(StackTrace *stack, u32 origin) {
Printf("%s", d.Warning());
Report(" WARNING: MemorySanitizer: use-of-uninitialized-value\n");
Printf("%s", d.End());
- StackTrace::PrintStack(stack->trace, stack->size);
+ stack->Print();
if (origin) {
DescribeOrigin(origin);
}
@@ -86,16 +101,162 @@ void ReportExpectedUMRNotFound(StackTrace *stack) {
SpinMutexLock l(&CommonSanitizerReportMutex);
Printf(" WARNING: Expected use of uninitialized value not found\n");
- StackTrace::PrintStack(stack->trace, stack->size);
+ stack->Print();
+}
+
+void ReportStats() {
+ SpinMutexLock l(&CommonSanitizerReportMutex);
+
+ if (__msan_get_track_origins() > 0) {
+ StackDepotStats *stack_depot_stats = StackDepotGetStats();
+ // FIXME: we want this at normal exit, too!
+ // FIXME: but only with verbosity=1 or something
+ Printf("Unique heap origins: %zu\n", stack_depot_stats->n_uniq_ids);
+ Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats->allocated);
+
+ StackDepotStats *chained_origin_depot_stats = ChainedOriginDepotGetStats();
+ Printf("Unique origin histories: %zu\n",
+ chained_origin_depot_stats->n_uniq_ids);
+ Printf("History depot allocated bytes: %zu\n",
+ chained_origin_depot_stats->allocated);
+ }
}
void ReportAtExitStatistics() {
SpinMutexLock l(&CommonSanitizerReportMutex);
+ if (msan_report_count > 0) {
+ Decorator d;
+ Printf("%s", d.Warning());
+ Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count);
+ Printf("%s", d.End());
+ }
+}
+
+class OriginSet {
+ public:
+ OriginSet() : next_id_(0) {}
+ int insert(u32 o) {
+ // Scan from the end for better locality.
+ for (int i = next_id_ - 1; i >= 0; --i)
+ if (origins_[i] == o) return i;
+ if (next_id_ == kMaxSize_) return OVERFLOW;
+ int id = next_id_++;
+ origins_[id] = o;
+ return id;
+ }
+ int size() { return next_id_; }
+ u32 get(int id) { return origins_[id]; }
+ static char asChar(int id) {
+ switch (id) {
+ case MISSING:
+ return '.';
+ case OVERFLOW:
+ return '*';
+ default:
+ return 'A' + id;
+ }
+ }
+ static const int OVERFLOW = -1;
+ static const int MISSING = -2;
+
+ private:
+ static const int kMaxSize_ = 'Z' - 'A' + 1;
+ u32 origins_[kMaxSize_];
+ int next_id_;
+};
+
+void DescribeMemoryRange(const void *x, uptr size) {
+ // Real limits.
+ uptr start = MEM_TO_SHADOW(x);
+ uptr end = start + size;
+ // Scan limits: align start down to 4; align size up to 16.
+ uptr s = start & ~3UL;
+ size = end - s;
+ size = (size + 15) & ~15UL;
+ uptr e = s + size;
+
+ // Single letter names to origin id mapping.
+ OriginSet origin_set;
+
+ uptr pos = 0; // Offset from aligned start.
+ bool with_origins = __msan_get_track_origins();
+ // True if there is at least 1 poisoned bit in the last 4-byte group.
+ bool last_quad_poisoned;
+ int origin_ids[4]; // Single letter origin ids for the current line.
+
Decorator d;
Printf("%s", d.Warning());
- Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count);
+ Printf("Shadow map of [%p, %p), %zu bytes:\n", start, end, end - start);
Printf("%s", d.End());
+ while (s < e) {
+ // Line start.
+ if (pos % 16 == 0) {
+ for (int i = 0; i < 4; ++i) origin_ids[i] = -1;
+ Printf("%p:", s);
+ }
+ // Group start.
+ if (pos % 4 == 0) {
+ Printf(" ");
+ last_quad_poisoned = false;
+ }
+ // Print shadow byte.
+ if (s < start || s >= end) {
+ Printf("..");
+ } else {
+ unsigned char v = *(unsigned char *)s;
+ if (v) last_quad_poisoned = true;
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ Printf("%x%x", v & 0xf, v >> 4);
+#else
+ Printf("%x%x", v >> 4, v & 0xf);
+#endif
+ }
+ // Group end.
+ if (pos % 4 == 3 && with_origins) {
+ int id = OriginSet::MISSING;
+ if (last_quad_poisoned) {
+ u32 o = *(u32 *)SHADOW_TO_ORIGIN(s - 3);
+ id = origin_set.insert(o);
+ }
+ origin_ids[(pos % 16) / 4] = id;
+ }
+ // Line end.
+ if (pos % 16 == 15) {
+ if (with_origins) {
+ Printf(" |");
+ for (int i = 0; i < 4; ++i) {
+ char c = OriginSet::asChar(origin_ids[i]);
+ Printf("%c", c);
+ if (i != 3) Printf(" ");
+ }
+ Printf("|");
+ }
+ Printf("\n");
+ }
+ size--;
+ s++;
+ pos++;
+ }
+
+ Printf("\n");
+
+ for (int i = 0; i < origin_set.size(); ++i) {
+ u32 o = origin_set.get(i);
+ Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i), o);
+ DescribeOrigin(o);
+ }
+}
+
+void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size,
+ uptr offset) {
+ Decorator d;
+ Printf("%s", d.Warning());
+ Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",
+ d.Warning(), d.Name(), what, d.Warning(), offset, start, size,
+ d.End());
+ if (__sanitizer::common_flags()->verbosity > 0)
+ DescribeMemoryRange(start, size);
}
} // namespace __msan
diff --git a/lib/msan/msan_thread.cc b/lib/msan/msan_thread.cc
new file mode 100644
index 0000000000000..f29a4b053a367
--- /dev/null
+++ b/lib/msan/msan_thread.cc
@@ -0,0 +1,93 @@
+
+#include "msan.h"
+#include "msan_thread.h"
+#include "msan_interface_internal.h"
+
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+
+namespace __msan {
+
+MsanThread *MsanThread::Create(thread_callback_t start_routine,
+ void *arg) {
+ uptr PageSize = GetPageSizeCached();
+ uptr size = RoundUpTo(sizeof(MsanThread), PageSize);
+ MsanThread *thread = (MsanThread*)MmapOrDie(size, __func__);
+ thread->start_routine_ = start_routine;
+ thread->arg_ = arg;
+ thread->destructor_iterations_ = kPthreadDestructorIterations;
+
+ return thread;
+}
+
+void MsanThread::SetThreadStackAndTls() {
+ uptr tls_size = 0;
+ uptr stack_size = 0;
+ GetThreadStackAndTls(IsMainThread(), &stack_bottom_, &stack_size,
+ &tls_begin_, &tls_size);
+ stack_top_ = stack_bottom_ + stack_size;
+ tls_end_ = tls_begin_ + tls_size;
+
+ int local;
+ CHECK(AddrIsInStack((uptr)&local));
+}
+
+void MsanThread::ClearShadowForThreadStackAndTLS() {
+ __msan_unpoison((void *)stack_bottom_, stack_top_ - stack_bottom_);
+ if (tls_begin_ != tls_end_)
+ __msan_unpoison((void *)tls_begin_, tls_end_ - tls_begin_);
+ DTLS *dtls = DTLS_Get();
+ CHECK_NE(dtls, 0);
+ for (uptr i = 0; i < dtls->dtv_size; ++i)
+ __msan_unpoison((void *)(dtls->dtv[i].beg), dtls->dtv[i].size);
+}
+
+void MsanThread::Init() {
+ SetThreadStackAndTls();
+ CHECK(MEM_IS_APP(stack_bottom_));
+ CHECK(MEM_IS_APP(stack_top_ - 1));
+ ClearShadowForThreadStackAndTLS();
+}
+
+void MsanThread::TSDDtor(void *tsd) {
+ MsanThread *t = (MsanThread*)tsd;
+ t->Destroy();
+}
+
+void MsanThread::Destroy() {
+ malloc_storage().CommitBack();
+ // We also clear the shadow on thread destruction because
+ // some code may still be executing in later TSD destructors
+ // and we don't want it to have any poisoned stack.
+ ClearShadowForThreadStackAndTLS();
+ uptr size = RoundUpTo(sizeof(MsanThread), GetPageSizeCached());
+ UnmapOrDie(this, size);
+ DTLS_Destroy();
+}
+
+thread_return_t MsanThread::ThreadStart() {
+ Init();
+
+ if (!start_routine_) {
+ // start_routine_ == 0 if we're on the main thread or on one of the
+ // OS X libdispatch worker threads. But nobody is supposed to call
+ // ThreadStart() for the worker threads.
+ return 0;
+ }
+
+ thread_return_t res = start_routine_(arg_);
+
+ return res;
+}
+
+MsanThread *GetCurrentThread() {
+ return reinterpret_cast<MsanThread *>(MsanTSDGet());
+}
+
+void SetCurrentThread(MsanThread *t) {
+ // Make sure we do not reset the current MsanThread.
+ CHECK_EQ(0, MsanTSDGet());
+ MsanTSDSet(t);
+ CHECK_EQ(t, MsanTSDGet());
+}
+
+} // namespace __msan
diff --git a/lib/msan/msan_thread.h b/lib/msan/msan_thread.h
new file mode 100644
index 0000000000000..bc605b89a505f
--- /dev/null
+++ b/lib/msan/msan_thread.h
@@ -0,0 +1,71 @@
+//===-- msan_thread.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_THREAD_H
+#define MSAN_THREAD_H
+
+#include "msan_allocator.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+class MsanThread {
+ public:
+ static MsanThread *Create(thread_callback_t start_routine, void *arg);
+ static void TSDDtor(void *tsd);
+ void Destroy();
+
+ void Init(); // Should be called from the thread itself.
+ thread_return_t ThreadStart();
+
+ uptr stack_top() { return stack_top_; }
+ uptr stack_bottom() { return stack_bottom_; }
+ uptr tls_begin() { return tls_begin_; }
+ uptr tls_end() { return tls_end_; }
+ bool IsMainThread() { return start_routine_ == 0; }
+
+ bool AddrIsInStack(uptr addr) {
+ return addr >= stack_bottom_ && addr < stack_top_;
+ }
+
+ bool InSignalHandler() { return in_signal_handler_; }
+ void EnterSignalHandler() { in_signal_handler_++; }
+ void LeaveSignalHandler() { in_signal_handler_--; }
+
+ MsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
+
+ int destructor_iterations_;
+
+ private:
+ // NOTE: There is no MsanThread constructor. It is allocated
+ // via mmap() and *must* be valid in zero-initialized state.
+ void SetThreadStackAndTls();
+ void ClearShadowForThreadStackAndTLS();
+ thread_callback_t start_routine_;
+ void *arg_;
+ uptr stack_top_;
+ uptr stack_bottom_;
+ uptr tls_begin_;
+ uptr tls_end_;
+
+ unsigned in_signal_handler_;
+
+ MsanThreadLocalMallocStorage malloc_storage_;
+};
+
+MsanThread *GetCurrentThread();
+void SetCurrentThread(MsanThread *t);
+
+} // namespace __msan
+
+#endif // MSAN_THREAD_H
diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt
index 9c49f167fa19e..53e1b549b70d7 100644
--- a/lib/msan/tests/CMakeLists.txt
+++ b/lib/msan/tests/CMakeLists.txt
@@ -5,46 +5,24 @@ include(CompilerRTLink)
include_directories(..)
include_directories(../..)
-# Instrumented libcxx sources and build flags.
-file(GLOB MSAN_LIBCXX_SOURCES ${MSAN_LIBCXX_PATH}/src/*.cpp)
set(MSAN_LIBCXX_CFLAGS
- -I${MSAN_LIBCXX_PATH}/include
-fsanitize=memory
-fsanitize-memory-track-origins
- -fPIC
- -Wno-\#warnings
- -g
- -O2
- -std=c++0x
- -fstrict-aliasing
- -fno-exceptions
- -nostdinc++
- -fno-omit-frame-pointer
- -mno-omit-leaf-frame-pointer)
-set(MSAN_LIBCXX_LINK_FLAGS
- -nodefaultlibs
- -lpthread
- -lrt
- -lc
- -lstdc++
- -fsanitize=memory)
+ -Wno-pedantic)
# Unittest sources and build flags.
set(MSAN_UNITTEST_SOURCES msan_test.cc msan_test_main.cc)
set(MSAN_LOADABLE_SOURCE msan_loadable.cc)
set(MSAN_UNITTEST_HEADERS
msan_test_config.h
- msandr_test_so.h
../../../include/sanitizer/msan_interface.h
)
-set(MSANDR_UNITTEST_SOURCE msandr_test_so.cc)
set(MSAN_UNITTEST_COMMON_CFLAGS
- -I${MSAN_LIBCXX_PATH}/include
- ${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
+ -I${COMPILER_RT_LIBCXX_PATH}/include
+ ${COMPILER_RT_GTEST_CFLAGS}
-I${COMPILER_RT_SOURCE_DIR}/include
-I${COMPILER_RT_SOURCE_DIR}/lib
-I${COMPILER_RT_SOURCE_DIR}/lib/msan
- -std=c++0x
-stdlib=libc++
-g
-O2
@@ -52,6 +30,9 @@ set(MSAN_UNITTEST_COMMON_CFLAGS
-fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer
-Wno-deprecated-declarations
+ -Wno-unused-variable
+ -Wno-zero-length-array
+ -Werror=sign-compare
)
set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS
${MSAN_UNITTEST_COMMON_CFLAGS}
@@ -61,10 +42,11 @@ set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS
)
set(MSAN_UNITTEST_LINK_FLAGS
-fsanitize=memory
- -ldl
# FIXME: we build libcxx without cxxabi and need libstdc++ to provide it.
-lstdc++
)
+
+append_list_if(COMPILER_RT_HAS_LIBDL -ldl MSAN_UNITTEST_LINK_FLAGS)
set(MSAN_LOADABLE_LINK_FLAGS
-fsanitize=memory
-shared
@@ -72,20 +54,27 @@ set(MSAN_LOADABLE_LINK_FLAGS
# Compile source for the given architecture, using compiler
# options in ${ARGN}, and add it to the object list.
-macro(msan_compile obj_list source arch)
+macro(msan_compile obj_list source arch kind)
get_filename_component(basename ${source} NAME)
- set(output_obj "${basename}.${arch}.o")
+ set(output_obj "${basename}.${arch}${kind}.o")
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
+ set(COMPILE_DEPS ${MSAN_UNITTEST_HEADERS})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND COMPILE_DEPS gtest msan)
+ endif()
clang_compile(${output_obj} ${source}
CFLAGS ${ARGN} ${TARGET_CFLAGS}
- DEPS gtest ${MSAN_RUNTIME_LIBRARIES} ${MSAN_UNITTEST_HEADERS})
+ DEPS ${COMPILE_DEPS})
list(APPEND ${obj_list} ${output_obj})
endmacro()
-macro(msan_link_shared so_list so_name arch)
+macro(msan_link_shared so_list so_name arch kind)
parse_arguments(SOURCE "OBJECTS;LINKFLAGS;DEPS" "" ${ARGN})
- set(output_so "${CMAKE_CURRENT_BINARY_DIR}/${so_name}.${arch}.so")
+ set(output_so "${CMAKE_CURRENT_BINARY_DIR}/${so_name}.${arch}${kind}.so")
get_target_flags_for_arch(${arch} TARGET_LINKFLAGS)
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND SOURCE_DEPS msan)
+ endif()
clang_link_shared(${output_so}
OBJECTS ${SOURCE_OBJECTS}
LINKFLAGS ${TARGET_LINKFLAGS} ${SOURCE_LINKFLAGS}
@@ -93,80 +82,62 @@ macro(msan_link_shared so_list so_name arch)
list(APPEND ${so_list} ${output_so})
endmacro()
-# Link MSan unit test for a given architecture from a set
-# of objects in ${ARGN}.
-macro(add_msan_test test_suite test_name arch)
- get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
- add_compiler_rt_test(${test_suite} ${test_name}
- OBJECTS ${ARGN}
- DEPS ${MSAN_RUNTIME_LIBRARIES} ${ARGN}
- ${MSAN_LOADABLE_SO}
- LINK_FLAGS ${MSAN_UNITTEST_LINK_FLAGS}
- ${TARGET_LINK_FLAGS}
- "-Wl,-rpath=${CMAKE_CURRENT_BINARY_DIR}")
-endmacro()
-
# Main MemorySanitizer unit tests.
add_custom_target(MsanUnitTests)
set_target_properties(MsanUnitTests PROPERTIES FOLDER "MSan unit tests")
# Adds MSan unit tests and benchmarks for architecture.
-macro(add_msan_tests_for_arch arch)
+macro(add_msan_tests_for_arch arch kind)
+ set(LIBCXX_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../libcxx_msan${kind})
+ add_custom_libcxx(libcxx_msan${kind} ${LIBCXX_PREFIX}
+ DEPS ${MSAN_RUNTIME_LIBRARIES}
+ CFLAGS ${MSAN_LIBCXX_CFLAGS} ${ARGN})
+ set(MSAN_LIBCXX_SO ${LIBCXX_PREFIX}/lib/libc++.so)
+
# Build gtest instrumented with MSan.
set(MSAN_INST_GTEST)
- msan_compile(MSAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch}
- ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS})
-
- # Build libcxx instrumented with MSan.
- set(MSAN_INST_LIBCXX_OBJECTS)
- foreach(SOURCE ${MSAN_LIBCXX_SOURCES})
- msan_compile(MSAN_INST_LIBCXX_OBJECTS ${SOURCE} ${arch}
- ${MSAN_LIBCXX_CFLAGS})
- endforeach(SOURCE)
-
- set(MSAN_INST_LIBCXX)
- msan_link_shared(MSAN_INST_LIBCXX "libcxx" ${arch}
- OBJECTS ${MSAN_INST_LIBCXX_OBJECTS}
- LINKFLAGS ${MSAN_LIBCXX_LINK_FLAGS}
- DEPS ${MSAN_INST_LIBCXX_OBJECTS} ${MSAN_RUNTIME_LIBRARIES})
+ msan_compile(MSAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch} "${kind}"
+ ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
# Instrumented tests.
set(MSAN_INST_TEST_OBJECTS)
foreach (SOURCE ${MSAN_UNITTEST_SOURCES})
- msan_compile(MSAN_INST_TEST_OBJECTS ${SOURCE} ${arch}
- ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ msan_compile(MSAN_INST_TEST_OBJECTS ${SOURCE} ${arch} "${kind}"
+ ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
endforeach(SOURCE)
# Instrumented loadable module objects.
set(MSAN_INST_LOADABLE_OBJECTS)
- msan_compile(MSAN_INST_LOADABLE_OBJECTS ${MSAN_LOADABLE_SOURCE} ${arch}
- ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS})
-
- # Uninstrumented shared object for MSanDR tests.
- set(MSANDR_TEST_OBJECTS)
- msan_compile(MSANDR_TEST_OBJECTS ${MSANDR_UNITTEST_SOURCE} ${arch}
- ${MSAN_UNITTEST_COMMON_CFLAGS})
+ msan_compile(MSAN_INST_LOADABLE_OBJECTS ${MSAN_LOADABLE_SOURCE} ${arch} "${kind}"
+ ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
# Instrumented loadable library tests.
set(MSAN_LOADABLE_SO)
- msan_link_shared(MSAN_LOADABLE_SO "libmsan_loadable" ${arch}
+ msan_link_shared(MSAN_LOADABLE_SO "libmsan_loadable" ${arch} "${kind}"
OBJECTS ${MSAN_INST_LOADABLE_OBJECTS}
- DEPS ${MSAN_INST_LOADABLE_OBJECTS} ${MSAN_RUNTIME_LIBRARIES})
-
- # Uninstrumented shared library tests.
- set(MSANDR_TEST_SO)
- msan_link_shared(MSANDR_TEST_SO "libmsandr_test" ${arch}
- OBJECTS ${MSANDR_TEST_OBJECTS}
- DEPS ${MSANDR_TEST_OBJECTS} ${MSAN_RUNTIME_LIBRARIES})
+ DEPS ${MSAN_INST_LOADABLE_OBJECTS})
- # Link everything together.
- add_msan_test(MsanUnitTests "Msan-${arch}-Test" ${arch}
- ${MSAN_INST_TEST_OBJECTS} ${MSAN_INST_GTEST}
- ${MSAN_INST_LIBCXX} ${MSANDR_TEST_SO})
+ set(MSAN_TEST_OBJECTS ${MSAN_INST_TEST_OBJECTS} ${MSAN_INST_GTEST})
+ set(MSAN_TEST_DEPS ${MSAN_TEST_OBJECTS} libcxx_msan${kind}
+ ${MSAN_LOADABLE_SO})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND MSAN_TEST_DEPS msan)
+ endif()
+ get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
+ add_compiler_rt_test(MsanUnitTests "Msan-${arch}${kind}-Test" ${arch}
+ OBJECTS ${MSAN_TEST_OBJECTS} ${MSAN_LIBCXX_SO}
+ DEPS ${MSAN_TEST_DEPS}
+ LINK_FLAGS ${MSAN_UNITTEST_LINK_FLAGS}
+ ${TARGET_LINK_FLAGS}
+ "-Wl,-rpath=${CMAKE_CURRENT_BINARY_DIR}"
+ "-Wl,-rpath=${LIBCXX_PREFIX}/lib")
endmacro()
-if(COMPILER_RT_CAN_EXECUTE_TESTS AND MSAN_CAN_INSTRUMENT_LIBCXX)
+# We should only build MSan unit tests if we can build instrumented libcxx.
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND COMPILER_RT_HAS_LIBCXX_SOURCES)
if(CAN_TARGET_x86_64)
- add_msan_tests_for_arch(x86_64)
+ add_msan_tests_for_arch(x86_64 "")
+ add_msan_tests_for_arch(x86_64 "-with-call"
+ -mllvm -msan-instrumentation-with-call-threshold=0)
endif()
endif()
diff --git a/lib/msan/tests/msan_loadable.cc b/lib/msan/tests/msan_loadable.cc
index db3bf489853dc..06e880f90dee1 100644
--- a/lib/msan/tests/msan_loadable.cc
+++ b/lib/msan/tests/msan_loadable.cc
@@ -20,24 +20,6 @@ static void *dso_global;
// No name mangling.
extern "C" {
-__attribute__((constructor))
-void loadable_module_init(void) {
- if (!__msan_has_dynamic_component())
- return;
- // The real test is that this compare should not make an uninit.
- if (dso_global == NULL)
- dso_global = malloc(4);
-}
-
-__attribute__((destructor))
-void loadable_module_fini(void) {
- if (!__msan_has_dynamic_component())
- return;
- free(dso_global);
- // *Don't* overwrite it with NULL! That would unpoison it, but our test
- // relies on reloading at the same address and keeping the poison.
-}
-
void **get_dso_global() {
return &dso_global;
}
diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc
index f95bb4e7c618b..554265da6aa97 100644
--- a/lib/msan/tests/msan_test.cc
+++ b/lib/msan/tests/msan_test.cc
@@ -16,14 +16,15 @@
#include "msan_test_config.h"
#endif // MSAN_EXTERNAL_TEST_CONFIG
+#include "sanitizer_common/tests/sanitizer_test_utils.h"
+
+#include "sanitizer/allocator_interface.h"
#include "sanitizer/msan_interface.h"
-#include "msandr_test_so.h"
#include <inttypes.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
-#include <assert.h>
#include <wchar.h>
#include <math.h>
#include <malloc.h>
@@ -63,7 +64,11 @@
# define MSAN_HAS_M128 0
#endif
-static const int kPageSize = 4096;
+#ifdef __AVX2__
+# include <immintrin.h>
+#endif
+
+static const size_t kPageSize = 4096;
typedef unsigned char U1;
typedef unsigned short U2; // NOLINT
@@ -100,20 +105,6 @@ static bool TrackingOrigins() {
EXPECT_EQ(origin, __msan_get_umr_origin()); \
} while (0)
-#define EXPECT_UMR_S(action, stack_origin) \
- do { \
- __msan_set_expect_umr(1); \
- action; \
- __msan_set_expect_umr(0); \
- U4 id = __msan_get_umr_origin(); \
- const char *str = __msan_get_origin_descr_if_stack(id); \
- if (!str || strcmp(str, stack_origin)) { \
- fprintf(stderr, "EXPECT_POISONED_S: id=%u %s, %s", \
- id, stack_origin, str); \
- EXPECT_EQ(1, 0); \
- } \
- } while (0)
-
#define EXPECT_POISONED(x) ExpectPoisoned(x)
template<typename T>
@@ -131,21 +122,6 @@ void ExpectPoisonedWithOrigin(const T& t, unsigned origin) {
EXPECT_EQ(origin, __msan_get_origin((void*)&t));
}
-#define EXPECT_POISONED_S(x, stack_origin) \
- ExpectPoisonedWithStackOrigin(x, stack_origin)
-
-template<typename T>
-void ExpectPoisonedWithStackOrigin(const T& t, const char *stack_origin) {
- EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t)));
- U4 id = __msan_get_origin((void*)&t);
- const char *str = __msan_get_origin_descr_if_stack(id);
- if (!str || strcmp(str, stack_origin)) {
- fprintf(stderr, "EXPECT_POISONED_S: id=%u %s, %s",
- id, stack_origin, str);
- EXPECT_EQ(1, 0);
- }
-}
-
#define EXPECT_NOT_POISONED(x) ExpectNotPoisoned(x)
template<typename T>
@@ -171,13 +147,10 @@ T *GetPoisonedO(int i, U4 origin, T val = 0) {
return res;
}
-// This function returns its parameter but in such a way that compiler
-// can not prove it.
-template<class T>
-NOINLINE
-static T Ident(T t) {
- volatile T ret = t;
- return ret;
+template<typename T>
+T Poisoned(T v = 0, T s = (T)(-1)) {
+ __msan_partial_poison(&v, &s, sizeof(T));
+ return v;
}
template<class T> NOINLINE T ReturnPoisoned() { return *GetPoisoned<T>(); }
@@ -277,7 +250,6 @@ TEST(MemorySanitizer, ArgTest) {
TEST(MemorySanitizer, CallAndRet) {
- if (!__msan_has_dynamic_component()) return;
ReturnPoisoned<S1>();
ReturnPoisoned<S2>();
ReturnPoisoned<S4>();
@@ -327,10 +299,27 @@ TEST(MemorySanitizer, Realloc) {
TEST(MemorySanitizer, Calloc) {
S4 *x = (int*)Ident(calloc(1, sizeof(S4)));
EXPECT_NOT_POISONED(*x); // Should not be poisoned.
- // EXPECT_EQ(0, *x);
+ EXPECT_EQ(0, *x);
free(x);
}
+TEST(MemorySanitizer, CallocReturnsZeroMem) {
+ size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
+ for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) {
+ size_t size = sizes[s];
+ for (size_t iter = 0; iter < 5; iter++) {
+ char *x = Ident((char*)calloc(1, size));
+ EXPECT_EQ(x[0], 0);
+ EXPECT_EQ(x[size - 1], 0);
+ EXPECT_EQ(x[size / 2], 0);
+ EXPECT_EQ(x[size / 3], 0);
+ EXPECT_EQ(x[size / 4], 0);
+ memset(x, 0x42, size);
+ free(Ident(x));
+ }
+ }
+}
+
TEST(MemorySanitizer, AndOr) {
U4 *p = GetPoisoned<U4>();
// We poison two bytes in the midle of a 4-byte word to make the test
@@ -503,14 +492,12 @@ TEST(MemorySanitizer, DynMem) {
static char *DynRetTestStr;
TEST(MemorySanitizer, DynRet) {
- if (!__msan_has_dynamic_component()) return;
ReturnPoisoned<S8>();
EXPECT_NOT_POISONED(clearenv());
}
TEST(MemorySanitizer, DynRet1) {
- if (!__msan_has_dynamic_component()) return;
ReturnPoisoned<S8>();
}
@@ -573,39 +560,39 @@ TEST(MemorySanitizer, strerror_r) {
TEST(MemorySanitizer, fread) {
char *x = new char[32];
FILE *f = fopen("/proc/self/stat", "r");
- assert(f);
+ ASSERT_TRUE(f != NULL);
fread(x, 1, 32, f);
EXPECT_NOT_POISONED(x[0]);
EXPECT_NOT_POISONED(x[16]);
EXPECT_NOT_POISONED(x[31]);
fclose(f);
- delete x;
+ delete[] x;
}
TEST(MemorySanitizer, read) {
char *x = new char[32];
int fd = open("/proc/self/stat", O_RDONLY);
- assert(fd > 0);
+ ASSERT_GT(fd, 0);
int sz = read(fd, x, 32);
- assert(sz == 32);
+ ASSERT_EQ(sz, 32);
EXPECT_NOT_POISONED(x[0]);
EXPECT_NOT_POISONED(x[16]);
EXPECT_NOT_POISONED(x[31]);
close(fd);
- delete x;
+ delete[] x;
}
TEST(MemorySanitizer, pread) {
char *x = new char[32];
int fd = open("/proc/self/stat", O_RDONLY);
- assert(fd > 0);
+ ASSERT_GT(fd, 0);
int sz = pread(fd, x, 32, 0);
- assert(sz == 32);
+ ASSERT_EQ(sz, 32);
EXPECT_NOT_POISONED(x[0]);
EXPECT_NOT_POISONED(x[16]);
EXPECT_NOT_POISONED(x[31]);
close(fd);
- delete x;
+ delete[] x;
}
TEST(MemorySanitizer, readv) {
@@ -616,10 +603,11 @@ TEST(MemorySanitizer, readv) {
iov[1].iov_base = buf + 10;
iov[1].iov_len = 2000;
int fd = open("/proc/self/stat", O_RDONLY);
- assert(fd > 0);
+ ASSERT_GT(fd, 0);
int sz = readv(fd, iov, 2);
+ ASSERT_GE(sz, 0);
ASSERT_LT(sz, 5 + 2000);
- ASSERT_GT(sz, iov[0].iov_len);
+ ASSERT_GT((size_t)sz, iov[0].iov_len);
EXPECT_POISONED(buf[0]);
EXPECT_NOT_POISONED(buf[1]);
EXPECT_NOT_POISONED(buf[5]);
@@ -639,10 +627,11 @@ TEST(MemorySanitizer, preadv) {
iov[1].iov_base = buf + 10;
iov[1].iov_len = 2000;
int fd = open("/proc/self/stat", O_RDONLY);
- assert(fd > 0);
+ ASSERT_GT(fd, 0);
int sz = preadv(fd, iov, 2, 3);
+ ASSERT_GE(sz, 0);
ASSERT_LT(sz, 5 + 2000);
- ASSERT_GT(sz, iov[0].iov_len);
+ ASSERT_GT((size_t)sz, iov[0].iov_len);
EXPECT_POISONED(buf[0]);
EXPECT_NOT_POISONED(buf[1]);
EXPECT_NOT_POISONED(buf[5]);
@@ -672,7 +661,7 @@ TEST(MemorySanitizer, readlink) {
TEST(MemorySanitizer, stat) {
struct stat* st = new struct stat;
int res = stat("/proc/self/stat", st);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(st->st_dev);
EXPECT_NOT_POISONED(st->st_mode);
EXPECT_NOT_POISONED(st->st_size);
@@ -681,9 +670,9 @@ TEST(MemorySanitizer, stat) {
TEST(MemorySanitizer, fstatat) {
struct stat* st = new struct stat;
int dirfd = open("/proc/self", O_RDONLY);
- assert(dirfd > 0);
+ ASSERT_GT(dirfd, 0);
int res = fstatat(dirfd, "stat", st, 0);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(st->st_dev);
EXPECT_NOT_POISONED(st->st_mode);
EXPECT_NOT_POISONED(st->st_size);
@@ -693,7 +682,7 @@ TEST(MemorySanitizer, fstatat) {
TEST(MemorySanitizer, statfs) {
struct statfs st;
int res = statfs("/", &st);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(st.f_type);
EXPECT_NOT_POISONED(st.f_bfree);
EXPECT_NOT_POISONED(st.f_namelen);
@@ -702,7 +691,7 @@ TEST(MemorySanitizer, statfs) {
TEST(MemorySanitizer, statvfs) {
struct statvfs st;
int res = statvfs("/", &st);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(st.f_bsize);
EXPECT_NOT_POISONED(st.f_blocks);
EXPECT_NOT_POISONED(st.f_bfree);
@@ -713,7 +702,7 @@ TEST(MemorySanitizer, fstatvfs) {
struct statvfs st;
int fd = open("/", O_RDONLY | O_DIRECTORY);
int res = fstatvfs(fd, &st);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(st.f_bsize);
EXPECT_NOT_POISONED(st.f_blocks);
EXPECT_NOT_POISONED(st.f_bfree);
@@ -724,7 +713,7 @@ TEST(MemorySanitizer, fstatvfs) {
TEST(MemorySanitizer, pipe) {
int* pipefd = new int[2];
int res = pipe(pipefd);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(pipefd[0]);
EXPECT_NOT_POISONED(pipefd[1]);
close(pipefd[0]);
@@ -734,7 +723,7 @@ TEST(MemorySanitizer, pipe) {
TEST(MemorySanitizer, pipe2) {
int* pipefd = new int[2];
int res = pipe2(pipefd, O_NONBLOCK);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(pipefd[0]);
EXPECT_NOT_POISONED(pipefd[1]);
close(pipefd[0]);
@@ -744,7 +733,7 @@ TEST(MemorySanitizer, pipe2) {
TEST(MemorySanitizer, socketpair) {
int sv[2];
int res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(sv[0]);
EXPECT_NOT_POISONED(sv[1]);
close(sv[0]);
@@ -823,7 +812,7 @@ TEST(MemorySanitizer, bind_getsockname) {
sai.sin_family = AF_UNIX;
int res = bind(sock, (struct sockaddr *)&sai, sizeof(sai));
- assert(!res);
+ ASSERT_EQ(0, res);
char buf[200];
socklen_t addrlen;
EXPECT_UMR(getsockname(sock, (struct sockaddr *)&buf, &addrlen));
@@ -908,10 +897,10 @@ TEST(MemorySanitizer, getnameinfo) {
EXPECT_NOT_POISONED(host[0]);
EXPECT_POISONED(host[sizeof(host) - 1]);
- ASSERT_NE(0, strlen(host));
+ ASSERT_NE(0U, strlen(host));
EXPECT_NOT_POISONED(serv[0]);
EXPECT_POISONED(serv[sizeof(serv) - 1]);
- ASSERT_NE(0, strlen(serv));
+ ASSERT_NE(0U, strlen(serv));
}
#define EXPECT_HOSTENT_NOT_POISONED(he) \
@@ -1061,6 +1050,26 @@ TEST(MemorySanitizer, gethostbyname_r) {
EXPECT_NOT_POISONED(err);
}
+TEST(MemorySanitizer, gethostbyname_r_bad_host_name) {
+ char buf[2000];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostbyname_r("bad-host-name", &he, buf, sizeof(buf), &result, &err);
+ ASSERT_EQ((struct hostent *)0, result);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyname_r_erange) {
+ char buf[5];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostbyname_r("localhost", &he, buf, sizeof(buf), &result, &err);
+ ASSERT_EQ(ERANGE, res);
+ EXPECT_NOT_POISONED(err);
+}
+
TEST(MemorySanitizer, gethostbyname2_r) {
char buf[2000];
struct hostent he;
@@ -1105,20 +1114,20 @@ TEST(MemorySanitizer, getsockopt) {
TEST(MemorySanitizer, getcwd) {
char path[PATH_MAX + 1];
char* res = getcwd(path, sizeof(path));
- assert(res);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(path[0]);
}
TEST(MemorySanitizer, getcwd_gnu) {
char* res = getcwd(NULL, 0);
- assert(res);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(res[0]);
free(res);
}
TEST(MemorySanitizer, get_current_dir_name) {
char* res = get_current_dir_name();
- assert(res);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(res[0]);
free(res);
}
@@ -1209,7 +1218,7 @@ TEST(MemorySanitizer, confstr) {
TEST(MemorySanitizer, readdir) {
DIR *dir = opendir(".");
struct dirent *d = readdir(dir);
- assert(d);
+ ASSERT_TRUE(d != NULL);
EXPECT_NOT_POISONED(d->d_name[0]);
closedir(dir);
}
@@ -1219,7 +1228,7 @@ TEST(MemorySanitizer, readdir_r) {
struct dirent d;
struct dirent *pd;
int res = readdir_r(dir, &d, &pd);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(pd);
EXPECT_NOT_POISONED(d.d_name[0]);
closedir(dir);
@@ -1229,7 +1238,7 @@ TEST(MemorySanitizer, realpath) {
const char* relpath = ".";
char path[PATH_MAX + 1];
char* res = realpath(relpath, path);
- assert(res);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(path[0]);
}
@@ -1237,7 +1246,7 @@ TEST(MemorySanitizer, realpath_null) {
const char* relpath = ".";
char* res = realpath(relpath, NULL);
printf("%d, %s\n", errno, strerror(errno));
- assert(res);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(res[0]);
free(res);
}
@@ -1245,7 +1254,7 @@ TEST(MemorySanitizer, realpath_null) {
TEST(MemorySanitizer, canonicalize_file_name) {
const char* relpath = ".";
char* res = canonicalize_file_name(relpath);
- assert(res);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(res[0]);
free(res);
}
@@ -1279,33 +1288,56 @@ TEST(MemorySanitizer, memcpy) {
EXPECT_POISONED(y[1]);
}
-void TestUnalignedMemcpy(int left, int right, bool src_is_aligned) {
- const int sz = 20;
+void TestUnalignedMemcpy(unsigned left, unsigned right, bool src_is_aligned,
+ bool src_is_poisoned, bool dst_is_poisoned) {
+ fprintf(stderr, "%s(%d, %d, %d, %d, %d)\n", __func__, left, right,
+ src_is_aligned, src_is_poisoned, dst_is_poisoned);
+
+ const unsigned sz = 20;
+ U4 dst_origin, src_origin;
char *dst = (char *)malloc(sz);
- U4 origin = __msan_get_origin(dst);
+ if (dst_is_poisoned)
+ dst_origin = __msan_get_origin(dst);
+ else
+ memset(dst, 0, sz);
char *src = (char *)malloc(sz);
- memset(src, 0, sz);
+ if (src_is_poisoned)
+ src_origin = __msan_get_origin(src);
+ else
+ memset(src, 0, sz);
memcpy(dst + left, src_is_aligned ? src + left : src, sz - left - right);
- for (int i = 0; i < left; ++i)
- EXPECT_POISONED_O(dst[i], origin);
- for (int i = 0; i < right; ++i)
- EXPECT_POISONED_O(dst[sz - i - 1], origin);
- EXPECT_NOT_POISONED(dst[left]);
- EXPECT_NOT_POISONED(dst[sz - right - 1]);
+
+ for (unsigned i = 0; i < (left & (~3U)); ++i)
+ if (dst_is_poisoned)
+ EXPECT_POISONED_O(dst[i], dst_origin);
+ else
+ EXPECT_NOT_POISONED(dst[i]);
+
+ for (unsigned i = 0; i < (right & (~3U)); ++i)
+ if (dst_is_poisoned)
+ EXPECT_POISONED_O(dst[sz - i - 1], dst_origin);
+ else
+ EXPECT_NOT_POISONED(dst[sz - i - 1]);
+
+ for (unsigned i = left; i < sz - right; ++i)
+ if (src_is_poisoned)
+ EXPECT_POISONED_O(dst[i], src_origin);
+ else
+ EXPECT_NOT_POISONED(dst[i]);
free(dst);
free(src);
}
TEST(MemorySanitizer, memcpy_unaligned) {
- for (int i = 0; i < 10; ++i) {
- for (int j = 0; j < 10; ++j) {
- TestUnalignedMemcpy(i, j, true);
- TestUnalignedMemcpy(i, j, false);
- }
- }
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)
+ for (int aligned = 0; aligned < 2; ++aligned)
+ for (int srcp = 0; srcp < 2; ++srcp)
+ for (int dstp = 0; dstp < 2; ++dstp)
+ TestUnalignedMemcpy(i, j, aligned, srcp, dstp);
}
TEST(MemorySanitizer, memmove) {
@@ -1412,17 +1444,12 @@ TEST(MemorySanitizer, strndup_short) {
template<class T, int size>
void TestOverlapMemmove() {
T *x = new T[size];
- assert(size >= 3);
+ ASSERT_GE(size, 3);
x[2] = 0;
memmove(x, x + 1, (size - 1) * sizeof(T));
EXPECT_NOT_POISONED(x[1]);
- if (!__msan_has_dynamic_component()) {
- // FIXME: under DR we will lose this information
- // because accesses in memmove will unpoisin the shadow.
- // We need to use our own memove implementation instead of libc's.
- EXPECT_POISONED(x[0]);
- EXPECT_POISONED(x[2]);
- }
+ EXPECT_POISONED(x[0]);
+ EXPECT_POISONED(x[2]);
delete [] x;
}
@@ -1447,14 +1474,16 @@ TEST(MemorySanitizer, strcpy) { // NOLINT
TEST(MemorySanitizer, strncpy) { // NOLINT
char* x = new char[3];
- char* y = new char[3];
+ char* y = new char[5];
x[0] = 'a';
x[1] = *GetPoisoned<char>(1, 1);
- x[2] = 0;
- strncpy(y, x, 2); // NOLINT
+ x[2] = '\0';
+ strncpy(y, x, 4); // NOLINT
EXPECT_NOT_POISONED(y[0]);
EXPECT_POISONED(y[1]);
- EXPECT_POISONED(y[2]);
+ EXPECT_NOT_POISONED(y[2]);
+ EXPECT_NOT_POISONED(y[3]);
+ EXPECT_POISONED(y[4]);
}
TEST(MemorySanitizer, stpcpy) { // NOLINT
@@ -1470,71 +1499,144 @@ TEST(MemorySanitizer, stpcpy) { // NOLINT
EXPECT_NOT_POISONED(y[2]);
}
-TEST(MemorySanitizer, strtol) {
- char *e;
- assert(1 == strtol("1", &e, 10));
- EXPECT_NOT_POISONED((S8) e);
-}
+TEST(MemorySanitizer, strcat) { // NOLINT
+ char a[10];
+ char b[] = "def";
+ strcpy(a, "abc");
+ __msan_poison(b + 1, 1);
+ strcat(a, b);
+ EXPECT_NOT_POISONED(a[3]);
+ EXPECT_POISONED(a[4]);
+ EXPECT_NOT_POISONED(a[5]);
+ EXPECT_NOT_POISONED(a[6]);
+ EXPECT_POISONED(a[7]);
+}
+
+TEST(MemorySanitizer, strncat) { // NOLINT
+ char a[10];
+ char b[] = "def";
+ strcpy(a, "abc");
+ __msan_poison(b + 1, 1);
+ strncat(a, b, 5);
+ EXPECT_NOT_POISONED(a[3]);
+ EXPECT_POISONED(a[4]);
+ EXPECT_NOT_POISONED(a[5]);
+ EXPECT_NOT_POISONED(a[6]);
+ EXPECT_POISONED(a[7]);
+}
+
+TEST(MemorySanitizer, strncat_overflow) { // NOLINT
+ char a[10];
+ char b[] = "def";
+ strcpy(a, "abc");
+ __msan_poison(b + 1, 1);
+ strncat(a, b, 2);
+ EXPECT_NOT_POISONED(a[3]);
+ EXPECT_POISONED(a[4]);
+ EXPECT_NOT_POISONED(a[5]);
+ EXPECT_POISONED(a[6]);
+ EXPECT_POISONED(a[7]);
+}
+
+#define TEST_STRTO_INT(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ char_type *e; \
+ EXPECT_EQ(1U, func_name(str_prefix##"1", &e, 10)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ }
-TEST(MemorySanitizer, strtoll) {
- char *e;
- assert(1 == strtoll("1", &e, 10));
- EXPECT_NOT_POISONED((S8) e);
-}
+#define TEST_STRTO_FLOAT(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ char_type *e; \
+ EXPECT_NE(0, func_name(str_prefix##"1.5", &e)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ }
-TEST(MemorySanitizer, strtoul) {
- char *e;
- assert(1 == strtoul("1", &e, 10));
- EXPECT_NOT_POISONED((S8) e);
-}
+#define TEST_STRTO_FLOAT_LOC(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); \
+ char_type *e; \
+ EXPECT_NE(0, func_name(str_prefix##"1.5", &e, loc)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ freelocale(loc); \
+ }
+
+#define TEST_STRTO_INT_LOC(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); \
+ char_type *e; \
+ ASSERT_EQ(1U, func_name(str_prefix##"1", &e, 10, loc)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ freelocale(loc); \
+ }
+
+TEST_STRTO_INT(strtol, char, )
+TEST_STRTO_INT(strtoll, char, )
+TEST_STRTO_INT(strtoul, char, )
+TEST_STRTO_INT(strtoull, char, )
+
+TEST_STRTO_FLOAT(strtof, char, )
+TEST_STRTO_FLOAT(strtod, char, )
+TEST_STRTO_FLOAT(strtold, char, )
+
+TEST_STRTO_FLOAT_LOC(strtof_l, char, )
+TEST_STRTO_FLOAT_LOC(strtod_l, char, )
+TEST_STRTO_FLOAT_LOC(strtold_l, char, )
+
+TEST_STRTO_INT_LOC(strtol_l, char, )
+TEST_STRTO_INT_LOC(strtoll_l, char, )
+TEST_STRTO_INT_LOC(strtoul_l, char, )
+TEST_STRTO_INT_LOC(strtoull_l, char, )
+
+TEST_STRTO_INT(wcstol, wchar_t, L)
+TEST_STRTO_INT(wcstoll, wchar_t, L)
+TEST_STRTO_INT(wcstoul, wchar_t, L)
+TEST_STRTO_INT(wcstoull, wchar_t, L)
+
+TEST_STRTO_FLOAT(wcstof, wchar_t, L)
+TEST_STRTO_FLOAT(wcstod, wchar_t, L)
+TEST_STRTO_FLOAT(wcstold, wchar_t, L)
+
+TEST_STRTO_FLOAT_LOC(wcstof_l, wchar_t, L)
+TEST_STRTO_FLOAT_LOC(wcstod_l, wchar_t, L)
+TEST_STRTO_FLOAT_LOC(wcstold_l, wchar_t, L)
+
+TEST_STRTO_INT_LOC(wcstol_l, wchar_t, L)
+TEST_STRTO_INT_LOC(wcstoll_l, wchar_t, L)
+TEST_STRTO_INT_LOC(wcstoul_l, wchar_t, L)
+TEST_STRTO_INT_LOC(wcstoull_l, wchar_t, L)
-TEST(MemorySanitizer, strtoull) {
- char *e;
- assert(1 == strtoull("1", &e, 10));
- EXPECT_NOT_POISONED((S8) e);
-}
TEST(MemorySanitizer, strtoimax) {
char *e;
- assert(1 == strtoimax("1", &e, 10));
+ ASSERT_EQ(1, strtoimax("1", &e, 10));
EXPECT_NOT_POISONED((S8) e);
}
TEST(MemorySanitizer, strtoumax) {
char *e;
- assert(1 == strtoumax("1", &e, 10));
- EXPECT_NOT_POISONED((S8) e);
-}
-
-TEST(MemorySanitizer, strtod) {
- char *e;
- assert(0 != strtod("1.5", &e));
+ ASSERT_EQ(1U, strtoumax("1", &e, 10));
EXPECT_NOT_POISONED((S8) e);
}
#ifdef __GLIBC__
+extern "C" float __strtof_l(const char *nptr, char **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__strtof_l, char, )
extern "C" double __strtod_l(const char *nptr, char **endptr, locale_t loc);
-TEST(MemorySanitizer, __strtod_l) {
- locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
- char *e;
- assert(0 != __strtod_l("1.5", &e, loc));
- EXPECT_NOT_POISONED((S8) e);
- freelocale(loc);
-}
+TEST_STRTO_FLOAT_LOC(__strtod_l, char, )
+extern "C" long double __strtold_l(const char *nptr, char **endptr,
+ locale_t loc);
+TEST_STRTO_FLOAT_LOC(__strtold_l, char, )
+
+extern "C" float __wcstof_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__wcstof_l, wchar_t, L)
+extern "C" double __wcstod_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__wcstod_l, wchar_t, L)
+extern "C" long double __wcstold_l(const wchar_t *nptr, wchar_t **endptr,
+ locale_t loc);
+TEST_STRTO_FLOAT_LOC(__wcstold_l, wchar_t, L)
#endif // __GLIBC__
-TEST(MemorySanitizer, strtof) {
- char *e;
- assert(0 != strtof("1.5", &e));
- EXPECT_NOT_POISONED((S8) e);
-}
-
-TEST(MemorySanitizer, strtold) {
- char *e;
- assert(0 != strtold("1.5", &e));
- EXPECT_NOT_POISONED((S8) e);
-}
-
TEST(MemorySanitizer, modf) {
double x, y;
x = modf(2.1, &y);
@@ -1655,12 +1757,12 @@ TEST(MemorySanitizer, sprintf) { // NOLINT
break_optimization(buff);
EXPECT_POISONED(buff[0]);
int res = sprintf(buff, "%d", 1234567); // NOLINT
- assert(res == 7);
- assert(buff[0] == '1');
- assert(buff[1] == '2');
- assert(buff[2] == '3');
- assert(buff[6] == '7');
- assert(buff[7] == 0);
+ ASSERT_EQ(res, 7);
+ ASSERT_EQ(buff[0], '1');
+ ASSERT_EQ(buff[1], '2');
+ ASSERT_EQ(buff[2], '3');
+ ASSERT_EQ(buff[6], '7');
+ ASSERT_EQ(buff[7], 0);
EXPECT_POISONED(buff[8]);
}
@@ -1669,27 +1771,27 @@ TEST(MemorySanitizer, snprintf) {
break_optimization(buff);
EXPECT_POISONED(buff[0]);
int res = snprintf(buff, sizeof(buff), "%d", 1234567);
- assert(res == 7);
- assert(buff[0] == '1');
- assert(buff[1] == '2');
- assert(buff[2] == '3');
- assert(buff[6] == '7');
- assert(buff[7] == 0);
+ ASSERT_EQ(res, 7);
+ ASSERT_EQ(buff[0], '1');
+ ASSERT_EQ(buff[1], '2');
+ ASSERT_EQ(buff[2], '3');
+ ASSERT_EQ(buff[6], '7');
+ ASSERT_EQ(buff[7], 0);
EXPECT_POISONED(buff[8]);
}
TEST(MemorySanitizer, swprintf) {
wchar_t buff[10];
- assert(sizeof(wchar_t) == 4);
+ ASSERT_EQ(4U, sizeof(wchar_t));
break_optimization(buff);
EXPECT_POISONED(buff[0]);
int res = swprintf(buff, 9, L"%d", 1234567);
- assert(res == 7);
- assert(buff[0] == '1');
- assert(buff[1] == '2');
- assert(buff[2] == '3');
- assert(buff[6] == '7');
- assert(buff[7] == 0);
+ ASSERT_EQ(res, 7);
+ ASSERT_EQ(buff[0], '1');
+ ASSERT_EQ(buff[1], '2');
+ ASSERT_EQ(buff[2], '3');
+ ASSERT_EQ(buff[6], '7');
+ ASSERT_EQ(buff[7], 0);
EXPECT_POISONED(buff[8]);
}
@@ -1697,13 +1799,13 @@ TEST(MemorySanitizer, asprintf) { // NOLINT
char *pbuf;
EXPECT_POISONED(pbuf);
int res = asprintf(&pbuf, "%d", 1234567); // NOLINT
- assert(res == 7);
+ ASSERT_EQ(res, 7);
EXPECT_NOT_POISONED(pbuf);
- assert(pbuf[0] == '1');
- assert(pbuf[1] == '2');
- assert(pbuf[2] == '3');
- assert(pbuf[6] == '7');
- assert(pbuf[7] == 0);
+ ASSERT_EQ(pbuf[0], '1');
+ ASSERT_EQ(pbuf[1], '2');
+ ASSERT_EQ(pbuf[2], '3');
+ ASSERT_EQ(pbuf[6], '7');
+ ASSERT_EQ(pbuf[7], 0);
free(pbuf);
}
@@ -1758,6 +1860,16 @@ TEST(MemorySanitizer, wcsnrtombs) {
EXPECT_POISONED(buff[2]);
}
+TEST(MemorySanitizer, wmemset) {
+ wchar_t x[25];
+ break_optimization(x);
+ EXPECT_POISONED(x[0]);
+ wmemset(x, L'A', 10);
+ EXPECT_EQ(x[0], L'A');
+ EXPECT_EQ(x[9], L'A');
+ EXPECT_POISONED(x[10]);
+}
+
TEST(MemorySanitizer, mbtowc) {
const char *x = "abc";
wchar_t wx;
@@ -1776,18 +1888,29 @@ TEST(MemorySanitizer, mbrtowc) {
EXPECT_NOT_POISONED(wx);
}
+TEST(MemorySanitizer, wcsftime) {
+ wchar_t x[100];
+ time_t t = time(NULL);
+ struct tm tms;
+ struct tm *tmres = localtime_r(&t, &tms);
+ ASSERT_NE((void *)0, tmres);
+ size_t res = wcsftime(x, sizeof(x) / sizeof(x[0]), L"%Y-%m-%d", tmres);
+ EXPECT_GT(res, 0UL);
+ EXPECT_EQ(res, wcslen(x));
+}
+
TEST(MemorySanitizer, gettimeofday) {
struct timeval tv;
struct timezone tz;
break_optimization(&tv);
break_optimization(&tz);
- assert(sizeof(tv) == 16);
- assert(sizeof(tz) == 8);
+ ASSERT_EQ(16U, sizeof(tv));
+ ASSERT_EQ(8U, sizeof(tz));
EXPECT_POISONED(tv.tv_sec);
EXPECT_POISONED(tv.tv_usec);
EXPECT_POISONED(tz.tz_minuteswest);
EXPECT_POISONED(tz.tz_dsttime);
- assert(0 == gettimeofday(&tv, &tz));
+ ASSERT_EQ(0, gettimeofday(&tv, &tz));
EXPECT_NOT_POISONED(tv.tv_sec);
EXPECT_NOT_POISONED(tv.tv_usec);
EXPECT_NOT_POISONED(tz.tz_minuteswest);
@@ -1798,7 +1921,7 @@ TEST(MemorySanitizer, clock_gettime) {
struct timespec tp;
EXPECT_POISONED(tp.tv_sec);
EXPECT_POISONED(tp.tv_nsec);
- assert(0 == clock_gettime(CLOCK_REALTIME, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &tp));
EXPECT_NOT_POISONED(tp.tv_sec);
EXPECT_NOT_POISONED(tp.tv_nsec);
}
@@ -1807,10 +1930,10 @@ TEST(MemorySanitizer, clock_getres) {
struct timespec tp;
EXPECT_POISONED(tp.tv_sec);
EXPECT_POISONED(tp.tv_nsec);
- assert(0 == clock_getres(CLOCK_REALTIME, 0));
+ ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, 0));
EXPECT_POISONED(tp.tv_sec);
EXPECT_POISONED(tp.tv_nsec);
- assert(0 == clock_getres(CLOCK_REALTIME, &tp));
+ ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, &tp));
EXPECT_NOT_POISONED(tp.tv_sec);
EXPECT_NOT_POISONED(tp.tv_nsec);
}
@@ -1823,7 +1946,7 @@ TEST(MemorySanitizer, getitimer) {
EXPECT_POISONED(it1.it_value.tv_sec);
EXPECT_POISONED(it1.it_value.tv_usec);
res = getitimer(ITIMER_VIRTUAL, &it1);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(it1.it_interval.tv_sec);
EXPECT_NOT_POISONED(it1.it_interval.tv_usec);
EXPECT_NOT_POISONED(it1.it_value.tv_sec);
@@ -1833,7 +1956,7 @@ TEST(MemorySanitizer, getitimer) {
it1.it_interval.tv_usec = it1.it_value.tv_usec = 0;
res = setitimer(ITIMER_VIRTUAL, &it1, &it2);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(it2.it_interval.tv_sec);
EXPECT_NOT_POISONED(it2.it_interval.tv_usec);
EXPECT_NOT_POISONED(it2.it_value.tv_sec);
@@ -1842,7 +1965,7 @@ TEST(MemorySanitizer, getitimer) {
// Check that old_value can be 0, and disable the timer.
memset(&it1, 0, sizeof(it1));
res = setitimer(ITIMER_VIRTUAL, &it1, 0);
- assert(!res);
+ ASSERT_EQ(0, res);
}
TEST(MemorySanitizer, setitimer_null) {
@@ -1856,14 +1979,14 @@ TEST(MemorySanitizer, time) {
time_t t;
EXPECT_POISONED(t);
time_t t2 = time(&t);
- assert(t2 != (time_t)-1);
+ ASSERT_NE(t2, (time_t)-1);
EXPECT_NOT_POISONED(t);
}
TEST(MemorySanitizer, strptime) {
struct tm time;
char *p = strptime("11/1/2013-05:39", "%m/%d/%Y-%H:%M", &time);
- assert(p != 0);
+ ASSERT_TRUE(p != NULL);
EXPECT_NOT_POISONED(time.tm_sec);
EXPECT_NOT_POISONED(time.tm_hour);
EXPECT_NOT_POISONED(time.tm_year);
@@ -1872,34 +1995,34 @@ TEST(MemorySanitizer, strptime) {
TEST(MemorySanitizer, localtime) {
time_t t = 123;
struct tm *time = localtime(&t);
- assert(time != 0);
+ ASSERT_TRUE(time != NULL);
EXPECT_NOT_POISONED(time->tm_sec);
EXPECT_NOT_POISONED(time->tm_hour);
EXPECT_NOT_POISONED(time->tm_year);
EXPECT_NOT_POISONED(time->tm_isdst);
- EXPECT_NE(0, strlen(time->tm_zone));
+ EXPECT_NE(0U, strlen(time->tm_zone));
}
TEST(MemorySanitizer, localtime_r) {
time_t t = 123;
struct tm time;
struct tm *res = localtime_r(&t, &time);
- assert(res != 0);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(time.tm_sec);
EXPECT_NOT_POISONED(time.tm_hour);
EXPECT_NOT_POISONED(time.tm_year);
EXPECT_NOT_POISONED(time.tm_isdst);
- EXPECT_NE(0, strlen(time.tm_zone));
+ EXPECT_NE(0U, strlen(time.tm_zone));
}
TEST(MemorySanitizer, getmntent) {
FILE *fp = setmntent("/etc/fstab", "r");
struct mntent *mnt = getmntent(fp);
- ASSERT_NE((void *)0, mnt);
- ASSERT_NE(0, strlen(mnt->mnt_fsname));
- ASSERT_NE(0, strlen(mnt->mnt_dir));
- ASSERT_NE(0, strlen(mnt->mnt_type));
- ASSERT_NE(0, strlen(mnt->mnt_opts));
+ ASSERT_TRUE(mnt != NULL);
+ ASSERT_NE(0U, strlen(mnt->mnt_fsname));
+ ASSERT_NE(0U, strlen(mnt->mnt_dir));
+ ASSERT_NE(0U, strlen(mnt->mnt_type));
+ ASSERT_NE(0U, strlen(mnt->mnt_opts));
EXPECT_NOT_POISONED(mnt->mnt_freq);
EXPECT_NOT_POISONED(mnt->mnt_passno);
fclose(fp);
@@ -1910,11 +2033,11 @@ TEST(MemorySanitizer, getmntent_r) {
struct mntent mntbuf;
char buf[1000];
struct mntent *mnt = getmntent_r(fp, &mntbuf, buf, sizeof(buf));
- ASSERT_NE((void *)0, mnt);
- ASSERT_NE(0, strlen(mnt->mnt_fsname));
- ASSERT_NE(0, strlen(mnt->mnt_dir));
- ASSERT_NE(0, strlen(mnt->mnt_type));
- ASSERT_NE(0, strlen(mnt->mnt_opts));
+ ASSERT_TRUE(mnt != NULL);
+ ASSERT_NE(0U, strlen(mnt->mnt_fsname));
+ ASSERT_NE(0U, strlen(mnt->mnt_dir));
+ ASSERT_NE(0U, strlen(mnt->mnt_type));
+ ASSERT_NE(0U, strlen(mnt->mnt_opts));
EXPECT_NOT_POISONED(mnt->mnt_freq);
EXPECT_NOT_POISONED(mnt->mnt_passno);
fclose(fp);
@@ -1931,12 +2054,12 @@ TEST(MemorySanitizer, ether) {
EXPECT_NOT_POISONED(addr);
char *s = ether_ntoa(&addr);
- ASSERT_NE(0, strlen(s));
+ ASSERT_NE(0U, strlen(s));
char buf[100];
s = ether_ntoa_r(&addr, buf);
ASSERT_EQ(s, buf);
- ASSERT_NE(0, strlen(buf));
+ ASSERT_NE(0U, strlen(buf));
}
TEST(MemorySanitizer, mmap) {
@@ -1969,6 +2092,56 @@ TEST(MemorySanitizer, fcvt) {
char *str = fcvt(12345.6789, 10, &a, &b);
EXPECT_NOT_POISONED(a);
EXPECT_NOT_POISONED(b);
+ ASSERT_NE(nullptr, str);
+ EXPECT_NOT_POISONED(str[0]);
+ ASSERT_NE(0U, strlen(str));
+}
+
+TEST(MemorySanitizer, fcvt_long) {
+ int a, b;
+ break_optimization(&a);
+ break_optimization(&b);
+ EXPECT_POISONED(a);
+ EXPECT_POISONED(b);
+ char *str = fcvt(111111112345.6789, 10, &a, &b);
+ EXPECT_NOT_POISONED(a);
+ EXPECT_NOT_POISONED(b);
+ ASSERT_NE(nullptr, str);
+ EXPECT_NOT_POISONED(str[0]);
+ ASSERT_NE(0U, strlen(str));
+}
+
+
+TEST(MemorySanitizer, memchr) {
+ char x[10];
+ break_optimization(x);
+ EXPECT_POISONED(x[0]);
+ x[2] = '2';
+ void *res;
+ EXPECT_UMR(res = memchr(x, '2', 10));
+ EXPECT_NOT_POISONED(res);
+ x[0] = '0';
+ x[1] = '1';
+ res = memchr(x, '2', 10);
+ EXPECT_EQ(&x[2], res);
+ EXPECT_UMR(res = memchr(x, '3', 10));
+ EXPECT_NOT_POISONED(res);
+}
+
+TEST(MemorySanitizer, memrchr) {
+ char x[10];
+ break_optimization(x);
+ EXPECT_POISONED(x[0]);
+ x[9] = '9';
+ void *res;
+ EXPECT_UMR(res = memrchr(x, '9', 10));
+ EXPECT_NOT_POISONED(res);
+ x[0] = '0';
+ x[1] = '1';
+ res = memrchr(x, '0', 2);
+ EXPECT_EQ(&x[0], res);
+ EXPECT_UMR(res = memrchr(x, '7', 10));
+ EXPECT_NOT_POISONED(res);
}
TEST(MemorySanitizer, frexp) {
@@ -1994,8 +2167,8 @@ namespace {
static int cnt;
void SigactionHandler(int signo, siginfo_t* si, void* uc) {
- assert(signo == SIGPROF);
- assert(si);
+ ASSERT_EQ(signo, SIGPROF);
+ ASSERT_TRUE(si != NULL);
EXPECT_NOT_POISONED(si->si_errno);
EXPECT_NOT_POISONED(si->si_pid);
#if __linux__
@@ -2308,6 +2481,41 @@ struct StructByVal {
int a, b, c, d, e, f;
};
+static void vaargsfn_structbyval(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ {
+ StructByVal s = va_arg(vl, StructByVal);
+ EXPECT_NOT_POISONED(s.a);
+ EXPECT_POISONED(s.b);
+ EXPECT_NOT_POISONED(s.c);
+ EXPECT_POISONED(s.d);
+ EXPECT_NOT_POISONED(s.e);
+ EXPECT_POISONED(s.f);
+ }
+ {
+ StructByVal s = va_arg(vl, StructByVal);
+ EXPECT_NOT_POISONED(s.a);
+ EXPECT_POISONED(s.b);
+ EXPECT_NOT_POISONED(s.c);
+ EXPECT_POISONED(s.d);
+ EXPECT_NOT_POISONED(s.e);
+ EXPECT_POISONED(s.f);
+ }
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgStructByVal) {
+ StructByVal s;
+ s.a = 1;
+ s.b = *GetPoisoned<int>();
+ s.c = 2;
+ s.d = *GetPoisoned<int>();
+ s.e = 3;
+ s.f = *GetPoisoned<int>();
+ vaargsfn_structbyval(0, s, s);
+}
+
NOINLINE void StructByValTestFunc(struct StructByVal s) {
EXPECT_NOT_POISONED(s.a);
EXPECT_POISONED(s.b);
@@ -2481,7 +2689,7 @@ TEST(MemorySanitizer, getrlimit) {
struct rlimit limit;
__msan_poison(&limit, sizeof(limit));
int result = getrlimit(RLIMIT_DATA, &limit);
- assert(result == 0);
+ ASSERT_EQ(result, 0);
EXPECT_NOT_POISONED(limit.rlim_cur);
EXPECT_NOT_POISONED(limit.rlim_max);
}
@@ -2490,7 +2698,7 @@ TEST(MemorySanitizer, getrusage) {
struct rusage usage;
__msan_poison(&usage, sizeof(usage));
int result = getrusage(RUSAGE_SELF, &usage);
- assert(result == 0);
+ ASSERT_EQ(result, 0);
EXPECT_NOT_POISONED(usage.ru_utime.tv_sec);
EXPECT_NOT_POISONED(usage.ru_utime.tv_usec);
EXPECT_NOT_POISONED(usage.ru_stime.tv_sec);
@@ -2516,7 +2724,7 @@ TEST(MemorySanitizer, dladdr) {
Dl_info info;
__msan_poison(&info, sizeof(info));
int result = dladdr((const void*)dladdr_testfn, &info);
- assert(result != 0);
+ ASSERT_NE(result, 0);
EXPECT_NOT_POISONED((unsigned long)info.dli_fname);
if (info.dli_fname)
EXPECT_NOT_POISONED(strlen(info.dli_fname));
@@ -2548,13 +2756,14 @@ static int PathToLoadable(char *buf, size_t sz) {
assert(last_slash);
int res =
snprintf(buf, sz, "%.*s/%s", int(last_slash - argv0), argv0, basename);
- return res < sz ? 0 : res;
+ assert(res >= 0);
+ return (size_t)res < sz ? 0 : res;
}
TEST(MemorySanitizer, dl_iterate_phdr) {
char path[4096];
int res = PathToLoadable(path, sizeof(path));
- assert(!res);
+ ASSERT_EQ(0, res);
// Having at least one dlopen'ed library in the process makes this more
// entertaining.
@@ -2563,7 +2772,7 @@ TEST(MemorySanitizer, dl_iterate_phdr) {
int count = 0;
int result = dl_iterate_phdr(dl_phdr_callback, &count);
- assert(count > 0);
+ ASSERT_GT(count, 0);
dlclose(lib);
}
@@ -2572,7 +2781,7 @@ TEST(MemorySanitizer, dl_iterate_phdr) {
TEST(MemorySanitizer, dlopen) {
char path[4096];
int res = PathToLoadable(path, sizeof(path));
- assert(!res);
+ ASSERT_EQ(0, res);
// We need to clear shadow for globals when doing dlopen. In order to test
// this, we have to poison the shadow for the DSO before we load it. In
@@ -2583,10 +2792,10 @@ TEST(MemorySanitizer, dlopen) {
void *lib = dlopen(path, RTLD_LAZY);
if (lib == NULL) {
printf("dlerror: %s\n", dlerror());
- assert(lib != NULL);
+ ASSERT_TRUE(lib != NULL);
}
void **(*get_dso_global)() = (void **(*)())dlsym(lib, "get_dso_global");
- assert(get_dso_global);
+ ASSERT_TRUE(get_dso_global != NULL);
void **dso_global = get_dso_global();
EXPECT_NOT_POISONED(*dso_global);
__msan_poison(dso_global, sizeof(*dso_global));
@@ -2599,7 +2808,7 @@ TEST(MemorySanitizer, dlopen) {
TEST(MemorySanitizer, dlopenFailed) {
const char *path = "/libmsan_loadable_does_not_exist.x86_64.so";
void *lib = dlopen(path, RTLD_LAZY);
- ASSERT_EQ(0, lib);
+ ASSERT_TRUE(lib == NULL);
}
#endif // MSAN_TEST_DISABLE_DLOPEN
@@ -2617,7 +2826,7 @@ TEST(MemorySanitizer, scanf) {
char* s = new char[7];
int res = sscanf(input, "%d %5s", d, s);
printf("res %d\n", res);
- assert(res == 2);
+ ASSERT_EQ(res, 2);
EXPECT_NOT_POISONED(*d);
EXPECT_NOT_POISONED(s[0]);
EXPECT_NOT_POISONED(s[1]);
@@ -2626,7 +2835,7 @@ TEST(MemorySanitizer, scanf) {
EXPECT_NOT_POISONED(s[4]);
EXPECT_NOT_POISONED(s[5]);
EXPECT_POISONED(s[6]);
- delete s;
+ delete[] s;
delete d;
}
@@ -2638,10 +2847,10 @@ TEST(MemorySanitizer, SimpleThread) {
pthread_t t;
void *p;
int res = pthread_create(&t, NULL, SimpleThread_threadfn, NULL);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(t);
res = pthread_join(t, &p);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(p);
delete (int*)p;
}
@@ -2667,22 +2876,22 @@ TEST(MemorySanitizer, SmallStackThread) {
ASSERT_EQ(0, res);
}
-TEST(MemorySanitizer, PreAllocatedStackThread) {
+TEST(MemorySanitizer, SmallPreAllocatedStackThread) {
pthread_attr_t attr;
pthread_t t;
int res;
res = pthread_attr_init(&attr);
ASSERT_EQ(0, res);
void *stack;
- const size_t kStackSize = 64 * 1024;
+ const size_t kStackSize = 16 * 1024;
res = posix_memalign(&stack, 4096, kStackSize);
ASSERT_EQ(0, res);
res = pthread_attr_setstack(&attr, stack, kStackSize);
ASSERT_EQ(0, res);
- // A small self-allocated stack can not be extended by the tool.
- // In this case pthread_create is expected to fail.
res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL);
- EXPECT_NE(0, res);
+ EXPECT_EQ(0, res);
+ res = pthread_join(t, NULL);
+ ASSERT_EQ(0, res);
res = pthread_attr_destroy(&attr);
ASSERT_EQ(0, res);
}
@@ -2764,10 +2973,10 @@ TEST(MemorySanitizer, pthread_getschedparam) {
TEST(MemorySanitizer, pthread_key_create) {
pthread_key_t key;
int res = pthread_key_create(&key, NULL);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(key);
res = pthread_key_delete(key);
- assert(!res);
+ ASSERT_EQ(0, res);
}
namespace {
@@ -2801,14 +3010,14 @@ TEST(MemorySanitizer, pthread_cond_wait) {
pthread_t thr;
pthread_create(&thr, 0, SignalCond, &args);
int res = pthread_cond_wait(&cond, &mu);
- assert(!res);
+ ASSERT_EQ(0, res);
pthread_join(thr, 0);
// broadcast
args.broadcast = true;
pthread_create(&thr, 0, SignalCond, &args);
res = pthread_cond_wait(&cond, &mu);
- assert(!res);
+ ASSERT_EQ(0, res);
pthread_join(thr, 0);
pthread_mutex_unlock(&mu);
@@ -2854,12 +3063,12 @@ TEST(MemorySanitizer, valloc) {
TEST(MemorySanitizer, pvalloc) {
void *p = pvalloc(kPageSize + 100);
EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
- EXPECT_EQ(2 * kPageSize, __msan_get_allocated_size(p));
+ EXPECT_EQ(2 * kPageSize, __sanitizer_get_allocated_size(p));
free(p);
p = pvalloc(0); // pvalloc(0) should allocate at least one page.
EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
- EXPECT_EQ(kPageSize, __msan_get_allocated_size(p));
+ EXPECT_EQ(kPageSize, __sanitizer_get_allocated_size(p));
free(p);
}
@@ -2890,7 +3099,7 @@ TEST(MemorySanitizer, inet_aton) {
TEST(MemorySanitizer, uname) {
struct utsname u;
int res = uname(&u);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(strlen(u.sysname));
EXPECT_NOT_POISONED(strlen(u.nodename));
EXPECT_NOT_POISONED(strlen(u.release));
@@ -2901,25 +3110,39 @@ TEST(MemorySanitizer, uname) {
TEST(MemorySanitizer, gethostname) {
char buf[100];
int res = gethostname(buf, 100);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(strlen(buf));
}
TEST(MemorySanitizer, sysinfo) {
struct sysinfo info;
int res = sysinfo(&info);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(info);
}
TEST(MemorySanitizer, getpwuid) {
struct passwd *p = getpwuid(0); // root
- assert(p);
+ ASSERT_TRUE(p != NULL);
EXPECT_NOT_POISONED(p->pw_name);
- assert(p->pw_name);
+ ASSERT_TRUE(p->pw_name != NULL);
EXPECT_NOT_POISONED(p->pw_name[0]);
EXPECT_NOT_POISONED(p->pw_uid);
- assert(p->pw_uid == 0);
+ ASSERT_EQ(0U, p->pw_uid);
+}
+
+TEST(MemorySanitizer, getpwuid_r) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char buf[10000];
+ int res = getpwuid_r(0, &pwd, buf, sizeof(buf), &pwdres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pwd.pw_name);
+ ASSERT_TRUE(pwd.pw_name != NULL);
+ EXPECT_NOT_POISONED(pwd.pw_name[0]);
+ EXPECT_NOT_POISONED(pwd.pw_uid);
+ ASSERT_EQ(0U, pwd.pw_uid);
+ EXPECT_NOT_POISONED(pwdres);
}
TEST(MemorySanitizer, getpwnam_r) {
@@ -2927,12 +3150,13 @@ TEST(MemorySanitizer, getpwnam_r) {
struct passwd *pwdres;
char buf[10000];
int res = getpwnam_r("root", &pwd, buf, sizeof(buf), &pwdres);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(pwd.pw_name);
- assert(pwd.pw_name);
+ ASSERT_TRUE(pwd.pw_name != NULL);
EXPECT_NOT_POISONED(pwd.pw_name[0]);
EXPECT_NOT_POISONED(pwd.pw_uid);
- assert(pwd.pw_uid == 0);
+ ASSERT_EQ(0U, pwd.pw_uid);
+ EXPECT_NOT_POISONED(pwdres);
}
TEST(MemorySanitizer, getpwnam_r_positive) {
@@ -2951,11 +3175,102 @@ TEST(MemorySanitizer, getgrnam_r) {
struct group *grpres;
char buf[10000];
int res = getgrnam_r("root", &grp, buf, sizeof(buf), &grpres);
- assert(!res);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(grp.gr_name);
+ ASSERT_TRUE(grp.gr_name != NULL);
+ EXPECT_NOT_POISONED(grp.gr_name[0]);
+ EXPECT_NOT_POISONED(grp.gr_gid);
+ EXPECT_NOT_POISONED(grpres);
+}
+
+TEST(MemorySanitizer, getpwent) {
+ setpwent();
+ struct passwd *p = getpwent();
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->pw_name);
+ ASSERT_TRUE(p->pw_name != NULL);
+ EXPECT_NOT_POISONED(p->pw_name[0]);
+ EXPECT_NOT_POISONED(p->pw_uid);
+}
+
+TEST(MemorySanitizer, getpwent_r) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char buf[10000];
+ setpwent();
+ int res = getpwent_r(&pwd, buf, sizeof(buf), &pwdres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pwd.pw_name);
+ ASSERT_TRUE(pwd.pw_name != NULL);
+ EXPECT_NOT_POISONED(pwd.pw_name[0]);
+ EXPECT_NOT_POISONED(pwd.pw_uid);
+ EXPECT_NOT_POISONED(pwdres);
+}
+
+TEST(MemorySanitizer, fgetpwent) {
+ FILE *fp = fopen("/etc/passwd", "r");
+ struct passwd *p = fgetpwent(fp);
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->pw_name);
+ ASSERT_TRUE(p->pw_name != NULL);
+ EXPECT_NOT_POISONED(p->pw_name[0]);
+ EXPECT_NOT_POISONED(p->pw_uid);
+ fclose(fp);
+}
+
+TEST(MemorySanitizer, getgrent) {
+ setgrent();
+ struct group *p = getgrent();
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->gr_name);
+ ASSERT_TRUE(p->gr_name != NULL);
+ EXPECT_NOT_POISONED(p->gr_name[0]);
+ EXPECT_NOT_POISONED(p->gr_gid);
+}
+
+TEST(MemorySanitizer, fgetgrent) {
+ FILE *fp = fopen("/etc/group", "r");
+ struct group *grp = fgetgrent(fp);
+ ASSERT_TRUE(grp != NULL);
+ EXPECT_NOT_POISONED(grp->gr_name);
+ ASSERT_TRUE(grp->gr_name != NULL);
+ EXPECT_NOT_POISONED(grp->gr_name[0]);
+ EXPECT_NOT_POISONED(grp->gr_gid);
+ for (char **p = grp->gr_mem; *p; ++p) {
+ EXPECT_NOT_POISONED((*p)[0]);
+ EXPECT_TRUE(strlen(*p) > 0);
+ }
+ fclose(fp);
+}
+
+TEST(MemorySanitizer, getgrent_r) {
+ struct group grp;
+ struct group *grpres;
+ char buf[10000];
+ setgrent();
+ int res = getgrent_r(&grp, buf, sizeof(buf), &grpres);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(grp.gr_name);
- assert(grp.gr_name);
+ ASSERT_TRUE(grp.gr_name != NULL);
EXPECT_NOT_POISONED(grp.gr_name[0]);
EXPECT_NOT_POISONED(grp.gr_gid);
+ EXPECT_NOT_POISONED(grpres);
+}
+
+TEST(MemorySanitizer, fgetgrent_r) {
+ FILE *fp = fopen("/etc/group", "r");
+ struct group grp;
+ struct group *grpres;
+ char buf[10000];
+ setgrent();
+ int res = fgetgrent_r(fp, &grp, buf, sizeof(buf), &grpres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(grp.gr_name);
+ ASSERT_TRUE(grp.gr_name != NULL);
+ EXPECT_NOT_POISONED(grp.gr_name[0]);
+ EXPECT_NOT_POISONED(grp.gr_gid);
+ EXPECT_NOT_POISONED(grpres);
+ fclose(fp);
}
TEST(MemorySanitizer, getgroups) {
@@ -2971,7 +3286,7 @@ TEST(MemorySanitizer, wordexp) {
wordexp_t w;
int res = wordexp("a b c", &w, 0);
ASSERT_EQ(0, res);
- ASSERT_EQ(3, w.we_wordc);
+ ASSERT_EQ(3U, w.we_wordc);
ASSERT_STREQ("a", w.we_wordv[0]);
ASSERT_STREQ("b", w.we_wordv[1]);
ASSERT_STREQ("c", w.we_wordv[2]);
@@ -3085,141 +3400,376 @@ TEST(MemorySanitizer, VolatileBitfield) {
TEST(MemorySanitizer, UnalignedLoad) {
char x[32];
+ U4 origin = __LINE__;
+ for (unsigned i = 0; i < sizeof(x) / 4; ++i)
+ __msan_set_origin(x + 4 * i, 4, origin + i);
+
memset(x + 8, 0, 16);
- EXPECT_POISONED(__sanitizer_unaligned_load16(x+6));
- EXPECT_POISONED(__sanitizer_unaligned_load16(x+7));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x+8));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x+9));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x+22));
- EXPECT_POISONED(__sanitizer_unaligned_load16(x+23));
- EXPECT_POISONED(__sanitizer_unaligned_load16(x+24));
-
- EXPECT_POISONED(__sanitizer_unaligned_load32(x+4));
- EXPECT_POISONED(__sanitizer_unaligned_load32(x+7));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x+8));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x+9));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x+20));
- EXPECT_POISONED(__sanitizer_unaligned_load32(x+21));
- EXPECT_POISONED(__sanitizer_unaligned_load32(x+24));
-
- EXPECT_POISONED(__sanitizer_unaligned_load64(x));
- EXPECT_POISONED(__sanitizer_unaligned_load64(x+1));
- EXPECT_POISONED(__sanitizer_unaligned_load64(x+7));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x+8));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x+9));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x+16));
- EXPECT_POISONED(__sanitizer_unaligned_load64(x+17));
- EXPECT_POISONED(__sanitizer_unaligned_load64(x+21));
- EXPECT_POISONED(__sanitizer_unaligned_load64(x+24));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 6), origin + 1);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 7), origin + 1);
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 8));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 9));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 22));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 23), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 24), origin + 6);
+
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 4), origin + 1);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 7), origin + 1);
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 8));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 9));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 20));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 21), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 24), origin + 6);
+
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x), origin);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 1), origin);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 7), origin + 1);
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 8));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 9));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 16));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 17), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 21), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 24), origin + 6);
}
TEST(MemorySanitizer, UnalignedStore16) {
char x[5];
- U2 y = 0;
- __msan_poison(&y, 1);
- __sanitizer_unaligned_store16(x + 1, y);
- EXPECT_POISONED(x[0]);
- EXPECT_POISONED(x[1]);
+ U2 y2 = 0;
+ U4 origin = __LINE__;
+ __msan_poison(&y2, 1);
+ __msan_set_origin(&y2, 1, origin);
+
+ __sanitizer_unaligned_store16(x + 1, y2);
+ EXPECT_POISONED_O(x[0], origin);
+ EXPECT_POISONED_O(x[1], origin);
EXPECT_NOT_POISONED(x[2]);
- EXPECT_POISONED(x[3]);
- EXPECT_POISONED(x[4]);
+ EXPECT_POISONED_O(x[3], origin);
+ EXPECT_POISONED_O(x[4], origin);
}
TEST(MemorySanitizer, UnalignedStore32) {
char x[8];
U4 y4 = 0;
+ U4 origin = __LINE__;
__msan_poison(&y4, 2);
- __sanitizer_unaligned_store32(x+3, y4);
- EXPECT_POISONED(x[0]);
- EXPECT_POISONED(x[1]);
- EXPECT_POISONED(x[2]);
- EXPECT_POISONED(x[3]);
- EXPECT_POISONED(x[4]);
+ __msan_set_origin(&y4, 2, origin);
+
+ __sanitizer_unaligned_store32(x + 3, y4);
+ EXPECT_POISONED_O(x[0], origin);
+ EXPECT_POISONED_O(x[1], origin);
+ EXPECT_POISONED_O(x[2], origin);
+ EXPECT_POISONED_O(x[3], origin);
+ EXPECT_POISONED_O(x[4], origin);
EXPECT_NOT_POISONED(x[5]);
EXPECT_NOT_POISONED(x[6]);
- EXPECT_POISONED(x[7]);
+ EXPECT_POISONED_O(x[7], origin);
}
TEST(MemorySanitizer, UnalignedStore64) {
char x[16];
- U8 y = 0;
- __msan_poison(&y, 3);
- __msan_poison(((char *)&y) + sizeof(y) - 2, 1);
- __sanitizer_unaligned_store64(x+3, y);
- EXPECT_POISONED(x[0]);
- EXPECT_POISONED(x[1]);
- EXPECT_POISONED(x[2]);
- EXPECT_POISONED(x[3]);
- EXPECT_POISONED(x[4]);
- EXPECT_POISONED(x[5]);
+ U8 y8 = 0;
+ U4 origin = __LINE__;
+ __msan_poison(&y8, 3);
+ __msan_poison(((char *)&y8) + sizeof(y8) - 2, 1);
+ __msan_set_origin(&y8, 8, origin);
+
+ __sanitizer_unaligned_store64(x + 3, y8);
+ EXPECT_POISONED_O(x[0], origin);
+ EXPECT_POISONED_O(x[1], origin);
+ EXPECT_POISONED_O(x[2], origin);
+ EXPECT_POISONED_O(x[3], origin);
+ EXPECT_POISONED_O(x[4], origin);
+ EXPECT_POISONED_O(x[5], origin);
EXPECT_NOT_POISONED(x[6]);
EXPECT_NOT_POISONED(x[7]);
EXPECT_NOT_POISONED(x[8]);
- EXPECT_POISONED(x[9]);
+ EXPECT_POISONED_O(x[9], origin);
EXPECT_NOT_POISONED(x[10]);
- EXPECT_POISONED(x[11]);
+ EXPECT_POISONED_O(x[11], origin);
}
-TEST(MemorySanitizerDr, StoreInDSOTest) {
- if (!__msan_has_dynamic_component()) return;
- char* s = new char[10];
- dso_memfill(s, 9);
- EXPECT_NOT_POISONED(s[5]);
- EXPECT_POISONED(s[9]);
+TEST(MemorySanitizer, UnalignedStore16_precise) {
+ char x[8];
+ U2 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_poison(((char *)&y) + 1, 1);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store16(x + 3, y);
+ EXPECT_POISONED_O(x[0], originx1);
+ EXPECT_POISONED_O(x[1], originx1);
+ EXPECT_POISONED_O(x[2], originx1);
+ EXPECT_NOT_POISONED(x[3]);
+ EXPECT_POISONED_O(x[4], originy);
+ EXPECT_POISONED_O(x[5], originy);
+ EXPECT_POISONED_O(x[6], originy);
+ EXPECT_POISONED_O(x[7], originy);
}
-int return_poisoned_int() {
- return ReturnPoisoned<U8>();
-}
+TEST(MemorySanitizer, UnalignedStore16_precise2) {
+ char x[8];
+ U2 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_poison(((char *)&y), 1);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store16(x + 3, y);
+ EXPECT_POISONED_O(x[0], originy);
+ EXPECT_POISONED_O(x[1], originy);
+ EXPECT_POISONED_O(x[2], originy);
+ EXPECT_POISONED_O(x[3], originy);
+ EXPECT_NOT_POISONED(x[4]);
+ EXPECT_POISONED_O(x[5], originx2);
+ EXPECT_POISONED_O(x[6], originx2);
+ EXPECT_POISONED_O(x[7], originx2);
+}
+
+TEST(MemorySanitizer, UnalignedStore64_precise) {
+ char x[12];
+ U8 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originx3 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_set_origin(x + 8, 4, originx3);
+ __msan_poison(((char *)&y) + 1, 1);
+ __msan_poison(((char *)&y) + 7, 1);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store64(x + 2, y);
+ EXPECT_POISONED_O(x[0], originy);
+ EXPECT_POISONED_O(x[1], originy);
+ EXPECT_NOT_POISONED(x[2]);
+ EXPECT_POISONED_O(x[3], originy);
+
+ EXPECT_NOT_POISONED(x[4]);
+ EXPECT_NOT_POISONED(x[5]);
+ EXPECT_NOT_POISONED(x[6]);
+ EXPECT_NOT_POISONED(x[7]);
-TEST(MemorySanitizerDr, ReturnFromDSOTest) {
- if (!__msan_has_dynamic_component()) return;
- EXPECT_NOT_POISONED(dso_callfn(return_poisoned_int));
+ EXPECT_NOT_POISONED(x[8]);
+ EXPECT_POISONED_O(x[9], originy);
+ EXPECT_POISONED_O(x[10], originy);
+ EXPECT_POISONED_O(x[11], originy);
}
-NOINLINE int TrashParamTLS(long long x, long long y, long long z) { //NOLINT
- EXPECT_POISONED(x);
- EXPECT_POISONED(y);
- EXPECT_POISONED(z);
- return 0;
+TEST(MemorySanitizer, UnalignedStore64_precise2) {
+ char x[12];
+ U8 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originx3 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_set_origin(x + 8, 4, originx3);
+ __msan_poison(((char *)&y) + 3, 3);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store64(x + 2, y);
+ EXPECT_POISONED_O(x[0], originx1);
+ EXPECT_POISONED_O(x[1], originx1);
+ EXPECT_NOT_POISONED(x[2]);
+ EXPECT_NOT_POISONED(x[3]);
+
+ EXPECT_NOT_POISONED(x[4]);
+ EXPECT_POISONED_O(x[5], originy);
+ EXPECT_POISONED_O(x[6], originy);
+ EXPECT_POISONED_O(x[7], originy);
+
+ EXPECT_NOT_POISONED(x[8]);
+ EXPECT_NOT_POISONED(x[9]);
+ EXPECT_POISONED_O(x[10], originx3);
+ EXPECT_POISONED_O(x[11], originx3);
}
-static int CheckParamTLS(long long x, long long y, long long z) { //NOLINT
- EXPECT_NOT_POISONED(x);
- EXPECT_NOT_POISONED(y);
- EXPECT_NOT_POISONED(z);
- return 0;
+#if defined(__clang__)
+namespace {
+typedef U1 V16x8 __attribute__((__vector_size__(16)));
+typedef U2 V8x16 __attribute__((__vector_size__(16)));
+typedef U4 V4x32 __attribute__((__vector_size__(16)));
+typedef U8 V2x64 __attribute__((__vector_size__(16)));
+typedef U4 V8x32 __attribute__((__vector_size__(32)));
+typedef U8 V4x64 __attribute__((__vector_size__(32)));
+typedef U4 V2x32 __attribute__((__vector_size__(8)));
+typedef U2 V4x16 __attribute__((__vector_size__(8)));
+typedef U1 V8x8 __attribute__((__vector_size__(8)));
+
+
+V8x16 shift_sse2_left_scalar(V8x16 x, U4 y) {
+ return _mm_slli_epi16(x, y);
+}
+
+V8x16 shift_sse2_left(V8x16 x, V8x16 y) {
+ return _mm_sll_epi16(x, y);
+}
+
+TEST(VectorShiftTest, sse2_left_scalar) {
+ V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
+ V8x16 u = shift_sse2_left_scalar(v, 2);
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_NOT_POISONED(u[0] | (3U << 2));
+ EXPECT_NOT_POISONED(u[1] | (7U << 2));
+ u[0] = u[1] = 0;
+ EXPECT_NOT_POISONED(u);
+}
+
+TEST(VectorShiftTest, sse2_left_scalar_by_uninit) {
+ V8x16 v = {0, 1, 2, 3, 4, 5, 6, 7};
+ V8x16 u = shift_sse2_left_scalar(v, Poisoned<U4>());
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_POISONED(u[2]);
+ EXPECT_POISONED(u[3]);
+ EXPECT_POISONED(u[4]);
+ EXPECT_POISONED(u[5]);
+ EXPECT_POISONED(u[6]);
+ EXPECT_POISONED(u[7]);
+}
+
+TEST(VectorShiftTest, sse2_left) {
+ V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
+ // Top 64 bits of shift count don't affect the result.
+ V2x64 s = {2, Poisoned<U8>()};
+ V8x16 u = shift_sse2_left(v, s);
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_NOT_POISONED(u[0] | (3U << 2));
+ EXPECT_NOT_POISONED(u[1] | (7U << 2));
+ u[0] = u[1] = 0;
+ EXPECT_NOT_POISONED(u);
+}
+
+TEST(VectorShiftTest, sse2_left_by_uninit) {
+ V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
+ V2x64 s = {Poisoned<U8>(), Poisoned<U8>()};
+ V8x16 u = shift_sse2_left(v, s);
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_POISONED(u[2]);
+ EXPECT_POISONED(u[3]);
+ EXPECT_POISONED(u[4]);
+ EXPECT_POISONED(u[5]);
+ EXPECT_POISONED(u[6]);
+ EXPECT_POISONED(u[7]);
+}
+
+#ifdef __AVX2__
+V4x32 shift_avx2_left(V4x32 x, V4x32 y) {
+ return _mm_sllv_epi32(x, y);
+}
+// This is variable vector shift that's only available starting with AVX2.
+// V4x32 shift_avx2_left(V4x32 x, V4x32 y) {
+TEST(VectorShiftTest, avx2_left) {
+ V4x32 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3};
+ V4x32 s = {2, Poisoned<U4>(), 3, Poisoned<U4>()};
+ V4x32 u = shift_avx2_left(v, s);
+ EXPECT_POISONED(u[0]);
+ EXPECT_NOT_POISONED(u[0] | (~7U));
+ EXPECT_POISONED(u[1]);
+ EXPECT_POISONED(u[1] | (~31U));
+ EXPECT_NOT_POISONED(u[2]);
+ EXPECT_POISONED(u[3]);
+ EXPECT_POISONED(u[3] | (~31U));
+}
+#endif // __AVX2__
+} // namespace
+
+TEST(VectorPackTest, sse2_packssdw_128) {
+ const unsigned S2_max = (1 << 15) - 1;
+ V4x32 a = {Poisoned<U4>(0, 0xFF0000), Poisoned<U4>(0, 0xFFFF0000),
+ S2_max + 100, 4};
+ V4x32 b = {Poisoned<U4>(0, 0xFF), S2_max + 10000, Poisoned<U4>(0, 0xFF00),
+ S2_max};
+
+ V8x16 c = _mm_packs_epi32(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_POISONED(c[1]);
+ EXPECT_NOT_POISONED(c[2]);
+ EXPECT_NOT_POISONED(c[3]);
+ EXPECT_POISONED(c[4]);
+ EXPECT_NOT_POISONED(c[5]);
+ EXPECT_POISONED(c[6]);
+ EXPECT_NOT_POISONED(c[7]);
+
+ EXPECT_EQ(c[2], S2_max);
+ EXPECT_EQ(c[3], 4);
+ EXPECT_EQ(c[5], S2_max);
+ EXPECT_EQ(c[7], S2_max);
}
-TEST(MemorySanitizerDr, CallFromDSOTest) {
- if (!__msan_has_dynamic_component()) return;
- S8* x = GetPoisoned<S8>();
- S8* y = GetPoisoned<S8>();
- S8* z = GetPoisoned<S8>();
- EXPECT_NOT_POISONED(TrashParamTLS(*x, *y, *z));
- EXPECT_NOT_POISONED(dso_callfn1(CheckParamTLS));
+TEST(VectorPackTest, mmx_packuswb) {
+ const unsigned U1_max = (1 << 8) - 1;
+ V4x16 a = {Poisoned<U2>(0, 0xFF00), Poisoned<U2>(0, 0xF000U), U1_max + 100,
+ 4};
+ V4x16 b = {Poisoned<U2>(0, 0xFF), U1_max - 1, Poisoned<U2>(0, 0xF), U1_max};
+ V8x8 c = _mm_packs_pu16(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_POISONED(c[1]);
+ EXPECT_NOT_POISONED(c[2]);
+ EXPECT_NOT_POISONED(c[3]);
+ EXPECT_POISONED(c[4]);
+ EXPECT_NOT_POISONED(c[5]);
+ EXPECT_POISONED(c[6]);
+ EXPECT_NOT_POISONED(c[7]);
+
+ EXPECT_EQ(c[2], U1_max);
+ EXPECT_EQ(c[3], 4);
+ EXPECT_EQ(c[5], U1_max - 1);
+ EXPECT_EQ(c[7], U1_max);
}
-static void StackStoreInDSOFn(int* x, int* y) {
- EXPECT_NOT_POISONED(*x);
- EXPECT_NOT_POISONED(*y);
+TEST(VectorSadTest, sse2_psad_bw) {
+ V16x8 a = {Poisoned<U1>(), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+ V16x8 b = {100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115};
+ V2x64 c = _mm_sad_epu8(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_NOT_POISONED(c[1]);
+
+ EXPECT_EQ(800U, c[1]);
}
-TEST(MemorySanitizerDr, StackStoreInDSOTest) {
- if (!__msan_has_dynamic_component()) return;
- dso_stack_store(StackStoreInDSOFn, 1);
+TEST(VectorMaddTest, mmx_pmadd_wd) {
+ V4x16 a = {Poisoned<U2>(), 1, 2, 3};
+ V4x16 b = {100, 101, 102, 103};
+ V2x32 c = _mm_madd_pi16(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_NOT_POISONED(c[1]);
+
+ EXPECT_EQ((unsigned)(2 * 102 + 3 * 103), c[1]);
}
+#endif // defined(__clang__)
TEST(MemorySanitizerOrigins, SetGet) {
EXPECT_EQ(TrackingOrigins(), __msan_get_track_origins());
if (!TrackingOrigins()) return;
int x;
__msan_set_origin(&x, sizeof(x), 1234);
- EXPECT_EQ(1234, __msan_get_origin(&x));
+ EXPECT_EQ(1234U, __msan_get_origin(&x));
__msan_set_origin(&x, sizeof(x), 5678);
- EXPECT_EQ(5678, __msan_get_origin(&x));
+ EXPECT_EQ(5678U, __msan_get_origin(&x));
__msan_set_origin(&x, sizeof(x), 0);
- EXPECT_EQ(0, __msan_get_origin(&x));
+ EXPECT_EQ(0U, __msan_get_origin(&x));
}
namespace {
@@ -3229,8 +3779,7 @@ struct S {
U2 b;
};
-// http://code.google.com/p/memory-sanitizer/issues/detail?id=6
-TEST(MemorySanitizerOrigins, DISABLED_InitializedStoreDoesNotChangeOrigin) {
+TEST(MemorySanitizerOrigins, InitializedStoreDoesNotChangeOrigin) {
if (!TrackingOrigins()) return;
S s;
@@ -3403,29 +3952,6 @@ TEST(MemorySanitizerOrigins, Select) {
EXPECT_POISONED_O(g_0 ? 1 : *GetPoisonedO<S4>(0, __LINE__), __LINE__);
}
-extern "C"
-NOINLINE char AllocaTO() {
- int ar[100];
- break_optimization(ar);
- return ar[10];
- // fprintf(stderr, "Descr: %s\n",
- // __msan_get_origin_descr_if_stack(__msan_get_origin_tls()));
-}
-
-TEST(MemorySanitizerOrigins, Alloca) {
- if (!TrackingOrigins()) return;
- EXPECT_POISONED_S(AllocaTO(), "ar@AllocaTO");
- EXPECT_POISONED_S(AllocaTO(), "ar@AllocaTO");
- EXPECT_POISONED_S(AllocaTO(), "ar@AllocaTO");
- EXPECT_POISONED_S(AllocaTO(), "ar@AllocaTO");
-}
-
-// FIXME: replace with a lit-like test.
-TEST(MemorySanitizerOrigins, DISABLED_AllocaDeath) {
- if (!TrackingOrigins()) return;
- EXPECT_DEATH(AllocaTO(), "ORIGIN: stack allocation: ar@AllocaTO");
-}
-
NOINLINE int RetvalOriginTest(U4 origin) {
int *a = new int;
break_optimization(a);
@@ -3513,6 +4039,26 @@ TEST(MemorySanitizer, Select) {
EXPECT_POISONED(z);
}
+TEST(MemorySanitizer, SelectPartial) {
+ // Precise instrumentation of select.
+ // Some bits of the result do not depend on select condition, and must stay
+ // initialized even if select condition is not. These are the bits that are
+ // equal and initialized in both left and right select arguments.
+ U4 x = 0xFFFFABCDU;
+ U4 x_s = 0xFFFF0000U;
+ __msan_partial_poison(&x, &x_s, sizeof(x));
+ U4 y = 0xAB00U;
+ U1 cond = true;
+ __msan_poison(&cond, sizeof(cond));
+ U4 z = cond ? x : y;
+ __msan_print_shadow(&z, sizeof(z));
+ EXPECT_POISONED(z & 0xFFU);
+ EXPECT_NOT_POISONED(z & 0xFF00U);
+ EXPECT_POISONED(z & 0xFF0000U);
+ EXPECT_POISONED(z & 0xFF000000U);
+ EXPECT_EQ(0xAB00U, z & 0xFF00U);
+}
+
TEST(MemorySanitizerStress, DISABLED_MallocStackTrace) {
RecursiveMalloc(22);
}
@@ -3520,7 +4066,7 @@ TEST(MemorySanitizerStress, DISABLED_MallocStackTrace) {
TEST(MemorySanitizerAllocator, get_estimated_allocated_size) {
size_t sizes[] = {0, 20, 5000, 1<<20};
for (size_t i = 0; i < sizeof(sizes) / sizeof(*sizes); ++i) {
- size_t alloc_size = __msan_get_estimated_allocated_size(sizes[i]);
+ size_t alloc_size = __sanitizer_get_estimated_allocated_size(sizes[i]);
EXPECT_EQ(alloc_size, sizes[i]);
}
}
@@ -3529,26 +4075,26 @@ TEST(MemorySanitizerAllocator, get_allocated_size_and_ownership) {
char *array = reinterpret_cast<char*>(malloc(100));
int *int_ptr = new int;
- EXPECT_TRUE(__msan_get_ownership(array));
- EXPECT_EQ(100, __msan_get_allocated_size(array));
+ EXPECT_TRUE(__sanitizer_get_ownership(array));
+ EXPECT_EQ(100U, __sanitizer_get_allocated_size(array));
- EXPECT_TRUE(__msan_get_ownership(int_ptr));
- EXPECT_EQ(sizeof(*int_ptr), __msan_get_allocated_size(int_ptr));
+ EXPECT_TRUE(__sanitizer_get_ownership(int_ptr));
+ EXPECT_EQ(sizeof(*int_ptr), __sanitizer_get_allocated_size(int_ptr));
void *wild_addr = reinterpret_cast<void*>(0x1);
- EXPECT_FALSE(__msan_get_ownership(wild_addr));
- EXPECT_EQ(0, __msan_get_allocated_size(wild_addr));
+ EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(wild_addr));
- EXPECT_FALSE(__msan_get_ownership(array + 50));
- EXPECT_EQ(0, __msan_get_allocated_size(array + 50));
+ EXPECT_FALSE(__sanitizer_get_ownership(array + 50));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(array + 50));
+
+ // NULL is a valid argument for GetAllocatedSize but is not owned.
+ EXPECT_FALSE(__sanitizer_get_ownership(NULL));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL));
- // NULL is a valid argument for GetAllocatedSize but is not owned.
- EXPECT_FALSE(__msan_get_ownership(NULL));
- EXPECT_EQ(0, __msan_get_allocated_size(NULL));
-
free(array);
- EXPECT_FALSE(__msan_get_ownership(array));
- EXPECT_EQ(0, __msan_get_allocated_size(array));
+ EXPECT_FALSE(__sanitizer_get_ownership(array));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(array));
delete int_ptr;
}
@@ -3559,3 +4105,39 @@ TEST(MemorySanitizer, MlockTest) {
EXPECT_EQ(0, munlockall());
EXPECT_EQ(0, munlock((void*)0x987, 0x654));
}
+
+// Test that LargeAllocator unpoisons memory before releasing it to the OS.
+TEST(MemorySanitizer, LargeAllocatorUnpoisonsOnFree) {
+ void *p = malloc(1024 * 1024);
+ free(p);
+
+ typedef void *(*mmap_fn)(void *, size_t, int, int, int, off_t);
+ mmap_fn real_mmap = (mmap_fn)dlsym(RTLD_NEXT, "mmap");
+
+ // Allocate the page that was released to the OS in free() with the real mmap,
+ // bypassing the interceptor.
+ char *q = (char *)real_mmap(p, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ ASSERT_NE((char *)0, q);
+
+ ASSERT_TRUE(q <= p);
+ ASSERT_TRUE(q + 4096 > p);
+
+ EXPECT_NOT_POISONED(q[0]);
+ EXPECT_NOT_POISONED(q[10]);
+ EXPECT_NOT_POISONED(q[100]);
+
+ munmap(q, 4096);
+}
+
+#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
+TEST(MemorySanitizer, MallocUsableSizeTest) {
+ const size_t kArraySize = 100;
+ char *array = Ident((char*)malloc(kArraySize));
+ int *int_ptr = Ident(new int);
+ EXPECT_EQ(0U, malloc_usable_size(NULL));
+ EXPECT_EQ(kArraySize, malloc_usable_size(array));
+ EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
+ free(array);
+ delete int_ptr;
+}
+#endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
diff --git a/lib/msan/tests/msandr_test_so.cc b/lib/msan/tests/msandr_test_so.cc
deleted file mode 100644
index eb605d4dba12c..0000000000000
--- a/lib/msan/tests/msandr_test_so.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-//===-- msandr_test_so.cc ------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of MemorySanitizer.
-//
-// MemorySanitizer unit tests.
-//===----------------------------------------------------------------------===//
-
-#include "msandr_test_so.h"
-
-void dso_memfill(char* s, unsigned n) {
- for (unsigned i = 0; i < n; ++i)
- s[i] = i;
-}
-
-int dso_callfn(int (*fn)(void)) {
- volatile int x = fn();
- return x;
-}
-
-int dso_callfn1(int (*fn)(long long, long long, long long)) { //NOLINT
- volatile int x = fn(1, 2, 3);
- return x;
-}
-
-int dso_stack_store(void (*fn)(int*, int*), int x) {
- int y = x + 1;
- fn(&x, &y);
- return y;
-}
-
-void break_optimization(void *x) {}
diff --git a/lib/msan/tests/msandr_test_so.h b/lib/msan/tests/msandr_test_so.h
deleted file mode 100644
index cd75ff34f3874..0000000000000
--- a/lib/msan/tests/msandr_test_so.h
+++ /dev/null
@@ -1,24 +0,0 @@
-//===-- msandr_test_so.h ----------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of MemorySanitizer.
-//
-// MemorySanitizer unit tests.
-//===----------------------------------------------------------------------===//
-
-#ifndef MSANDR_MSANDR_TEST_SO_H
-#define MSANDR_MSANDR_TEST_SO_H
-
-void dso_memfill(char* s, unsigned n);
-int dso_callfn(int (*fn)(void));
-int dso_callfn1(int (*fn)(long long, long long, long long)); //NOLINT
-int dso_stack_store(void (*fn)(int*, int*), int x);
-void break_optimization(void *x);
-
-#endif