Index: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc =================================================================== --- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc +++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc @@ -20,8 +20,10 @@ #include "tsan_interface_ann.h" #include "sanitizer_common/sanitizer_addrhashmap.h" +#include #include #include +#include #if defined(__has_include) && __has_include() #include @@ -29,6 +31,11 @@ typedef long long_t; // NOLINT +extern "C" { +int getcontext(ucontext_t *ucp) __attribute__((returns_twice)); +int setcontext(const ucontext_t *ucp); +} + namespace __tsan { // The non-barrier versions of OSAtomic* functions are semantically mo_relaxed, @@ -353,6 +360,31 @@ return result; } +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); + } + } + return ret; +} + // On macOS, libc++ is always linked dynamically, so intercepting works the // usual way. #define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR Index: compiler-rt/trunk/lib/tsan/rtl/tsan_interface.cc =================================================================== --- compiler-rt/trunk/lib/tsan/rtl/tsan_interface.cc +++ compiler-rt/trunk/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: compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc =================================================================== --- compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc +++ compiler-rt/trunk/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: compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc =================================================================== --- compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc +++ compiler-rt/trunk/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: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h =================================================================== --- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h +++ compiler-rt/trunk/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: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc =================================================================== --- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc +++ compiler-rt/trunk/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: compiler-rt/trunk/test/lsan/TestCases/swapcontext.cc =================================================================== --- compiler-rt/trunk/test/lsan/TestCases/swapcontext.cc +++ compiler-rt/trunk/test/lsan/TestCases/swapcontext.cc @@ -6,13 +6,8 @@ // RUN: %env_lsan_opts= not %run %t foo 2>&1 | FileCheck %s // UNSUPPORTED: arm,powerpc64 +#include "sanitizer_common/sanitizer_ucontext.h" #include -#if defined(__APPLE__) -// Note: ucontext.h is deprecated on OSX, so this test may stop working -// someday. We define _XOPEN_SOURCE to keep using ucontext.h for now. -#define _XOPEN_SOURCE 1 -#endif -#include #include const int kStackSize = 1 << 20; Index: compiler-rt/trunk/test/sanitizer_common/sanitizer_ucontext.h =================================================================== --- compiler-rt/trunk/test/sanitizer_common/sanitizer_ucontext.h +++ compiler-rt/trunk/test/sanitizer_common/sanitizer_ucontext.h @@ -0,0 +1,11 @@ +#ifdef __APPLE__ +// ucontext.h is deprecated on macOS, so tests that include it may stop working +// someday. We define _XOPEN_SOURCE to keep using ucontext.h for now. +#ifdef _STRUCT_UCONTEXT +#error incomplete ucontext_t already defined, change #include order +#endif +#define _XOPEN_SOURCE 700 +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + +#include Index: compiler-rt/trunk/test/tsan/fiber_asm.cc =================================================================== --- compiler-rt/trunk/test/tsan/fiber_asm.cc +++ compiler-rt/trunk/test/tsan/fiber_asm.cc @@ -1,6 +1,6 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s // REQUIRES: x86_64-target-arch -// UNSUPPORTED: darwin +// UNSUPPORTED: tvos, watchos #include "test.h" struct ucontext { @@ -13,8 +13,8 @@ void ucontext_trampoline(); } -__asm__(".global ucontext_do_switch\n" - "ucontext_do_switch:\n\t" +__asm__(".global " ASM_SYMBOL(ucontext_do_switch) "\n" + ASM_SYMBOL(ucontext_do_switch) ":\n\t" "pushq %rbp\n\t" "pushq %r15\n\t" "pushq %r14\n\t" @@ -31,8 +31,8 @@ "popq %rbp\n\t" "retq"); -__asm__(".global ucontext_trampoline\n" - "ucontext_trampoline:\n\t" +__asm__(".global " ASM_SYMBOL(ucontext_trampoline) "\n" + ASM_SYMBOL(ucontext_trampoline) ":\n\t" ".cfi_startproc\n\t" ".cfi_undefined rip\n\t" "movq %r12, %rdi\n\t" Index: compiler-rt/trunk/test/tsan/fiber_from_thread.cc =================================================================== --- compiler-rt/trunk/test/tsan/fiber_from_thread.cc +++ compiler-rt/trunk/test/tsan/fiber_from_thread.cc @@ -1,7 +1,7 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: darwin +// UNSUPPORTED: tvos, watchos +#include "sanitizer_common/sanitizer_ucontext.h" #include "test.h" -#include char stack[64 * 1024] __attribute__((aligned(16))); Index: compiler-rt/trunk/test/tsan/fiber_longjmp.cc =================================================================== --- compiler-rt/trunk/test/tsan/fiber_longjmp.cc +++ compiler-rt/trunk/test/tsan/fiber_longjmp.cc @@ -1,8 +1,8 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: darwin +// UNSUPPORTED: tvos, watchos +#include "sanitizer_common/sanitizer_ucontext.h" #include "test.h" #include -#include char stack[64 * 1024] __attribute__((aligned(16))); Index: compiler-rt/trunk/test/tsan/fiber_race.cc =================================================================== --- compiler-rt/trunk/test/tsan/fiber_race.cc +++ compiler-rt/trunk/test/tsan/fiber_race.cc @@ -1,7 +1,7 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: darwin +// UNSUPPORTED: tvos, watchos +#include "sanitizer_common/sanitizer_ucontext.h" #include "test.h" -#include char stack[64 * 1024] __attribute__((aligned(16))); Index: compiler-rt/trunk/test/tsan/fiber_simple.cc =================================================================== --- compiler-rt/trunk/test/tsan/fiber_simple.cc +++ compiler-rt/trunk/test/tsan/fiber_simple.cc @@ -1,7 +1,7 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: darwin +// UNSUPPORTED: tvos, watchos +#include "sanitizer_common/sanitizer_ucontext.h" #include "test.h" -#include char stack[64 * 1024] __attribute__((aligned(16))); Index: compiler-rt/trunk/test/tsan/fiber_two_threads.cc =================================================================== --- compiler-rt/trunk/test/tsan/fiber_two_threads.cc +++ compiler-rt/trunk/test/tsan/fiber_two_threads.cc @@ -1,7 +1,7 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: darwin +// UNSUPPORTED: tvos, watchos +#include "sanitizer_common/sanitizer_ucontext.h" #include "test.h" -#include char stack[64 * 1024] __attribute__((aligned(16))); Index: compiler-rt/trunk/test/tsan/test.h =================================================================== --- compiler-rt/trunk/test/tsan/test.h +++ compiler-rt/trunk/test/tsan/test.h @@ -89,3 +89,9 @@ AnnotateRWLockAcquired(__FILE__, __LINE__, m, is_w) #define ANNOTATE_RWLOCK_RELEASED(m, is_w) \ AnnotateRWLockReleased(__FILE__, __LINE__, m, is_w) + +#ifdef __APPLE__ +#define ASM_SYMBOL(symbol) "_" #symbol +#else +#define ASM_SYMBOL(symbol) #symbol +#endif