diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc index b157de21a780..62c96cb42047 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc @@ -295,6 +295,20 @@ ScopedInterceptor::~ScopedInterceptor() { } } +void ScopedInterceptor::UserCallbackStart() { + if (in_ignored_lib_) { + thr_->in_ignored_lib = false; + ThreadIgnoreEnd(thr_, pc_); + } +} + +void ScopedInterceptor::UserCallbackEnd() { + if (in_ignored_lib_) { + thr_->in_ignored_lib = true; + ThreadIgnoreBegin(thr_, pc_); + } +} + #define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func) #if SANITIZER_FREEBSD # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func) diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.h b/compiler-rt/lib/tsan/rtl/tsan_interceptors.h index 451e8645fc82..d831620cfafe 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.h +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.h @@ -10,6 +10,8 @@ class ScopedInterceptor { public: ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc); ~ScopedInterceptor(); + void UserCallbackStart(); + void UserCallbackEnd(); private: ThreadState *const thr_; const uptr pc_; @@ -36,6 +38,12 @@ class ScopedInterceptor { return REAL(func)(__VA_ARGS__); \ /**/ +#define SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START() \ + si.UserCallbackStart(); + +#define SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END() \ + si.UserCallbackEnd(); + #define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__) #if SANITIZER_FREEBSD diff --git a/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc b/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc index 391b3f67bad0..617dc91b33d0 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc @@ -94,7 +94,9 @@ static void dispatch_callback_wrap_acquire(void *param) { // In serial queues, work items can be executed on different threads, we need // to explicitly synchronize on the queue itself. if (IsQueueSerial(context->queue)) Acquire(thr, pc, (uptr)context->queue); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); context->orig_work(context->orig_context); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); if (IsQueueSerial(context->queue)) Release(thr, pc, (uptr)context->queue); user_free(thr, pc, context); } @@ -108,11 +110,15 @@ static void invoke_and_release_block(void *param) { #define DISPATCH_INTERCEPT_B(name) \ TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, dispatch_block_t block) { \ SCOPED_TSAN_INTERCEPTOR(name, q, block); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ dispatch_block_t heap_block = Block_copy(block); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ tsan_block_context_t *new_context = \ AllocContext(thr, pc, q, heap_block, &invoke_and_release_block); \ Release(thr, pc, (uptr)new_context); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ REAL(name##_f)(q, new_context, dispatch_callback_wrap_acquire); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ } #define DISPATCH_INTERCEPT_F(name) \ @@ -122,7 +128,9 @@ static void invoke_and_release_block(void *param) { tsan_block_context_t *new_context = \ AllocContext(thr, pc, q, context, work); \ Release(thr, pc, (uptr)new_context); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ REAL(name)(q, new_context, dispatch_callback_wrap_acquire); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ } // We wrap dispatch_async, dispatch_sync and friends where we allocate a new @@ -158,7 +166,9 @@ TSAN_INTERCEPTOR(void, dispatch_once, dispatch_once_t *predicate, u32 v = atomic_load(a, memory_order_acquire); if (v == 0 && atomic_compare_exchange_strong(a, &v, 1, memory_order_relaxed)) { + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); block(); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); Release(thr, pc, (uptr)a); atomic_store(a, 2, memory_order_release); } else { @@ -174,9 +184,11 @@ TSAN_INTERCEPTOR(void, dispatch_once, dispatch_once_t *predicate, TSAN_INTERCEPTOR(void, dispatch_once_f, dispatch_once_t *predicate, void *context, dispatch_function_t function) { SCOPED_TSAN_INTERCEPTOR(dispatch_once_f, predicate, context, function); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); WRAP(dispatch_once)(predicate, ^(void) { function(context); }); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); } TSAN_INTERCEPTOR(long_t, dispatch_semaphore_signal, @@ -236,7 +248,9 @@ TSAN_INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, TSAN_INTERCEPTOR(void, dispatch_group_notify, dispatch_group_t group, dispatch_queue_t q, dispatch_block_t block) { SCOPED_TSAN_INTERCEPTOR(dispatch_group_notify, group, q, block); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); dispatch_block_t heap_block = Block_copy(block); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); tsan_block_context_t *new_context = AllocContext(thr, pc, q, heap_block, &invoke_and_release_block); new_context->object_to_acquire = (uptr)group;