[compiler-rt] r274619 - [tsan] Fix false positives with GCD dispatch_source_*

Kuba Brecka via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 6 04:02:52 PDT 2016


Author: kuba.brecka
Date: Wed Jul  6 06:02:49 2016
New Revision: 274619

URL: http://llvm.org/viewvc/llvm-project?rev=274619&view=rev
Log:
[tsan] Fix false positives with GCD dispatch_source_*

We already have interceptors for dispatch_source API (e.g. dispatch_source_set_event_handler), but they currently only handle submission synchronization. We also need to synchronize based on the target queue (serial, concurrent), in other words, we need to use dispatch_callback_wrap. This patch implements that.

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


Added:
    compiler-rt/trunk/test/tsan/Darwin/gcd-source-serial.mm
Modified:
    compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc?rev=274619&r1=274618&r2=274619&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc Wed Jul  6 06:02:49 2016
@@ -67,6 +67,15 @@ static bool IsQueueSerial(dispatch_queue
   return width == 1;
 }
 
+static dispatch_queue_t GetTargetQueueFromSource(dispatch_source_t source) {
+  CHECK_EQ(dispatch_queue_offsets.dqo_target_queue_size, 8);
+  dispatch_queue_t target_queue =
+      *(dispatch_queue_t *)(((uptr)source) +
+                            dispatch_queue_offsets.dqo_target_queue);
+  CHECK_NE(target_queue, 0);
+  return target_queue;
+}
+
 static tsan_block_context_t *AllocContext(ThreadState *thr, uptr pc,
                                           dispatch_queue_t queue,
                                           void *orig_context,
@@ -106,6 +115,11 @@ static void dispatch_callback_wrap(void
   if (context->free_context_in_callback) user_free(thr, pc, context);
 }
 
+static void invoke_block(void *param) {
+  dispatch_block_t block = (dispatch_block_t)param;
+  block();
+}
+
 static void invoke_and_release_block(void *param) {
   dispatch_block_t block = (dispatch_block_t)param;
   block();
@@ -342,15 +356,17 @@ TSAN_INTERCEPTOR(void, dispatch_source_s
   SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_event_handler, source, handler);
   if (handler == nullptr)
     return REAL(dispatch_source_set_event_handler)(source, nullptr);
-  dispatch_block_t new_handler = ^(void) {
-    {
-      SCOPED_INTERCEPTOR_RAW(dispatch_source_set_event_handler_callback);
-      Acquire(thr, pc, (uptr)source);
-    }
-    handler();
-  };
-  Release(thr, pc, (uptr)source);
+  dispatch_queue_t q = GetTargetQueueFromSource(source);
+  __block tsan_block_context_t new_context = {
+      q, handler, &invoke_block, false, false, false };
+  dispatch_block_t new_handler = Block_copy(^(void) {
+    new_context.orig_context = handler;  // To explicitly capture "handler".
+    dispatch_callback_wrap(&new_context);
+  });
+  uptr submit_sync = (uptr)&new_context;
+  Release(thr, pc, submit_sync);
   REAL(dispatch_source_set_event_handler)(source, new_handler);
+  Block_release(new_handler);
 }
 
 TSAN_INTERCEPTOR(void, dispatch_source_set_event_handler_f,
@@ -369,15 +385,17 @@ TSAN_INTERCEPTOR(void, dispatch_source_s
   SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_cancel_handler, source, handler);
   if (handler == nullptr)
     return REAL(dispatch_source_set_cancel_handler)(source, nullptr);
-  dispatch_block_t new_handler = ^(void) {
-    {
-      SCOPED_INTERCEPTOR_RAW(dispatch_source_set_cancel_handler_callback);
-      Acquire(thr, pc, (uptr)source);
-    }
-    handler();
-  };
-  Release(thr, pc, (uptr)source);
+  dispatch_queue_t q = GetTargetQueueFromSource(source);
+  __block tsan_block_context_t new_context = {
+      q, handler, &invoke_block, false, false, false };
+  dispatch_block_t new_handler = Block_copy(^(void) {
+    new_context.orig_context = handler;  // To explicitly capture "handler".
+    dispatch_callback_wrap(&new_context);
+  });
+  uptr submit_sync = (uptr)&new_context;
+  Release(thr, pc, submit_sync);
   REAL(dispatch_source_set_cancel_handler)(source, new_handler);
+  Block_release(new_handler);
 }
 
 TSAN_INTERCEPTOR(void, dispatch_source_set_cancel_handler_f,
@@ -398,15 +416,17 @@ TSAN_INTERCEPTOR(void, dispatch_source_s
                           handler);
   if (handler == nullptr)
     return REAL(dispatch_source_set_registration_handler)(source, nullptr);
-  dispatch_block_t new_handler = ^(void) {
-    {
-      SCOPED_INTERCEPTOR_RAW(dispatch_source_set_registration_handler_callback);
-      Acquire(thr, pc, (uptr)source);
-    }
-    handler();
-  };
-  Release(thr, pc, (uptr)source);
+  dispatch_queue_t q = GetTargetQueueFromSource(source);
+  __block tsan_block_context_t new_context = {
+      q, handler, &invoke_block, false, false, false };
+  dispatch_block_t new_handler = Block_copy(^(void) {
+    new_context.orig_context = handler;  // To explicitly capture "handler".
+    dispatch_callback_wrap(&new_context);
+  });
+  uptr submit_sync = (uptr)&new_context;
+  Release(thr, pc, submit_sync);
   REAL(dispatch_source_set_registration_handler)(source, new_handler);
+  Block_release(new_handler);
 }
 
 TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler_f,

Added: compiler-rt/trunk/test/tsan/Darwin/gcd-source-serial.mm
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/Darwin/gcd-source-serial.mm?rev=274619&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/Darwin/gcd-source-serial.mm (added)
+++ compiler-rt/trunk/test/tsan/Darwin/gcd-source-serial.mm Wed Jul  6 06:02:49 2016
@@ -0,0 +1,33 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+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);
+  dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, q);
+  long long interval_ms = 10;
+  dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 0), interval_ms * NSEC_PER_MSEC, 0);
+  dispatch_source_set_event_handler(timer, ^{
+    fprintf(stderr, "timer\n");
+    global++;
+
+    if (global > 50) {
+      dispatch_semaphore_signal(sem);
+    }
+  });
+  dispatch_resume(timer);
+
+  dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+  fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.




More information about the llvm-commits mailing list