Index: lib/tsan/rtl/tsan_libdispatch_mac.cc =================================================================== --- lib/tsan/rtl/tsan_libdispatch_mac.cc +++ lib/tsan/rtl/tsan_libdispatch_mac.cc @@ -447,6 +447,20 @@ WRAP(dispatch_apply)(iterations, queue, new_block); } +TSAN_INTERCEPTOR(dispatch_data_t, dispatch_data_create, const void *buffer, + size_t size, dispatch_queue_t q, dispatch_block_t destructor) { + SCOPED_TSAN_INTERCEPTOR(dispatch_data_create, buffer, size, q, destructor); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + dispatch_block_t heap_block = Block_copy(destructor); + 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); + return REAL(dispatch_data_create)(buffer, size, q, ^(void) { + dispatch_callback_wrap(new_context); + }); +} + } // namespace __tsan #endif // SANITIZER_MAC Index: test/tsan/Darwin/gcd-data.mm =================================================================== --- test/tsan/Darwin/gcd-data.mm +++ test/tsan/Darwin/gcd-data.mm @@ -0,0 +1,32 @@ +// RUN: %clang_tsan %s -o %t -framework Foundation +// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s + +#import + +long global; + +int main(int argc, const char *argv[]) { + fprintf(stderr, "Hello world.\n"); + + dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL); + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + + global = 44; + dispatch_data_t data = dispatch_data_create("buffer", 6, q, ^{ + fprintf(stderr, "Data destructor.\n"); + global++; + + dispatch_semaphore_signal(sem); + }); + dispatch_release(data); + data = nil; + + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello world. +// CHECK: Data destructor. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: Done.