diff options
Diffstat (limited to 'lib/msan/lit_tests')
57 files changed, 1250 insertions, 105 deletions
diff --git a/lib/msan/lit_tests/CMakeLists.txt b/lib/msan/lit_tests/CMakeLists.txt index ed2da6b839f5..38d1e59e709e 100644 --- a/lib/msan/lit_tests/CMakeLists.txt +++ b/lib/msan/lit_tests/CMakeLists.txt @@ -3,24 +3,23 @@ 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 -  ) +  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg) -configure_lit_site_cfg( -  ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in -  ${CMAKE_CURRENT_BINARY_DIR}/Unit/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) +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) +    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" diff --git a/lib/msan/lit_tests/Linux/glob.cc b/lib/msan/lit_tests/Linux/glob.cc index 513679c6d3d7..387ce3cf5f1a 100644 --- a/lib/msan/lit_tests/Linux/glob.cc +++ b/lib/msan/lit_tests/Linux/glob.cc @@ -1,4 +1,5 @@  // 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> diff --git a/lib/msan/lit_tests/Linux/glob_altdirfunc.cc b/lib/msan/lit_tests/Linux/glob_altdirfunc.cc new file mode 100644 index 000000000000..b8200c3ee899 --- /dev/null +++ b/lib/msan/lit_tests/Linux/glob_altdirfunc.cc @@ -0,0 +1,78 @@ +// 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 new file mode 100644 index 000000000000..0262034aec5b --- /dev/null +++ b/lib/msan/lit_tests/Linux/glob_nomatch.cc @@ -0,0 +1,21 @@ +// 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/syscalls.cc b/lib/msan/lit_tests/Linux/syscalls.cc index c12eda39189e..ec308bfe30ca 100644 --- a/lib/msan/lit_tests/Linux/syscalls.cc +++ b/lib/msan/lit_tests/Linux/syscalls.cc @@ -7,6 +7,10 @@  #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> @@ -16,6 +20,7 @@  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); @@ -46,5 +51,50 @@ int main(int argc, char *argv[]) {    __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 new file mode 100644 index 000000000000..e6e101db884f --- /dev/null +++ b/lib/msan/lit_tests/Linux/tcgetattr.cc @@ -0,0 +1,21 @@ +// 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 new file mode 100644 index 000000000000..8930a7159246 --- /dev/null +++ b/lib/msan/lit_tests/SharedLibs/dso-origin-so.cc @@ -0,0 +1,14 @@ +#include <stdlib.h> + +#include "dso-origin.h" + +void my_access(int *p) { +  volatile int tmp; +  // Force initialize-ness check. +  if (*p) +    tmp = 1; +} + +void *my_alloc(unsigned sz) { +  return malloc(sz); +} diff --git a/lib/msan/lit_tests/SharedLibs/dso-origin.h b/lib/msan/lit_tests/SharedLibs/dso-origin.h new file mode 100644 index 000000000000..ff926b3f61c8 --- /dev/null +++ b/lib/msan/lit_tests/SharedLibs/dso-origin.h @@ -0,0 +1,4 @@ +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 new file mode 100644 index 000000000000..b3677c17a0f2 --- /dev/null +++ b/lib/msan/lit_tests/SharedLibs/lit.local.cfg @@ -0,0 +1,4 @@ +# Sources in this directory are compiled as shared libraries and used by +# tests in parent directory. + +config.suffixes = [] diff --git a/lib/msan/lit_tests/Unit/lit.cfg b/lib/msan/lit_tests/Unit/lit.cfg deleted file mode 100644 index ee379d0deaed..000000000000 --- a/lib/msan/lit_tests/Unit/lit.cfg +++ /dev/null @@ -1,26 +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. -compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root') -compiler_rt_lit_unit_cfg = os.path.join(compiler_rt_src_root, "lib", -                                        "lit.common.unit.cfg") -lit.load_config(config, compiler_rt_lit_unit_cfg) - -# 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. -msan_binary_dir = get_required_attr(config, "msan_binary_dir") -config.test_exec_root = os.path.join(msan_binary_dir, "tests") -config.test_source_root = config.test_exec_root diff --git a/lib/msan/lit_tests/Unit/lit.site.cfg.in b/lib/msan/lit_tests/Unit/lit.site.cfg.in index a91f6713303a..8e67f557d7fd 100644 --- a/lib/msan/lit_tests/Unit/lit.site.cfg.in +++ b/lib/msan/lit_tests/Unit/lit.site.cfg.in @@ -1,17 +1,13 @@  ## Autogenerated by LLVM/Clang configuration.  # Do not edit! -config.target_triple = "@TARGET_TRIPLE@" -config.llvm_src_root = "@LLVM_SOURCE_DIR@" -config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@" -config.llvm_build_mode = "@LLVM_BUILD_MODE@" -config.msan_binary_dir = "@MSAN_BINARY_DIR@" +# Load common config for all compiler-rt unit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured") -try: -  config.llvm_build_mode = config.llvm_build_mode % lit.params -except KeyError,e: -  key, = e.args -  lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key)) +# Setup config name. +config.name = 'MemorySanitizer-Unit' -# Let the main config do the real work. -lit.load_config(config, "@MSAN_SOURCE_DIR@/lit_tests/Unit/lit.cfg") +# 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 new file mode 100644 index 000000000000..aaa85cce7113 --- /dev/null +++ b/lib/msan/lit_tests/allocator_returns_null.cc @@ -0,0 +1,81 @@ +// Test the behavior of malloc/calloc/realloc when the allocation size is huge. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0. +// +// RUN: %clangxx_msan -O0 %s -o %t +// RUN: not %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 new file mode 100644 index 000000000000..48684c29c60d --- /dev/null +++ b/lib/msan/lit_tests/backtrace.cc @@ -0,0 +1,26 @@ +// 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/cxa_atexit.cc b/lib/msan/lit_tests/cxa_atexit.cc new file mode 100644 index 000000000000..f3641aadce03 --- /dev/null +++ b/lib/msan/lit_tests/cxa_atexit.cc @@ -0,0 +1,28 @@ +// 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/dlerror.cc b/lib/msan/lit_tests/dlerror.cc new file mode 100644 index 000000000000..281b3164fd7e --- /dev/null +++ b/lib/msan/lit_tests/dlerror.cc @@ -0,0 +1,14 @@ +// 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 new file mode 100644 index 000000000000..13661c65e744 --- /dev/null +++ b/lib/msan/lit_tests/dso-origin.cc @@ -0,0 +1,25 @@ +// Build a library with origin tracking and an executable w/o origin tracking. +// Test that origin tracking is enabled at runtime. +// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %p/SharedLibs/dso-origin-so.cc \ +// RUN:     -fPIC -shared -o %t-so.so +// RUN: %clangxx_msan -m64 -O0 %s %t-so.so -o %t && not %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 new file mode 100644 index 000000000000..af27ad0b0329 --- /dev/null +++ b/lib/msan/lit_tests/errno.cc @@ -0,0 +1,17 @@ +// 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 index f16679cc2aa2..7fde1fdfab93 100644 --- a/lib/msan/lit_tests/getaddrinfo-positive.cc +++ b/lib/msan/lit_tests/getaddrinfo-positive.cc @@ -8,12 +8,16 @@  #include <netdb.h>  #include <stdlib.h> +volatile int z; +  int main(void) {    struct addrinfo *ai;    struct addrinfo hint; -  int res = getaddrinfo("localhost", NULL, &hint, &ai); +  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: Use of uninitialized value +  // 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/getline.cc b/lib/msan/lit_tests/getline.cc new file mode 100644 index 000000000000..27168a885606 --- /dev/null +++ b/lib/msan/lit_tests/getline.cc @@ -0,0 +1,30 @@ +// 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 new file mode 100644 index 000000000000..5ba1d4cec0dd --- /dev/null +++ b/lib/msan/lit_tests/getline_test_data @@ -0,0 +1,2 @@ +abcde +12345 diff --git a/lib/msan/lit_tests/heap-origin.cc b/lib/msan/lit_tests/heap-origin.cc index 54e2c31438ff..dfe7edd27e82 100644 --- a/lib/msan/lit_tests/heap-origin.cc +++ b/lib/msan/lit_tests/heap-origin.cc @@ -19,15 +19,13 @@  #include <stdlib.h>  int main(int argc, char **argv) {    char *volatile x = (char*)malloc(5 * sizeof(char)); -  if (*x) -    exit(0); -  // CHECK: WARNING: Use of uninitialized value -  // CHECK: {{#0 0x.* in main .*heap-origin.cc:}}[[@LINE-3]] +  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-8]] +  // CHECK-ORIGINS: {{#1 0x.* in main .*heap-origin.cc:}}[[@LINE-7]]    // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*heap-origin.cc:.* main}} -  return 0;  } diff --git a/lib/msan/lit_tests/initgroups.cc b/lib/msan/lit_tests/initgroups.cc new file mode 100644 index 000000000000..adba5369579a --- /dev/null +++ b/lib/msan/lit_tests/initgroups.cc @@ -0,0 +1,11 @@ +// 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 new file mode 100644 index 000000000000..4aeb15583f84 --- /dev/null +++ b/lib/msan/lit_tests/inline.cc @@ -0,0 +1,20 @@ +// 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 new file mode 100644 index 000000000000..769ea45f8c4d --- /dev/null +++ b/lib/msan/lit_tests/insertvalue_origin.cc @@ -0,0 +1,35 @@ +// 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 new file mode 100644 index 000000000000..caff80c2e5d7 --- /dev/null +++ b/lib/msan/lit_tests/ioctl.cc @@ -0,0 +1,20 @@ +// 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 new file mode 100644 index 000000000000..94ed528c70b9 --- /dev/null +++ b/lib/msan/lit_tests/ioctl_custom.cc @@ -0,0 +1,33 @@ +// 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 new file mode 100644 index 000000000000..6d006756a110 --- /dev/null +++ b/lib/msan/lit_tests/keep-going-dso.cc @@ -0,0 +1,33 @@ +// 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 new file mode 100644 index 000000000000..e33b137c76f7 --- /dev/null +++ b/lib/msan/lit_tests/keep-going.cc @@ -0,0 +1,34 @@ +// 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 index 42381885fe8e..da1bde6dd04a 100644 --- a/lib/msan/lit_tests/lit.cfg +++ b/lib/msan/lit_tests/lit.cfg @@ -2,12 +2,15 @@  import os +import lit.util +  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) +    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. @@ -17,9 +20,9 @@ config.name = 'MemorySanitizer'  config.test_source_root = os.path.dirname(__file__)  def DisplayNoConfigMessage(): -  lit.fatal("No site specific configuration available! " + -            "Try running your test from the build tree or running " + -            "make check-msan") +  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) @@ -27,9 +30,9 @@ 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.params.get('msan_site_config', None) +  msan_site_cfg = lit_config.params.get('msan_site_config', None)    if (msan_site_cfg) and (os.path.exists(msan_site_cfg)): -    lit.load_config(config, 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 @@ -45,25 +48,17 @@ if llvm_src_root is None:    if (not msan_site_cfg) or (not os.path.exists(msan_site_cfg)):      DisplayNoConfigMessage() -  lit.load_config(config, msan_site_cfg) +  lit_config.load_config(config, msan_site_cfg)    raise SystemExit -# Setup attributes common for all compiler-rt projects. -compiler_rt_src_root = get_required_attr(config, "compiler_rt_src_root") -compiler_rt_lit_cfg = os.path.join(compiler_rt_src_root, "lib", -                                   "lit.common.cfg") -if (not compiler_rt_lit_cfg) or (not os.path.exists(compiler_rt_lit_cfg)): -  lit.fatal("Can't find common compiler-rt lit config at: %r" -            % compiler_rt_lit_cfg) -lit.load_config(config, compiler_rt_lit_cfg) -  # 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"] -clang_msan_cxxflags = ["-ccc-cxx "] + clang_msan_cflags +                     "-g", +                     "-m64"] +clang_msan_cxxflags = ["--driver-mode=g++ "] + clang_msan_cflags  config.substitutions.append( ("%clang_msan ",                                " ".join([config.clang] + clang_msan_cflags) +                                 " ") ) @@ -71,12 +66,6 @@ config.substitutions.append( ("%clangxx_msan ",                                " ".join([config.clang] + clang_msan_cxxflags) +                                 " ") ) -# Setup path to external LLVM symbolizer to run MemorySanitizer output tests. -llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) -if llvm_tools_dir: -  llvm_symbolizer_path = os.path.join(llvm_tools_dir, "llvm-symbolizer") -  config.environment['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer_path -  # Default test suffixes.  config.suffixes = ['.c', '.cc', '.cpp'] diff --git a/lib/msan/lit_tests/lit.site.cfg.in b/lib/msan/lit_tests/lit.site.cfg.in index 3b969e0b0614..946df778f3d3 100644 --- a/lib/msan/lit_tests/lit.site.cfg.in +++ b/lib/msan/lit_tests/lit.site.cfg.in @@ -1,18 +1,5 @@ -config.target_triple = "@TARGET_TRIPLE@" -config.host_os = "@HOST_OS@" -config.llvm_src_root = "@LLVM_SOURCE_DIR@" -config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@" -config.llvm_obj_root = "@LLVM_BINARY_DIR@" -config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" -config.clang = "@LLVM_BINARY_DIR@/bin/clang" +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured") -# LLVM tools dir can be passed in lit parameters, so try to -# apply substitution. -try: -  config.llvm_tools_dir = config.llvm_tools_dir % lit.params -except KeyError,e: -  key, = e.args -  lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key)) - -# Let the main config do the real work. -lit.load_config(config, "@MSAN_SOURCE_DIR@/lit_tests/lit.cfg") +# 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 new file mode 100644 index 000000000000..fc68fbc35fbb --- /dev/null +++ b/lib/msan/lit_tests/malloc_hook.cc @@ -0,0 +1,36 @@ +// 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_prop.cc b/lib/msan/lit_tests/no_sanitize_memory_prop.cc index c74ca6b89db9..355152478852 100644 --- a/lib/msan/lit_tests/no_sanitize_memory_prop.cc +++ b/lib/msan/lit_tests/no_sanitize_memory_prop.cc @@ -25,7 +25,7 @@ int main(void) {    int x;    int * volatile p = &x;    int y = f(*p); -  // CHECK: WARNING: Use of uninitialized value +  // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value    // CHECK: {{#0 0x.* in main .*no_sanitize_memory_prop.cc:}}[[@LINE+1]]    if (y)      exit(0); diff --git a/lib/msan/lit_tests/poison_in_free.cc b/lib/msan/lit_tests/poison_in_free.cc new file mode 100644 index 000000000000..f134d05abb1e --- /dev/null +++ b/lib/msan/lit_tests/poison_in_free.cc @@ -0,0 +1,16 @@ +// 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 new file mode 100644 index 000000000000..d0e83eabd6a4 --- /dev/null +++ b/lib/msan/lit_tests/ptrace.cc @@ -0,0 +1,36 @@ +// 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, ®s); +    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/scandir.cc b/lib/msan/lit_tests/scandir.cc new file mode 100644 index 000000000000..94672e1adbee --- /dev/null +++ b/lib/msan/lit_tests/scandir.cc @@ -0,0 +1,56 @@ +// 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 new file mode 100644 index 000000000000..84af7f418d21 --- /dev/null +++ b/lib/msan/lit_tests/scandir_null.cc @@ -0,0 +1,34 @@ +// 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 new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/lib/msan/lit_tests/scandir_test_root/aaa diff --git a/lib/msan/lit_tests/scandir_test_root/aab b/lib/msan/lit_tests/scandir_test_root/aab new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/lib/msan/lit_tests/scandir_test_root/aab diff --git a/lib/msan/lit_tests/scandir_test_root/bbb b/lib/msan/lit_tests/scandir_test_root/bbb new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/lib/msan/lit_tests/scandir_test_root/bbb diff --git a/lib/msan/lit_tests/select.cc b/lib/msan/lit_tests/select.cc new file mode 100644 index 000000000000..a169a2dd9118 --- /dev/null +++ b/lib/msan/lit_tests/select.cc @@ -0,0 +1,22 @@ +// 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 new file mode 100644 index 000000000000..a22b744d74db --- /dev/null +++ b/lib/msan/lit_tests/setlocale.cc @@ -0,0 +1,13 @@ +// 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 new file mode 100644 index 000000000000..ea75eae1bdaa --- /dev/null +++ b/lib/msan/lit_tests/signal_stress_test.cc @@ -0,0 +1,71 @@ +// 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 new file mode 100644 index 000000000000..29aa86c938f2 --- /dev/null +++ b/lib/msan/lit_tests/sigwait.cc @@ -0,0 +1,30 @@ +// 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 new file mode 100644 index 000000000000..d4f004598a62 --- /dev/null +++ b/lib/msan/lit_tests/sigwaitinfo.cc @@ -0,0 +1,31 @@ +// 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 index 90f527309224..b0b05d9658bf 100644 --- a/lib/msan/lit_tests/stack-origin.cc +++ b/lib/msan/lit_tests/stack-origin.cc @@ -20,13 +20,12 @@  int main(int argc, char **argv) {    int x;    int *volatile p = &x; -  if (*p) -    exit(0); -  // CHECK: WARNING: Use of uninitialized value -  // CHECK: {{#0 0x.* in main .*stack-origin.cc:}}[[@LINE-3]] +  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}} -  return 0;  } diff --git a/lib/msan/lit_tests/sync_lock_set_and_test.cc b/lib/msan/lit_tests/sync_lock_set_and_test.cc new file mode 100644 index 000000000000..1023b3e54368 --- /dev/null +++ b/lib/msan/lit_tests/sync_lock_set_and_test.cc @@ -0,0 +1,7 @@ +// 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 new file mode 100644 index 000000000000..7e1c2cfad566 --- /dev/null +++ b/lib/msan/lit_tests/tzset.cc @@ -0,0 +1,16 @@ +// 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 new file mode 100644 index 000000000000..fa29ab69de1b --- /dev/null +++ b/lib/msan/lit_tests/unaligned_read_origin.cc @@ -0,0 +1,16 @@ +// 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 new file mode 100644 index 000000000000..ac47c0233a10 --- /dev/null +++ b/lib/msan/lit_tests/use-after-free.cc @@ -0,0 +1,34 @@ +// 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 new file mode 100644 index 000000000000..c200c77de96a --- /dev/null +++ b/lib/msan/lit_tests/vector_cvt.cc @@ -0,0 +1,23 @@ +// 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 new file mode 100644 index 000000000000..e8d55423293c --- /dev/null +++ b/lib/msan/lit_tests/vector_select.cc @@ -0,0 +1,13 @@ +// RUN: %clangxx_msan -m64 -O0 %s -c -o %t +// RUN: %clangxx_msan -m64 -O3 %s -c -o %t + +// Regression test for MemorySanitizer instrumentation of a select instruction +// with vector arguments. + +#include <emmintrin.h> + +__m128d select(bool b, __m128d c, __m128d d) +{ +  return b ? c : d; +} + diff --git a/lib/msan/lit_tests/wrap_indirect_calls.cc b/lib/msan/lit_tests/wrap_indirect_calls.cc new file mode 100644 index 000000000000..b4bac1ecbd22 --- /dev/null +++ b/lib/msan/lit_tests/wrap_indirect_calls.cc @@ -0,0 +1,64 @@ +// Test indirect call wrapping in MemorySanitizer. + +// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/two.cc -fPIC -shared -o %t-two-so.so +// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/wrapper.cc -fPIC -shared -o %t-wrapper-so.so + +// Disable fast path. + +// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc %s \ +// RUN:     %t-two-so.so %t-wrapper-so.so \ +// RUN:     -mllvm -msan-wrap-indirect-calls=wrapper \ +// RUN:     -mllvm -msan-wrap-indirect-calls-fast=0 \ +// RUN:     -DSLOW=1 \ +// RUN:     -Wl,--defsym=__executable_start=0 -o %t +// RUN: %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 new file mode 100644 index 000000000000..a0af8b7bb0c5 --- /dev/null +++ b/lib/msan/lit_tests/wrap_indirect_calls/caller.cc @@ -0,0 +1,51 @@ +// Indirectly call a bunch of functions. + +#include <assert.h> + +extern int cnt; + +typedef int (*F)(int, int); + +// A function in the same object. +int f_local(int x, int y) { +  return x + y; +} + +// A function in another object. +int f_other_object(int x, int y); + +// A function in another DSO. +int f_dso(int x, int y); + +// A function in another DSO that is replaced by the wrapper. +int f_replaced(int x, int y); + +void run_test(void) { +  int x; +  int expected_cnt = 0; +  volatile F f; + +  if (SLOW) ++expected_cnt; +  f = &f_local; +  x = f(1, 2); +  assert(x == 3); +  assert(cnt == expected_cnt); + +  if (SLOW) ++expected_cnt; +  f = &f_other_object; +  x = f(2, 3); +  assert(x == 6); +  assert(cnt == expected_cnt); + +  ++expected_cnt; +  f = &f_dso; +  x = f(2, 3); +  assert(x == 7); +  assert(cnt == expected_cnt); + +  ++expected_cnt; +  f = &f_replaced; +  x = f(2, 3); +  assert(x == 11); +  assert(cnt == expected_cnt); +} diff --git a/lib/msan/lit_tests/wrap_indirect_calls/lit.local.cfg b/lib/msan/lit_tests/wrap_indirect_calls/lit.local.cfg new file mode 100644 index 000000000000..5e01230c0986 --- /dev/null +++ b/lib/msan/lit_tests/wrap_indirect_calls/lit.local.cfg @@ -0,0 +1,3 @@ +# Sources in this directory are used by tests in parent directory. + +config.suffixes = [] diff --git a/lib/msan/lit_tests/wrap_indirect_calls/one.cc b/lib/msan/lit_tests/wrap_indirect_calls/one.cc new file mode 100644 index 000000000000..ab7bf4125c0a --- /dev/null +++ b/lib/msan/lit_tests/wrap_indirect_calls/one.cc @@ -0,0 +1,3 @@ +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 new file mode 100644 index 000000000000..c939a993bc9a --- /dev/null +++ b/lib/msan/lit_tests/wrap_indirect_calls/two.cc @@ -0,0 +1,11 @@ +int f_dso(int x, int y) { +  return 2 * x + y; +} + +int f_replaced(int x, int y) { +  return x + y + 5; +} + +int f_replacement(int x, int y) { +  return x + y + 6; +} diff --git a/lib/msan/lit_tests/wrap_indirect_calls/wrapper.cc b/lib/msan/lit_tests/wrap_indirect_calls/wrapper.cc new file mode 100644 index 000000000000..8fcd0c635d96 --- /dev/null +++ b/lib/msan/lit_tests/wrap_indirect_calls/wrapper.cc @@ -0,0 +1,11 @@ +int f_replaced(int x, int y); +int f_replacement(int x, int y); + +int cnt; + +extern "C" void *wrapper(void *p) { +  ++cnt; +  if (p == (void *)f_replaced) +    return (void *)f_replacement; +  return p; +}  | 
