[compiler-rt] r317587 - tsan: allow usage of global vars with ctors in interceptors

Dmitry Vyukov via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 7 08:31:09 PST 2017


Author: dvyukov
Date: Tue Nov  7 08:31:08 2017
New Revision: 317587

URL: http://llvm.org/viewvc/llvm-project?rev=317587&view=rev
Log:
tsan: allow usage of global vars with ctors in interceptors

We allow usage of global/per-thread data with non-trivial ctors/dtors
throughout tsan code base by placing all global/per-thread data into
Context/ThreadState and then explicitly constructing them with
placement new. This greatly simplifies code by restricting the
"linker initialized plague" to only these 2 objects.

Do the same for interceptors data.

This allows to use Vector instead of bunch of hand-written code in:
https://reviews.llvm.org/D39619

Reviewed in: https://reviews.llvm.org/D39721


Modified:
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc?rev=317587&r1=317586&r2=317587&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Tue Nov  7 08:31:08 2017
@@ -213,8 +213,6 @@ const int SIG_SETMASK = 2;
 #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED \
   (!cur_thread()->is_inited)
 
-static sigaction_t sigactions[kSigCount];
-
 namespace __tsan {
 struct SignalDesc {
   bool armed;
@@ -233,11 +231,31 @@ struct ThreadSignalContext {
   __sanitizer_sigset_t oldset;
 };
 
-// The object is 64-byte aligned, because we want hot data to be located in
-// a single cache line if possible (it's accessed in every interceptor).
-static ALIGNED(64) char libignore_placeholder[sizeof(LibIgnore)];
+// InterceptorContext holds all global data required for interceptors.
+// It's explicitly constructed in InitializeInterceptors with placement new
+// and is never destroyed. This allows usage of members with non-trivial
+// constructors and destructors.
+struct InterceptorContext {
+  // The object is 64-byte aligned, because we want hot data to be located
+  // in a single cache line if possible (it's accessed in every interceptor).
+  ALIGNED(64) LibIgnore libignore;
+  sigaction_t sigactions[kSigCount];
+#if !SANITIZER_MAC && !SANITIZER_NETBSD
+  unsigned finalize_key;
+#endif
+
+  InterceptorContext()
+      : libignore(LINKER_INITIALIZED) {
+  }
+};
+
+static ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)];
+InterceptorContext *interceptor_ctx() {
+  return reinterpret_cast<InterceptorContext*>(&interceptor_placeholder[0]);
+}
+
 LibIgnore *libignore() {
-  return reinterpret_cast<LibIgnore*>(&libignore_placeholder[0]);
+  return &interceptor_ctx()->libignore;
 }
 
 void InitializeLibIgnore() {
@@ -265,10 +283,6 @@ static ThreadSignalContext *SigCtx(Threa
   return ctx;
 }
 
-#if !SANITIZER_MAC && !SANITIZER_NETBSD
-static unsigned g_thread_finalize_key;
-#endif
-
 ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
                                      uptr pc)
     : thr_(thr), pc_(pc), in_ignored_lib_(false), ignoring_(false) {
@@ -873,7 +887,8 @@ void DestroyThreadState() {
 static void thread_finalize(void *v) {
   uptr iter = (uptr)v;
   if (iter > 1) {
-    if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
+    if (pthread_setspecific(interceptor_ctx()->finalize_key,
+        (void*)(iter - 1))) {
       Printf("ThreadSanitizer: failed to set thread key\n");
       Die();
     }
@@ -901,7 +916,7 @@ extern "C" void *__tsan_thread_start_fun
     ScopedIgnoreInterceptors ignore;
 #if !SANITIZER_MAC && !SANITIZER_NETBSD
     ThreadIgnoreBegin(thr, 0);
-    if (pthread_setspecific(g_thread_finalize_key,
+    if (pthread_setspecific(interceptor_ctx()->finalize_key,
                             (void *)GetPthreadDestructorIterations())) {
       Printf("ThreadSanitizer: failed to set thread key\n");
       Die();
@@ -1802,6 +1817,7 @@ namespace __tsan {
 
 static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
     bool sigact, int sig, my_siginfo_t *info, void *uctx) {
+  sigaction_t *sigactions = interceptor_ctx()->sigactions;
   if (acquire)
     Acquire(thr, 0, (uptr)&sigactions[sig]);
   // Signals are generally asynchronous, so if we receive a signals when
@@ -1953,6 +1969,7 @@ TSAN_INTERCEPTOR(int, sigaction, int sig
   // the signal handler through rtl_sigaction, very bad things will happen.
   // The handler will run synchronously and corrupt tsan per-thread state.
   SCOPED_INTERCEPTOR_RAW(sigaction, sig, act, old);
+  sigaction_t *sigactions = interceptor_ctx()->sigactions;
   if (old)
     internal_memcpy(old, &sigactions[sig], sizeof(*old));
   if (act == 0)
@@ -2490,6 +2507,8 @@ void InitializeInterceptors() {
   mallopt(-3, 32*1024);  // M_MMAP_THRESHOLD
 #endif
 
+  new(interceptor_ctx()) InterceptorContext();
+
   InitializeCommonInterceptors();
 
 #if !SANITIZER_MAC
@@ -2641,7 +2660,7 @@ void InitializeInterceptors() {
   }
 
 #if !SANITIZER_MAC && !SANITIZER_NETBSD
-  if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
+  if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) {
     Printf("ThreadSanitizer: failed to create thread key\n");
     Die();
   }




More information about the llvm-commits mailing list