Fix a deadlock in __cxa_guard_abort in tsan
authorMatt Kulukundis <matt.fowles@gmail.com>
Mon, 15 Nov 2021 09:31:19 +0000 (10:31 +0100)
committerDmitry Vyukov <dvyukov@google.com>
Mon, 15 Nov 2021 09:39:08 +0000 (10:39 +0100)
hat tip: @The_Whole_Daisy for helping to isolate

Reviewed By: dvyukov, fowles

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

compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
compiler-rt/test/tsan/static_init7.cpp [new file with mode: 0644]

index 9a85ee0..9b62b20 100644 (file)
@@ -880,10 +880,11 @@ static int guard_acquire(ThreadState *thr, uptr pc, atomic_uint32_t *g,
   }
 }
 
-static void guard_release(ThreadState *thr, uptr pc, atomic_uint32_t *g) {
+static void guard_release(ThreadState *thr, uptr pc, atomic_uint32_t *g,
+                          u32 v) {
   if (!thr->in_ignored_lib)
     Release(thr, pc, (uptr)g);
-  u32 old = atomic_exchange(g, kGuardDone, memory_order_release);
+  u32 old = atomic_exchange(g, v, memory_order_release);
   if (old & kGuardWaiter)
     FutexWake(g, 1 << 30);
 }
@@ -913,12 +914,12 @@ STDCXX_INTERCEPTOR(int, __cxa_guard_acquire, atomic_uint32_t *g) {
 
 STDCXX_INTERCEPTOR(void, __cxa_guard_release, atomic_uint32_t *g) {
   SCOPED_INTERCEPTOR_RAW(__cxa_guard_release, g);
-  guard_release(thr, pc, g);
+  guard_release(thr, pc, g, kGuardDone);
 }
 
 STDCXX_INTERCEPTOR(void, __cxa_guard_abort, atomic_uint32_t *g) {
   SCOPED_INTERCEPTOR_RAW(__cxa_guard_abort, g);
-  atomic_store(g, kGuardInit, memory_order_relaxed);
+  guard_release(thr, pc, g, kGuardInit);
 }
 
 namespace __tsan {
@@ -1515,7 +1516,7 @@ TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
   // result in crashes due to too little stack space.
   if (guard_acquire(thr, pc, a, !SANITIZER_MAC)) {
     (*f)();
-    guard_release(thr, pc, a);
+    guard_release(thr, pc, a, kGuardDone);
   }
   return 0;
 }
diff --git a/compiler-rt/test/tsan/static_init7.cpp b/compiler-rt/test/tsan/static_init7.cpp
new file mode 100644 (file)
index 0000000..7d48302
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct P {
+  int x;
+  int y;
+};
+
+int Helper() {
+  try {
+    static int i = []() {
+      throw P{};
+      return 1;
+    }();
+    return i;
+  } catch (P) {
+    return 0;
+  }
+}
+
+void *Thread(void *x) {
+  for (int i = 0; i < 1000; ++i) {
+    Helper();
+  }
+  return 0;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], 0, Thread, 0);
+  pthread_create(&t[1], 0, Thread, 0);
+  pthread_join(t[0], 0);
+  pthread_join(t[1], 0);
+  fprintf(stderr, "PASS\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race