[compiler-rt] r252159 - [tsan] Alternative ThreadState storage for OS X

Kuba Brecka via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 5 05:54:50 PST 2015


Author: kuba.brecka
Date: Thu Nov  5 07:54:50 2015
New Revision: 252159

URL: http://llvm.org/viewvc/llvm-project?rev=252159&view=rev
Log:
[tsan] Alternative ThreadState storage for OS X

This implements a "poor man's TLV" to be used for TSan's ThreadState on OS X. Based on the fact that `pthread_self()` is always available and reliable and returns a valid pointer to memory, we'll use the shadow memory of this pointer as a thread-local storage. No user code should ever read/write to this internal libpthread structure, so it's safe to use it for this purpose. We lazily allocate the ThreadState object and store the pointer here.

Differential Revision: http://reviews.llvm.org/D14288


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

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=252159&r1=252158&r2=252159&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Thu Nov  5 07:54:50 2015
@@ -819,6 +819,7 @@ void DestroyThreadState() {
     thr->signal_ctx = 0;
     UnmapOrDie(sctx, sizeof(*sctx));
   }
+  cur_thread_finalize();
 }
 }  // namespace __tsan
 

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc?rev=252159&r1=252158&r2=252159&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc Thu Nov  5 07:54:50 2015
@@ -15,8 +15,10 @@
 #include "sanitizer_common/sanitizer_platform.h"
 #if SANITIZER_MAC
 
+#include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_posix.h"
 #include "sanitizer_common/sanitizer_procmaps.h"
 #include "tsan_platform.h"
 #include "tsan_rtl.h"
@@ -40,6 +42,62 @@
 
 namespace __tsan {
 
+static void *SignalSafeGetOrAllocate(uptr *dst, uptr size) {
+  atomic_uintptr_t *a = (atomic_uintptr_t *)dst;
+  void *val = (void *)atomic_load_relaxed(a);
+  atomic_signal_fence(memory_order_acquire);  // Turns the previous load into
+                                              // acquire wrt signals.
+  if (UNLIKELY(val == nullptr)) {
+    val = (void *)internal_mmap(nullptr, size, PROT_READ | PROT_WRITE,
+                                MAP_PRIVATE | MAP_ANON, -1, 0);
+    CHECK(val);
+    void *cmp = nullptr;
+    if (!atomic_compare_exchange_strong(a, (uintptr_t *)&cmp, (uintptr_t)val,
+                                        memory_order_acq_rel)) {
+      internal_munmap(val, size);
+      val = cmp;
+    }
+  }
+  return val;
+}
+
+#ifndef SANITIZER_GO
+// On OS X, accessing TLVs via __thread or manually by using pthread_key_* is
+// problematic, because there are several places where interceptors are called
+// when TLVs are not accessible (early process startup, thread cleanup, ...).
+// The following provides a "poor man's TLV" implementation, where we use the
+// shadow memory of the pointer returned by pthread_self() to store a pointer to
+// the ThreadState object. The main thread's ThreadState pointer is stored
+// separately in a static variable, because we need to access it even before the
+// shadow memory is set up.
+static uptr main_thread_identity = 0;
+static ThreadState *main_thread_state = nullptr;
+
+ThreadState *cur_thread() {
+  ThreadState **fake_tls;
+  uptr thread_identity = (uptr)pthread_self();
+  if (thread_identity == main_thread_identity || main_thread_identity == 0) {
+    fake_tls = &main_thread_state;
+  } else {
+    fake_tls = (ThreadState **)MemToShadow(thread_identity);
+  }
+  ThreadState *thr = (ThreadState *)SignalSafeGetOrAllocate(
+      (uptr *)fake_tls, sizeof(ThreadState));
+  return thr;
+}
+
+// TODO(kuba.brecka): This is not async-signal-safe. In particular, we call
+// munmap first and then clear `fake_tls`; if we receive a signal in between,
+// handler will try to access the unmapped ThreadState.
+void cur_thread_finalize() {
+  uptr thread_identity = (uptr)pthread_self();
+  CHECK_NE(thread_identity, main_thread_identity);
+  ThreadState **fake_tls = (ThreadState **)MemToShadow(thread_identity);
+  internal_munmap(*fake_tls, sizeof(ThreadState));
+  *fake_tls = nullptr;
+}
+#endif
+
 uptr GetShadowMemoryConsumption() {
   return 0;
 }
@@ -95,6 +153,9 @@ void InitializePlatform() {
   DisableCoreDumperIfNecessary();
 #ifndef SANITIZER_GO
   CheckAndProtect();
+
+  CHECK_EQ(main_thread_identity, 0);
+  main_thread_identity = (uptr)pthread_self();
 #endif
 
   prev_pthread_introspection_hook =

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc?rev=252159&r1=252158&r2=252159&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc Thu Nov  5 07:54:50 2015
@@ -44,7 +44,7 @@ extern "C" void __tsan_resume() {
 
 namespace __tsan {
 
-#ifndef SANITIZER_GO
+#if !defined(SANITIZER_GO) && !SANITIZER_MAC
 THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
 #endif
 static char ctx_placeholder[sizeof(Context)] ALIGNED(64);

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h?rev=252159&r1=252158&r2=252159&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Thu Nov  5 07:54:50 2015
@@ -410,12 +410,18 @@ struct ThreadState {
 };
 
 #ifndef SANITIZER_GO
+#if SANITIZER_MAC
+ThreadState *cur_thread();
+void cur_thread_finalize();
+#else
 __attribute__((tls_model("initial-exec")))
 extern THREADLOCAL char cur_thread_placeholder[];
 INLINE ThreadState *cur_thread() {
   return reinterpret_cast<ThreadState *>(&cur_thread_placeholder);
 }
-#endif
+INLINE void cur_thread_finalize() { }
+#endif  // SANITIZER_MAC
+#endif  // SANITIZER_GO
 
 class ThreadContext : public ThreadContextBase {
  public:




More information about the llvm-commits mailing list