aboutsummaryrefslogtreecommitdiff
path: root/test/tsan/Darwin
diff options
context:
space:
mode:
Diffstat (limited to 'test/tsan/Darwin')
-rw-r--r--test/tsan/Darwin/gcd-apply-race.mm4
-rw-r--r--test/tsan/Darwin/gcd-apply.mm4
-rw-r--r--test/tsan/Darwin/gcd-suspend.mm45
-rw-r--r--test/tsan/Darwin/gcd-target-queue-norace.mm41
-rw-r--r--test/tsan/Darwin/libcxx-call-once.mm34
-rw-r--r--test/tsan/Darwin/libcxx-future.mm30
-rw-r--r--test/tsan/Darwin/norace-objcxx-run-time.mm113
-rw-r--r--test/tsan/Darwin/objc-double-property.mm21
-rw-r--r--test/tsan/Darwin/osatomics-bitops.mm34
-rw-r--r--test/tsan/Darwin/realloc-zero.cc20
10 files changed, 346 insertions, 0 deletions
diff --git a/test/tsan/Darwin/gcd-apply-race.mm b/test/tsan/Darwin/gcd-apply-race.mm
index 13b24e0fdb90..028be1ac5b1c 100644
--- a/test/tsan/Darwin/gcd-apply-race.mm
+++ b/test/tsan/Darwin/gcd-apply-race.mm
@@ -10,6 +10,10 @@ long global;
int main(int argc, const char *argv[]) {
barrier_init(&barrier, 2);
fprintf(stderr, "start\n");
+
+ // Warm up GCD (workaround for macOS Sierra where dispatch_apply might run single-threaded).
+ dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ });
+
dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(2, q, ^(size_t i) {
global = i;
diff --git a/test/tsan/Darwin/gcd-apply.mm b/test/tsan/Darwin/gcd-apply.mm
index e68a4b18205d..a7dc3740dc7b 100644
--- a/test/tsan/Darwin/gcd-apply.mm
+++ b/test/tsan/Darwin/gcd-apply.mm
@@ -17,6 +17,10 @@ void callback(void *context, size_t i) {
int main(int argc, const char *argv[]) {
barrier_init(&barrier, 2);
fprintf(stderr, "start\n");
+
+ // Warm up GCD (workaround for macOS Sierra where dispatch_apply might run single-threaded).
+ dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ });
+
dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
global = 42;
diff --git a/test/tsan/Darwin/gcd-suspend.mm b/test/tsan/Darwin/gcd-suspend.mm
new file mode 100644
index 000000000000..3e8818a2d56e
--- /dev/null
+++ b/test/tsan/Darwin/gcd-suspend.mm
@@ -0,0 +1,45 @@
+// 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 q1 = dispatch_queue_create("queue1", NULL);
+ dispatch_queue_t q2 = dispatch_queue_create("queue2", NULL);
+ dispatch_group_t g = dispatch_group_create();
+
+ dispatch_sync(q1, ^{
+ dispatch_suspend(q1);
+ dispatch_async(q2, ^{
+ my_global++;
+ dispatch_resume(q1);
+ });
+ });
+
+ dispatch_sync(q1, ^{
+ my_global++;
+ });
+
+ dispatch_sync(q1, ^{
+ dispatch_suspend(q1);
+ dispatch_group_enter(g);
+ dispatch_async(q1,^{ my_global++; });
+ dispatch_async(q1,^{ my_global++; });
+ dispatch_async(q1,^{ my_global++; dispatch_group_leave(g); });
+ my_global++;
+ dispatch_resume(q1);
+ });
+
+ dispatch_group_wait(g, 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-target-queue-norace.mm b/test/tsan/Darwin/gcd-target-queue-norace.mm
new file mode 100644
index 000000000000..36cb1b9298de
--- /dev/null
+++ b/test/tsan/Darwin/gcd-target-queue-norace.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 global;
+
+int main(int argc, const char *argv[]) {
+ dispatch_queue_t target_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
+ dispatch_queue_t q1 = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
+ dispatch_queue_t q2 = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
+ dispatch_set_target_queue(q1, target_queue);
+ dispatch_set_target_queue(q2, target_queue);
+
+ for (int i = 0; i < 100000; i++) {
+ dispatch_async(q1, ^{
+ global++;
+
+ if (global == 200000) {
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ }
+ });
+ dispatch_async(q2, ^{
+ global++;
+
+ if (global == 200000) {
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ }
+ });
+ }
+
+ CFRunLoopRun();
+ NSLog(@"Done.");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/libcxx-call-once.mm b/test/tsan/Darwin/libcxx-call-once.mm
new file mode 100644
index 000000000000..5388e495c9c2
--- /dev/null
+++ b/test/tsan/Darwin/libcxx-call-once.mm
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation -std=c++11
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import <iostream>
+#import <thread>
+
+long my_global;
+std::once_flag once_token;
+
+void thread_func() {
+ std::call_once(once_token, [] {
+ my_global = 17;
+ });
+
+ long val = my_global;
+ fprintf(stderr, "my_global = %ld\n", val);
+}
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ std::thread t1(thread_func);
+ std::thread t2(thread_func);
+ t1.join();
+ t2.join();
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/libcxx-future.mm b/test/tsan/Darwin/libcxx-future.mm
new file mode 100644
index 000000000000..902f267ecb89
--- /dev/null
+++ b/test/tsan/Darwin/libcxx-future.mm
@@ -0,0 +1,30 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#include <iostream>
+#include <future>
+#include <vector>
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ auto my_task = [] { return 42; };
+
+ std::vector<std::thread> threads;
+
+ for (int i = 0; i < 100; i++) {
+ std::packaged_task<int(void)> task(my_task);
+ std::future<int> future = task.get_future();
+ threads.push_back(std::thread(std::move(task)));
+ }
+
+ for (auto &t : threads) {
+ t.join();
+ }
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/norace-objcxx-run-time.mm b/test/tsan/Darwin/norace-objcxx-run-time.mm
new file mode 100644
index 000000000000..0cf729e7f2d8
--- /dev/null
+++ b/test/tsan/Darwin/norace-objcxx-run-time.mm
@@ -0,0 +1,113 @@
+// RUN: %clang_tsan %s -lc++ -fobjc-arc -lobjc -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+// Check that we do not report races between:
+// - Object retain and initialize
+// - Object release and dealloc
+// - Object release and .cxx_destruct
+
+#import <Foundation/Foundation.h>
+#include "../test.h"
+invisible_barrier_t barrier2;
+
+class NeedCleanup {
+ public:
+ int x;
+ NeedCleanup() {
+ x = 1;
+ }
+ ~NeedCleanup() {
+ x = 0;
+ }
+};
+
+@interface TestDeallocObject : NSObject {
+ @public
+ int v;
+ }
+ - (id)init;
+ - (void)accessMember;
+ - (void)dealloc;
+@end
+
+@implementation TestDeallocObject
+ - (id)init {
+ if ([super self]) {
+ v = 1;
+ return self;
+ }
+ return nil;
+ }
+ - (void)accessMember {
+ int local = v;
+ local++;
+ }
+ - (void)dealloc {
+ v = 0;
+ }
+@end
+
+@interface TestCXXDestructObject : NSObject {
+ @public
+ NeedCleanup cxxMemberWithCleanup;
+ }
+ - (void)accessMember;
+@end
+
+@implementation TestCXXDestructObject
+ - (void)accessMember {
+ int local = cxxMemberWithCleanup.x;
+ local++;
+ }
+@end
+
+@interface TestInitializeObject : NSObject
+@end
+
+@implementation TestInitializeObject
+ static long InitializerAccessedGlobal = 0;
+ + (void)initialize {
+ InitializerAccessedGlobal = 42;
+ }
+@end
+
+int main(int argc, const char *argv[]) {
+ // Ensure that there is no race when calling initialize on TestInitializeObject;
+ // otherwise, the locking from ObjC runtime becomes observable. Also ensures that
+ // blocks are dispatched to 2 different threads.
+ barrier_init(&barrier, 2);
+ // Ensure that objects are destructed during block object release.
+ barrier_init(&barrier2, 3);
+
+ TestDeallocObject *tdo = [[TestDeallocObject alloc] init];
+ TestCXXDestructObject *tcxxdo = [[TestCXXDestructObject alloc] init];
+ [tdo accessMember];
+ [tcxxdo accessMember];
+ {
+ dispatch_queue_t q = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
+ dispatch_async(q, ^{
+ [TestInitializeObject new];
+ barrier_wait(&barrier);
+ long local = InitializerAccessedGlobal;
+ local++;
+ [tdo accessMember];
+ [tcxxdo accessMember];
+ barrier_wait(&barrier2);
+ });
+ dispatch_async(q, ^{
+ barrier_wait(&barrier);
+ [TestInitializeObject new];
+ long local = InitializerAccessedGlobal;
+ local++;
+ [tdo accessMember];
+ [tcxxdo accessMember];
+ barrier_wait(&barrier2);
+ });
+ }
+ barrier_wait(&barrier2);
+ NSLog(@"Done.");
+ return 0;
+}
+
+// CHECK: Done.
+// CHECK-NOT: ThreadSanitizer: data race
diff --git a/test/tsan/Darwin/objc-double-property.mm b/test/tsan/Darwin/objc-double-property.mm
new file mode 100644
index 000000000000..51b10f21c9ca
--- /dev/null
+++ b/test/tsan/Darwin/objc-double-property.mm
@@ -0,0 +1,21 @@
+// RUN: %clangxx_tsan -O0 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O2 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O3 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+@interface MyClass : NSObject
+@property float a;
+@property double b;
+@property long double c;
+@end
+
+@implementation MyClass
+@end
+
+int main() {
+ NSLog(@"Hello world");
+}
+
+// CHECK: Hello world
diff --git a/test/tsan/Darwin/osatomics-bitops.mm b/test/tsan/Darwin/osatomics-bitops.mm
new file mode 100644
index 000000000000..68badb792fd6
--- /dev/null
+++ b/test/tsan/Darwin/osatomics-bitops.mm
@@ -0,0 +1,34 @@
+// 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>
+
+int main(int argc, const char *argv[]) {
+ int value = 1;
+ bool ret = OSAtomicTestAndClear(7, &value);
+ fprintf(stderr, "value = %d, ret = %d\n", value, ret);
+ // CHECK: value = 0, ret = 1
+
+ ret = OSAtomicTestAndSet(4, &value);
+ fprintf(stderr, "value = %d, ret = %d\n", value, ret);
+ // CHECK: value = 8, ret = 0
+
+ ret = OSAtomicTestAndClear(4, &value);
+ fprintf(stderr, "value = %d, ret = %d\n", value, ret);
+ // CHECK: value = 0, ret = 1
+
+ ret = OSAtomicTestAndSet(12, &value);
+ fprintf(stderr, "value = %d, ret = %d\n", value, ret);
+ // CHECK: value = 2048, ret = 0
+
+ ret = OSAtomicTestAndSet(13, &value);
+ fprintf(stderr, "value = %d, ret = %d\n", value, ret);
+ // CHECK: value = 3072, ret = 0
+
+ ret = OSAtomicTestAndClear(12, &value);
+ fprintf(stderr, "value = %d, ret = %d\n", value, ret);
+ // CHECK: value = 1024, ret = 1
+
+ return 0;
+}
diff --git a/test/tsan/Darwin/realloc-zero.cc b/test/tsan/Darwin/realloc-zero.cc
new file mode 100644
index 000000000000..98262463cb2d
--- /dev/null
+++ b/test/tsan/Darwin/realloc-zero.cc
@@ -0,0 +1,20 @@
+// Test that realloc(nullptr, 0) return a non-NULL pointer.
+
+// RUN: %clang_tsan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <malloc/malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+int main() {
+ void *p = realloc(NULL, 0);
+ if (!p) {
+ abort();
+ }
+ fprintf(stderr, "Okay.\n");
+ return 0;
+}
+
+// CHECK: Okay.