Skip to content

Commit

Permalink
[tsan] Fix scoping of ScopedInteceptor in libdispatch support
Browse files Browse the repository at this point in the history
Some interceptors in tsan_libdispatch_mac.cc currently wrongly use TSAN_SCOPED_INTERCEPTOR/ScopedInterceptor. Its constructor can start ignoring memory accesses, and the destructor the stops this -- however, e.g. dispatch_sync can call user's code, so the ignoring will extend to user's code as well. This is not expected and we should only limit the scope of ScopedInterceptor to TSan code.  This patch introduces annotations that mark the beginning and ending of a callback into user's code.

Differential Revision: http://reviews.llvm.org/D15419

llvm-svn: 255995
  • Loading branch information
kubamracek committed Dec 18, 2015
1 parent ed23793 commit f9cc9d7
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 0 deletions.
14 changes: 14 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_interceptors.h
Expand Up @@ -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_;
Expand All @@ -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
Expand Down
14 changes: 14 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc
Expand Up @@ -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);
}
Expand All @@ -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) \
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit f9cc9d7

Please sign in to comment.