[compiler-rt] r280920 - [tsan] Support C++11 call_once in TSan on Darwin

Kuba Brecka via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 8 03:15:21 PDT 2016


Author: kuba.brecka
Date: Thu Sep  8 05:15:20 2016
New Revision: 280920

URL: http://llvm.org/viewvc/llvm-project?rev=280920&view=rev
Log:
[tsan] Support C++11 call_once in TSan on Darwin

This patch adds a wrapper for call_once, which uses an already-compiled helper __call_once with an atomic release which is invisible to TSan. To avoid false positives, the interceptor performs an explicit atomic release in the callback wrapper.

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


Added:
    compiler-rt/trunk/test/tsan/Darwin/libcxx-call-once.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=280920&r1=280919&r2=280920&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc Thu Sep  8 05:15:20 2016
@@ -327,6 +327,33 @@ STDCXX_INTERCEPTOR(void, _ZNSt3__119__sh
   }
 }
 
+namespace {
+struct call_once_callback_args {
+  void (*orig_func)(void *arg);
+  void *orig_arg;
+  void *flag;
+};
+
+void call_once_callback_wrapper(void *arg) {
+  call_once_callback_args *new_args = (call_once_callback_args *)arg;
+  new_args->orig_func(new_args->orig_arg);
+  __tsan_release(new_args->flag);
+}
+}  // namespace
+
+// This adds a libc++ interceptor for:
+//     void __call_once(volatile unsigned long&, void*, void(*)(void*));
+// C++11 call_once is implemented via an internal function __call_once which is
+// inside libc++.dylib, and the atomic release store inside it is thus
+// TSan-invisible. To avoid false positives, this interceptor wraps the callback
+// function and performs an explicit Release after the user code has run.
+STDCXX_INTERCEPTOR(void, _ZNSt3__111__call_onceERVmPvPFvS2_E, void *flag,
+                   void *arg, void (*func)(void *arg)) {
+  call_once_callback_args new_args = {func, arg, flag};
+  REAL(_ZNSt3__111__call_onceERVmPvPFvS2_E)(flag, &new_args,
+                                            call_once_callback_wrapper);
+}
+
 }  // namespace __tsan
 
 #endif  // SANITIZER_MAC

Added: compiler-rt/trunk/test/tsan/Darwin/libcxx-call-once.mm
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/Darwin/libcxx-call-once.mm?rev=280920&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/Darwin/libcxx-call-once.mm (added)
+++ compiler-rt/trunk/test/tsan/Darwin/libcxx-call-once.mm Thu Sep  8 05:15:20 2016
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation -std=c++11
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import <iostream>
+#import <thread>
+
+long my_global;
+std::once_flag once_token;
+
+void thread_func() {
+  std::call_once(once_token, [] {
+    my_global = 17;
+  });
+
+  long val = my_global;
+  fprintf(stderr, "my_global = %ld\n", val);
+}
+
+int main(int argc, const char *argv[]) {
+  fprintf(stderr, "Hello world.\n");
+
+  std::thread t1(thread_func);
+  std::thread t2(thread_func);
+  t1.join();
+  t2.join();
+
+  fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.




More information about the llvm-commits mailing list