aboutsummaryrefslogtreecommitdiff
path: root/test/tsan/Darwin
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-07-23 20:45:36 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-07-23 20:45:36 +0000
commit6f08730ec5f639f05f2f15354171e4a3c9af9dc1 (patch)
tree7374e9d4448083010ada98d17976199c7e945d47 /test/tsan/Darwin
parentc003a57e2e4a1ad9be0338806bc1038b6987155f (diff)
downloadsrc-6f08730ec5f639f05f2f15354171e4a3c9af9dc1.tar.gz
src-6f08730ec5f639f05f2f15354171e4a3c9af9dc1.zip
Vendor import of compiler-rt release_39 branch r276489:vendor/compiler-rt/compiler-rt-release_39-r276489
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=303235 svn path=/vendor/compiler-rt/compiler-rt-release_39-r276489/; revision=303236; tag=vendor/compiler-rt/compiler-rt-release_39-r276489
Diffstat (limited to 'test/tsan/Darwin')
-rw-r--r--test/tsan/Darwin/dispatch_main.mm38
-rw-r--r--test/tsan/Darwin/dispatch_once_deadlock.mm41
-rw-r--r--test/tsan/Darwin/dlopen.cc41
-rw-r--r--test/tsan/Darwin/gcd-after.mm41
-rw-r--r--test/tsan/Darwin/gcd-apply-race.mm26
-rw-r--r--test/tsan/Darwin/gcd-apply.mm44
-rw-r--r--test/tsan/Darwin/gcd-async-norace.mm2
-rw-r--r--test/tsan/Darwin/gcd-async-race.mm6
-rw-r--r--test/tsan/Darwin/gcd-barrier-race.mm48
-rw-r--r--test/tsan/Darwin/gcd-barrier.mm49
-rw-r--r--test/tsan/Darwin/gcd-blocks.mm34
-rw-r--r--test/tsan/Darwin/gcd-data.mm36
-rw-r--r--test/tsan/Darwin/gcd-fd.mm60
-rw-r--r--test/tsan/Darwin/gcd-groups-destructor.mm43
-rw-r--r--test/tsan/Darwin/gcd-groups-leave.mm56
-rw-r--r--test/tsan/Darwin/gcd-groups-norace.mm2
-rw-r--r--test/tsan/Darwin/gcd-groups-stress.mm4
-rw-r--r--test/tsan/Darwin/gcd-io-barrier-race.mm55
-rw-r--r--test/tsan/Darwin/gcd-io-barrier.mm48
-rw-r--r--test/tsan/Darwin/gcd-io-cleanup.mm56
-rw-r--r--test/tsan/Darwin/gcd-io-race.mm56
-rw-r--r--test/tsan/Darwin/gcd-io.mm117
-rw-r--r--test/tsan/Darwin/gcd-once.mm2
-rw-r--r--test/tsan/Darwin/gcd-semaphore-norace.mm2
-rw-r--r--test/tsan/Darwin/gcd-serial-queue-norace.mm2
-rw-r--r--test/tsan/Darwin/gcd-source-cancel.mm36
-rw-r--r--test/tsan/Darwin/gcd-source-cancel2.mm38
-rw-r--r--test/tsan/Darwin/gcd-source-event.mm35
-rw-r--r--test/tsan/Darwin/gcd-source-event2.mm37
-rw-r--r--test/tsan/Darwin/gcd-source-registration.mm33
-rw-r--r--test/tsan/Darwin/gcd-source-registration2.mm35
-rw-r--r--test/tsan/Darwin/gcd-source-serial.mm33
-rw-r--r--test/tsan/Darwin/gcd-sync-norace.mm2
-rw-r--r--test/tsan/Darwin/gcd-sync-race.mm6
-rw-r--r--test/tsan/Darwin/ignored-interceptors.mm55
-rw-r--r--test/tsan/Darwin/libcxx-shared-ptr-recursive.mm36
-rw-r--r--test/tsan/Darwin/libcxx-shared-ptr-stress.mm75
-rw-r--r--test/tsan/Darwin/libcxx-shared-ptr.mm50
-rw-r--r--test/tsan/Darwin/malloc-stack-logging.cc24
-rw-r--r--test/tsan/Darwin/malloc_size.mm57
-rw-r--r--test/tsan/Darwin/objc-race.mm4
-rw-r--r--test/tsan/Darwin/objc-simple.mm2
-rw-r--r--test/tsan/Darwin/osatomics-add.mm48
-rw-r--r--test/tsan/Darwin/osatomics-list.mm43
-rw-r--r--test/tsan/Darwin/xpc-race.mm81
-rw-r--r--test/tsan/Darwin/xpc.mm74
46 files changed, 1696 insertions, 17 deletions
diff --git a/test/tsan/Darwin/dispatch_main.mm b/test/tsan/Darwin/dispatch_main.mm
new file mode 100644
index 000000000000..75887547c606
--- /dev/null
+++ b/test/tsan/Darwin/dispatch_main.mm
@@ -0,0 +1,38 @@
+// Check that we don't crash when dispatch_main calls pthread_exit which
+// quits the main thread.
+
+// 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>
+
+int main() {
+ fprintf(stderr,"Hello world");
+
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL);
+
+ dispatch_async(q, ^{
+ fprintf(stderr,"1");
+ });
+
+ dispatch_async(q, ^{
+ fprintf(stderr,"2");
+ });
+
+ dispatch_async(q, ^{
+ fprintf(stderr,"3");
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ fprintf(stderr,"Done.");
+ sleep(1);
+ exit(0);
+ });
+ });
+
+ dispatch_main();
+}
+
+// CHECK: Hello world
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK-NOT: CHECK failed
diff --git a/test/tsan/Darwin/dispatch_once_deadlock.mm b/test/tsan/Darwin/dispatch_once_deadlock.mm
new file mode 100644
index 000000000000..e88cdc0d0da5
--- /dev/null
+++ b/test/tsan/Darwin/dispatch_once_deadlock.mm
@@ -0,0 +1,41 @@
+// Check that calling dispatch_once from a report callback works.
+
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 not %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <pthread.h>
+
+long g = 0;
+long h = 0;
+void f() {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ g++;
+ });
+ h++;
+}
+
+extern "C" void __tsan_on_report() {
+ fprintf(stderr, "Report.\n");
+ f();
+}
+
+int main() {
+ fprintf(stderr, "Hello world.\n");
+
+ f();
+
+ pthread_mutex_t mutex = {0};
+ pthread_mutex_lock(&mutex);
+
+ fprintf(stderr, "g = %ld.\n", g);
+ fprintf(stderr, "h = %ld.\n", h);
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: Report.
+// CHECK: g = 1
+// CHECK: h = 2
+// CHECK: Done.
diff --git a/test/tsan/Darwin/dlopen.cc b/test/tsan/Darwin/dlopen.cc
new file mode 100644
index 000000000000..7382a6de28c5
--- /dev/null
+++ b/test/tsan/Darwin/dlopen.cc
@@ -0,0 +1,41 @@
+// Checks that on OS X 10.11+ (where we do not re-exec anymore, because
+// interceptors work automatically), dlopen'ing a TSanified library from a
+// non-instrumented program exits with a user-friendly message.
+
+// REQUIRES: osx-autointerception
+
+// RUN: %clangxx_tsan %s -o %t.so -shared -DSHARED_LIB
+// RUN: %clangxx_tsan -fno-sanitize=thread %s -o %t
+
+// RUN: TSAN_DYLIB_PATH=`%clangxx_tsan %s -### 2>&1 \
+// RUN: | grep "libclang_rt.tsan_osx_dynamic.dylib" \
+// RUN: | sed -e 's/.*"\(.*libclang_rt.tsan_osx_dynamic.dylib\)".*/\1/'`
+
+// Launching a non-instrumented binary that dlopen's an instrumented library should fail.
+// RUN: not %run %t %t.so 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// Launching a non-instrumented binary with an explicit DYLD_INSERT_LIBRARIES should work.
+// RUN: DYLD_INSERT_LIBRARIES=$TSAN_DYLIB_PATH %run %t %t.so 2>&1 | FileCheck %s
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#if defined(SHARED_LIB)
+extern "C" void foo() {
+ fprintf(stderr, "Hello world.\n");
+}
+#else // defined(SHARED_LIB)
+int main(int argc, char *argv[]) {
+ void *handle = dlopen(argv[1], RTLD_NOW);
+ fprintf(stderr, "handle = %p\n", handle);
+ void (*foo)() = (void (*)())dlsym(handle, "foo");
+ fprintf(stderr, "foo = %p\n", foo);
+ foo();
+}
+#endif // defined(SHARED_LIB)
+
+// CHECK: Hello world.
+// CHECK-NOT: ERROR: Interceptors are not working.
+
+// CHECK-FAIL-NOT: Hello world.
+// CHECK-FAIL: ERROR: Interceptors are not working.
diff --git a/test/tsan/Darwin/gcd-after.mm b/test/tsan/Darwin/gcd-after.mm
new file mode 100644
index 000000000000..49b6bc6f71e9
--- /dev/null
+++ b/test/tsan/Darwin/gcd-after.mm
@@ -0,0 +1,41 @@
+// 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 my_global;
+long my_global2;
+
+void callback(void *context) {
+ my_global2 = 42;
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetMain());
+ });
+}
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "start\n");
+
+ my_global = 10;
+ dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_MSEC)), q, ^{
+ my_global = 42;
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetMain());
+ });
+ });
+ CFRunLoopRun();
+
+ my_global2 = 10;
+ dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_MSEC)), q, NULL, &callback);
+ CFRunLoopRun();
+
+ fprintf(stderr, "done\n");
+ return 0;
+}
+
+// CHECK: start
+// CHECK: done
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-apply-race.mm b/test/tsan/Darwin/gcd-apply-race.mm
new file mode 100644
index 000000000000..13b24e0fdb90
--- /dev/null
+++ b/test/tsan/Darwin/gcd-apply-race.mm
@@ -0,0 +1,26 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+long global;
+
+int main(int argc, const char *argv[]) {
+ barrier_init(&barrier, 2);
+ fprintf(stderr, "start\n");
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ dispatch_apply(2, q, ^(size_t i) {
+ global = i;
+ barrier_wait(&barrier);
+ });
+
+ fprintf(stderr, "done\n");
+ return 0;
+}
+
+// CHECK: start
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is global 'global'
+// CHECK: done
diff --git a/test/tsan/Darwin/gcd-apply.mm b/test/tsan/Darwin/gcd-apply.mm
new file mode 100644
index 000000000000..e68a4b18205d
--- /dev/null
+++ b/test/tsan/Darwin/gcd-apply.mm
@@ -0,0 +1,44 @@
+// 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>
+
+#import "../test.h"
+
+long global;
+long array[2];
+
+void callback(void *context, size_t i) {
+ long n = global;
+ array[i] = n + i;
+ barrier_wait(&barrier);
+}
+
+int main(int argc, const char *argv[]) {
+ barrier_init(&barrier, 2);
+ fprintf(stderr, "start\n");
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ global = 42;
+
+ dispatch_apply(100, q, ^(size_t i) {
+ long n = global;
+ array[i] = n + i;
+ barrier_wait(&barrier);
+ });
+
+ for (int i = 0; i < 100; i++) {
+ fprintf(stderr, "array[%d] = %ld\n", i, array[i]);
+ }
+
+ global = 43;
+
+ dispatch_apply_f(100, q, NULL, &callback);
+
+ fprintf(stderr, "done\n");
+ return 0;
+}
+
+// CHECK: start
+// CHECK: done
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-async-norace.mm b/test/tsan/Darwin/gcd-async-norace.mm
index b987e00656fb..c7e28b4ce791 100644
--- a/test/tsan/Darwin/gcd-async-norace.mm
+++ b/test/tsan/Darwin/gcd-async-norace.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/gcd-async-race.mm b/test/tsan/Darwin/gcd-async-race.mm
index 31163f972896..1002a56b0a16 100644
--- a/test/tsan/Darwin/gcd-async-race.mm
+++ b/test/tsan/Darwin/gcd-async-race.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %deflake %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
@@ -9,7 +9,7 @@ long global;
int main() {
NSLog(@"Hello world.");
- NSLog(@"addr=%p\n", &global);
+ print_address("addr=", 1, &global);
barrier_init(&barrier, 2);
global = 42;
@@ -34,5 +34,5 @@ int main() {
// CHECK: Hello world.
// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is global 'global' at [[ADDR]] (global_race.cc.exe+0x{{[0-9,a-f]+}})
+// CHECK: Location is global 'global' {{(of size 8 )?}}at [[ADDR]] (gcd-async-race.mm.tmp+0x{{[0-9,a-f]+}})
// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-barrier-race.mm b/test/tsan/Darwin/gcd-barrier-race.mm
new file mode 100644
index 000000000000..c42eaebded2b
--- /dev/null
+++ b/test/tsan/Darwin/gcd-barrier-race.mm
@@ -0,0 +1,48 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+long global;
+
+int main() {
+ fprintf(stderr, "Hello world.\n");
+ print_address("addr=", 1, &global);
+ barrier_init(&barrier, 2);
+
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ dispatch_queue_t bgq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ dispatch_barrier_sync(q, ^{
+ global = 42;
+ });
+
+ dispatch_async(bgq, ^{
+ dispatch_sync(q, ^{
+ global = 43;
+ barrier_wait(&barrier);
+ });
+ });
+
+ dispatch_async(bgq, ^{
+ dispatch_sync(q, ^{
+ barrier_wait(&barrier);
+ global = 44;
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+ });
+
+ CFRunLoopRun();
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is global 'global' {{(of size 8 )?}}at [[ADDR]] (gcd-barrier-race.mm.tmp+0x{{[0-9,a-f]+}})
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-barrier.mm b/test/tsan/Darwin/gcd-barrier.mm
new file mode 100644
index 000000000000..6f58cae7d8f5
--- /dev/null
+++ b/test/tsan/Darwin/gcd-barrier.mm
@@ -0,0 +1,49 @@
+// 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>
+
+#import "../test.h"
+
+long global;
+
+int main() {
+ fprintf(stderr, "Hello world.\n");
+ print_address("addr=", 1, &global);
+ barrier_init(&barrier, 2);
+
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ dispatch_queue_t bgq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ dispatch_async(bgq, ^{
+ dispatch_sync(q, ^{
+ global = 42;
+ });
+ barrier_wait(&barrier);
+ });
+
+ dispatch_async(bgq, ^{
+ barrier_wait(&barrier);
+ dispatch_barrier_sync(q, ^{
+ global = 43;
+ });
+
+ dispatch_async(bgq, ^{
+ barrier_wait(&barrier);
+ global = 44;
+ });
+
+ barrier_wait(&barrier);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+
+ CFRunLoopRun();
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-blocks.mm b/test/tsan/Darwin/gcd-blocks.mm
new file mode 100644
index 000000000000..e0082605f24e
--- /dev/null
+++ b/test/tsan/Darwin/gcd-blocks.mm
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+int main() {
+ fprintf(stderr, "start\n");
+
+ dispatch_queue_t background_q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_queue_t main_q = dispatch_get_main_queue();
+
+ dispatch_async(background_q, ^{
+ __block long block_var = 0;
+
+ dispatch_sync(main_q, ^{
+ block_var = 42;
+ });
+
+ fprintf(stderr, "block_var = %ld\n", block_var);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+
+ CFRunLoopRun();
+ fprintf(stderr, "done\n");
+}
+
+// CHECK: start
+// CHECK: block_var = 42
+// CHECK: done
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK-NOT: CHECK failed
diff --git a/test/tsan/Darwin/gcd-data.mm b/test/tsan/Darwin/gcd-data.mm
new file mode 100644
index 000000000000..a5154dc3598d
--- /dev/null
+++ b/test/tsan/Darwin/gcd-data.mm
@@ -0,0 +1,36 @@
+// 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);
+
+ 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);
+
+ data = dispatch_data_create("buffer", 6, q, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+ dispatch_release(data);
+ data = nil;
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: Data destructor.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-fd.mm b/test/tsan/Darwin/gcd-fd.mm
new file mode 100644
index 000000000000..75da9cd4252d
--- /dev/null
+++ b/test/tsan/Darwin/gcd-fd.mm
@@ -0,0 +1,60 @@
+// 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 my_global = 0;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ dispatch_queue_t queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL);
+ dispatch_semaphore_t sem = dispatch_semaphore_create(0);
+
+ NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"temp-gcd-io.%d", getpid()]];
+
+ dispatch_io_t channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path.fileSystemRepresentation, O_CREAT | O_WRONLY,
+ 0666, queue, ^(int error) { });
+ dispatch_io_set_high_water(channel, 1);
+
+ NSData *ns_data = [NSMutableData dataWithLength:1000];
+ dispatch_data_t data = dispatch_data_create(ns_data.bytes, ns_data.length, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+
+ my_global++;
+ dispatch_io_write(channel, 0, data, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ my_global++;
+ dispatch_async(queue, ^{
+ my_global++;
+ if (done) {
+ dispatch_semaphore_signal(sem);
+ }
+ });
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ my_global++;
+ dispatch_io_close(channel, 0);
+ channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path.fileSystemRepresentation, O_RDONLY,
+ 0, queue, ^(int error) { });
+ dispatch_io_set_high_water(channel, 1);
+
+ my_global++;
+ dispatch_io_read(channel, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ my_global++;
+ dispatch_async(queue, ^{
+ my_global++;
+ if (done) {
+ dispatch_semaphore_signal(sem);
+ }
+ });
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ my_global++;
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-groups-destructor.mm b/test/tsan/Darwin/gcd-groups-destructor.mm
new file mode 100644
index 000000000000..19c2c9bd147f
--- /dev/null
+++ b/test/tsan/Darwin/gcd-groups-destructor.mm
@@ -0,0 +1,43 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import <memory>
+#import <stdatomic.h>
+
+_Atomic(long) destructor_counter = 0;
+
+struct MyStruct {
+ virtual ~MyStruct() {
+ usleep(10000);
+ atomic_fetch_add_explicit(&destructor_counter, 1, memory_order_relaxed);
+ }
+};
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_group_t g = dispatch_group_create();
+
+ for (int i = 0; i < 100; i++) {
+ std::shared_ptr<MyStruct> shared(new MyStruct());
+
+ dispatch_group_async(g, q, ^{
+ shared.get(); // just to make sure the object is captured by the block
+ });
+ }
+
+ dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+
+ if (destructor_counter != 100) {
+ abort();
+ }
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-groups-leave.mm b/test/tsan/Darwin/gcd-groups-leave.mm
new file mode 100644
index 000000000000..6ecf85f5ff0d
--- /dev/null
+++ b/test/tsan/Darwin/gcd-groups-leave.mm
@@ -0,0 +1,56 @@
+// 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>
+
+#import "../test.h"
+
+dispatch_semaphore_t sem;
+
+long global;
+long global2;
+
+void callback(void *context) {
+ global2 = 48;
+ barrier_wait(&barrier);
+
+ dispatch_semaphore_signal(sem);
+}
+
+int main() {
+ fprintf(stderr, "Hello world.\n");
+ barrier_init(&barrier, 2);
+
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ dispatch_group_t g = dispatch_group_create();
+ sem = dispatch_semaphore_create(0);
+
+ dispatch_group_enter(g);
+ dispatch_async(q, ^{
+ global = 47;
+ dispatch_group_leave(g);
+ barrier_wait(&barrier);
+ });
+ dispatch_group_notify(g, q, ^{
+ global = 48;
+ barrier_wait(&barrier);
+
+ dispatch_semaphore_signal(sem);
+ });
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+ dispatch_group_enter(g);
+ dispatch_async(q, ^{
+ global2 = 47;
+ dispatch_group_leave(g);
+ barrier_wait(&barrier);
+ });
+ dispatch_group_notify_f(g, q, NULL, &callback);
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-groups-norace.mm b/test/tsan/Darwin/gcd-groups-norace.mm
index fb4d804ed8c7..64ec386ca40f 100644
--- a/test/tsan/Darwin/gcd-groups-norace.mm
+++ b/test/tsan/Darwin/gcd-groups-norace.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/gcd-groups-stress.mm b/test/tsan/Darwin/gcd-groups-stress.mm
index 62a80085ed8d..457d9afd9c93 100644
--- a/test/tsan/Darwin/gcd-groups-stress.mm
+++ b/test/tsan/Darwin/gcd-groups-stress.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
@@ -30,7 +30,7 @@ int main() {
dispatch_async(q, ^{
dispatch_group_leave(g);
});
- dispatch_group_notify_f(g, q, nullptr, &notify_callback);
+ dispatch_group_notify_f(g, q, NULL, &notify_callback);
dispatch_release(g);
}
diff --git a/test/tsan/Darwin/gcd-io-barrier-race.mm b/test/tsan/Darwin/gcd-io-barrier-race.mm
new file mode 100644
index 000000000000..fffc19bd16de
--- /dev/null
+++ b/test/tsan/Darwin/gcd-io-barrier-race.mm
@@ -0,0 +1,55 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+dispatch_queue_t queue;
+dispatch_data_t data;
+dispatch_semaphore_t sem;
+const char *path;
+
+long my_global = 0;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+ print_address("addr=", 1, &my_global);
+ barrier_init(&barrier, 2);
+
+ queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ sem = dispatch_semaphore_create(0);
+ NSString *ns_path = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"temp-gcd-io.%d", getpid()]];
+ path = ns_path.fileSystemRepresentation;
+ NSData *ns_data = [NSMutableData dataWithLength:1000];
+ data = dispatch_data_create(ns_data.bytes, ns_data.length, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+
+ dispatch_io_t channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_CREAT | O_WRONLY, 0666, queue, ^(int error) { });
+ if (! channel) abort();
+ dispatch_io_set_high_water(channel, 1);
+
+ dispatch_io_write(channel, 0, data, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ if (error) abort();
+ my_global = 42;
+ barrier_wait(&barrier);
+ });
+
+ dispatch_io_barrier(channel, ^{
+ barrier_wait(&barrier);
+ my_global = 43;
+
+ dispatch_semaphore_signal(sem);
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ dispatch_io_close(channel, 0);
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is global 'my_global' {{(of size 8 )?}}at [[ADDR]] (gcd-io-barrier-race.mm.tmp+0x{{[0-9,a-f]+}})
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-io-barrier.mm b/test/tsan/Darwin/gcd-io-barrier.mm
new file mode 100644
index 000000000000..fe30138f6036
--- /dev/null
+++ b/test/tsan/Darwin/gcd-io-barrier.mm
@@ -0,0 +1,48 @@
+// 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>
+
+dispatch_queue_t queue;
+dispatch_data_t data;
+dispatch_semaphore_t sem;
+const char *path;
+
+long my_global = 0;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ sem = dispatch_semaphore_create(0);
+ NSString *ns_path = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"temp-gcd-io.%d", getpid()]];
+ path = ns_path.fileSystemRepresentation;
+ NSData *ns_data = [NSMutableData dataWithLength:1000];
+ data = dispatch_data_create(ns_data.bytes, ns_data.length, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+
+ dispatch_io_t channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_CREAT | O_WRONLY, 0666, queue, ^(int error) { });
+ if (! channel) abort();
+ dispatch_io_set_high_water(channel, 1);
+
+ for (int i = 0; i < 1000; i++) {
+ dispatch_io_barrier(channel, ^{
+ my_global = 42;
+ });
+ }
+
+ dispatch_io_barrier(channel, ^{
+ my_global = 43;
+
+ dispatch_semaphore_signal(sem);
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ dispatch_io_close(channel, 0);
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-io-cleanup.mm b/test/tsan/Darwin/gcd-io-cleanup.mm
new file mode 100644
index 000000000000..b15fa0dc2532
--- /dev/null
+++ b/test/tsan/Darwin/gcd-io-cleanup.mm
@@ -0,0 +1,56 @@
+// 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 my_global = 0;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ dispatch_queue_t queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ dispatch_semaphore_t sem = dispatch_semaphore_create(0);
+ NSString *ns_path = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"temp-gcd-io.%d", getpid()]];
+ const char *path = ns_path.fileSystemRepresentation;
+ dispatch_io_t channel;
+
+ dispatch_fd_t fd = open(path, O_CREAT | O_WRONLY, 0666);
+ my_global++;
+ channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error) {
+ my_global++;
+ dispatch_semaphore_signal(sem);
+ });
+ if (! channel) abort();
+ my_global++;
+ dispatch_io_close(channel, 0);
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+ my_global++;
+ channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_CREAT | O_WRONLY, 0666, queue, ^(int error) {
+ my_global++;
+ dispatch_semaphore_signal(sem);
+ });
+ if (! channel) abort();
+ my_global++;
+ dispatch_io_close(channel, 0);
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+ my_global++;
+ dispatch_io_t other_channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_CREAT | O_WRONLY, 0666, queue, ^(int error) { });
+ channel = dispatch_io_create_with_io(DISPATCH_IO_STREAM, other_channel, queue, ^(int error) {
+ my_global++;
+ dispatch_semaphore_signal(sem);
+ });
+ if (! channel) abort();
+ my_global++;
+ dispatch_io_close(channel, 0);
+ dispatch_io_close(other_channel, 0);
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-io-race.mm b/test/tsan/Darwin/gcd-io-race.mm
new file mode 100644
index 000000000000..0bec28fdb758
--- /dev/null
+++ b/test/tsan/Darwin/gcd-io-race.mm
@@ -0,0 +1,56 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+
+// REQUIRES: disabled
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+dispatch_queue_t queue;
+dispatch_data_t data;
+dispatch_semaphore_t sem;
+const char *path;
+
+long my_global = 0;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+ print_address("addr=", 1, &my_global);
+ barrier_init(&barrier, 2);
+
+ queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ sem = dispatch_semaphore_create(0);
+ NSString *ns_path = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"temp-gcd-io.%d", getpid()]];
+ path = ns_path.fileSystemRepresentation;
+ NSData *ns_data = [NSMutableData dataWithLength:1000];
+ data = dispatch_data_create(ns_data.bytes, ns_data.length, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+
+ dispatch_io_t channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_CREAT | O_WRONLY, 0666, queue, ^(int error) { });
+ if (! channel) abort();
+ dispatch_io_set_high_water(channel, 1);
+
+ dispatch_io_write(channel, 0, data, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ my_global = 42;
+ barrier_wait(&barrier);
+ });
+
+ dispatch_io_write(channel, 0, data, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ barrier_wait(&barrier);
+ my_global = 42;
+
+ dispatch_semaphore_signal(sem);
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ dispatch_io_close(channel, 0);
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is global 'my_global' {{(of size 8 )?}}at [[ADDR]] (gcd-io-race.mm.tmp+0x{{[0-9,a-f]+}})
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-io.mm b/test/tsan/Darwin/gcd-io.mm
new file mode 100644
index 000000000000..4a1726dac8c7
--- /dev/null
+++ b/test/tsan/Darwin/gcd-io.mm
@@ -0,0 +1,117 @@
+// 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>
+
+dispatch_queue_t queue;
+dispatch_data_t data;
+dispatch_semaphore_t sem;
+const char *path;
+
+long my_global = 0;
+
+void test_dispatch_io_write() {
+ dispatch_io_t channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_CREAT | O_WRONLY, 0666, queue, ^(int error) { });
+ if (! channel) abort();
+ dispatch_io_set_high_water(channel, 1);
+
+ my_global++;
+ dispatch_io_write(channel, 0, data, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ if (error) abort();
+ my_global++;
+ dispatch_async(queue, ^{
+ my_global++;
+ if (done) {
+ dispatch_semaphore_signal(sem);
+ }
+ });
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ my_global++;
+ dispatch_io_close(channel, 0);
+}
+
+void test_dispatch_write() {
+ dispatch_fd_t fd = open(path, O_CREAT | O_WRONLY, 0666);
+ if (fd == -1) abort();
+
+ my_global++;
+ dispatch_write(fd, data, queue, ^(dispatch_data_t data, int error) {
+ if (error) abort();
+ my_global++;
+ dispatch_async(queue, ^{
+ my_global++;
+
+ dispatch_semaphore_signal(sem);
+ });
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ my_global++;
+ close(fd);
+}
+
+void test_dispatch_io_read() {
+ dispatch_io_t channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_RDONLY,
+ 0, queue, ^(int error) { });
+ dispatch_io_set_high_water(channel, 1);
+
+ my_global++;
+ dispatch_io_read(channel, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ if (error) abort();
+ my_global++;
+ dispatch_async(queue, ^{
+ my_global++;
+ if (done) {
+ dispatch_semaphore_signal(sem);
+ }
+ });
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ my_global++;
+ dispatch_io_close(channel, 0);
+}
+
+void test_dispatch_read() {
+ dispatch_fd_t fd = open(path, O_RDONLY, 0);
+ if (fd == -1) abort();
+
+ my_global++;
+ dispatch_read(fd, SIZE_MAX, queue, ^(dispatch_data_t data, int error) {
+ if (error) abort();
+ my_global++;
+ dispatch_async(queue, ^{
+ my_global++;
+ dispatch_semaphore_signal(sem);
+ });
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ my_global++;
+ close(fd);
+}
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL);
+ sem = dispatch_semaphore_create(0);
+ NSString *ns_path = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"temp-gcd-io.%d", getpid()]];
+ path = ns_path.fileSystemRepresentation;
+ NSData *ns_data = [NSMutableData dataWithLength:1000];
+ data = dispatch_data_create(ns_data.bytes, ns_data.length, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+
+ test_dispatch_io_write();
+ test_dispatch_write();
+ test_dispatch_io_read();
+ test_dispatch_read();
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-once.mm b/test/tsan/Darwin/gcd-once.mm
index 17757d203751..3e4a5335607c 100644
--- a/test/tsan/Darwin/gcd-once.mm
+++ b/test/tsan/Darwin/gcd-once.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/gcd-semaphore-norace.mm b/test/tsan/Darwin/gcd-semaphore-norace.mm
index cd52a79ca65a..20bc5724d165 100644
--- a/test/tsan/Darwin/gcd-semaphore-norace.mm
+++ b/test/tsan/Darwin/gcd-semaphore-norace.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/gcd-serial-queue-norace.mm b/test/tsan/Darwin/gcd-serial-queue-norace.mm
index 8f6de27695a5..95efbb764c53 100644
--- a/test/tsan/Darwin/gcd-serial-queue-norace.mm
+++ b/test/tsan/Darwin/gcd-serial-queue-norace.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/gcd-source-cancel.mm b/test/tsan/Darwin/gcd-source-cancel.mm
new file mode 100644
index 000000000000..86e1b28a61c4
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-cancel.mm
@@ -0,0 +1,36 @@
+// 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[]) {
+ dispatch_queue_t queue =
+ dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ dispatch_source_t source =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+
+ dispatch_source_set_timer(source, dispatch_walltime(NULL, 0), 1e9, 5);
+
+ global = 42;
+
+ dispatch_source_set_cancel_handler(source, ^{
+ fprintf(stderr, "global = %ld\n", global);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+
+ dispatch_resume(source);
+ dispatch_cancel(source);
+
+ CFRunLoopRun();
+
+ return 0;
+}
+
+// CHECK: global = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-source-cancel2.mm b/test/tsan/Darwin/gcd-source-cancel2.mm
new file mode 100644
index 000000000000..956fe87298bb
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-cancel2.mm
@@ -0,0 +1,38 @@
+// 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;
+
+void handler(void *arg) {
+ fprintf(stderr, "global = %ld\n", global);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+}
+
+int main(int argc, const char *argv[]) {
+ dispatch_queue_t queue =
+ dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ dispatch_source_t source =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+
+ dispatch_source_set_timer(source, dispatch_walltime(NULL, 0), 1e9, 5);
+
+ global = 42;
+
+ dispatch_source_set_cancel_handler_f(source, &handler);
+
+ dispatch_resume(source);
+ dispatch_cancel(source);
+
+ CFRunLoopRun();
+
+ return 0;
+}
+
+// CHECK: global = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-source-event.mm b/test/tsan/Darwin/gcd-source-event.mm
new file mode 100644
index 000000000000..e50cb568de1e
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-event.mm
@@ -0,0 +1,35 @@
+// 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[]) {
+ dispatch_queue_t queue =
+ dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ dispatch_source_t source =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+
+ dispatch_source_set_timer(source, dispatch_walltime(NULL, 0), 1e9, 5);
+
+ global = 42;
+
+ dispatch_source_set_event_handler(source, ^{
+ fprintf(stderr, "global = %ld\n", global);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+
+ dispatch_resume(source);
+
+ CFRunLoopRun();
+
+ return 0;
+}
+
+// CHECK: global = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-source-event2.mm b/test/tsan/Darwin/gcd-source-event2.mm
new file mode 100644
index 000000000000..c45d481a0028
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-event2.mm
@@ -0,0 +1,37 @@
+// 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;
+
+void handler(void *arg) {
+ fprintf(stderr, "global = %ld\n", global);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+}
+
+int main(int argc, const char *argv[]) {
+ dispatch_queue_t queue =
+ dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ dispatch_source_t source =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+
+ dispatch_source_set_timer(source, dispatch_walltime(NULL, 0), 1e9, 5);
+
+ global = 42;
+
+ dispatch_source_set_event_handler_f(source, &handler);
+
+ dispatch_resume(source);
+
+ CFRunLoopRun();
+
+ return 0;
+}
+
+// CHECK: global = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-source-registration.mm b/test/tsan/Darwin/gcd-source-registration.mm
new file mode 100644
index 000000000000..db22613eddae
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-registration.mm
@@ -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[]) {
+ dispatch_queue_t queue =
+ dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ dispatch_source_t source =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGHUP, 0, queue);
+
+ global = 42;
+
+ dispatch_source_set_registration_handler(source, ^{
+ fprintf(stderr, "global = %ld\n", global);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+
+ dispatch_resume(source);
+
+ CFRunLoopRun();
+
+ return 0;
+}
+
+// CHECK: global = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-source-registration2.mm b/test/tsan/Darwin/gcd-source-registration2.mm
new file mode 100644
index 000000000000..4431bc9d6898
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-registration2.mm
@@ -0,0 +1,35 @@
+// 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;
+
+void handler(void *arg) {
+ fprintf(stderr, "global = %ld\n", global);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+}
+
+int main(int argc, const char *argv[]) {
+ dispatch_queue_t queue =
+ dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ dispatch_source_t source =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGHUP, 0, queue);
+
+ global = 42;
+
+ dispatch_source_set_registration_handler_f(source, handler);
+
+ dispatch_resume(source);
+
+ CFRunLoopRun();
+
+ return 0;
+}
+
+// CHECK: global = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-source-serial.mm b/test/tsan/Darwin/gcd-source-serial.mm
new file mode 100644
index 000000000000..c0989fcc732a
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-serial.mm
@@ -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.
diff --git a/test/tsan/Darwin/gcd-sync-norace.mm b/test/tsan/Darwin/gcd-sync-norace.mm
index f21cfdedbce1..c683524f73b6 100644
--- a/test/tsan/Darwin/gcd-sync-norace.mm
+++ b/test/tsan/Darwin/gcd-sync-norace.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/gcd-sync-race.mm b/test/tsan/Darwin/gcd-sync-race.mm
index 62901d9b2612..650faa4e082c 100644
--- a/test/tsan/Darwin/gcd-sync-race.mm
+++ b/test/tsan/Darwin/gcd-sync-race.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %deflake %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
@@ -9,7 +9,7 @@ long global;
int main() {
NSLog(@"Hello world.");
- NSLog(@"addr=%p\n", &global);
+ print_address("addr=", 1, &global);
barrier_init(&barrier, 2);
dispatch_queue_t q1 = dispatch_queue_create("my.queue1", DISPATCH_QUEUE_CONCURRENT);
@@ -40,5 +40,5 @@ int main() {
// CHECK: Hello world.
// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is global 'global' at [[ADDR]] (global_race.cc.exe+0x{{[0-9,a-f]+}})
+// CHECK: Location is global 'global' {{(of size 8 )?}}at [[ADDR]] (gcd-sync-race.mm.tmp+0x{{[0-9,a-f]+}})
// CHECK: Done.
diff --git a/test/tsan/Darwin/ignored-interceptors.mm b/test/tsan/Darwin/ignored-interceptors.mm
new file mode 100644
index 000000000000..d51314281844
--- /dev/null
+++ b/test/tsan/Darwin/ignored-interceptors.mm
@@ -0,0 +1,55 @@
+// Check that ignore_interceptors_accesses=1 supresses reporting races from
+// system libraries on OS X. There are currently false positives coming from
+// libxpc, libdispatch, CoreFoundation and others, because these libraries use
+// TSan-invisible atomics as synchronization.
+
+// RUN: %clang_tsan %s -o %t -framework Foundation
+
+// Check that without the flag, there are false positives.
+// RUN: %deflake %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RACE
+
+// With ignore_interceptors_accesses=1, no races are reported.
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+// With ignore_interceptors_accesses=1, races in user's code are still reported.
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t race 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-RACE
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+long global;
+
+void *Thread1(void *x) {
+ barrier_wait(&barrier);
+ global = 42;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ global = 43;
+ barrier_wait(&barrier);
+ return NULL;
+}
+
+int main(int argc, char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ // NSUserDefaults uses XPC which triggers the false positive.
+ NSDictionary *d = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
+
+ if (argc > 1 && strcmp(argv[1], "race") == 0) {
+ barrier_init(&barrier, 2);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ }
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-RACE: SUMMARY: ThreadSanitizer: data race
+// CHECK: Done.
diff --git a/test/tsan/Darwin/libcxx-shared-ptr-recursive.mm b/test/tsan/Darwin/libcxx-shared-ptr-recursive.mm
new file mode 100644
index 000000000000..eea02dc561e1
--- /dev/null
+++ b/test/tsan/Darwin/libcxx-shared-ptr-recursive.mm
@@ -0,0 +1,36 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import <memory>
+
+struct InnerStruct {
+ ~InnerStruct() {
+ fprintf(stderr, "~InnerStruct\n");
+ }
+};
+
+struct MyStruct {
+ std::shared_ptr<InnerStruct> inner_object;
+ ~MyStruct() {
+ fprintf(stderr, "~MyStruct\n");
+ }
+};
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ {
+ std::shared_ptr<MyStruct> shared(new MyStruct());
+ shared->inner_object = std::shared_ptr<InnerStruct>(new InnerStruct());
+ }
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: ~MyStruct
+// CHECK: ~InnerStruct
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/libcxx-shared-ptr-stress.mm b/test/tsan/Darwin/libcxx-shared-ptr-stress.mm
new file mode 100644
index 000000000000..7c36729f010f
--- /dev/null
+++ b/test/tsan/Darwin/libcxx-shared-ptr-stress.mm
@@ -0,0 +1,75 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import <assert.h>
+#import <memory>
+#import <stdatomic.h>
+
+_Atomic(long) shared_call_counter = 0;
+_Atomic(long) weak_call_counter = 0;
+_Atomic(long) destructor_counter = 0;
+_Atomic(long) weak_destroyed_counter = 0;
+
+struct MyStruct {
+ _Atomic(long) self_counter = 0;
+ virtual void shared_call() {
+ atomic_fetch_add_explicit(&self_counter, 1, memory_order_relaxed);
+ atomic_fetch_add_explicit(&shared_call_counter, 1, memory_order_relaxed);
+ }
+ virtual void weak_call() {
+ atomic_fetch_add_explicit(&weak_call_counter, 1, memory_order_relaxed);
+ }
+ virtual ~MyStruct() {
+ long n = self_counter;
+ assert(n == 1000);
+ atomic_fetch_add_explicit(&destructor_counter, 1, memory_order_relaxed);
+ }
+};
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ dispatch_group_t g = dispatch_group_create();
+
+ for (int i = 0; i < 1000; i++) {
+ std::shared_ptr<MyStruct> shared(new MyStruct());
+ std::weak_ptr<MyStruct> weak(shared);
+
+ dispatch_group_async(g, q, ^{
+ for (int j = 0; j < 1000; j++) {
+ std::shared_ptr<MyStruct> shared_copy(shared);
+ shared_copy->shared_call();
+ }
+ });
+ dispatch_group_async(g, q, ^{
+ for (int j = 0; j < 1000; j++) {
+ std::shared_ptr<MyStruct> weak_copy = weak.lock();
+ if (weak_copy) {
+ weak_copy->weak_call();
+ } else {
+ atomic_fetch_add_explicit(&weak_destroyed_counter, 1, memory_order_relaxed);
+ break;
+ }
+ }
+ });
+ }
+
+ dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+
+ fprintf(stderr, "shared_call_counter = %ld\n", shared_call_counter);
+ fprintf(stderr, "weak_call_counter = %ld\n", weak_call_counter);
+ fprintf(stderr, "destructor_counter = %ld\n", destructor_counter);
+ fprintf(stderr, "weak_destroyed_counter = %ld\n", weak_destroyed_counter);
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: shared_call_counter = 1000000
+// CHECK: destructor_counter = 1000
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/libcxx-shared-ptr.mm b/test/tsan/Darwin/libcxx-shared-ptr.mm
new file mode 100644
index 000000000000..6187c438fec0
--- /dev/null
+++ b/test/tsan/Darwin/libcxx-shared-ptr.mm
@@ -0,0 +1,50 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import <memory>
+
+#import "../test.h"
+
+long my_global;
+
+struct MyStruct {
+ void setGlobal() {
+ my_global = 42;
+ }
+ ~MyStruct() {
+ my_global = 43;
+ }
+};
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+ print_address("addr=", 1, &my_global);
+ barrier_init(&barrier, 2);
+
+ std::shared_ptr<MyStruct> shared(new MyStruct());
+
+ dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ std::weak_ptr<MyStruct> weak(shared);
+
+ dispatch_async(q, ^{
+ {
+ std::shared_ptr<MyStruct> strong = weak.lock();
+ if (!strong) exit(1);
+
+ strong->setGlobal();
+ }
+ barrier_wait(&barrier);
+ });
+
+ barrier_wait(&barrier);
+ shared.reset();
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/malloc-stack-logging.cc b/test/tsan/Darwin/malloc-stack-logging.cc
new file mode 100644
index 000000000000..8d9c2122d0e6
--- /dev/null
+++ b/test/tsan/Darwin/malloc-stack-logging.cc
@@ -0,0 +1,24 @@
+// Test that MallocStackLogging=1 doesn't crash. MallocStackLogging turns on
+// callbacks from mmap/munmap libc function into libmalloc. Darwin-specific
+// ThreadState initialization needs to avoid calling the library functions (and
+// use syscalls directly) to make sure other interceptors aren't called.
+
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: MallocStackLogging=1 %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+void *foo(void *p) {
+ return NULL;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, NULL, foo, NULL);
+ pthread_join(t, NULL);
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Done.
diff --git a/test/tsan/Darwin/malloc_size.mm b/test/tsan/Darwin/malloc_size.mm
new file mode 100644
index 000000000000..485d85bba4f8
--- /dev/null
+++ b/test/tsan/Darwin/malloc_size.mm
@@ -0,0 +1,57 @@
+// Test that malloc_zone_from_ptr returns a valid zone for a 0-sized allocation.
+
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <malloc/malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+int some_global;
+
+void describe_zone(void *p) {
+ malloc_zone_t *z = malloc_zone_from_ptr(p);
+ if (z) {
+ fprintf(stderr, "zone = %p\n", z);
+ } else {
+ fprintf(stderr, "zone = no zone\n");
+ }
+}
+
+int main() {
+ void *p;
+ size_t s;
+
+ p = malloc(0x40);
+ s = malloc_size(p);
+ fprintf(stderr, "size = 0x%zx\n", s);
+ // CHECK: size = 0x40
+ describe_zone(p);
+ // CHECK: zone = 0x{{[0-9a-f]+}}
+
+ p = malloc(0);
+ s = malloc_size(p);
+ fprintf(stderr, "size = 0x%zx\n", s);
+ // CHECK: size = 0x1
+ describe_zone(p);
+ // CHECK: zone = 0x{{[0-9a-f]+}}
+
+ p = &some_global;
+ s = malloc_size(p);
+ fprintf(stderr, "size = 0x%zx\n", s);
+ // CHECK: size = 0x0
+ describe_zone(p);
+ // CHECK: zone = no zone
+
+ p = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+ if (!p) {
+ fprintf(stderr, "mmap failed\n");
+ exit(1);
+ }
+ s = malloc_size(p);
+ fprintf(stderr, "size = 0x%zx\n", s);
+ // CHECK: size = 0x0
+ describe_zone(p);
+ // CHECK: zone = no zone
+}
diff --git a/test/tsan/Darwin/objc-race.mm b/test/tsan/Darwin/objc-race.mm
index bd93d2f1c2ea..82fcc4ef1785 100644
--- a/test/tsan/Darwin/objc-race.mm
+++ b/test/tsan/Darwin/objc-race.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %deflake %run %t 2>&1
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
@@ -49,7 +49,7 @@ int main() {
// CHECK: WARNING: ThreadSanitizer: data race
// CHECK: Write of size 8
// CHECK: #0 -[MyClass method:]
-// CHECK: Write of size 8
+// CHECK: Previous write of size 8
// CHECK: #0 -[MyClass method:]
// CHECK: Location is heap block
// CHECK: Done.
diff --git a/test/tsan/Darwin/objc-simple.mm b/test/tsan/Darwin/objc-simple.mm
index a4bf1f1beaa0..a8fc35592962 100644
--- a/test/tsan/Darwin/objc-simple.mm
+++ b/test/tsan/Darwin/objc-simple.mm
@@ -1,7 +1,7 @@
// Test that a simple Obj-C program runs and exits without any warnings.
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/osatomics-add.mm b/test/tsan/Darwin/osatomics-add.mm
new file mode 100644
index 000000000000..087958eff0f8
--- /dev/null
+++ b/test/tsan/Darwin/osatomics-add.mm
@@ -0,0 +1,48 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation -std=c++11
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <libkern/OSAtomic.h>
+
+#include <thread>
+
+volatile int64_t retainCount = 0;
+
+long g = 0;
+
+void dealloc() {
+ g = 42;
+}
+
+void release() {
+ if (OSAtomicAdd64Barrier(-1, &retainCount) == 0) {
+ dealloc();
+ }
+}
+
+void retain() {
+ OSAtomicAdd64Barrier(1, &retainCount);
+}
+
+int main(int argc, const char * argv[]) {
+ fprintf(stderr, "start\n");
+ retain();
+ retain();
+
+ std::thread t([]{
+ release();
+ });
+
+ g = 47;
+
+ release();
+ t.join();
+
+ fprintf(stderr, "end, g = %ld\n", g);
+
+ return 0;
+}
+
+// CHECK: start
+// CHECK: end, g = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/osatomics-list.mm b/test/tsan/Darwin/osatomics-list.mm
new file mode 100644
index 000000000000..6c2fbe7e5c5a
--- /dev/null
+++ b/test/tsan/Darwin/osatomics-list.mm
@@ -0,0 +1,43 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation -std=c++11
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <libkern/OSAtomic.h>
+
+#include <thread>
+
+#include "../test.h"
+
+typedef struct {
+ void *next;
+ long data;
+} ListItem;
+
+OSQueueHead q;
+
+int main(int argc, const char *argv[]) {
+ barrier_init(&barrier, 2);
+
+ std::thread t1([] {
+ ListItem *li = new ListItem{nullptr, 42};
+ OSAtomicEnqueue(&q, li, 0);
+ barrier_wait(&barrier);
+ });
+
+ std::thread t2([] {
+ barrier_wait(&barrier);
+ ListItem *li = (ListItem *)OSAtomicDequeue(&q, 0);
+ fprintf(stderr, "data = %ld\n", li->data);
+ });
+
+ t1.join();
+ t2.join();
+
+ fprintf(stderr, "done\n");
+
+ return 0;
+}
+
+// CHECK: data = 42
+// CHECK: done
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/xpc-race.mm b/test/tsan/Darwin/xpc-race.mm
new file mode 100644
index 000000000000..9141da42e3a0
--- /dev/null
+++ b/test/tsan/Darwin/xpc-race.mm
@@ -0,0 +1,81 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <xpc/xpc.h>
+
+#import "../test.h"
+
+long global;
+
+long received_msgs;
+xpc_connection_t server_conn;
+xpc_connection_t client_conns[2];
+
+int main(int argc, const char *argv[]) {
+ @autoreleasepool {
+ NSLog(@"Hello world.");
+ barrier_init(&barrier, 2);
+
+ dispatch_queue_t server_q = dispatch_queue_create("server.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ server_conn = xpc_connection_create(NULL, server_q);
+
+ xpc_connection_set_event_handler(server_conn, ^(xpc_object_t client) {
+ NSLog(@"server event handler, client = %@", client);
+
+ if (client == XPC_ERROR_CONNECTION_INTERRUPTED || client == XPC_ERROR_CONNECTION_INVALID) {
+ return;
+ }
+ xpc_connection_set_event_handler(client, ^(xpc_object_t object) {
+ NSLog(@"received message: %@", object);
+
+ barrier_wait(&barrier);
+ global = 42;
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ received_msgs++;
+
+ if (received_msgs >= 2) {
+ xpc_connection_cancel(client_conns[0]);
+ xpc_connection_cancel(client_conns[1]);
+ xpc_connection_cancel(server_conn);
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ }
+ });
+ });
+
+ xpc_connection_resume(client);
+ });
+ xpc_connection_resume(server_conn);
+ xpc_endpoint_t endpoint = xpc_endpoint_create(server_conn);
+
+ for (int i = 0; i < 2; i++) {
+ client_conns[i] = xpc_connection_create_from_endpoint(endpoint);
+ xpc_connection_set_event_handler(client_conns[i], ^(xpc_object_t event) {
+ NSLog(@"client event handler, event = %@", event);
+ });
+
+ xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_dictionary_set_string(msg, "hello", "world");
+ NSLog(@"sending message: %@", msg);
+
+ xpc_connection_send_message(client_conns[i], msg);
+ xpc_connection_resume(client_conns[i]);
+ }
+
+ CFRunLoopRun();
+
+ NSLog(@"Done.");
+ }
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 8
+// CHECK: #0 {{.*}}xpc-race.mm:34
+// CHECK: Previous write of size 8
+// CHECK: #0 {{.*}}xpc-race.mm:34
+// CHECK: Location is global 'global'
+// CHECK: Done.
diff --git a/test/tsan/Darwin/xpc.mm b/test/tsan/Darwin/xpc.mm
new file mode 100644
index 000000000000..a939b02ef21a
--- /dev/null
+++ b/test/tsan/Darwin/xpc.mm
@@ -0,0 +1,74 @@
+// 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>
+#import <xpc/xpc.h>
+
+long global;
+
+int main(int argc, const char *argv[]) {
+ @autoreleasepool {
+ NSLog(@"Hello world.");
+
+ dispatch_queue_t server_q = dispatch_queue_create("server.queue", DISPATCH_QUEUE_CONCURRENT);
+ dispatch_queue_t client_q = dispatch_queue_create("client.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ xpc_connection_t server_conn = xpc_connection_create(NULL, server_q);
+
+ global = 42;
+
+ xpc_connection_set_event_handler(server_conn, ^(xpc_object_t client) {
+ NSLog(@"global = %ld", global);
+ NSLog(@"server event handler, client = %@", client);
+
+ if (client == XPC_ERROR_CONNECTION_INTERRUPTED || client == XPC_ERROR_CONNECTION_INVALID) {
+ return;
+ }
+ xpc_connection_set_event_handler(client, ^(xpc_object_t object) {
+ NSLog(@"received message: %@", object);
+
+ xpc_object_t reply = xpc_dictionary_create_reply(object);
+ if (!reply)
+ return;
+ xpc_dictionary_set_string(reply, "reply", "value");
+
+ xpc_connection_t remote = xpc_dictionary_get_remote_connection(object);
+ xpc_connection_send_message(remote, reply);
+ });
+
+ xpc_connection_resume(client);
+ });
+ xpc_connection_resume(server_conn);
+ xpc_endpoint_t endpoint = xpc_endpoint_create(server_conn);
+
+ xpc_connection_t client_conn = xpc_connection_create_from_endpoint(endpoint);
+ xpc_connection_set_event_handler(client_conn, ^(xpc_object_t event) {
+ NSLog(@"client event handler, event = %@", event);
+ });
+
+ xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_dictionary_set_string(msg, "hello", "world");
+ NSLog(@"sending message: %@", msg);
+
+ xpc_connection_send_message_with_reply(
+ client_conn, msg, client_q, ^(xpc_object_t object) {
+ NSLog(@"received reply: %@", object);
+
+ xpc_connection_cancel(client_conn);
+ xpc_connection_cancel(server_conn);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+ xpc_connection_resume(client_conn);
+
+ CFRunLoopRun();
+
+ NSLog(@"Done.");
+ }
+ return 0;
+}
+
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer