Index: lib/tsan/rtl/tsan_interceptors_mac.cc =================================================================== --- lib/tsan/rtl/tsan_interceptors_mac.cc +++ lib/tsan/rtl/tsan_interceptors_mac.cc @@ -273,6 +273,26 @@ (connection, message, replyq, new_handler); } +// On macOS, libc++ is always linked dynamically, so intercepting works the +// usual way. +#define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR + +// This adds a libc++ interceptor for: +// void __shared_weak_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 implements the mo_acq_rel semantics of the +// atomic decrement that is used to check when the object's refcount drops to 0. +STDCXX_INTERCEPTOR(void, _ZNSt3__119__shared_weak_count16__release_sharedEv, + void *o) { + SCOPED_INTERCEPTOR_RAW(_ZNSt3__119__shared_weak_count16__release_sharedEv, o); + Acquire(thr, pc, (uptr)o); + Release(thr, pc, (uptr)o); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + REAL(_ZNSt3__119__shared_weak_count16__release_sharedEv)(o); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); +} + } // namespace __tsan #endif // SANITIZER_MAC Index: test/tsan/Darwin/libcxx-shared-ptr.mm =================================================================== --- test/tsan/Darwin/libcxx-shared-ptr.mm +++ test/tsan/Darwin/libcxx-shared-ptr.mm @@ -0,0 +1,48 @@ +// RUN: %clang_tsan %s -o %t -framework Foundation +// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s + +#import + +#import + +#import "../test.h" + +long my_global; + +struct MyStruct { + void setGlobal() { + my_global = 42; + } + ~MyStruct() { + my_global = 43; + } +}; + +int main(int argc, const char *argv[]) { + fprintf(stderr, "Hello world.\n"); + print_address("addr=", 1, &my_global); + barrier_init(&barrier, 2); + + std::shared_ptr shared(new MyStruct()); + + dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + + std::weak_ptr weak(shared); + + dispatch_async(q, ^{ + std::shared_ptr strong = weak.lock(); + if (!strong) exit(1); + + strong->setGlobal(); + barrier_wait(&barrier); + }); + + barrier_wait(&barrier); + shared.reset(); + + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello world. +// CHECK: Done. +// CHECK-NOT: WARNING: ThreadSanitizer