Index: lib/sanitizer_common/sanitizer_mac.cc =================================================================== --- lib/sanitizer_common/sanitizer_mac.cc +++ lib/sanitizer_common/sanitizer_mac.cc @@ -627,6 +627,21 @@ 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; Index: test/tsan/Darwin/dlopen.cc =================================================================== --- test/tsan/Darwin/dlopen.cc +++ test/tsan/Darwin/dlopen.cc @@ -0,0 +1,46 @@ +// 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. + +// RUN: %clangxx_tsan %s -o %t-instr -DINSTRUMENTED_PART=1 +// RUN: %clangxx_tsan -fno-sanitize=thread %s -o %t-noninstr -DINSTRUMENTED_PART=0 -DINSTRUMENTED_PART_LIB_NAME="\"%t-instr\"" + +// Launching a regular instrumented binary just works. Either interceptors +// already work or we re-exec. +// RUN: %run %t-instr 2>&1 | FileCheck %s + +// RUN: IS_OSX_10_11_OR_HIGHER=$([ `sw_vers -productVersion | cut -d'.' -f2` -lt 11 ]; echo $?) +// 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/'` + +// RUN: if [ $IS_OSX_10_11_OR_HIGHER == 1 ]; then \ +// Launching a non-instrumented binary that dlopen's an instrumented library should fail. +// RUN: not %run %t-noninstr 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 2>&1 | FileCheck %s; \ +// RUN: fi + +#include +#include +#include + +#if INSTRUMENTED_PART == 1 +int main() { + fprintf(stderr, "Hello world.\n"); +} +#else // INSTRUMENTED_PART == 1 +int main() { + void *handle = dlopen(INSTRUMENTED_PART_LIB_NAME, RTLD_NOW); + fprintf(stderr, "handle = %p\n", handle); + int (*other_main)() = (int (*)())dlsym(handle, "main"); + fprintf(stderr, "other_main = %p\n", other_main); + other_main(); +} +#endif + +// CHECK: Hello world. +// CHECK-NOT: ERROR: Interceptors are not working. + +// CHECK-FAIL-NOT: Hello world. +// CHECK-FAIL: ERROR: Interceptors are not working.