diff options
Diffstat (limited to 'test/tsan/Darwin')
-rw-r--r-- | test/tsan/Darwin/gcd-apply-race.mm | 4 | ||||
-rw-r--r-- | test/tsan/Darwin/gcd-apply.mm | 4 | ||||
-rw-r--r-- | test/tsan/Darwin/gcd-suspend.mm | 45 | ||||
-rw-r--r-- | test/tsan/Darwin/gcd-target-queue-norace.mm | 41 | ||||
-rw-r--r-- | test/tsan/Darwin/libcxx-call-once.mm | 34 | ||||
-rw-r--r-- | test/tsan/Darwin/libcxx-future.mm | 30 | ||||
-rw-r--r-- | test/tsan/Darwin/norace-objcxx-run-time.mm | 113 | ||||
-rw-r--r-- | test/tsan/Darwin/objc-double-property.mm | 21 | ||||
-rw-r--r-- | test/tsan/Darwin/osatomics-bitops.mm | 34 | ||||
-rw-r--r-- | test/tsan/Darwin/realloc-zero.cc | 20 |
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. |