Index: lib/tsan/rtl/tsan_interceptors_mac.cc =================================================================== --- lib/tsan/rtl/tsan_interceptors_mac.cc +++ lib/tsan/rtl/tsan_interceptors_mac.cc @@ -14,6 +14,7 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_MAC +#define _XOPEN_SOURCE 700 #include "interception/interception.h" #include "tsan_interceptors.h" #include "tsan_interface.h" @@ -23,6 +24,9 @@ #include #include +#include +#include + #if defined(__has_include) && __has_include() #include #endif // #if defined(__has_include) && __has_include() @@ -353,6 +357,35 @@ return result; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +TSAN_INTERCEPTOR(int, swapcontext, ucontext_t *oucp, const ucontext_t *ucp) { + { + SCOPED_INTERCEPTOR_RAW(swapcontext, oucp, ucp); + } + // Bacause of swapcontext() semantics we have no option but to copy its + // impementation here + if (!oucp || !ucp) { + errno = EINVAL; + return -1; + } + ThreadState *thr = cur_thread(); + const int UCF_SWAPPED = 0x80000000; + oucp->uc_onstack &= ~UCF_SWAPPED; + thr->ignore_interceptors++; + int ret = getcontext(oucp); + if (!(oucp->uc_onstack & UCF_SWAPPED)) { + thr->ignore_interceptors--; + if (!ret) { + oucp->uc_onstack |= UCF_SWAPPED; + ret = setcontext(ucp); + } + } + asm(""); // Prevent tailcall + return ret; +} +#pragma clang diagnostic pop + // On macOS, libc++ is always linked dynamically, so intercepting works the // usual way. #define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR Index: lib/tsan/rtl/tsan_interface.cc =================================================================== --- lib/tsan/rtl/tsan_interface.cc +++ lib/tsan/rtl/tsan_interface.cc @@ -125,7 +125,6 @@ *addr = v; } -#if !SANITIZER_MAC && !SANITIZER_ANDROID SANITIZER_INTERFACE_ATTRIBUTE void *__tsan_get_current_fiber() { return cur_thread(); @@ -150,7 +149,6 @@ void __tsan_set_fiber_name(void *fiber, const char *name) { ThreadSetName(static_cast(fiber), name); } -#endif // !SANITIZER_MAC && !SANITIZER_ANDROID } // extern "C" void __tsan_acquire(void *addr) { Index: lib/tsan/rtl/tsan_platform_linux.cc =================================================================== --- lib/tsan/rtl/tsan_platform_linux.cc +++ lib/tsan/rtl/tsan_platform_linux.cc @@ -401,6 +401,10 @@ return thr; } +void set_cur_thread(ThreadState *thr) { + *get_android_tls_ptr() = reinterpret_cast(thr); +} + void cur_thread_finalize() { __sanitizer_sigset_t emptyset; internal_sigfillset(&emptyset); Index: lib/tsan/rtl/tsan_platform_mac.cc =================================================================== --- lib/tsan/rtl/tsan_platform_mac.cc +++ lib/tsan/rtl/tsan_platform_mac.cc @@ -73,22 +73,22 @@ // shadow memory is set up. static uptr main_thread_identity = 0; ALIGNED(64) static char main_thread_state[sizeof(ThreadState)]; +static ThreadState *main_thread_state_loc = (ThreadState *)main_thread_state; -ThreadState **cur_thread_location() { - ThreadState **thread_identity = (ThreadState **)pthread_self(); - return ((uptr)thread_identity == main_thread_identity) ? nullptr - : thread_identity; +static ThreadState **cur_thread_location() { + uptr thread_identity = (uptr)pthread_self(); + if (thread_identity == main_thread_identity || main_thread_identity == 0) + return &main_thread_state_loc; + return (ThreadState **)MemToShadow(thread_identity); } ThreadState *cur_thread() { - ThreadState **thr_state_loc = cur_thread_location(); - if (thr_state_loc == nullptr || main_thread_identity == 0) { - return (ThreadState *)&main_thread_state; - } - ThreadState **fake_tls = (ThreadState **)MemToShadow((uptr)thr_state_loc); - ThreadState *thr = (ThreadState *)SignalSafeGetOrAllocate( - (uptr *)fake_tls, sizeof(ThreadState)); - return thr; + return (ThreadState *)SignalSafeGetOrAllocate( + (uptr *)cur_thread_location(), sizeof(ThreadState)); +} + +void set_cur_thread(ThreadState *thr) { + *cur_thread_location() = thr; } // TODO(kuba.brecka): This is not async-signal-safe. In particular, we call @@ -96,14 +96,13 @@ // handler will try to access the unmapped ThreadState. void cur_thread_finalize() { ThreadState **thr_state_loc = cur_thread_location(); - if (thr_state_loc == nullptr) { + if (thr_state_loc == &main_thread_state_loc) { // Calling dispatch_main() or xpc_main() actually invokes pthread_exit to // exit the main thread. Let's keep the main thread's ThreadState. return; } - ThreadState **fake_tls = (ThreadState **)MemToShadow((uptr)thr_state_loc); - internal_munmap(*fake_tls, sizeof(ThreadState)); - *fake_tls = nullptr; + internal_munmap(*thr_state_loc, sizeof(ThreadState)); + *thr_state_loc = nullptr; } #endif @@ -265,11 +264,11 @@ // The pointer to the ThreadState object is stored in the shadow memory // of the tls. uptr tls_end = tls_addr + tls_size; - ThreadState **thr_state_loc = cur_thread_location(); - if (thr_state_loc == nullptr) { + uptr thread_identity = (uptr)pthread_self(); + if (thread_identity == main_thread_identity) { MemoryRangeImitateWrite(thr, /*pc=*/2, tls_addr, tls_size); } else { - uptr thr_state_start = (uptr)thr_state_loc; + uptr thr_state_start = thread_identity; uptr thr_state_end = thr_state_start + sizeof(uptr); CHECK_GE(thr_state_start, tls_addr); CHECK_LE(thr_state_start, tls_addr + tls_size); Index: lib/tsan/rtl/tsan_rtl.h =================================================================== --- lib/tsan/rtl/tsan_rtl.h +++ lib/tsan/rtl/tsan_rtl.h @@ -464,6 +464,7 @@ #if !SANITIZER_GO #if SANITIZER_MAC || SANITIZER_ANDROID ThreadState *cur_thread(); +void set_cur_thread(ThreadState *thr); void cur_thread_finalize(); INLINE void cur_thread_init() { } #else Index: lib/tsan/rtl/tsan_rtl_thread.cc =================================================================== --- lib/tsan/rtl/tsan_rtl_thread.cc +++ lib/tsan/rtl/tsan_rtl_thread.cc @@ -405,7 +405,7 @@ } } -#if !SANITIZER_MAC && !SANITIZER_ANDROID && !SANITIZER_GO +#if !SANITIZER_GO void FiberSwitchImpl(ThreadState *from, ThreadState *to) { Processor *proc = from->proc(); ProcUnwire(proc, from); Index: test/tsan/fiber_asm.cc =================================================================== --- test/tsan/fiber_asm.cc +++ test/tsan/fiber_asm.cc @@ -1,6 +1,5 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s // REQUIRES: x86_64-target-arch -// UNSUPPORTED: darwin #include "test.h" struct ucontext { @@ -13,8 +12,14 @@ void ucontext_trampoline(); } -__asm__(".global ucontext_do_switch\n" - "ucontext_do_switch:\n\t" +#ifdef __APPLE__ +#define UNDERSCORE "_" +#else +#define UNDERSCORE "" +#endif + +__asm__(".global " UNDERSCORE "ucontext_do_switch\n" + UNDERSCORE "ucontext_do_switch:\n\t" "pushq %rbp\n\t" "pushq %r15\n\t" "pushq %r14\n\t" @@ -31,8 +36,8 @@ "popq %rbp\n\t" "retq"); -__asm__(".global ucontext_trampoline\n" - "ucontext_trampoline:\n\t" +__asm__(".global " UNDERSCORE "ucontext_trampoline\n" + UNDERSCORE "ucontext_trampoline:\n\t" ".cfi_startproc\n\t" ".cfi_undefined rip\n\t" "movq %r12, %rdi\n\t" Index: test/tsan/fiber_from_thread.cc =================================================================== --- test/tsan/fiber_from_thread.cc +++ test/tsan/fiber_from_thread.cc @@ -1,5 +1,8 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: darwin +#ifdef __APPLE__ +#define _XOPEN_SOURCE 700 +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif #include "test.h" #include Index: test/tsan/fiber_longjmp.cc =================================================================== --- test/tsan/fiber_longjmp.cc +++ test/tsan/fiber_longjmp.cc @@ -1,5 +1,8 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: darwin +#ifdef __APPLE__ +#define _XOPEN_SOURCE 700 +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif #include "test.h" #include #include Index: test/tsan/fiber_race.cc =================================================================== --- test/tsan/fiber_race.cc +++ test/tsan/fiber_race.cc @@ -1,5 +1,8 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: darwin +#ifdef __APPLE__ +#define _XOPEN_SOURCE 700 +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif #include "test.h" #include Index: test/tsan/fiber_simple.cc =================================================================== --- test/tsan/fiber_simple.cc +++ test/tsan/fiber_simple.cc @@ -1,5 +1,8 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: darwin +#ifdef __APPLE__ +#define _XOPEN_SOURCE 700 +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif #include "test.h" #include Index: test/tsan/fiber_two_threads.cc =================================================================== --- test/tsan/fiber_two_threads.cc +++ test/tsan/fiber_two_threads.cc @@ -1,5 +1,8 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: darwin +#ifdef __APPLE__ +#define _XOPEN_SOURCE 700 +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif #include "test.h" #include