diff options
Diffstat (limited to 'lib/msan/tests')
-rw-r--r-- | lib/msan/tests/CMakeLists.txt | 50 | ||||
-rw-r--r-- | lib/msan/tests/lit.cfg | 29 | ||||
-rw-r--r-- | lib/msan/tests/lit.site.cfg.in | 9 | ||||
-rw-r--r-- | lib/msan/tests/msan_loadable.cc | 45 | ||||
-rw-r--r-- | lib/msan/tests/msan_test.cc | 1637 | ||||
-rw-r--r-- | lib/msan/tests/msan_test_config.h | 20 | ||||
-rw-r--r-- | lib/msan/tests/msan_test_main.cc | 21 | ||||
-rw-r--r-- | lib/msan/tests/msandr_test_so.cc | 2 | ||||
-rw-r--r-- | lib/msan/tests/msandr_test_so.h | 1 |
9 files changed, 1267 insertions, 547 deletions
diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt index d2a28b2cba5cf..7a784023d2dbd 100644 --- a/lib/msan/tests/CMakeLists.txt +++ b/lib/msan/tests/CMakeLists.txt @@ -31,8 +31,13 @@ set(MSAN_LIBCXX_LINK_FLAGS -fsanitize=memory) # Unittest sources and build flags. -set(MSAN_UNITTEST_SOURCE msan_test.cc) -set(MSAN_UNITTEST_HEADERS msandr_test_so.h) +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 @@ -42,7 +47,6 @@ set(MSAN_UNITTEST_COMMON_CFLAGS -I${COMPILER_RT_SOURCE_DIR}/lib/msan -std=c++0x -stdlib=libc++ - -fPIE -g -O2 -fno-exceptions @@ -57,11 +61,14 @@ set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS ) set(MSAN_UNITTEST_LINK_FLAGS -fsanitize=memory - -pie -ldl # FIXME: we build libcxx without cxxabi and need libstdc++ to provide it. -lstdc++ ) +set(MSAN_LOADABLE_LINK_FLAGS + -fsanitize=memory + -shared +) # Compile source for the given architecture, using compiler # options in ${ARGN}, and add it to the object list. @@ -77,9 +84,7 @@ endmacro() macro(msan_link_shared so_list so_name arch) parse_arguments(SOURCE "OBJECTS;LINKFLAGS;DEPS" "" ${ARGN}) - get_unittest_directory(OUTPUT_DIR) - file(MAKE_DIRECTORY ${OUTPUT_DIR}) - set(output_so "${OUTPUT_DIR}/${so_name}.${arch}.so") + set(output_so "${CMAKE_CURRENT_BINARY_DIR}/${so_name}.${arch}.so") get_target_flags_for_arch(${arch} TARGET_LINKFLAGS) clang_link_shared(${output_so} OBJECTS ${SOURCE_OBJECTS} @@ -92,13 +97,13 @@ endmacro() # of objects in ${ARGN}. macro(add_msan_test test_suite test_name arch) get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS) - get_unittest_directory(OUTPUT_DIR) 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=${OUTPUT_DIR}") + "-Wl,-rpath=${CMAKE_CURRENT_BINARY_DIR}") endmacro() # Main MemorySanitizer unit tests. @@ -127,7 +132,14 @@ macro(add_msan_tests_for_arch arch) # Instrumented tests. set(MSAN_INST_TEST_OBJECTS) - msan_compile(MSAN_INST_TEST_OBJECTS ${MSAN_UNITTEST_SOURCE} ${arch} + foreach (SOURCE ${MSAN_UNITTEST_SOURCES}) + msan_compile(MSAN_INST_TEST_OBJECTS ${SOURCE} ${arch} + ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS}) + 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. @@ -135,6 +147,12 @@ macro(add_msan_tests_for_arch arch) msan_compile(MSANDR_TEST_OBJECTS ${MSANDR_UNITTEST_SOURCE} ${arch} ${MSAN_UNITTEST_COMMON_CFLAGS}) + # Instrumented loadable library tests. + set(MSAN_LOADABLE_SO) + msan_link_shared(MSAN_LOADABLE_SO "libmsan_loadable" ${arch} + 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} @@ -151,16 +169,4 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND EXISTS ${MSAN_LIBCXX_PATH}/) if(CAN_TARGET_x86_64) add_msan_tests_for_arch(x86_64) endif() - - # Run unittests as a part of lit testsuite. - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg - ) - - add_lit_testsuite(check-msan "Running MemorySanitizer unittests" - ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS MsanUnitTests - ) - set_target_properties(check-msan PROPERTIES FOLDER "MemorySanitizer unittests") endif() diff --git a/lib/msan/tests/lit.cfg b/lib/msan/tests/lit.cfg deleted file mode 100644 index 38aa1380443f3..0000000000000 --- a/lib/msan/tests/lit.cfg +++ /dev/null @@ -1,29 +0,0 @@ -# -*- Python -*- - -import os - -def get_required_attr(config, attr_name): - attr_value = getattr(config, attr_name, None) - if not attr_value: - lit.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 attributes common for all compiler-rt projects. -llvm_src_root = get_required_attr(config, 'llvm_src_root') -compiler_rt_lit_unit_cfg = os.path.join(llvm_src_root, "projects", - "compiler-rt", "lib", - "lit.common.unit.cfg") -lit.load_config(config, compiler_rt_lit_unit_cfg) - -# Setup config name. -config.name = 'MemorySanitizer' - -# Setup test source and exec root. For unit tests, we define -# it as build directory with sanitizer_common unit tests. -llvm_obj_root = get_required_attr(config, "llvm_obj_root") -config.test_exec_root = os.path.join(llvm_obj_root, "projects", - "compiler-rt", "lib", - "msan", "tests") -config.test_source_root = config.test_exec_root diff --git a/lib/msan/tests/lit.site.cfg.in b/lib/msan/tests/lit.site.cfg.in deleted file mode 100644 index bb9a28d6a6cb7..0000000000000 --- a/lib/msan/tests/lit.site.cfg.in +++ /dev/null @@ -1,9 +0,0 @@ -## Autogenerated by LLVM/Clang configuration. -# Do not edit! - -config.build_type = "@CMAKE_BUILD_TYPE@" -config.llvm_obj_root = "@LLVM_BINARY_DIR@" -config.llvm_src_root = "@LLVM_SOURCE_DIR@" - -# Let the main config do the real work. -lit.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg") diff --git a/lib/msan/tests/msan_loadable.cc b/lib/msan/tests/msan_loadable.cc new file mode 100644 index 0000000000000..db3bf489853dc --- /dev/null +++ b/lib/msan/tests/msan_loadable.cc @@ -0,0 +1,45 @@ +//===-- msan_loadable.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 "msan/msan_interface_internal.h" +#include <stdlib.h> + +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 1ee7a27d56b16..1e05382e4b9f3 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -12,18 +12,25 @@ // MemorySanitizer unit tests. //===----------------------------------------------------------------------===// +#ifndef MSAN_EXTERNAL_TEST_CONFIG +#include "msan_test_config.h" +#endif // MSAN_EXTERNAL_TEST_CONFIG + #include "sanitizer/msan_interface.h" #include "msandr_test_so.h" -#include "gtest/gtest.h" #include <stdlib.h> #include <stdarg.h> #include <stdio.h> #include <assert.h> #include <wchar.h> +#include <math.h> +#include <arpa/inet.h> #include <dlfcn.h> +#include <grp.h> #include <unistd.h> +#include <link.h> #include <limits.h> #include <sys/time.h> #include <sys/types.h> @@ -34,6 +41,10 @@ #include <sys/utsname.h> #include <sys/mman.h> #include <sys/vfs.h> +#include <dirent.h> +#include <pwd.h> +#include <sys/socket.h> +#include <netdb.h> #if defined(__i386__) || defined(__x86_64__) # include <emmintrin.h> @@ -53,29 +64,36 @@ typedef signed long long S8; // NOLINT #define NOINLINE __attribute__((noinline)) #define INLINE __attribute__((always_inline)) +static bool TrackingOrigins() { + S8 x; + __msan_set_origin(&x, sizeof(x), 0x1234); + U4 origin = __msan_get_origin(&x); + __msan_set_origin(&x, sizeof(x), 0); + return origin == 0x1234; +} -#define EXPECT_POISONED(action) \ +#define EXPECT_UMR(action) \ do { \ __msan_set_expect_umr(1); \ action; \ __msan_set_expect_umr(0); \ } while (0) -#define EXPECT_POISONED_O(action, origin) \ +#define EXPECT_UMR_O(action, origin) \ do { \ __msan_set_expect_umr(1); \ action; \ __msan_set_expect_umr(0); \ if (TrackingOrigins()) \ - EXPECT_EQ(origin, __msan_get_origin_tls()); \ + EXPECT_EQ(origin, __msan_get_umr_origin()); \ } while (0) -#define EXPECT_POISONED_S(action, stack_origin) \ +#define EXPECT_UMR_S(action, stack_origin) \ do { \ __msan_set_expect_umr(1); \ action; \ __msan_set_expect_umr(0); \ - u32 id = __msan_get_origin_tls(); \ + 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", \ @@ -84,6 +102,44 @@ typedef signed long long S8; // NOLINT } \ } while (0) +#define EXPECT_POISONED(x) ExpectPoisoned(x) + +template<typename T> +void ExpectPoisoned(const T& t) { + EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t))); +} + +#define EXPECT_POISONED_O(x, origin) \ + ExpectPoisonedWithOrigin(x, origin) + +template<typename T> +void ExpectPoisonedWithOrigin(const T& t, unsigned origin) { + EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t))); + if (TrackingOrigins()) + 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> +void ExpectNotPoisoned(const T& t) { + EXPECT_EQ(-1, __msan_test_shadow((void*)&t, sizeof(t))); +} static U8 poisoned_array[100]; template<class T> @@ -95,7 +151,7 @@ T *GetPoisoned(int i = 0, T val = 0) { } template<class T> -T *GetPoisonedO(int i, u32 origin, T val = 0) { +T *GetPoisonedO(int i, U4 origin, T val = 0) { T *res = (T*)&poisoned_array[i]; *res = val; __msan_poison(&poisoned_array[i], sizeof(T)); @@ -112,81 +168,67 @@ static T Ident(T t) { return ret; } -static bool TrackingOrigins() { - S8 x; - __msan_set_origin(&x, sizeof(x), 0x1234); - u32 origin = __msan_get_origin(&x); - __msan_set_origin(&x, sizeof(x), 0); - return origin == 0x1234; -} - template<class T> NOINLINE T ReturnPoisoned() { return *GetPoisoned<T>(); } -static volatile S1 v_s1; -static volatile S2 v_s2; -static volatile S4 v_s4; -static volatile S8 v_s8; -static volatile U1 v_u1; -static volatile U2 v_u2; -static volatile U4 v_u4; -static volatile U8 v_u8; -static void* volatile v_p; -static volatile double v_d; static volatile int g_one = 1; static volatile int g_zero = 0; static volatile int g_0 = 0; static volatile int g_1 = 1; -#if MSAN_HAS_M128 -static volatile __m128i v_m128; -#endif - S4 a_s4[100]; S8 a_s8[100]; +// Check that malloc poisons memory. +// A lot of tests below depend on this. +TEST(MemorySanitizerSanity, PoisonInMalloc) { + int *x = (int*)malloc(sizeof(int)); + EXPECT_POISONED(*x); + free(x); +} + TEST(MemorySanitizer, NegativeTest1) { S4 *x = GetPoisoned<S4>(); if (g_one) *x = 0; - v_s4 = *x; + EXPECT_NOT_POISONED(*x); } TEST(MemorySanitizer, PositiveTest1) { // Load to store. - EXPECT_POISONED(v_s1 = *GetPoisoned<S1>()); - EXPECT_POISONED(v_s2 = *GetPoisoned<S2>()); - EXPECT_POISONED(v_s4 = *GetPoisoned<S4>()); - EXPECT_POISONED(v_s8 = *GetPoisoned<S8>()); + EXPECT_POISONED(*GetPoisoned<S1>()); + EXPECT_POISONED(*GetPoisoned<S2>()); + EXPECT_POISONED(*GetPoisoned<S4>()); + EXPECT_POISONED(*GetPoisoned<S8>()); // S->S conversions. - EXPECT_POISONED(v_s2 = *GetPoisoned<S1>()); - EXPECT_POISONED(v_s4 = *GetPoisoned<S1>()); - EXPECT_POISONED(v_s8 = *GetPoisoned<S1>()); + EXPECT_POISONED(*GetPoisoned<S1>()); + EXPECT_POISONED(*GetPoisoned<S1>()); + EXPECT_POISONED(*GetPoisoned<S1>()); - EXPECT_POISONED(v_s1 = *GetPoisoned<S2>()); - EXPECT_POISONED(v_s4 = *GetPoisoned<S2>()); - EXPECT_POISONED(v_s8 = *GetPoisoned<S2>()); + EXPECT_POISONED(*GetPoisoned<S2>()); + EXPECT_POISONED(*GetPoisoned<S2>()); + EXPECT_POISONED(*GetPoisoned<S2>()); - EXPECT_POISONED(v_s1 = *GetPoisoned<S4>()); - EXPECT_POISONED(v_s2 = *GetPoisoned<S4>()); - EXPECT_POISONED(v_s8 = *GetPoisoned<S4>()); + EXPECT_POISONED(*GetPoisoned<S4>()); + EXPECT_POISONED(*GetPoisoned<S4>()); + EXPECT_POISONED(*GetPoisoned<S4>()); - EXPECT_POISONED(v_s1 = *GetPoisoned<S8>()); - EXPECT_POISONED(v_s2 = *GetPoisoned<S8>()); - EXPECT_POISONED(v_s4 = *GetPoisoned<S8>()); + EXPECT_POISONED(*GetPoisoned<S8>()); + EXPECT_POISONED(*GetPoisoned<S8>()); + EXPECT_POISONED(*GetPoisoned<S8>()); // ZExt - EXPECT_POISONED(v_s2 = *GetPoisoned<U1>()); - EXPECT_POISONED(v_s4 = *GetPoisoned<U1>()); - EXPECT_POISONED(v_s8 = *GetPoisoned<U1>()); - EXPECT_POISONED(v_s4 = *GetPoisoned<U2>()); - EXPECT_POISONED(v_s8 = *GetPoisoned<U2>()); - EXPECT_POISONED(v_s8 = *GetPoisoned<U4>()); + EXPECT_POISONED(*GetPoisoned<U1>()); + EXPECT_POISONED(*GetPoisoned<U1>()); + EXPECT_POISONED(*GetPoisoned<U1>()); + EXPECT_POISONED(*GetPoisoned<U2>()); + EXPECT_POISONED(*GetPoisoned<U2>()); + EXPECT_POISONED(*GetPoisoned<U4>()); // Unary ops. - EXPECT_POISONED(v_s4 = - *GetPoisoned<S4>()); + EXPECT_POISONED(- *GetPoisoned<S4>()); - EXPECT_POISONED(a_s4[g_zero] = 100 / *GetPoisoned<S4>(0, 1)); + EXPECT_UMR(a_s4[g_zero] = 100 / *GetPoisoned<S4>(0, 1)); a_s4[g_zero] = 1 - *GetPoisoned<S4>(); @@ -198,22 +240,22 @@ TEST(MemorySanitizer, Phi1) { if (g_one) { c = *GetPoisoned<S4>(); } else { - __msan_break_optimization(0); + break_optimization(0); c = 0; } - EXPECT_POISONED(v_s4 = c); + EXPECT_POISONED(c); } TEST(MemorySanitizer, Phi2) { S4 i = *GetPoisoned<S4>(); S4 n = g_one; - EXPECT_POISONED(for (; i < g_one; i++);); - EXPECT_POISONED(v_s4 = i); + EXPECT_UMR(for (; i < g_one; i++);); + EXPECT_POISONED(i); } -NOINLINE void Arg1ExpectUMR(S4 a1) { EXPECT_POISONED(v_s4 = a1); } -NOINLINE void Arg2ExpectUMR(S4 a1, S4 a2) { EXPECT_POISONED(v_s4 = a2); } -NOINLINE void Arg3ExpectUMR(S1 a1, S4 a2, S8 a3) { EXPECT_POISONED(v_s8 = a3); } +NOINLINE void Arg1ExpectUMR(S4 a1) { EXPECT_POISONED(a1); } +NOINLINE void Arg2ExpectUMR(S4 a1, S4 a2) { EXPECT_POISONED(a2); } +NOINLINE void Arg3ExpectUMR(S1 a1, S4 a2, S8 a3) { EXPECT_POISONED(a3); } TEST(MemorySanitizer, ArgTest) { Arg1ExpectUMR(*GetPoisoned<S4>()); @@ -229,50 +271,50 @@ TEST(MemorySanitizer, CallAndRet) { ReturnPoisoned<S4>(); ReturnPoisoned<S8>(); - EXPECT_POISONED(v_s1 = ReturnPoisoned<S1>()); - EXPECT_POISONED(v_s2 = ReturnPoisoned<S2>()); - EXPECT_POISONED(v_s4 = ReturnPoisoned<S4>()); - EXPECT_POISONED(v_s8 = ReturnPoisoned<S8>()); + EXPECT_POISONED(ReturnPoisoned<S1>()); + EXPECT_POISONED(ReturnPoisoned<S2>()); + EXPECT_POISONED(ReturnPoisoned<S4>()); + EXPECT_POISONED(ReturnPoisoned<S8>()); } // malloc() in the following test may be optimized to produce a compile-time // undef value. Check that we trap on the volatile assignment anyway. TEST(MemorySanitizer, DISABLED_MallocNoIdent) { S4 *x = (int*)malloc(sizeof(S4)); - EXPECT_POISONED(v_s4 = *x); + EXPECT_POISONED(*x); free(x); } TEST(MemorySanitizer, Malloc) { S4 *x = (int*)Ident(malloc(sizeof(S4))); - EXPECT_POISONED(v_s4 = *x); + EXPECT_POISONED(*x); free(x); } TEST(MemorySanitizer, Realloc) { S4 *x = (int*)Ident(realloc(0, sizeof(S4))); - EXPECT_POISONED(v_s4 = x[0]); + EXPECT_POISONED(x[0]); x[0] = 1; x = (int*)Ident(realloc(x, 2 * sizeof(S4))); - v_s4 = x[0]; // Ok, was inited before. - EXPECT_POISONED(v_s4 = x[1]); + EXPECT_NOT_POISONED(x[0]); // Ok, was inited before. + EXPECT_POISONED(x[1]); x = (int*)Ident(realloc(x, 3 * sizeof(S4))); - v_s4 = x[0]; // Ok, was inited before. - EXPECT_POISONED(v_s4 = x[2]); - EXPECT_POISONED(v_s4 = x[1]); + EXPECT_NOT_POISONED(x[0]); // Ok, was inited before. + EXPECT_POISONED(x[2]); + EXPECT_POISONED(x[1]); x[2] = 1; // Init this here. Check that after realloc it is poisoned again. x = (int*)Ident(realloc(x, 2 * sizeof(S4))); - v_s4 = x[0]; // Ok, was inited before. - EXPECT_POISONED(v_s4 = x[1]); + EXPECT_NOT_POISONED(x[0]); // Ok, was inited before. + EXPECT_POISONED(x[1]); x = (int*)Ident(realloc(x, 3 * sizeof(S4))); - EXPECT_POISONED(v_s4 = x[1]); - EXPECT_POISONED(v_s4 = x[2]); + EXPECT_POISONED(x[1]); + EXPECT_POISONED(x[2]); free(x); } TEST(MemorySanitizer, Calloc) { S4 *x = (int*)Ident(calloc(1, sizeof(S4))); - v_s4 = *x; // Should not be poisoned. + EXPECT_NOT_POISONED(*x); // Should not be poisoned. // EXPECT_EQ(0, *x); free(x); } @@ -283,83 +325,79 @@ TEST(MemorySanitizer, AndOr) { // correct regardless of endianness. ((U1*)p)[1] = 0; ((U1*)p)[2] = 0xff; - v_u4 = *p & 0x00ffff00; - v_u4 = *p & 0x00ff0000; - v_u4 = *p & 0x0000ff00; - EXPECT_POISONED(v_u4 = *p & 0xff000000); - EXPECT_POISONED(v_u4 = *p & 0x000000ff); - EXPECT_POISONED(v_u4 = *p & 0x0000ffff); - EXPECT_POISONED(v_u4 = *p & 0xffff0000); + EXPECT_NOT_POISONED(*p & 0x00ffff00); + EXPECT_NOT_POISONED(*p & 0x00ff0000); + EXPECT_NOT_POISONED(*p & 0x0000ff00); + EXPECT_POISONED(*p & 0xff000000); + EXPECT_POISONED(*p & 0x000000ff); + EXPECT_POISONED(*p & 0x0000ffff); + EXPECT_POISONED(*p & 0xffff0000); - v_u4 = *p | 0xff0000ff; - v_u4 = *p | 0xff00ffff; - v_u4 = *p | 0xffff00ff; - EXPECT_POISONED(v_u4 = *p | 0xff000000); - EXPECT_POISONED(v_u4 = *p | 0x000000ff); - EXPECT_POISONED(v_u4 = *p | 0x0000ffff); - EXPECT_POISONED(v_u4 = *p | 0xffff0000); + EXPECT_NOT_POISONED(*p | 0xff0000ff); + EXPECT_NOT_POISONED(*p | 0xff00ffff); + EXPECT_NOT_POISONED(*p | 0xffff00ff); + EXPECT_POISONED(*p | 0xff000000); + EXPECT_POISONED(*p | 0x000000ff); + EXPECT_POISONED(*p | 0x0000ffff); + EXPECT_POISONED(*p | 0xffff0000); - EXPECT_POISONED(v_u4 = *GetPoisoned<bool>() & *GetPoisoned<bool>()); + EXPECT_POISONED(*GetPoisoned<bool>() & *GetPoisoned<bool>()); } template<class T> -static void testNot(T value, T shadow) { +static bool applyNot(T value, T shadow) { __msan_partial_poison(&value, &shadow, sizeof(T)); - volatile bool v_T = !value; + return !value; } TEST(MemorySanitizer, Not) { - testNot<U4>(0x0, 0x0); - testNot<U4>(0xFFFFFFFF, 0x0); - EXPECT_POISONED(testNot<U4>(0xFFFFFFFF, 0xFFFFFFFF)); - testNot<U4>(0xFF000000, 0x0FFFFFFF); - testNot<U4>(0xFF000000, 0x00FFFFFF); - testNot<U4>(0xFF000000, 0x0000FFFF); - testNot<U4>(0xFF000000, 0x00000000); - EXPECT_POISONED(testNot<U4>(0xFF000000, 0xFF000000)); - testNot<U4>(0xFF800000, 0xFF000000); - EXPECT_POISONED(testNot<U4>(0x00008000, 0x00008000)); - - testNot<U1>(0x0, 0x0); - testNot<U1>(0xFF, 0xFE); - testNot<U1>(0xFF, 0x0); - EXPECT_POISONED(testNot<U1>(0xFF, 0xFF)); - - EXPECT_POISONED(testNot<void*>((void*)0xFFFFFF, (void*)(-1))); - testNot<void*>((void*)0xFFFFFF, (void*)(-2)); + EXPECT_NOT_POISONED(applyNot<U4>(0x0, 0x0)); + EXPECT_NOT_POISONED(applyNot<U4>(0xFFFFFFFF, 0x0)); + EXPECT_POISONED(applyNot<U4>(0xFFFFFFFF, 0xFFFFFFFF)); + EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x0FFFFFFF)); + EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x00FFFFFF)); + EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x0000FFFF)); + EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x00000000)); + EXPECT_POISONED(applyNot<U4>(0xFF000000, 0xFF000000)); + EXPECT_NOT_POISONED(applyNot<U4>(0xFF800000, 0xFF000000)); + EXPECT_POISONED(applyNot<U4>(0x00008000, 0x00008000)); + + EXPECT_NOT_POISONED(applyNot<U1>(0x0, 0x0)); + EXPECT_NOT_POISONED(applyNot<U1>(0xFF, 0xFE)); + EXPECT_NOT_POISONED(applyNot<U1>(0xFF, 0x0)); + EXPECT_POISONED(applyNot<U1>(0xFF, 0xFF)); + + EXPECT_POISONED(applyNot<void*>((void*)0xFFFFFF, (void*)(-1))); + EXPECT_NOT_POISONED(applyNot<void*>((void*)0xFFFFFF, (void*)(-2))); } TEST(MemorySanitizer, Shift) { U4 *up = GetPoisoned<U4>(); ((U1*)up)[0] = 0; ((U1*)up)[3] = 0xff; - v_u4 = *up >> 30; - v_u4 = *up >> 24; - EXPECT_POISONED(v_u4 = *up >> 23); - EXPECT_POISONED(v_u4 = *up >> 10); + EXPECT_NOT_POISONED(*up >> 30); + EXPECT_NOT_POISONED(*up >> 24); + EXPECT_POISONED(*up >> 23); + EXPECT_POISONED(*up >> 10); - v_u4 = *up << 30; - v_u4 = *up << 24; - EXPECT_POISONED(v_u4 = *up << 23); - EXPECT_POISONED(v_u4 = *up << 10); + EXPECT_NOT_POISONED(*up << 30); + EXPECT_NOT_POISONED(*up << 24); + EXPECT_POISONED(*up << 23); + EXPECT_POISONED(*up << 10); S4 *sp = (S4*)up; - v_s4 = *sp >> 30; - v_s4 = *sp >> 24; - EXPECT_POISONED(v_s4 = *sp >> 23); - EXPECT_POISONED(v_s4 = *sp >> 10); + EXPECT_NOT_POISONED(*sp >> 30); + EXPECT_NOT_POISONED(*sp >> 24); + EXPECT_POISONED(*sp >> 23); + EXPECT_POISONED(*sp >> 10); sp = GetPoisoned<S4>(); ((S1*)sp)[1] = 0; ((S1*)sp)[2] = 0; - EXPECT_POISONED(v_s4 = *sp >> 31); + EXPECT_POISONED(*sp >> 31); - v_s4 = 100; - EXPECT_POISONED(v_s4 = v_s4 >> *GetPoisoned<S4>()); - v_u4 = 100; - EXPECT_POISONED(v_u4 = v_u4 >> *GetPoisoned<S4>()); - v_u4 = 100; - EXPECT_POISONED(v_u4 = v_u4 << *GetPoisoned<S4>()); + EXPECT_POISONED(100 >> *GetPoisoned<S4>()); + EXPECT_POISONED(100U >> *GetPoisoned<S4>()); } NOINLINE static int GetPoisonedZero() { @@ -374,14 +412,14 @@ NOINLINE static int GetPoisonedZero() { TEST(MemorySanitizer, LoadFromDirtyAddress) { int *a = new int; *a = 0; - EXPECT_POISONED(__msan_break_optimization((void*)(U8)a[GetPoisonedZero()])); + EXPECT_UMR(break_optimization((void*)(U8)a[GetPoisonedZero()])); delete a; } TEST(MemorySanitizer, StoreToDirtyAddress) { int *a = new int; - EXPECT_POISONED(a[GetPoisonedZero()] = 0); - __msan_break_optimization(a); + EXPECT_UMR(a[GetPoisonedZero()] = 0); + break_optimization(a); delete a; } @@ -393,19 +431,19 @@ NOINLINE void StackTestFunc() { S2 ok2 = 1; S1 p1; S1 ok1 = 1; - __msan_break_optimization(&p4); - __msan_break_optimization(&ok4); - __msan_break_optimization(&p2); - __msan_break_optimization(&ok2); - __msan_break_optimization(&p1); - __msan_break_optimization(&ok1); + break_optimization(&p4); + break_optimization(&ok4); + break_optimization(&p2); + break_optimization(&ok2); + break_optimization(&p1); + break_optimization(&ok1); - EXPECT_POISONED(v_s4 = p4); - EXPECT_POISONED(v_s2 = p2); - EXPECT_POISONED(v_s1 = p1); - v_s1 = ok1; - v_s2 = ok2; - v_s4 = ok4; + EXPECT_POISONED(p4); + EXPECT_POISONED(p2); + EXPECT_POISONED(p1); + EXPECT_NOT_POISONED(ok1); + EXPECT_NOT_POISONED(ok2); + EXPECT_NOT_POISONED(ok4); } TEST(MemorySanitizer, StackTest) { @@ -414,7 +452,7 @@ TEST(MemorySanitizer, StackTest) { NOINLINE void StackStressFunc() { int foo[10000]; - __msan_break_optimization(foo); + break_optimization(foo); } TEST(MemorySanitizer, DISABLED_StackStressTest) { @@ -426,12 +464,12 @@ template<class T> void TestFloatingPoint() { static volatile T v; static T g[100]; - __msan_break_optimization(&g); + break_optimization(&g); T *x = GetPoisoned<T>(); T *y = GetPoisoned<T>(1); - EXPECT_POISONED(v = *x); - EXPECT_POISONED(v_s8 = *x); - EXPECT_POISONED(v_s4 = *x); + EXPECT_POISONED(*x); + EXPECT_POISONED((long long)*x); + EXPECT_POISONED((int)*x); g[0] = *x; g[1] = *x + *y; g[2] = *x - *y; @@ -447,7 +485,7 @@ TEST(MemorySanitizer, DynMem) { S4 x = 0; S4 *y = GetPoisoned<S4>(); memcpy(y, &x, g_one * sizeof(S4)); - v_s4 = *y; + EXPECT_NOT_POISONED(*y); } static char *DynRetTestStr; @@ -455,7 +493,7 @@ static char *DynRetTestStr; TEST(MemorySanitizer, DynRet) { if (!__msan_has_dynamic_component()) return; ReturnPoisoned<S8>(); - v_s4 = clearenv(); + EXPECT_NOT_POISONED(clearenv()); } @@ -486,8 +524,8 @@ LargeStruct LargeRetTest() { TEST(MemorySanitizer, LargeRet) { LargeStruct a = LargeRetTest(); - EXPECT_POISONED(v_s4 = a.x[0]); - EXPECT_POISONED(v_s4 = a.x[9]); + EXPECT_POISONED(a.x[0]); + EXPECT_POISONED(a.x[9]); } TEST(MemorySanitizer, fread) { @@ -495,9 +533,9 @@ TEST(MemorySanitizer, fread) { FILE *f = fopen("/proc/self/stat", "r"); assert(f); fread(x, 1, 32, f); - v_s1 = x[0]; - v_s1 = x[16]; - v_s1 = x[31]; + EXPECT_NOT_POISONED(x[0]); + EXPECT_NOT_POISONED(x[16]); + EXPECT_NOT_POISONED(x[31]); fclose(f); delete x; } @@ -508,9 +546,9 @@ TEST(MemorySanitizer, read) { assert(fd > 0); int sz = read(fd, x, 32); assert(sz == 32); - v_s1 = x[0]; - v_s1 = x[16]; - v_s1 = x[31]; + EXPECT_NOT_POISONED(x[0]); + EXPECT_NOT_POISONED(x[16]); + EXPECT_NOT_POISONED(x[31]); close(fd); delete x; } @@ -521,9 +559,9 @@ TEST(MemorySanitizer, pread) { assert(fd > 0); int sz = pread(fd, x, 32, 0); assert(sz == 32); - v_s1 = x[0]; - v_s1 = x[16]; - v_s1 = x[31]; + EXPECT_NOT_POISONED(x[0]); + EXPECT_NOT_POISONED(x[16]); + EXPECT_NOT_POISONED(x[31]); close(fd); delete x; } @@ -532,13 +570,13 @@ TEST(MemorySanitizer, pread) { TEST(MemorySanitizer, DISABLED_ioctl) { struct winsize ws; EXPECT_EQ(ioctl(2, TIOCGWINSZ, &ws), 0); - v_s4 = ws.ws_col; + EXPECT_NOT_POISONED(ws.ws_col); } TEST(MemorySanitizer, readlink) { char *x = new char[1000]; readlink("/proc/self/exe", x, 1000); - v_s1 = x[0]; + EXPECT_NOT_POISONED(x[0]); delete [] x; } @@ -547,35 +585,205 @@ TEST(MemorySanitizer, stat) { struct stat* st = new struct stat; int res = stat("/proc/self/stat", st); assert(!res); - v_u8 = st->st_dev; - v_u8 = st->st_mode; - v_u8 = st->st_size; + EXPECT_NOT_POISONED(st->st_dev); + EXPECT_NOT_POISONED(st->st_mode); + EXPECT_NOT_POISONED(st->st_size); } TEST(MemorySanitizer, statfs) { struct statfs* st = new struct statfs; int res = statfs("/", st); assert(!res); - v_u8 = st->f_type; - v_u8 = st->f_bfree; - v_u8 = st->f_namelen; + EXPECT_NOT_POISONED(st->f_type); + EXPECT_NOT_POISONED(st->f_bfree); + EXPECT_NOT_POISONED(st->f_namelen); } TEST(MemorySanitizer, pipe) { int* pipefd = new int[2]; int res = pipe(pipefd); assert(!res); - v_u8 = pipefd[0]; - v_u8 = pipefd[1]; + EXPECT_NOT_POISONED(pipefd[0]); + EXPECT_NOT_POISONED(pipefd[1]); close(pipefd[0]); close(pipefd[1]); } +TEST(MemorySanitizer, pipe2) { + int* pipefd = new int[2]; + int res = pipe2(pipefd, O_NONBLOCK); + assert(!res); + EXPECT_NOT_POISONED(pipefd[0]); + EXPECT_NOT_POISONED(pipefd[1]); + close(pipefd[0]); + close(pipefd[1]); +} + +TEST(MemorySanitizer, socketpair) { + int sv[2]; + int res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + assert(!res); + EXPECT_NOT_POISONED(sv[0]); + EXPECT_NOT_POISONED(sv[1]); + close(sv[0]); + close(sv[1]); +} + +TEST(MemorySanitizer, bind_getsockname) { + int sock = socket(AF_UNIX, SOCK_STREAM, 0); + + struct sockaddr_in sai; + memset(&sai, 0, sizeof(sai)); + sai.sin_family = AF_UNIX; + int res = bind(sock, (struct sockaddr *)&sai, sizeof(sai)); + + assert(!res); + char buf[200]; + socklen_t addrlen; + EXPECT_UMR(getsockname(sock, (struct sockaddr *)&buf, &addrlen)); + + addrlen = sizeof(buf); + res = getsockname(sock, (struct sockaddr *)&buf, &addrlen); + EXPECT_NOT_POISONED(addrlen); + EXPECT_NOT_POISONED(buf[0]); + EXPECT_NOT_POISONED(buf[addrlen - 1]); + EXPECT_POISONED(buf[addrlen]); + close(sock); +} + +#define EXPECT_HOSTENT_NOT_POISONED(he) \ + do { \ + EXPECT_NOT_POISONED(*(he)); \ + ASSERT_NE((void *) 0, (he)->h_name); \ + ASSERT_NE((void *) 0, (he)->h_aliases); \ + ASSERT_NE((void *) 0, (he)->h_addr_list); \ + EXPECT_NOT_POISONED(strlen((he)->h_name)); \ + char **p = (he)->h_aliases; \ + while (*p) { \ + EXPECT_NOT_POISONED(strlen(*p)); \ + ++p; \ + } \ + char **q = (he)->h_addr_list; \ + while (*q) { \ + EXPECT_NOT_POISONED(*q[0]); \ + ++q; \ + } \ + EXPECT_NOT_POISONED(*q); \ + } while (0) + +TEST(MemorySanitizer, gethostent) { + struct hostent *he = gethostent(); + ASSERT_NE((void *)NULL, he); + EXPECT_HOSTENT_NOT_POISONED(he); +} + +TEST(MemorySanitizer, gethostbyname) { + struct hostent *he = gethostbyname("localhost"); + ASSERT_NE((void *)NULL, he); + EXPECT_HOSTENT_NOT_POISONED(he); +} + +TEST(MemorySanitizer, gethostbyname2) { + struct hostent *he = gethostbyname2("localhost", AF_INET); + ASSERT_NE((void *)NULL, he); + EXPECT_HOSTENT_NOT_POISONED(he); +} + +TEST(MemorySanitizer, gethostbyaddr) { + in_addr_t addr = inet_addr("127.0.0.1"); + EXPECT_NOT_POISONED(addr); + struct hostent *he = gethostbyaddr(&addr, sizeof(addr), AF_INET); + ASSERT_NE((void *)NULL, he); + EXPECT_HOSTENT_NOT_POISONED(he); +} + +TEST(MemorySanitizer, gethostent_r) { + char buf[2000]; + struct hostent he; + struct hostent *result; + int err; + int res = gethostent_r(&he, buf, sizeof(buf), &result, &err); + ASSERT_EQ(0, res); + EXPECT_NOT_POISONED(result); + ASSERT_NE((void *)NULL, result); + EXPECT_HOSTENT_NOT_POISONED(result); + EXPECT_NOT_POISONED(err); +} + +TEST(MemorySanitizer, gethostbyname_r) { + char buf[2000]; + struct hostent he; + struct hostent *result; + int err; + int res = gethostbyname_r("localhost", &he, buf, sizeof(buf), &result, &err); + ASSERT_EQ(0, res); + EXPECT_NOT_POISONED(result); + ASSERT_NE((void *)NULL, result); + EXPECT_HOSTENT_NOT_POISONED(result); + EXPECT_NOT_POISONED(err); +} + +TEST(MemorySanitizer, gethostbyname2_r) { + char buf[2000]; + struct hostent he; + struct hostent *result; + int err; + int res = gethostbyname2_r("localhost", AF_INET, &he, buf, sizeof(buf), + &result, &err); + ASSERT_EQ(0, res); + EXPECT_NOT_POISONED(result); + ASSERT_NE((void *)NULL, result); + EXPECT_HOSTENT_NOT_POISONED(result); + EXPECT_NOT_POISONED(err); +} + +TEST(MemorySanitizer, gethostbyaddr_r) { + char buf[2000]; + struct hostent he; + struct hostent *result; + int err; + in_addr_t addr = inet_addr("127.0.0.1"); + EXPECT_NOT_POISONED(addr); + int res = gethostbyaddr_r(&addr, sizeof(addr), AF_INET, &he, buf, sizeof(buf), + &result, &err); + ASSERT_EQ(0, res); + EXPECT_NOT_POISONED(result); + ASSERT_NE((void *)NULL, result); + EXPECT_HOSTENT_NOT_POISONED(result); + EXPECT_NOT_POISONED(err); +} + +TEST(MemorySanitizer, getsockopt) { + int sock = socket(AF_UNIX, SOCK_STREAM, 0); + struct linger l[2]; + socklen_t sz = sizeof(l[0]); + int res = getsockopt(sock, SOL_SOCKET, SO_LINGER, &l[0], &sz); + ASSERT_EQ(0, res); + ASSERT_EQ(sizeof(l[0]), sz); + EXPECT_NOT_POISONED(l[0]); + EXPECT_POISONED(*(char *)(l + 1)); +} + TEST(MemorySanitizer, getcwd) { char path[PATH_MAX + 1]; char* res = getcwd(path, sizeof(path)); assert(res); - v_s1 = path[0]; + EXPECT_NOT_POISONED(path[0]); +} + +TEST(MemorySanitizer, getcwd_gnu) { + char* res = getcwd(NULL, 0); + assert(res); + EXPECT_NOT_POISONED(res[0]); + free(res); +} + +TEST(MemorySanitizer, readdir) { + DIR *dir = opendir("."); + struct dirent *d = readdir(dir); + assert(d); + EXPECT_NOT_POISONED(d->d_name[0]); + closedir(dir); } TEST(MemorySanitizer, realpath) { @@ -583,7 +791,7 @@ TEST(MemorySanitizer, realpath) { char path[PATH_MAX + 1]; char* res = realpath(relpath, path); assert(res); - v_s1 = path[0]; + EXPECT_NOT_POISONED(path[0]); } TEST(MemorySanitizer, memcpy) { @@ -592,8 +800,8 @@ TEST(MemorySanitizer, memcpy) { x[0] = 1; x[1] = *GetPoisoned<char>(); memcpy(y, x, 2); - v_s4 = y[0]; - EXPECT_POISONED(v_s4 = y[1]); + EXPECT_NOT_POISONED(y[0]); + EXPECT_POISONED(y[1]); } TEST(MemorySanitizer, memmove) { @@ -602,29 +810,57 @@ TEST(MemorySanitizer, memmove) { x[0] = 1; x[1] = *GetPoisoned<char>(); memmove(y, x, 2); - v_s4 = y[0]; - EXPECT_POISONED(v_s4 = y[1]); + EXPECT_NOT_POISONED(y[0]); + EXPECT_POISONED(y[1]); } TEST(MemorySanitizer, strdup) { - char *x = strdup("zzz"); - v_s1 = *x; + char buf[4] = "abc"; + __msan_poison(buf + 2, sizeof(*buf)); + char *x = strdup(buf); + EXPECT_NOT_POISONED(x[0]); + EXPECT_NOT_POISONED(x[1]); + EXPECT_POISONED(x[2]); + EXPECT_NOT_POISONED(x[3]); + free(x); +} + +TEST(MemorySanitizer, strndup) { + char buf[4] = "abc"; + __msan_poison(buf + 2, sizeof(*buf)); + char *x = strndup(buf, 3); + EXPECT_NOT_POISONED(x[0]); + EXPECT_NOT_POISONED(x[1]); + EXPECT_POISONED(x[2]); + EXPECT_NOT_POISONED(x[3]); + free(x); +} + +TEST(MemorySanitizer, strndup_short) { + char buf[4] = "abc"; + __msan_poison(buf + 1, sizeof(*buf)); + __msan_poison(buf + 2, sizeof(*buf)); + char *x = strndup(buf, 2); + EXPECT_NOT_POISONED(x[0]); + EXPECT_POISONED(x[1]); + EXPECT_NOT_POISONED(x[2]); free(x); } + template<class T, int size> void TestOverlapMemmove() { T *x = new T[size]; assert(size >= 3); x[2] = 0; memmove(x, x + 1, (size - 1) * sizeof(T)); - v_s8 = x[1]; + 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(v_s8 = x[0]); - EXPECT_POISONED(v_s8 = x[2]); + EXPECT_POISONED(x[0]); + EXPECT_POISONED(x[2]); } delete [] x; } @@ -643,9 +879,9 @@ TEST(MemorySanitizer, strcpy) { // NOLINT x[1] = *GetPoisoned<char>(1, 1); x[2] = 0; strcpy(y, x); // NOLINT - v_s4 = y[0]; - EXPECT_POISONED(v_s4 = y[1]); - v_s4 = y[2]; + EXPECT_NOT_POISONED(y[0]); + EXPECT_POISONED(y[1]); + EXPECT_NOT_POISONED(y[2]); } TEST(MemorySanitizer, strncpy) { // NOLINT @@ -655,57 +891,57 @@ TEST(MemorySanitizer, strncpy) { // NOLINT x[1] = *GetPoisoned<char>(1, 1); x[2] = 0; strncpy(y, x, 2); // NOLINT - v_s4 = y[0]; - EXPECT_POISONED(v_s4 = y[1]); - EXPECT_POISONED(v_s4 = y[2]); + EXPECT_NOT_POISONED(y[0]); + EXPECT_POISONED(y[1]); + EXPECT_POISONED(y[2]); } TEST(MemorySanitizer, strtol) { char *e; assert(1 == strtol("1", &e, 10)); - v_s8 = (S8) e; + EXPECT_NOT_POISONED((S8) e); } TEST(MemorySanitizer, strtoll) { char *e; assert(1 == strtoll("1", &e, 10)); - v_s8 = (S8) e; + EXPECT_NOT_POISONED((S8) e); } TEST(MemorySanitizer, strtoul) { char *e; assert(1 == strtoul("1", &e, 10)); - v_s8 = (S8) e; + EXPECT_NOT_POISONED((S8) e); } TEST(MemorySanitizer, strtoull) { char *e; assert(1 == strtoull("1", &e, 10)); - v_s8 = (S8) e; + EXPECT_NOT_POISONED((S8) e); } TEST(MemorySanitizer, strtod) { char *e; assert(0 != strtod("1.5", &e)); - v_s8 = (S8) e; + EXPECT_NOT_POISONED((S8) e); } TEST(MemorySanitizer, strtof) { char *e; assert(0 != strtof("1.5", &e)); - v_s8 = (S8) e; + EXPECT_NOT_POISONED((S8) e); } TEST(MemorySanitizer, strtold) { char *e; assert(0 != strtold("1.5", &e)); - v_s8 = (S8) e; + EXPECT_NOT_POISONED((S8) e); } TEST(MemorySanitizer, sprintf) { // NOLINT char buff[10]; - __msan_break_optimization(buff); - EXPECT_POISONED(v_s1 = buff[0]); + break_optimization(buff); + EXPECT_POISONED(buff[0]); int res = sprintf(buff, "%d", 1234567); // NOLINT assert(res == 7); assert(buff[0] == '1'); @@ -713,13 +949,13 @@ TEST(MemorySanitizer, sprintf) { // NOLINT assert(buff[2] == '3'); assert(buff[6] == '7'); assert(buff[7] == 0); - EXPECT_POISONED(v_s1 = buff[8]); + EXPECT_POISONED(buff[8]); } TEST(MemorySanitizer, snprintf) { char buff[10]; - __msan_break_optimization(buff); - EXPECT_POISONED(v_s1 = buff[0]); + break_optimization(buff); + EXPECT_POISONED(buff[0]); int res = snprintf(buff, sizeof(buff), "%d", 1234567); assert(res == 7); assert(buff[0] == '1'); @@ -727,14 +963,14 @@ TEST(MemorySanitizer, snprintf) { assert(buff[2] == '3'); assert(buff[6] == '7'); assert(buff[7] == 0); - EXPECT_POISONED(v_s1 = buff[8]); + EXPECT_POISONED(buff[8]); } TEST(MemorySanitizer, swprintf) { wchar_t buff[10]; assert(sizeof(wchar_t) == 4); - __msan_break_optimization(buff); - EXPECT_POISONED(v_s1 = buff[0]); + break_optimization(buff); + EXPECT_POISONED(buff[0]); int res = swprintf(buff, 9, L"%d", 1234567); assert(res == 7); assert(buff[0] == '1'); @@ -742,7 +978,7 @@ TEST(MemorySanitizer, swprintf) { assert(buff[2] == '3'); assert(buff[6] == '7'); assert(buff[7] == 0); - EXPECT_POISONED(v_s4 = buff[8]); + EXPECT_POISONED(buff[8]); } TEST(MemorySanitizer, wcstombs) { @@ -758,19 +994,99 @@ TEST(MemorySanitizer, wcstombs) { TEST(MemorySanitizer, gettimeofday) { struct timeval tv; struct timezone tz; - __msan_break_optimization(&tv); - __msan_break_optimization(&tz); + break_optimization(&tv); + break_optimization(&tz); assert(sizeof(tv) == 16); assert(sizeof(tz) == 8); - EXPECT_POISONED(v_s8 = tv.tv_sec); - EXPECT_POISONED(v_s8 = tv.tv_usec); - EXPECT_POISONED(v_s4 = tz.tz_minuteswest); - EXPECT_POISONED(v_s4 = tz.tz_dsttime); + 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)); - v_s8 = tv.tv_sec; - v_s8 = tv.tv_usec; - v_s4 = tz.tz_minuteswest; - v_s4 = tz.tz_dsttime; + EXPECT_NOT_POISONED(tv.tv_sec); + EXPECT_NOT_POISONED(tv.tv_usec); + EXPECT_NOT_POISONED(tz.tz_minuteswest); + EXPECT_NOT_POISONED(tz.tz_dsttime); +} + +TEST(MemorySanitizer, clock_gettime) { + struct timespec tp; + EXPECT_POISONED(tp.tv_sec); + EXPECT_POISONED(tp.tv_nsec); + assert(0 == clock_gettime(CLOCK_REALTIME, &tp)); + EXPECT_NOT_POISONED(tp.tv_sec); + EXPECT_NOT_POISONED(tp.tv_nsec); +} + +TEST(MemorySanitizer, clock_getres) { + struct timespec tp; + EXPECT_POISONED(tp.tv_sec); + EXPECT_POISONED(tp.tv_nsec); + assert(0 == clock_getres(CLOCK_REALTIME, 0)); + EXPECT_POISONED(tp.tv_sec); + EXPECT_POISONED(tp.tv_nsec); + assert(0 == clock_getres(CLOCK_REALTIME, &tp)); + EXPECT_NOT_POISONED(tp.tv_sec); + EXPECT_NOT_POISONED(tp.tv_nsec); +} + +TEST(MemorySanitizer, getitimer) { + struct itimerval it1, it2; + int res; + EXPECT_POISONED(it1.it_interval.tv_sec); + EXPECT_POISONED(it1.it_interval.tv_usec); + EXPECT_POISONED(it1.it_value.tv_sec); + EXPECT_POISONED(it1.it_value.tv_usec); + res = getitimer(ITIMER_VIRTUAL, &it1); + assert(!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); + EXPECT_NOT_POISONED(it1.it_value.tv_usec); + + it1.it_interval.tv_sec = it1.it_value.tv_sec = 10000; + it1.it_interval.tv_usec = it1.it_value.tv_usec = 0; + + res = setitimer(ITIMER_VIRTUAL, &it1, &it2); + assert(!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); + EXPECT_NOT_POISONED(it2.it_value.tv_usec); + + // Check that old_value can be 0, and disable the timer. + memset(&it1, 0, sizeof(it1)); + res = setitimer(ITIMER_VIRTUAL, &it1, 0); + assert(!res); +} + +TEST(MemorySanitizer, time) { + time_t t; + EXPECT_POISONED(t); + time_t t2 = time(&t); + assert(t2 != (time_t)-1); + EXPECT_NOT_POISONED(t); +} + +TEST(MemorySanitizer, localtime) { + time_t t = 123; + struct tm *time = localtime(&t); + assert(time != 0); + EXPECT_NOT_POISONED(time->tm_sec); + EXPECT_NOT_POISONED(time->tm_hour); + EXPECT_NOT_POISONED(time->tm_year); + EXPECT_NOT_POISONED(time->tm_isdst); +} + +TEST(MemorySanitizer, localtime_r) { + time_t t = 123; + struct tm time; + struct tm *res = localtime_r(&t, &time); + assert(res != 0); + EXPECT_NOT_POISONED(time.tm_sec); + EXPECT_NOT_POISONED(time.tm_hour); + EXPECT_NOT_POISONED(time.tm_year); + EXPECT_NOT_POISONED(time.tm_isdst); } TEST(MemorySanitizer, mmap) { @@ -787,7 +1103,7 @@ TEST(MemorySanitizer, mmap) { munmap(p2, size); } if (p1 == p2) { - v_s1 = *(char*)p2; + EXPECT_NOT_POISONED(*(char*)p2); munmap(p2, size); } } @@ -796,76 +1112,143 @@ TEST(MemorySanitizer, mmap) { // FIXME: check why msandr does nt handle fcvt. TEST(MemorySanitizer, fcvt) { int a, b; - __msan_break_optimization(&a); - __msan_break_optimization(&b); - EXPECT_POISONED(v_s4 = a); - EXPECT_POISONED(v_s4 = b); + break_optimization(&a); + break_optimization(&b); + EXPECT_POISONED(a); + EXPECT_POISONED(b); char *str = fcvt(12345.6789, 10, &a, &b); - v_s4 = a; - v_s4 = b; + EXPECT_NOT_POISONED(a); + EXPECT_NOT_POISONED(b); } -TEST(MemorySanitizer, LoadUnpoisoned) { - S8 s = *GetPoisoned<S8>(); - EXPECT_POISONED(v_s8 = s); - S8 safe = *GetPoisoned<S8>(); - __msan_load_unpoisoned(&s, sizeof(s), &safe); - v_s8 = safe; +TEST(MemorySanitizer, frexp) { + int x; + x = *GetPoisoned<int>(); + double r = frexp(1.1, &x); + EXPECT_NOT_POISONED(r); + EXPECT_NOT_POISONED(x); + + x = *GetPoisoned<int>(); + float rf = frexpf(1.1, &x); + EXPECT_NOT_POISONED(rf); + EXPECT_NOT_POISONED(x); + + x = *GetPoisoned<int>(); + double rl = frexpl(1.1, &x); + EXPECT_NOT_POISONED(rl); + EXPECT_NOT_POISONED(x); +} + +namespace { + +static int cnt; + +void SigactionHandler(int signo, siginfo_t* si, void* uc) { + assert(signo == SIGPROF); + assert(si); + EXPECT_NOT_POISONED(si->si_errno); + EXPECT_NOT_POISONED(si->si_pid); +#if __linux__ +# if defined(__x86_64__) + EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_RIP]); +# elif defined(__i386__) + EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP]); +# endif +#endif + ++cnt; +} + +TEST(MemorySanitizer, sigaction) { + struct sigaction act = {}; + struct sigaction oldact = {}; + struct sigaction origact = {}; + + sigaction(SIGPROF, 0, &origact); + + act.sa_flags |= SA_SIGINFO; + act.sa_sigaction = &SigactionHandler; + sigaction(SIGPROF, &act, 0); + + kill(getpid(), SIGPROF); + + act.sa_flags &= ~SA_SIGINFO; + act.sa_handler = SIG_DFL; + sigaction(SIGPROF, &act, 0); + + act.sa_flags &= ~SA_SIGINFO; + act.sa_handler = SIG_IGN; + sigaction(SIGPROF, &act, &oldact); + EXPECT_FALSE(oldact.sa_flags & SA_SIGINFO); + EXPECT_EQ(SIG_DFL, oldact.sa_handler); + kill(getpid(), SIGPROF); + + act.sa_flags |= SA_SIGINFO; + act.sa_sigaction = &SigactionHandler; + sigaction(SIGPROF, &act, &oldact); + EXPECT_FALSE(oldact.sa_flags & SA_SIGINFO); + EXPECT_EQ(SIG_IGN, oldact.sa_handler); + kill(getpid(), SIGPROF); + + act.sa_flags &= ~SA_SIGINFO; + act.sa_handler = SIG_DFL; + sigaction(SIGPROF, &act, &oldact); + EXPECT_TRUE(oldact.sa_flags & SA_SIGINFO); + EXPECT_EQ(&SigactionHandler, oldact.sa_sigaction); + EXPECT_EQ(2, cnt); + + sigaction(SIGPROF, &origact, 0); } +} // namespace + struct StructWithDtor { ~StructWithDtor(); }; NOINLINE StructWithDtor::~StructWithDtor() { - __msan_break_optimization(0); -} - -NOINLINE void ExpectGood(int a) { v_s4 = a; } -NOINLINE void ExpectPoisoned(int a) { - EXPECT_POISONED(v_s4 = a); + break_optimization(0); } TEST(MemorySanitizer, Invoke) { StructWithDtor s; // Will cause the calls to become invokes. - ExpectGood(0); - ExpectPoisoned(*GetPoisoned<int>()); - ExpectGood(0); - ExpectPoisoned(*GetPoisoned<int>()); - EXPECT_POISONED(v_s4 = ReturnPoisoned<S4>()); + EXPECT_NOT_POISONED(0); + EXPECT_POISONED(*GetPoisoned<int>()); + EXPECT_NOT_POISONED(0); + EXPECT_POISONED(*GetPoisoned<int>()); + EXPECT_POISONED(ReturnPoisoned<S4>()); } TEST(MemorySanitizer, ptrtoint) { // Test that shadow is propagated through pointer-to-integer conversion. void* p = (void*)0xABCD; __msan_poison(((char*)&p) + 1, sizeof(p)); - v_u1 = (((uptr)p) & 0xFF) == 0; + EXPECT_NOT_POISONED((((uintptr_t)p) & 0xFF) == 0); void* q = (void*)0xABCD; __msan_poison(&q, sizeof(q) - 1); - EXPECT_POISONED(v_u1 = (((uptr)q) & 0xFF) == 0); + EXPECT_POISONED((((uintptr_t)q) & 0xFF) == 0); } static void vaargsfn2(int guard, ...) { va_list vl; va_start(vl, guard); - v_s4 = va_arg(vl, int); - v_s4 = va_arg(vl, int); - v_s4 = va_arg(vl, int); - EXPECT_POISONED(v_d = va_arg(vl, double)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, double)); va_end(vl); } static void vaargsfn(int guard, ...) { va_list vl; va_start(vl, guard); - v_s4 = va_arg(vl, int); - EXPECT_POISONED(v_s4 = va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, int)); // The following call will overwrite __msan_param_tls. // Checks after it test that arg shadow was somehow saved across the call. vaargsfn2(1, 2, 3, 4, *GetPoisoned<double>()); - v_s4 = va_arg(vl, int); - EXPECT_POISONED(v_s4 = va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, int)); va_end(vl); } @@ -878,16 +1261,16 @@ TEST(MemorySanitizer, VAArgTest) { static void vaargsfn_many(int guard, ...) { va_list vl; va_start(vl, guard); - v_s4 = va_arg(vl, int); - EXPECT_POISONED(v_s4 = va_arg(vl, int)); - v_s4 = va_arg(vl, int); - v_s4 = va_arg(vl, int); - v_s4 = va_arg(vl, int); - v_s4 = va_arg(vl, int); - v_s4 = va_arg(vl, int); - v_s4 = va_arg(vl, int); - v_s4 = va_arg(vl, int); - EXPECT_POISONED(v_s4 = va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, int)); va_end(vl); } @@ -898,15 +1281,15 @@ TEST(MemorySanitizer, VAArgManyTest) { } static void vaargsfn_pass2(va_list vl) { - v_s4 = va_arg(vl, int); - v_s4 = va_arg(vl, int); - EXPECT_POISONED(v_s4 = va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, int)); } static void vaargsfn_pass(int guard, ...) { va_list vl; va_start(vl, guard); - EXPECT_POISONED(v_s4 = va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, int)); vaargsfn_pass2(vl); va_end(vl); } @@ -918,20 +1301,20 @@ TEST(MemorySanitizer, VAArgPass) { } static void vaargsfn_copy2(va_list vl) { - v_s4 = va_arg(vl, int); - EXPECT_POISONED(v_s4 = va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, int)); } static void vaargsfn_copy(int guard, ...) { va_list vl; va_start(vl, guard); - v_s4 = va_arg(vl, int); - EXPECT_POISONED(v_s4 = va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, int)); va_list vl2; va_copy(vl2, vl); vaargsfn_copy2(vl2); - v_s4 = va_arg(vl, int); - EXPECT_POISONED(v_s4 = va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, int)); va_end(vl); } @@ -944,10 +1327,10 @@ TEST(MemorySanitizer, VAArgCopy) { static void vaargsfn_ptr(int guard, ...) { va_list vl; va_start(vl, guard); - v_p = va_arg(vl, int*); - EXPECT_POISONED(v_p = va_arg(vl, int*)); - v_p = va_arg(vl, int*); - EXPECT_POISONED(v_p = va_arg(vl, double*)); + EXPECT_NOT_POISONED(va_arg(vl, int*)); + EXPECT_POISONED(va_arg(vl, int*)); + EXPECT_NOT_POISONED(va_arg(vl, int*)); + EXPECT_POISONED(va_arg(vl, double*)); va_end(vl); } @@ -961,33 +1344,33 @@ TEST(MemorySanitizer, VAArgPtr) { static void vaargsfn_overflow(int guard, ...) { va_list vl; va_start(vl, guard); - v_s4 = va_arg(vl, int); - v_s4 = va_arg(vl, int); - EXPECT_POISONED(v_s4 = va_arg(vl, int)); - v_s4 = va_arg(vl, int); - v_s4 = va_arg(vl, int); - v_s4 = va_arg(vl, int); - - v_d = va_arg(vl, double); - v_d = va_arg(vl, double); - v_d = va_arg(vl, double); - EXPECT_POISONED(v_d = va_arg(vl, double)); - v_d = va_arg(vl, double); - EXPECT_POISONED(v_p = va_arg(vl, int*)); - v_d = va_arg(vl, double); - v_d = va_arg(vl, double); - - EXPECT_POISONED(v_s4 = va_arg(vl, int)); - EXPECT_POISONED(v_d = va_arg(vl, double)); - EXPECT_POISONED(v_p = va_arg(vl, int*)); - - v_s4 = va_arg(vl, int); - v_d = va_arg(vl, double); - v_p = va_arg(vl, int*); - - EXPECT_POISONED(v_s4 = va_arg(vl, int)); - EXPECT_POISONED(v_d = va_arg(vl, double)); - EXPECT_POISONED(v_p = va_arg(vl, int*)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, int)); + + EXPECT_NOT_POISONED(va_arg(vl, double)); + EXPECT_NOT_POISONED(va_arg(vl, double)); + EXPECT_NOT_POISONED(va_arg(vl, double)); + EXPECT_POISONED(va_arg(vl, double)); + EXPECT_NOT_POISONED(va_arg(vl, double)); + EXPECT_POISONED(va_arg(vl, int*)); + EXPECT_NOT_POISONED(va_arg(vl, double)); + EXPECT_NOT_POISONED(va_arg(vl, double)); + + EXPECT_POISONED(va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, double)); + EXPECT_POISONED(va_arg(vl, int*)); + + EXPECT_NOT_POISONED(va_arg(vl, int)); + EXPECT_NOT_POISONED(va_arg(vl, double)); + EXPECT_NOT_POISONED(va_arg(vl, int*)); + + EXPECT_POISONED(va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, double)); + EXPECT_POISONED(va_arg(vl, int*)); va_end(vl); } @@ -1009,7 +1392,7 @@ TEST(MemorySanitizer, VAArgOverflow) { static void vaargsfn_tlsoverwrite2(int guard, ...) { va_list vl; va_start(vl, guard); - v_s4 = va_arg(vl, int); + EXPECT_NOT_POISONED(va_arg(vl, int)); va_end(vl); } @@ -1018,7 +1401,7 @@ static void vaargsfn_tlsoverwrite(int guard, ...) { vaargsfn_tlsoverwrite2(2, 42); va_list vl; va_start(vl, guard); - EXPECT_POISONED(v_s4 = va_arg(vl, int)); + EXPECT_POISONED(va_arg(vl, int)); va_end(vl); } @@ -1032,12 +1415,12 @@ struct StructByVal { }; NOINLINE void StructByValTestFunc(struct StructByVal s) { - v_s4 = s.a; - EXPECT_POISONED(v_s4 = s.b); - v_s4 = s.c; - EXPECT_POISONED(v_s4 = s.d); - v_s4 = s.e; - EXPECT_POISONED(v_s4 = s.f); + 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); } NOINLINE void StructByValTestFunc1(struct StructByVal s) { @@ -1064,13 +1447,13 @@ TEST(MemorySanitizer, StructByVal) { #if MSAN_HAS_M128 -NOINLINE __m128i m128Eq(__m128i *a, __m128i *b) { return *a == *b; } -NOINLINE __m128i m128Lt(__m128i *a, __m128i *b) { return *a < *b; } +NOINLINE __m128i m128Eq(__m128i *a, __m128i *b) { return _mm_cmpeq_epi16(*a, *b); } +NOINLINE __m128i m128Lt(__m128i *a, __m128i *b) { return _mm_cmplt_epi16(*a, *b); } TEST(MemorySanitizer, m128) { __m128i a = _mm_set1_epi16(0x1234); __m128i b = _mm_set1_epi16(0x7890); - v_m128 = m128Eq(&a, &b); - v_m128 = m128Lt(&a, &b); + EXPECT_NOT_POISONED(m128Eq(&a, &b)); + EXPECT_NOT_POISONED(m128Lt(&a, &b)); } // FIXME: add more tests for __m128i. #endif // MSAN_HAS_M128 @@ -1092,7 +1475,7 @@ NOINLINE StructWithHole ReturnStructWithHole() { TEST(MemorySanitizer, StructWithHole) { StructWithHole a = ReturnStructWithHole(); - __msan_break_optimization(&a); + break_optimization(&a); } template <class T> @@ -1106,8 +1489,8 @@ NOINLINE T ReturnStruct() { template <class T> NOINLINE void TestReturnStruct() { T s1 = ReturnStruct<T>(); - v_s4 = s1.a; - EXPECT_POISONED(v_s4 = s1.b); + EXPECT_NOT_POISONED(s1.a); + EXPECT_POISONED(s1.b); } struct SSS1 { @@ -1177,27 +1560,27 @@ NOINLINE LongStruct ReturnLongStruct2() { TEST(MemorySanitizer, LongStruct) { LongStruct s1 = ReturnLongStruct1(); __msan_print_shadow(&s1, sizeof(s1)); - v_u1 = s1.a1; - v_u2 = s1.a2; - v_u4 = s1.a4; - v_u8 = s1.a8; + EXPECT_NOT_POISONED(s1.a1); + EXPECT_NOT_POISONED(s1.a2); + EXPECT_NOT_POISONED(s1.a4); + EXPECT_NOT_POISONED(s1.a8); - EXPECT_POISONED(v_u1 = s1.b1); - EXPECT_POISONED(v_u2 = s1.b2); - EXPECT_POISONED(v_u4 = s1.b4); - EXPECT_POISONED(v_u8 = s1.b8); + EXPECT_POISONED(s1.b1); + EXPECT_POISONED(s1.b2); + EXPECT_POISONED(s1.b4); + EXPECT_POISONED(s1.b8); LongStruct s2 = ReturnLongStruct2(); __msan_print_shadow(&s2, sizeof(s2)); - v_u1 = s2.b1; - v_u2 = s2.b2; - v_u4 = s2.b4; - v_u8 = s2.b8; + EXPECT_NOT_POISONED(s2.b1); + EXPECT_NOT_POISONED(s2.b2); + EXPECT_NOT_POISONED(s2.b4); + EXPECT_NOT_POISONED(s2.b8); - EXPECT_POISONED(v_u1 = s2.a1); - EXPECT_POISONED(v_u2 = s2.a2); - EXPECT_POISONED(v_u4 = s2.a4); - EXPECT_POISONED(v_u8 = s2.a8); + EXPECT_POISONED(s2.a1); + EXPECT_POISONED(s2.a2); + EXPECT_POISONED(s2.a4); + EXPECT_POISONED(s2.a8); } TEST(MemorySanitizer, getrlimit) { @@ -1205,9 +1588,8 @@ TEST(MemorySanitizer, getrlimit) { __msan_poison(&limit, sizeof(limit)); int result = getrlimit(RLIMIT_DATA, &limit); assert(result == 0); - volatile rlim_t t; - t = limit.rlim_cur; - t = limit.rlim_max; + EXPECT_NOT_POISONED(limit.rlim_cur); + EXPECT_NOT_POISONED(limit.rlim_max); } TEST(MemorySanitizer, getrusage) { @@ -1215,18 +1597,35 @@ TEST(MemorySanitizer, getrusage) { __msan_poison(&usage, sizeof(usage)); int result = getrusage(RUSAGE_SELF, &usage); assert(result == 0); - volatile struct timeval t; - v_u8 = usage.ru_utime.tv_sec; - v_u8 = usage.ru_utime.tv_usec; - v_u8 = usage.ru_stime.tv_sec; - v_u8 = usage.ru_stime.tv_usec; - v_s8 = usage.ru_maxrss; - v_s8 = usage.ru_minflt; - v_s8 = usage.ru_majflt; - v_s8 = usage.ru_inblock; - v_s8 = usage.ru_oublock; - v_s8 = usage.ru_nvcsw; - v_s8 = usage.ru_nivcsw; + EXPECT_NOT_POISONED(usage.ru_utime.tv_sec); + EXPECT_NOT_POISONED(usage.ru_utime.tv_usec); + EXPECT_NOT_POISONED(usage.ru_stime.tv_sec); + EXPECT_NOT_POISONED(usage.ru_stime.tv_usec); + EXPECT_NOT_POISONED(usage.ru_maxrss); + EXPECT_NOT_POISONED(usage.ru_minflt); + EXPECT_NOT_POISONED(usage.ru_majflt); + EXPECT_NOT_POISONED(usage.ru_inblock); + EXPECT_NOT_POISONED(usage.ru_oublock); + EXPECT_NOT_POISONED(usage.ru_nvcsw); + EXPECT_NOT_POISONED(usage.ru_nivcsw); +} + +#ifdef __GLIBC__ +extern char *program_invocation_name; +#else // __GLIBC__ +# error "TODO: port this" +#endif + +// Compute the path to our loadable DSO. We assume it's in the same +// directory. Only use string routines that we intercept so far to do this. +static int PathToLoadable(char *buf, size_t sz) { + const char *basename = "libmsan_loadable.x86_64.so"; + char *argv0 = program_invocation_name; + char *last_slash = strrchr(argv0, '/'); + assert(last_slash); + int res = + snprintf(buf, sz, "%.*s/%s", int(last_slash - argv0), argv0, basename); + return res < sz ? 0 : res; } static void dladdr_testfn() {} @@ -1236,14 +1635,75 @@ TEST(MemorySanitizer, dladdr) { __msan_poison(&info, sizeof(info)); int result = dladdr((const void*)dladdr_testfn, &info); assert(result != 0); - v_u8 = (unsigned long)info.dli_fname; + EXPECT_NOT_POISONED((unsigned long)info.dli_fname); if (info.dli_fname) - v_u8 = strlen(info.dli_fname); - v_u8 = (unsigned long)info.dli_fbase; - v_u8 = (unsigned long)info.dli_sname; + EXPECT_NOT_POISONED(strlen(info.dli_fname)); + EXPECT_NOT_POISONED((unsigned long)info.dli_fbase); + EXPECT_NOT_POISONED((unsigned long)info.dli_sname); if (info.dli_sname) - v_u8 = strlen(info.dli_sname); - v_u8 = (unsigned long)info.dli_saddr; + EXPECT_NOT_POISONED(strlen(info.dli_sname)); + EXPECT_NOT_POISONED((unsigned long)info.dli_saddr); +} + +static int dl_phdr_callback(struct dl_phdr_info *info, size_t size, void *data) { + (*(int *)data)++; + EXPECT_NOT_POISONED(info->dlpi_addr); + EXPECT_NOT_POISONED(strlen(info->dlpi_name)); + EXPECT_NOT_POISONED(info->dlpi_phnum); + for (int i = 0; i < info->dlpi_phnum; ++i) + EXPECT_NOT_POISONED(info->dlpi_phdr[i]); + return 0; +} + +TEST(MemorySanitizer, dl_iterate_phdr) { + char path[4096]; + int res = PathToLoadable(path, sizeof(path)); + assert(!res); + + // Having at least one dlopen'ed library in the process makes this more + // entertaining. + void *lib = dlopen(path, RTLD_LAZY); + ASSERT_NE((void*)0, lib); + + int count = 0; + int result = dl_iterate_phdr(dl_phdr_callback, &count); + assert(count > 0); + + dlclose(lib); +} + + +TEST(MemorySanitizer, dlopen) { + char path[4096]; + int res = PathToLoadable(path, sizeof(path)); + assert(!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 + // general this is difficult, but the loader tends to reload things in the + // same place, so we open, close, and then reopen. The global should always + // start out clean after dlopen. + for (int i = 0; i < 2; i++) { + void *lib = dlopen(path, RTLD_LAZY); + if (lib == NULL) { + printf("dlerror: %s\n", dlerror()); + assert(lib != NULL); + } + void **(*get_dso_global)() = (void **(*)())dlsym(lib, "get_dso_global"); + assert(get_dso_global); + void **dso_global = get_dso_global(); + EXPECT_NOT_POISONED(*dso_global); + __msan_poison(dso_global, sizeof(*dso_global)); + EXPECT_POISONED(*dso_global); + dlclose(lib); + } +} + +// Regression test for a crash in dlopen() interceptor. +TEST(MemorySanitizer, dlopenFailed) { + const char *path = "/libmsan_loadable_does_not_exist.x86_64.so"; + void *lib = dlopen(path, RTLD_LAZY); + ASSERT_EQ(0, lib); } TEST(MemorySanitizer, scanf) { @@ -1253,27 +1713,28 @@ TEST(MemorySanitizer, scanf) { int res = sscanf(input, "%d %5s", d, s); printf("res %d\n", res); assert(res == 2); - v_s4 = *d; - v_u1 = s[0]; - v_u1 = s[1]; - v_u1 = s[2]; - v_u1 = s[3]; - v_u1 = s[4]; - v_u1 = s[5]; - EXPECT_POISONED(v_u1 = s[6]); + EXPECT_NOT_POISONED(*d); + EXPECT_NOT_POISONED(s[0]); + EXPECT_NOT_POISONED(s[1]); + EXPECT_NOT_POISONED(s[2]); + EXPECT_NOT_POISONED(s[3]); + EXPECT_NOT_POISONED(s[4]); + EXPECT_NOT_POISONED(s[5]); + EXPECT_POISONED(s[6]); delete s; delete d; } -static void* SimpleThread_threadfn(void* data) { +static void *SimpleThread_threadfn(void* data) { return new int; } TEST(MemorySanitizer, SimpleThread) { pthread_t t; - void* p; + void *p; int res = pthread_create(&t, NULL, SimpleThread_threadfn, NULL); assert(!res); + EXPECT_NOT_POISONED(t); res = pthread_join(t, &p); assert(!res); if (!__msan_has_dynamic_component()) // FIXME: intercept pthread_join (?). @@ -1281,56 +1742,256 @@ TEST(MemorySanitizer, SimpleThread) { delete (int*)p; } +static void *SmallStackThread_threadfn(void* data) { + return 0; +} + +TEST(MemorySanitizer, SmallStackThread) { + pthread_attr_t attr; + pthread_t t; + void *p; + int res; + res = pthread_attr_init(&attr); + ASSERT_EQ(0, res); + res = pthread_attr_setstacksize(&attr, 64 * 1024); + ASSERT_EQ(0, res); + res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL); + ASSERT_EQ(0, res); + res = pthread_join(t, &p); + ASSERT_EQ(0, res); + res = pthread_attr_destroy(&attr); + ASSERT_EQ(0, res); +} + +TEST(MemorySanitizer, PreAllocatedStackThread) { + 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; + 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); + res = pthread_attr_destroy(&attr); + ASSERT_EQ(0, res); +} + +TEST(MemorySanitizer, pthread_getschedparam) { + int policy; + struct sched_param param; + int res = pthread_getschedparam(pthread_self(), &policy, ¶m); + ASSERT_EQ(0, res); + EXPECT_NOT_POISONED(policy); + EXPECT_NOT_POISONED(param.sched_priority); +} + +TEST(MemorySanitizer, posix_memalign) { + void *p; + EXPECT_POISONED(p); + int res = posix_memalign(&p, 4096, 13); + ASSERT_EQ(0, res); + EXPECT_NOT_POISONED(p); + free(p); +} + +TEST(MemorySanitizer, inet_pton) { + const char *s = "1:0:0:0:0:0:0:8"; + unsigned char buf[sizeof(struct in6_addr)]; + int res = inet_pton(AF_INET6, s, buf); + ASSERT_EQ(1, res); + EXPECT_NOT_POISONED(buf[0]); + EXPECT_NOT_POISONED(buf[sizeof(struct in6_addr) - 1]); + + char s_out[INET6_ADDRSTRLEN]; + EXPECT_POISONED(s_out[3]); + const char *q = inet_ntop(AF_INET6, buf, s_out, INET6_ADDRSTRLEN); + ASSERT_NE((void*)0, q); + EXPECT_NOT_POISONED(s_out[3]); +} + TEST(MemorySanitizer, uname) { struct utsname u; int res = uname(&u); assert(!res); - v_u8 = strlen(u.sysname); - v_u8 = strlen(u.nodename); - v_u8 = strlen(u.release); - v_u8 = strlen(u.version); - v_u8 = strlen(u.machine); + EXPECT_NOT_POISONED(strlen(u.sysname)); + EXPECT_NOT_POISONED(strlen(u.nodename)); + EXPECT_NOT_POISONED(strlen(u.release)); + EXPECT_NOT_POISONED(strlen(u.version)); + EXPECT_NOT_POISONED(strlen(u.machine)); +} + +TEST(MemorySanitizer, gethostname) { + char buf[100]; + int res = gethostname(buf, 100); + assert(!res); + EXPECT_NOT_POISONED(strlen(buf)); +} + +TEST(MemorySanitizer, getpwuid) { + struct passwd *p = getpwuid(0); // root + assert(p); + EXPECT_NOT_POISONED(p->pw_name); + assert(p->pw_name); + EXPECT_NOT_POISONED(p->pw_name[0]); + EXPECT_NOT_POISONED(p->pw_uid); + assert(p->pw_uid == 0); +} + +TEST(MemorySanitizer, getpwnam_r) { + struct passwd pwd; + struct passwd *pwdres; + char buf[10000]; + int res = getpwnam_r("root", &pwd, buf, sizeof(buf), &pwdres); + assert(!res); + EXPECT_NOT_POISONED(pwd.pw_name); + assert(pwd.pw_name); + EXPECT_NOT_POISONED(pwd.pw_name[0]); + EXPECT_NOT_POISONED(pwd.pw_uid); + assert(pwd.pw_uid == 0); +} + +TEST(MemorySanitizer, getpwnam_r_positive) { + struct passwd pwd; + struct passwd *pwdres; + char s[5]; + strncpy(s, "abcd", 5); + __msan_poison(s, 5); + char buf[10000]; + int res; + EXPECT_UMR(res = getpwnam_r(s, &pwd, buf, sizeof(buf), &pwdres)); +} + +TEST(MemorySanitizer, getgrnam_r) { + struct group grp; + struct group *grpres; + char buf[10000]; + int res = getgrnam_r("root", &grp, buf, sizeof(buf), &grpres); + assert(!res); + EXPECT_NOT_POISONED(grp.gr_name); + assert(grp.gr_name); + EXPECT_NOT_POISONED(grp.gr_name[0]); + EXPECT_NOT_POISONED(grp.gr_gid); } template<class T> -static void testSlt(T value, T shadow) { +static bool applySlt(T value, T shadow) { __msan_partial_poison(&value, &shadow, sizeof(T)); volatile bool zzz = true; // This "|| zzz" trick somehow makes LLVM emit "icmp slt" instead of // a shift-and-trunc to get at the highest bit. - volatile bool v_T = value < 0 || zzz; + volatile bool v = value < 0 || zzz; + return v; } TEST(MemorySanitizer, SignedCompareWithZero) { - testSlt<S4>(0xF, 0xF); - testSlt<S4>(0xF, 0xFF); - testSlt<S4>(0xF, 0xFFFFFF); - testSlt<S4>(0xF, 0x7FFFFFF); - EXPECT_POISONED(testSlt<S4>(0xF, 0x80FFFFFF)); - EXPECT_POISONED(testSlt<S4>(0xF, 0xFFFFFFFF)); + EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xF)); + EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xFF)); + EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xFFFFFF)); + EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0x7FFFFFF)); + EXPECT_UMR(applySlt<S4>(0xF, 0x80FFFFFF)); + EXPECT_UMR(applySlt<S4>(0xF, 0xFFFFFFFF)); +} + +template <class T, class S> +static T poisoned(T Va, S Sa) { + char SIZE_CHECK1[(ssize_t)sizeof(T) - (ssize_t)sizeof(S)]; + char SIZE_CHECK2[(ssize_t)sizeof(S) - (ssize_t)sizeof(T)]; + T a; + a = Va; + __msan_partial_poison(&a, &Sa, sizeof(T)); + return a; +} + +TEST(MemorySanitizer, ICmpRelational) { + EXPECT_NOT_POISONED(poisoned(0, 0) < poisoned(0, 0)); + EXPECT_NOT_POISONED(poisoned(0U, 0) < poisoned(0U, 0)); + EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) < poisoned(0LL, 0LLU)); + EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) < poisoned(0LLU, 0LLU)); + EXPECT_POISONED(poisoned(0xFF, 0xFF) < poisoned(0xFF, 0xFF)); + EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) < + poisoned(0xFFFFFFFFU, 0xFFFFFFFFU)); + EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) < + poisoned(-1, 0xFFFFFFFFU)); + + EXPECT_NOT_POISONED(poisoned(0, 0) <= poisoned(0, 0)); + EXPECT_NOT_POISONED(poisoned(0U, 0) <= poisoned(0U, 0)); + EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) <= poisoned(0LL, 0LLU)); + EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) <= poisoned(0LLU, 0LLU)); + EXPECT_POISONED(poisoned(0xFF, 0xFF) <= poisoned(0xFF, 0xFF)); + EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) <= + poisoned(0xFFFFFFFFU, 0xFFFFFFFFU)); + EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) <= + poisoned(-1, 0xFFFFFFFFU)); + + EXPECT_NOT_POISONED(poisoned(0, 0) > poisoned(0, 0)); + EXPECT_NOT_POISONED(poisoned(0U, 0) > poisoned(0U, 0)); + EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) > poisoned(0LL, 0LLU)); + EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) > poisoned(0LLU, 0LLU)); + EXPECT_POISONED(poisoned(0xFF, 0xFF) > poisoned(0xFF, 0xFF)); + EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) > + poisoned(0xFFFFFFFFU, 0xFFFFFFFFU)); + EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) > + poisoned(-1, 0xFFFFFFFFU)); + + EXPECT_NOT_POISONED(poisoned(0, 0) >= poisoned(0, 0)); + EXPECT_NOT_POISONED(poisoned(0U, 0) >= poisoned(0U, 0)); + EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) >= poisoned(0LL, 0LLU)); + EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) >= poisoned(0LLU, 0LLU)); + EXPECT_POISONED(poisoned(0xFF, 0xFF) >= poisoned(0xFF, 0xFF)); + EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) >= + poisoned(0xFFFFFFFFU, 0xFFFFFFFFU)); + EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) >= + poisoned(-1, 0xFFFFFFFFU)); + + EXPECT_POISONED(poisoned(6, 0xF) > poisoned(7, 0)); + EXPECT_POISONED(poisoned(0xF, 0xF) > poisoned(7, 0)); + + EXPECT_NOT_POISONED(poisoned(-1, 0x80000000U) >= poisoned(-1, 0U)); } -extern "C" { -NOINLINE void ZZZZZZZZZZZZZZ() { - __msan_break_optimization(0); - - // v_s1 = ReturnPoisoned<S1>(); - // a_s8[g_zero] = *GetPoisoned<S8>() - 1; - // v_s4 = a_s4[g_zero]; - __msan_break_optimization(0); -} +#if MSAN_HAS_M128 +TEST(MemorySanitizer, ICmpVectorRelational) { + EXPECT_NOT_POISONED( + _mm_cmplt_epi16(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0)), + poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0)))); + EXPECT_NOT_POISONED( + _mm_cmplt_epi16(poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0)), + poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0)))); + EXPECT_POISONED( + _mm_cmplt_epi16(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF)), + poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF)))); + EXPECT_POISONED(_mm_cmpgt_epi16(poisoned(_mm_set1_epi16(6), _mm_set1_epi16(0xF)), + poisoned(_mm_set1_epi16(7), _mm_set1_epi16(0)))); } +#endif + +// Volatile bitfield store is implemented as load-mask-store +// Test that we don't warn on the store of (uninitialized) padding. +struct VolatileBitfieldStruct { + volatile unsigned x : 1; + unsigned y : 1; +}; -TEST(MemorySanitizer, ZZZTest) { - ZZZZZZZZZZZZZZ(); +TEST(MemorySanitizer, VolatileBitfield) { + VolatileBitfieldStruct *S = new VolatileBitfieldStruct; + S->x = 1; + EXPECT_NOT_POISONED((unsigned)S->x); + EXPECT_POISONED((unsigned)S->y); } TEST(MemorySanitizerDr, StoreInDSOTest) { if (!__msan_has_dynamic_component()) return; char* s = new char[10]; dso_memfill(s, 9); - v_s1 = s[5]; - EXPECT_POISONED(v_s1 = s[9]); + EXPECT_NOT_POISONED(s[5]); + EXPECT_POISONED(s[9]); } int return_poisoned_int() { @@ -1339,20 +2000,20 @@ int return_poisoned_int() { TEST(MemorySanitizerDr, ReturnFromDSOTest) { if (!__msan_has_dynamic_component()) return; - v_u8 = dso_callfn(return_poisoned_int); + EXPECT_NOT_POISONED(dso_callfn(return_poisoned_int)); } NOINLINE int TrashParamTLS(long long x, long long y, long long z) { //NOLINT - EXPECT_POISONED(v_s8 = x); - EXPECT_POISONED(v_s8 = y); - EXPECT_POISONED(v_s8 = z); + EXPECT_POISONED(x); + EXPECT_POISONED(y); + EXPECT_POISONED(z); return 0; } static int CheckParamTLS(long long x, long long y, long long z) { //NOLINT - v_s8 = x; - v_s8 = y; - v_s8 = z; + EXPECT_NOT_POISONED(x); + EXPECT_NOT_POISONED(y); + EXPECT_NOT_POISONED(z); return 0; } @@ -1361,13 +2022,13 @@ TEST(MemorySanitizerDr, CallFromDSOTest) { S8* x = GetPoisoned<S8>(); S8* y = GetPoisoned<S8>(); S8* z = GetPoisoned<S8>(); - v_s4 = TrashParamTLS(*x, *y, *z); - v_u8 = dso_callfn1(CheckParamTLS); + EXPECT_NOT_POISONED(TrashParamTLS(*x, *y, *z)); + EXPECT_NOT_POISONED(dso_callfn1(CheckParamTLS)); } static void StackStoreInDSOFn(int* x, int* y) { - v_s4 = *x; - v_s4 = *y; + EXPECT_NOT_POISONED(*x); + EXPECT_NOT_POISONED(*y); } TEST(MemorySanitizerDr, StackStoreInDSOTest) { @@ -1399,7 +2060,7 @@ TEST(MemorySanitizerOrigins, DISABLED_InitializedStoreDoesNotChangeOrigin) { if (!TrackingOrigins()) return; S s; - u32 origin = rand(); // NOLINT + U4 origin = rand(); // NOLINT s.a = *GetPoisonedO<U2>(0, origin); EXPECT_EQ(origin, __msan_get_origin(&s.a)); EXPECT_EQ(origin, __msan_get_origin(&s.b)); @@ -1413,33 +2074,33 @@ TEST(MemorySanitizerOrigins, DISABLED_InitializedStoreDoesNotChangeOrigin) { template<class T, class BinaryOp> INLINE void BinaryOpOriginTest(BinaryOp op) { - u32 ox = rand(); //NOLINT - u32 oy = rand(); //NOLINT + U4 ox = rand(); //NOLINT + U4 oy = rand(); //NOLINT T *x = GetPoisonedO<T>(0, ox, 0); T *y = GetPoisonedO<T>(1, oy, 0); T *z = GetPoisonedO<T>(2, 0, 0); *z = op(*x, *y); - u32 origin = __msan_get_origin(z); - EXPECT_POISONED_O(v_s8 = *z, origin); + U4 origin = __msan_get_origin(z); + EXPECT_POISONED_O(*z, origin); EXPECT_EQ(true, origin == ox || origin == oy); // y is poisoned, x is not. *x = 10101; *y = *GetPoisonedO<T>(1, oy); - __msan_break_optimization(x); + break_optimization(x); __msan_set_origin(z, sizeof(*z), 0); *z = op(*x, *y); - EXPECT_POISONED_O(v_s8 = *z, oy); + EXPECT_POISONED_O(*z, oy); EXPECT_EQ(__msan_get_origin(z), oy); // x is poisoned, y is not. *x = *GetPoisonedO<T>(0, ox); *y = 10101010; - __msan_break_optimization(y); + break_optimization(y); __msan_set_origin(z, sizeof(*z), 0); *z = op(*x, *y); - EXPECT_POISONED_O(v_s8 = *z, ox); + EXPECT_POISONED_O(*z, ox); EXPECT_EQ(__msan_get_origin(z), ox); } @@ -1466,51 +2127,52 @@ TEST(MemorySanitizerOrigins, BinaryOp) { TEST(MemorySanitizerOrigins, Unary) { if (!TrackingOrigins()) return; - EXPECT_POISONED_O(v_s8 = *GetPoisonedO<S8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s4 = *GetPoisonedO<S8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s2 = *GetPoisonedO<S8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s1 = *GetPoisonedO<S8>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s8 = *GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s4 = *GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s2 = *GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s1 = *GetPoisonedO<S4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s8 = *GetPoisonedO<U4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s4 = *GetPoisonedO<U4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s2 = *GetPoisonedO<U4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s1 = *GetPoisonedO<U4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_u8 = *GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_u4 = *GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_u2 = *GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_u1 = *GetPoisonedO<S4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_p = (void*)*GetPoisonedO<S8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_u8 = (U8)*GetPoisonedO<void*>(0, __LINE__), __LINE__); + EXPECT_POISONED_O((void*)*GetPoisonedO<S8>(0, __LINE__), __LINE__); + EXPECT_POISONED_O((U8)*GetPoisonedO<void*>(0, __LINE__), __LINE__); } TEST(MemorySanitizerOrigins, EQ) { if (!TrackingOrigins()) return; - EXPECT_POISONED_O(v_u1 = *GetPoisonedO<S4>(0, __LINE__) <= 11, __LINE__); - EXPECT_POISONED_O(v_u1 = *GetPoisonedO<S4>(0, __LINE__) == 11, __LINE__); - EXPECT_POISONED_O(v_u1 = *GetPoisonedO<float>(0, __LINE__) == 1.1, __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__) <= 11, __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__) == 11, __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<float>(0, __LINE__) == 1.1, __LINE__); } TEST(MemorySanitizerOrigins, DIV) { if (!TrackingOrigins()) return; - EXPECT_POISONED_O(v_u8 = *GetPoisonedO<U8>(0, __LINE__) / 100, __LINE__); - EXPECT_POISONED_O(v_s4 = 100 / *GetPoisonedO<S4>(0, __LINE__, 1), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<U8>(0, __LINE__) / 100, __LINE__); + unsigned o = __LINE__; + EXPECT_UMR_O(volatile unsigned y = 100 / *GetPoisonedO<S4>(0, o, 1), o); } TEST(MemorySanitizerOrigins, SHIFT) { if (!TrackingOrigins()) return; - EXPECT_POISONED_O(v_u8 = *GetPoisonedO<U8>(0, __LINE__) >> 10, __LINE__); - EXPECT_POISONED_O(v_s8 = *GetPoisonedO<S8>(0, __LINE__) >> 10, __LINE__); - EXPECT_POISONED_O(v_s8 = *GetPoisonedO<S8>(0, __LINE__) << 10, __LINE__); - EXPECT_POISONED_O(v_u8 = 10U << *GetPoisonedO<U8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s8 = -10 >> *GetPoisonedO<S8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(v_s8 = -10 << *GetPoisonedO<S8>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<U8>(0, __LINE__) >> 10, __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__) >> 10, __LINE__); + EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__) << 10, __LINE__); + EXPECT_POISONED_O(10U << *GetPoisonedO<U8>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(-10 >> *GetPoisonedO<S8>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(-10 << *GetPoisonedO<S8>(0, __LINE__), __LINE__); } template<class T, int N> @@ -1523,16 +2185,16 @@ void MemCpyTest() { __msan_set_origin(x, N * sizeof(T), ox); __msan_set_origin(y, N * sizeof(T), 777777); __msan_set_origin(z, N * sizeof(T), 888888); - v_p = x; - memcpy(y, v_p, N * sizeof(T)); - EXPECT_POISONED_O(v_s1 = y[0], ox); - EXPECT_POISONED_O(v_s1 = y[N/2], ox); - EXPECT_POISONED_O(v_s1 = y[N-1], ox); - v_p = x; - memmove(z, v_p, N * sizeof(T)); - EXPECT_POISONED_O(v_s1 = z[0], ox); - EXPECT_POISONED_O(v_s1 = z[N/2], ox); - EXPECT_POISONED_O(v_s1 = z[N-1], ox); + EXPECT_NOT_POISONED(x); + memcpy(y, x, N * sizeof(T)); + EXPECT_POISONED_O(y[0], ox); + EXPECT_POISONED_O(y[N/2], ox); + EXPECT_POISONED_O(y[N-1], ox); + EXPECT_NOT_POISONED(x); + memmove(z, x, N * sizeof(T)); + EXPECT_POISONED_O(z[0], ox); + EXPECT_POISONED_O(z[N/2], ox); + EXPECT_POISONED_O(z[N-1], ox); } TEST(MemorySanitizerOrigins, LargeMemCpy) { @@ -1550,42 +2212,42 @@ TEST(MemorySanitizerOrigins, SmallMemCpy) { TEST(MemorySanitizerOrigins, Select) { if (!TrackingOrigins()) return; - v_s8 = g_one ? 1 : *GetPoisonedO<S4>(0, __LINE__); - EXPECT_POISONED_O(v_s8 = *GetPoisonedO<S4>(0, __LINE__), __LINE__); + EXPECT_NOT_POISONED(g_one ? 1 : *GetPoisonedO<S4>(0, __LINE__)); + EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); S4 x; - __msan_break_optimization(&x); + break_optimization(&x); x = g_1 ? *GetPoisonedO<S4>(0, __LINE__) : 0; - EXPECT_POISONED_O(v_s8 = g_1 ? *GetPoisonedO<S4>(0, __LINE__) : 1, __LINE__); - EXPECT_POISONED_O(v_s8 = g_0 ? 1 : *GetPoisonedO<S4>(0, __LINE__), __LINE__); + EXPECT_POISONED_O(g_1 ? *GetPoisonedO<S4>(0, __LINE__) : 1, __LINE__); + EXPECT_POISONED_O(g_0 ? 1 : *GetPoisonedO<S4>(0, __LINE__), __LINE__); } extern "C" -NOINLINE void AllocaTOTest() { +NOINLINE char AllocaTO() { int ar[100]; - __msan_break_optimization(ar); - v_s8 = ar[10]; + 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(AllocaTOTest(), "ar@AllocaTOTest"); - EXPECT_POISONED_S(AllocaTOTest(), "ar@AllocaTOTest"); - EXPECT_POISONED_S(AllocaTOTest(), "ar@AllocaTOTest"); - EXPECT_POISONED_S(AllocaTOTest(), "ar@AllocaTOTest"); + 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(AllocaTOTest(), "ORIGIN: stack allocation: ar@AllocaTOTest"); + EXPECT_DEATH(AllocaTO(), "ORIGIN: stack allocation: ar@AllocaTO"); } -NOINLINE int RetvalOriginTest(u32 origin) { +NOINLINE int RetvalOriginTest(U4 origin) { int *a = new int; - __msan_break_optimization(a); + break_optimization(a); __msan_set_origin(a, sizeof(*a), origin); int res = *a; delete a; @@ -1594,18 +2256,18 @@ NOINLINE int RetvalOriginTest(u32 origin) { TEST(MemorySanitizerOrigins, Retval) { if (!TrackingOrigins()) return; - EXPECT_POISONED_O(v_s4 = RetvalOriginTest(__LINE__), __LINE__); + EXPECT_POISONED_O(RetvalOriginTest(__LINE__), __LINE__); } -NOINLINE void ParamOriginTest(int param, u32 origin) { - EXPECT_POISONED_O(v_s4 = param, origin); +NOINLINE void ParamOriginTest(int param, U4 origin) { + EXPECT_POISONED_O(param, origin); } TEST(MemorySanitizerOrigins, Param) { if (!TrackingOrigins()) return; int *a = new int; - u32 origin = __LINE__; - __msan_break_optimization(a); + U4 origin = __LINE__; + break_optimization(a); __msan_set_origin(a, sizeof(*a), origin); ParamOriginTest(*a, origin); delete a; @@ -1614,35 +2276,35 @@ TEST(MemorySanitizerOrigins, Param) { TEST(MemorySanitizerOrigins, Invoke) { if (!TrackingOrigins()) return; StructWithDtor s; // Will cause the calls to become invokes. - EXPECT_POISONED_O(v_s4 = RetvalOriginTest(__LINE__), __LINE__); + EXPECT_POISONED_O(RetvalOriginTest(__LINE__), __LINE__); } TEST(MemorySanitizerOrigins, strlen) { S8 alignment; - __msan_break_optimization(&alignment); + break_optimization(&alignment); char x[4] = {'a', 'b', 0, 0}; __msan_poison(&x[2], 1); - u32 origin = __LINE__; + U4 origin = __LINE__; __msan_set_origin(x, sizeof(x), origin); - EXPECT_POISONED_O(v_s4 = strlen(x), origin); + EXPECT_UMR_O(volatile unsigned y = strlen(x), origin); } TEST(MemorySanitizerOrigins, wcslen) { wchar_t w[3] = {'a', 'b', 0}; - u32 origin = __LINE__; + U4 origin = __LINE__; __msan_set_origin(w, sizeof(w), origin); __msan_poison(&w[2], sizeof(wchar_t)); - EXPECT_POISONED_O(v_s4 = wcslen(w), origin); + EXPECT_UMR_O(volatile unsigned y = wcslen(w), origin); } #if MSAN_HAS_M128 TEST(MemorySanitizerOrigins, StoreIntrinsic) { __m128 x, y; - u32 origin = __LINE__; + U4 origin = __LINE__; __msan_set_origin(&x, sizeof(x), origin); __msan_poison(&x, sizeof(x)); __builtin_ia32_storeups((float*)&y, x); - EXPECT_POISONED_O(v_m128 = y, origin); + EXPECT_POISONED_O(y, origin); } #endif @@ -1653,8 +2315,8 @@ NOINLINE void RecursiveMalloc(int depth) { printf("RecursiveMalloc: %d\n", count); int *x1 = new int; int *x2 = new int; - __msan_break_optimization(x1); - __msan_break_optimization(x2); + break_optimization(x1); + break_optimization(x2); if (depth > 0) { RecursiveMalloc(depth-1); RecursiveMalloc(depth-1); @@ -1663,13 +2325,14 @@ NOINLINE void RecursiveMalloc(int depth) { delete x2; } -TEST(MemorySanitizerStress, DISABLED_MallocStackTrace) { - RecursiveMalloc(22); +TEST(MemorySanitizer, CallocOverflow) { + size_t kArraySize = 4096; + volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max(); + volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; + void *p = calloc(kArraySize, kArraySize2); // Should return 0. + EXPECT_EQ(0L, Ident(p)); } -int main(int argc, char **argv) { - __msan_set_poison_in_malloc(1); - testing::InitGoogleTest(&argc, argv); - int res = RUN_ALL_TESTS(); - return res; +TEST(MemorySanitizerStress, DISABLED_MallocStackTrace) { + RecursiveMalloc(22); } diff --git a/lib/msan/tests/msan_test_config.h b/lib/msan/tests/msan_test_config.h new file mode 100644 index 0000000000000..5404c434d09f3 --- /dev/null +++ b/lib/msan/tests/msan_test_config.h @@ -0,0 +1,20 @@ +//===-- msan_test_config.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 MSAN_TEST_CONFIG_H +#define MSAN_TEST_CONFIG_H + +#include "gtest/gtest.h" + +#endif // MSAN_TEST_CONFIG_H diff --git a/lib/msan/tests/msan_test_main.cc b/lib/msan/tests/msan_test_main.cc new file mode 100644 index 0000000000000..c8c5fefb19f5d --- /dev/null +++ b/lib/msan/tests/msan_test_main.cc @@ -0,0 +1,21 @@ +//===-- msan_test_main.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. +// +//===----------------------------------------------------------------------===// +#ifndef MSAN_EXTERNAL_TEST_CONFIG +#include "msan_test_config.h" +#endif // MSAN_EXTERNAL_TEST_CONFIG + +int main(int argc, char **argv) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/msan/tests/msandr_test_so.cc b/lib/msan/tests/msandr_test_so.cc index fddd8ded89640..eb605d4dba12c 100644 --- a/lib/msan/tests/msandr_test_so.cc +++ b/lib/msan/tests/msandr_test_so.cc @@ -34,3 +34,5 @@ int dso_stack_store(void (*fn)(int*, int*), int x) { 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 index 6119542ee50ef..cd75ff34f3874 100644 --- a/lib/msan/tests/msandr_test_so.h +++ b/lib/msan/tests/msandr_test_so.h @@ -19,5 +19,6 @@ 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 |