From faef7d034a9ec6cb757137adce8e8670ec6c2d7b Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Tue, 21 Aug 2018 21:24:22 +0000 Subject: [PATCH] [tsan] Avoid calling Block_copy in the "sync" GCD interceptors The synchronous dispatch functions in GCD (dispatch_sync, dispatch_barrier_sync), don't make a copy of the passed block. To maintain binary compatibility, we should avoid doing that as well in TSan, as there's no reason to do that. The synchronous dispatch functions will not return before the block is actually executed. rdar://problem/42242579 Differential Revision: https://reviews.llvm.org/D50920 llvm-svn: 340342 --- compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc | 5 +--- .../test/tsan/Darwin/gcd-sync-block-copy.mm | 34 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 compiler-rt/test/tsan/Darwin/gcd-sync-block-copy.mm diff --git a/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc b/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc index d6c1ca6..23c4380 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc @@ -185,11 +185,8 @@ static void invoke_and_release_block(void *param) { TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, \ DISPATCH_NOESCAPE 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 = { \ - q, heap_block, &invoke_and_release_block, false, true, barrier, 0}; \ + q, block, &invoke_and_release_block, false, true, barrier, 0}; \ Release(thr, pc, (uptr)&new_context); \ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ REAL(name##_f)(q, &new_context, dispatch_callback_wrap); \ diff --git a/compiler-rt/test/tsan/Darwin/gcd-sync-block-copy.mm b/compiler-rt/test/tsan/Darwin/gcd-sync-block-copy.mm new file mode 100644 index 0000000..87658d7 --- /dev/null +++ b/compiler-rt/test/tsan/Darwin/gcd-sync-block-copy.mm @@ -0,0 +1,34 @@ +// This test verifies that dispatch_sync() doesn't actually copy the block under TSan (without TSan, it doesn't). + +// RUN: %clang_tsan -fno-sanitize=thread %s -o %t_no_tsan -framework Foundation +// RUN: %run %t_no_tsan 2>&1 | FileCheck %s + +// RUN: %clang_tsan %s -o %t_with_tsan -framework Foundation +// RUN: %run %t_with_tsan 2>&1 | FileCheck %s + +#import + +@interface MyClass : NSObject +@end + +@implementation MyClass +- (instancetype)retain { + // Copying the dispatch_sync'd block below will increment the retain count of + // this object. Abort if that happens. + abort(); +} +@end + +int main(int argc, const char* argv[]) { + dispatch_queue_t q = dispatch_queue_create("my.queue", NULL); + id object = [[MyClass alloc] init]; + dispatch_sync(q, ^{ + NSLog(@"%@", object); + }); + [object release]; + NSLog(@"Done."); + return 0; +} + +// CHECK: Done. +// CHECK-NOT: WARNING: ThreadSanitizer -- 2.7.4