diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp @@ -55,6 +55,28 @@ #ifdef TSAN_EXTERNAL_HOOKS bool OnFinalize(bool failed); void OnInitialize(); +extern "C" void __tsan_on_initialize(); +extern "C" bool __tsan_on_finalize(bool failed); +#elif SANITIZER_MAC +#include +// On Darwin, strong definitions overriding weak ones is only guaranteed within +// a linkage unit (e.g., when linking .o files). There is just one case where +// strong in one linkage unit overrides a weak in another. That is when the +// strong dylib/exe was built, it linked against a dylib with a weak-def +// (__tsan_default_options() relies on this). We want to use these hooks from +// other libraries (i.e., the Swift runtime) so we need to use dlsym() to look +// them up. +static void __tsan_on_initialize() { + if (auto ptr = dlsym(RTLD_DEFAULT, "__tsan_on_initialize")) { + return reinterpret_cast(ptr)(); + } +} +static bool __tsan_on_finalize(bool failed) { + if (auto ptr = dlsym(RTLD_DEFAULT, "__tsan_on_finalize")) { + return reinterpret_cast(ptr)(failed); + } + return failed; +} #else SANITIZER_WEAK_CXX_DEFAULT_IMPL bool OnFinalize(bool failed) { @@ -62,6 +84,13 @@ } SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnInitialize() {} +// FIXME: adopt new hooks downstream and remove old ones. +SANITIZER_WEAK_DEFAULT_IMPL void __tsan_on_initialize() { + OnInitialize(); +} +SANITIZER_WEAK_DEFAULT_IMPL bool __tsan_on_finalize(bool failed) { + return OnFinalize(failed); +} #endif static char thread_registry_placeholder[sizeof(ThreadRegistry)]; @@ -432,7 +461,7 @@ while (__tsan_resumed == 0) {} } - OnInitialize(); + __tsan_on_initialize(); } void MaybeSpawnBackgroundThread() { @@ -492,7 +521,7 @@ PrintMatchedBenignRaces(); #endif - failed = OnFinalize(failed); + failed = __tsan_on_finalize(failed); #if TSAN_COLLECT_STATS StatAggregate(ctx->stat, thr->stat); diff --git a/compiler-rt/test/tsan/on_initialize_finalize_hooks.cpp b/compiler-rt/test/tsan/on_initialize_finalize_hooks.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/tsan/on_initialize_finalize_hooks.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_tsan -O1 %s -o %t.lib -fno-sanitize=thread -shared -DBUILD_LIB=1 +// RUN: %clang_tsan -O1 %s %t.lib -o %t +// RUN: %run %t | FileCheck %s + +// Test that initialization/finalization hooks are called, even when they are +// not defined in the main executable, but by another another library that +// doesn't directly link against the TSan runtime. + +#include + +#if BUILD_LIB + +extern "C" void __tsan_on_initialize() { + printf("__tsan_on_initialize()\n"); +} + +extern "C" bool __tsan_on_finalize(bool failed) { + printf("__tsan_on_finalize()\n"); + return failed; +} + +#else // BUILD_LIB + +int main() { + printf("main()\n"); + return 0; +} + +#endif // BUILD_LIB + +// CHECK: __tsan_on_initialize() +// CHECK: main() +// CHECK: __tsan_on_finalize()