[compiler-rt] 26e0fb8 - [TSan] Support initialize/finalize hooks in dynamic libraries

Julian Lettner via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 24 12:39:24 PDT 2021


Author: Julian Lettner
Date: 2021-03-24T12:38:39-07:00
New Revision: 26e0fb88a30ad1ab96f66969f4d6da3e71c697b1

URL: https://github.com/llvm/llvm-project/commit/26e0fb88a30ad1ab96f66969f4d6da3e71c697b1
DIFF: https://github.com/llvm/llvm-project/commit/26e0fb88a30ad1ab96f66969f4d6da3e71c697b1.diff

LOG: [TSan] Support initialize/finalize hooks in dynamic libraries

Make TSan runtime initialization and finalization hooks work
even if these hooks are not built in the main executable.  When these
hooks are defined in another library that is not directly linked against
the TSan runtime (e.g., Swift runtime) we cannot rely on the "strong-def
overriding weak-def" mechanics and have to look them up via `dlsym()`.

Let's also define hooks that are easier to use from C-only code:
```
extern "C" void __tsan_on_initialize();
extern "C" int __tsan_on_finalize(int failed);
```
For now, these will call through to the old hooks.  Eventually, we want
to adopt the new hooks downstream and remove the old ones.

This is part of the effort to support Swift Tasks (async/await and
actors) in TSan.

rdar://74256720

Reviewed By: vitalybuka, delcypher

Differential Revision: https://reviews.llvm.org/D98810

Added: 
    compiler-rt/test/tsan/on_initialize_finalize_hooks.cpp

Modified: 
    compiler-rt/include/sanitizer/tsan_interface.h
    compiler-rt/lib/tsan/rtl/tsan_interface.h
    compiler-rt/lib/tsan/rtl/tsan_rtl.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/include/sanitizer/tsan_interface.h b/compiler-rt/include/sanitizer/tsan_interface.h
index 96b8ad58541c..cfa9d3b5f632 100644
--- a/compiler-rt/include/sanitizer/tsan_interface.h
+++ b/compiler-rt/include/sanitizer/tsan_interface.h
@@ -141,7 +141,7 @@ void __tsan_external_write(void *addr, void *caller_pc, void *tag);
 //     and freed by __tsan_destroy_fiber.
 //   - TSAN context of current fiber or thread can be obtained
 //     by calling __tsan_get_current_fiber.
-//   - __tsan_switch_to_fiber should be called immediatly before switch
+//   - __tsan_switch_to_fiber should be called immediately before switch
 //     to fiber, such as call of swapcontext.
 //   - Fiber name can be set by __tsan_set_fiber_name.
 void *__tsan_get_current_fiber(void);
@@ -154,6 +154,15 @@ void __tsan_set_fiber_name(void *fiber, const char *name);
 // 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.
+void __tsan_on_initialize();
+
+// User-provided callback invoked on TSan shutdown.
+// `failed` - Nonzero if TSan did detect issues, zero otherwise.
+// Return `0` if TSan should exit as if no issues were detected.  Return nonzero
+// if TSan should exit as if issues were detected.
+int __tsan_on_finalize(int failed);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif

diff  --git a/compiler-rt/lib/tsan/rtl/tsan_interface.h b/compiler-rt/lib/tsan/rtl/tsan_interface.h
index e7131f498b50..6e022b56850c 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interface.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_interface.h
@@ -415,6 +415,13 @@ void __tsan_go_atomic32_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
 SANITIZER_INTERFACE_ATTRIBUTE
 void __tsan_go_atomic64_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
                                          u8 *a);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_on_initialize();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_on_finalize(int failed);
+
 }  // extern "C"
 
 }  // namespace __tsan

diff  --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
index 530dd30ab72c..ed6cc83450d9 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
@@ -21,6 +21,7 @@
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
 #include "tsan_defs.h"
+#include "tsan_interface.h"
 #include "tsan_mman.h"
 #include "tsan_platform.h"
 #include "tsan_suppressions.h"
@@ -57,12 +58,23 @@ Context *ctx;
 bool OnFinalize(bool failed);
 void OnInitialize();
 #else
+#include <dlfcn.h>
 SANITIZER_WEAK_CXX_DEFAULT_IMPL
 bool OnFinalize(bool failed) {
+#if !SANITIZER_GO
+  if (auto *ptr = dlsym(RTLD_DEFAULT, "__tsan_on_finalize"))
+    return reinterpret_cast<decltype(&__tsan_on_finalize)>(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<decltype(&__tsan_on_initialize)>(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
index 000000000000..0b82ec176179
--- /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 <stdio.h>
+
+#if BUILD_LIB
+
+extern "C" void __tsan_on_initialize() {
+  printf("__tsan_on_initialize()\n");
+}
+
+extern "C" int __tsan_on_finalize(int 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()


        


More information about the llvm-commits mailing list