Skip to content

Commit

Permalink
[sanitizer] On OS X, verify that interceptors work and abort if not
Browse files Browse the repository at this point in the history
On OS X 10.11+, we have "automatic interceptors", so we don't need to use DYLD_INSERT_LIBRARIES when launching instrumented programs. However, non-instrumented programs that load TSan late (e.g. via dlopen) are currently broken, as TSan will still try to initialize, but the program will crash/hang at random places (because the interceptors don't work). This patch adds an explicit check that interceptors are working, and if not, it aborts and prints out an error message suggesting to explicitly use DYLD_INSERT_LIBRARIES.

Differential Revision: http://reviews.llvm.org/D18121

llvm-svn: 263551
  • Loading branch information
kubamracek committed Mar 15, 2016
1 parent 96f4b12 commit 69b5943
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
15 changes: 15 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_mac.cc
Expand Up @@ -627,6 +627,21 @@ void MaybeReexec() {
CHECK("execv failed" && 0);
}

// Verify that interceptors really work. We'll use dlsym to locate
// "pthread_create", if interceptors are working, it should really point to
// "wrap_pthread_create" within our own dylib.
Dl_info info_pthread_create;
void *dlopen_addr = dlsym(RTLD_DEFAULT, "pthread_create");
CHECK(dladdr(dlopen_addr, &info_pthread_create));
if (internal_strcmp(info.dli_fname, info_pthread_create.dli_fname) != 0) {
Report(
"ERROR: Interceptors are not working. This may be because %s is "
"loaded too late (e.g. via dlopen). Please launch the executable "
"with:\n%s=%s\n",
SanitizerToolName, kDyldInsertLibraries, info.dli_fname);
CHECK("interceptors not installed" && 0);
}

if (!lib_is_in_env)
return;

Expand Down
8 changes: 8 additions & 0 deletions compiler-rt/test/lit.common.cfg
Expand Up @@ -118,6 +118,14 @@ if config.can_symbolize:

lit.util.usePlatformSdkOnDarwin(config, lit_config)

if config.host_os == 'Darwin':
ld_cmd = subprocess.Popen(["bash", "-c", "sw_vers -productVersion | awk -F '.' '{print $1 \".\" $2}'"], stdout = subprocess.PIPE)
ld_out = ld_cmd.stdout.read().decode()
ld_cmd.wait()
osx_version = float(ld_out)
if osx_version >= 10.11:
config.available_features.add('osx-autointerception')

sancovcc_path = os.path.join(llvm_tools_dir, "sancov")
if os.path.exists(sancovcc_path):
config.available_features.add("has_sancovcc")
Expand Down
41 changes: 41 additions & 0 deletions compiler-rt/test/tsan/Darwin/dlopen.cc
@@ -0,0 +1,41 @@
// Checks that on OS X 10.11+ (where we do not re-exec anymore, because
// interceptors work automatically), dlopen'ing a TSanified library from a
// non-instrumented program exits with a user-friendly message.

// REQUIRES: osx-autointerception

// RUN: %clangxx_tsan %s -o %t.so -shared -DSHARED_LIB
// RUN: %clangxx_tsan -fno-sanitize=thread %s -o %t

// RUN: TSAN_DYLIB_PATH=`%clangxx_tsan %s -### 2>&1 \
// RUN: | grep "libclang_rt.tsan_osx_dynamic.dylib" \
// RUN: | sed -e 's/.*"\(.*libclang_rt.tsan_osx_dynamic.dylib\)".*/\1/'`

// Launching a non-instrumented binary that dlopen's an instrumented library should fail.
// RUN: not %run %t-noninstr %t.so 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
// Launching a non-instrumented binary with an explicit DYLD_INSERT_LIBRARIES should work.
// RUN: DYLD_INSERT_LIBRARIES=$TSAN_DYLIB_PATH %run %t-noninstr %t.so 2>&1 | FileCheck %s

#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>

#if defined(SHARED_LIB)
void foo() {
fprintf(stderr, "Hello world.\n");
}
#else // defined(SHARED_LIB)
int main(int argc, char *argv[]) {
void *handle = dlopen(argv[1], RTLD_NOW);
fprintf(stderr, "handle = %p\n", handle);
void (*foo)() = (void (*)())dlsym(handle, "foo");
fprintf(stderr, "foo = %p\n", foo);
foo();
}
#endif // defined(SHARED_LIB)

// CHECK: Hello world.
// CHECK-NOT: ERROR: Interceptors are not working.

// CHECK-FAIL-NOT: Hello world.
// CHECK-FAIL: ERROR: Interceptors are not working.

0 comments on commit 69b5943

Please sign in to comment.