[compiler-rt] r289831 - [tsan] Add interceptor for libcxx __shared_count::__release_shared()

Kuba Mracek via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 15 08:45:28 PST 2016


Author: kuba.brecka
Date: Thu Dec 15 10:45:28 2016
New Revision: 289831

URL: http://llvm.org/viewvc/llvm-project?rev=289831&view=rev
Log:
[tsan] Add interceptor for libcxx __shared_count::__release_shared()

We already have an interceptor for __shared_weak_count::__release_shared, this patch handles __shared_count::__release_shared in the same way. This should get rid of TSan false positives when using std::future.

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


Added:
    compiler-rt/trunk/test/tsan/Darwin/libcxx-future.mm
Modified:
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc?rev=289831&r1=289830&r2=289831&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc Thu Dec 15 10:45:28 2016
@@ -297,18 +297,20 @@ struct fake_shared_weak_count {
 };
 }  // namespace
 
-// This adds a libc++ interceptor for:
+// The following code adds libc++ interceptors for:
 //     void __shared_weak_count::__release_shared() _NOEXCEPT;
+//     bool __shared_count::__release_shared() _NOEXCEPT;
 // Shared and weak pointers in C++ maintain reference counts via atomics in
 // libc++.dylib, which are TSan-invisible, and this leads to false positives in
-// destructor code.  This interceptor re-implements the whole function so that
+// destructor code. These interceptors re-implements the whole functions so that
 // the mo_acq_rel semantics of the atomic decrement are visible.
 //
-// Unfortunately, this interceptor cannot simply Acquire/Release some sync
+// Unfortunately, the interceptors cannot simply Acquire/Release some sync
 // object and call the original function, because it would have a race between
 // the sync and the destruction of the object.  Calling both under a lock will
 // not work because the destructor can invoke this interceptor again (and even
 // in a different thread, so recursive locks don't help).
+
 STDCXX_INTERCEPTOR(void, _ZNSt3__119__shared_weak_count16__release_sharedEv,
                    fake_shared_weak_count *o) {
   if (!flags()->shared_ptr_interceptor)
@@ -327,6 +329,20 @@ STDCXX_INTERCEPTOR(void, _ZNSt3__119__sh
   }
 }
 
+STDCXX_INTERCEPTOR(bool, _ZNSt3__114__shared_count16__release_sharedEv,
+                   fake_shared_weak_count *o) {
+  if (!flags()->shared_ptr_interceptor)
+    return REAL(_ZNSt3__114__shared_count16__release_sharedEv)(o);
+
+  SCOPED_TSAN_INTERCEPTOR(_ZNSt3__114__shared_count16__release_sharedEv, o);
+  if (__tsan_atomic64_fetch_add(&o->shared_owners, -1, mo_release) == 0) {
+    Acquire(thr, pc, (uptr)&o->shared_owners);
+    o->on_zero_shared();
+    return true;
+  }
+  return false;
+}
+
 namespace {
 struct call_once_callback_args {
   void (*orig_func)(void *arg);

Added: compiler-rt/trunk/test/tsan/Darwin/libcxx-future.mm
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/Darwin/libcxx-future.mm?rev=289831&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/Darwin/libcxx-future.mm (added)
+++ compiler-rt/trunk/test/tsan/Darwin/libcxx-future.mm Thu Dec 15 10:45:28 2016
@@ -0,0 +1,30 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#include <iostream>
+#include <future>
+#include <vector>
+
+int main(int argc, const char *argv[]) {
+  fprintf(stderr, "Hello world.\n");
+
+  auto my_task = [] { return 42; };
+
+  std::vector<std::thread> threads;
+
+  for (int i = 0; i < 1000; i++) {
+    std::packaged_task<int(void)> task(my_task);
+    std::future<int> future = task.get_future();
+    threads.push_back(std::thread(std::move(task)));
+  }
+
+  for (auto &t : threads) {
+    t.join();
+  }
+
+  fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.




More information about the llvm-commits mailing list