diff --git a/compiler-rt/include/sanitizer/tsan_interface.h b/compiler-rt/include/sanitizer/tsan_interface.h --- a/compiler-rt/include/sanitizer/tsan_interface.h +++ b/compiler-rt/include/sanitizer/tsan_interface.h @@ -154,6 +154,12 @@ // Do not establish a happens-before relation between fibers static const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0; +// User-provided callback invoked on tsan initialization. +const void __tsan_on_initialize(); + +// User-provided callback invoked on tsan shutdown. +const int __tsan_on_finalize(int failed); + #ifdef __cplusplus } // extern "C" #endif 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 @@ -56,12 +56,23 @@ bool OnFinalize(bool failed); void OnInitialize(); #else +#include SANITIZER_WEAK_CXX_DEFAULT_IMPL bool OnFinalize(bool failed) { +#if !SANITIZER_GO + if (auto ptr = dlsym(RTLD_DEFAULT, "__tsan_on_finalize")) + return reinterpret_cast(ptr)(failed); +#endif return failed; } SANITIZER_WEAK_CXX_DEFAULT_IMPL -void OnInitialize() {} +void OnInitialize() { +#if !SANITIZER_GO + if (auto ptr = dlsym(RTLD_DEFAULT, "__tsan_on_initialize")) { + return reinterpret_cast(ptr)(); + } +#endif +} #endif static char thread_registry_placeholder[sizeof(ThreadRegistry)]; 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 -fPIC -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()