tsan: fix handling of pthread_detach
authorDmitry Vyukov <dvyukov@google.com>
Mon, 20 Apr 2015 10:35:10 +0000 (10:35 +0000)
committerDmitry Vyukov <dvyukov@google.com>
Mon, 20 Apr 2015 10:35:10 +0000 (10:35 +0000)
Fixes https://llvm.org/bugs/show_bug.cgi?id=23235

If pthread_create is followed by pthread_detach,
the new thread may not acquire synchronize with
the parent thread.

llvm-svn: 235293

compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
compiler-rt/test/tsan/thread_detach2.c [new file with mode: 0644]

index df4d5fd..24749ca 100644 (file)
@@ -935,8 +935,8 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
     ThreadIgnoreEnd(thr, 0);
     while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
       pthread_yield();
-    atomic_store(&p->tid, 0, memory_order_release);
     ThreadStart(thr, tid, GetTid());
+    atomic_store(&p->tid, 0, memory_order_release);
   }
   void *res = callback(param);
   // Prevent the callback from being tail called,
@@ -984,6 +984,13 @@ TSAN_INTERCEPTOR(int, pthread_create,
   if (res == 0) {
     int tid = ThreadCreate(thr, pc, *(uptr*)th, detached);
     CHECK_NE(tid, 0);
+    // Synchronization on p.tid serves two purposes:
+    // 1. ThreadCreate must finish before the new thread starts.
+    //    Otherwise the new thread can call pthread_detach, but the pthread_t
+    //    identifier is not yet registered in ThreadRegistry by ThreadCreate.
+    // 2. ThreadStart must finish before this thread continues.
+    //    Otherwise, this thread can call pthread_detach and reset thr->sync
+    //    before the new thread got a chance to acquire from it in ThreadStart.
     atomic_store(&p.tid, tid, memory_order_release);
     while (atomic_load(&p.tid, memory_order_acquire) != 0)
       pthread_yield();
diff --git a/compiler-rt/test/tsan/thread_detach2.c b/compiler-rt/test/tsan/thread_detach2.c
new file mode 100644 (file)
index 0000000..8133980
--- /dev/null
@@ -0,0 +1,28 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+
+// Test for https://llvm.org/bugs/show_bug.cgi?id=23235
+// The bug was that synchronization between thread creation and thread start
+// is not established if pthread_create is followed by pthread_detach.
+
+int x;
+
+void *Thread(void *a) {
+  x = 42;
+  barrier_wait(&barrier);
+  return 0;
+}
+
+int main() {
+  barrier_init(&barrier, 2);
+  pthread_t t;
+  x = 43;
+  pthread_create(&t, 0, Thread, 0);
+  pthread_detach(t);
+  barrier_wait(&barrier);
+  printf("PASS\n");
+  return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: PASS