aboutsummaryrefslogtreecommitdiff
path: root/test/tsan
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
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')
-rw-r--r--test/tsan/CMakeLists.txt3
-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
-rw-r--r--test/tsan/Linux/check_preinit.cc60
-rw-r--r--test/tsan/Linux/user_malloc.cc2
-rw-r--r--test/tsan/Unit/lit.site.cfg.in3
-rw-r--r--test/tsan/aligned_vs_unaligned_race.cc4
-rw-r--r--test/tsan/benign_race.cc2
-rw-r--r--test/tsan/blacklist.cc2
-rw-r--r--test/tsan/blacklist2.cc2
-rw-r--r--test/tsan/debugging.cc108
-rw-r--r--test/tsan/dl_iterate_phdr.cc2
-rw-r--r--test/tsan/dtls.c62
-rw-r--r--test/tsan/fd_close_norace.cc2
-rw-r--r--test/tsan/fd_close_norace2.cc2
-rw-r--r--test/tsan/fd_dup_norace.cc2
-rw-r--r--test/tsan/fd_dup_norace2.cc2
-rw-r--r--test/tsan/fd_dup_race.cc2
-rw-r--r--test/tsan/fd_pipe_norace.cc2
-rw-r--r--test/tsan/fd_socket_connect_norace.cc2
-rw-r--r--test/tsan/fd_socket_norace.cc2
-rw-r--r--test/tsan/fd_socketpair_norace.cc2
-rw-r--r--test/tsan/fork_atexit.cc1
-rw-r--r--test/tsan/fork_deadlock.cc11
-rw-r--r--test/tsan/fork_multithreaded.cc3
-rw-r--r--test/tsan/fork_multithreaded3.cc1
-rw-r--r--test/tsan/ignore_lib4.cc48
-rw-r--r--test/tsan/ignore_race.cc2
-rw-r--r--test/tsan/ignored-interceptors-mmap.cc61
-rw-r--r--test/tsan/inlined_memcpy_race.cc4
-rw-r--r--test/tsan/inlined_memcpy_race2.cc6
-rw-r--r--test/tsan/interface_atomic_test.c4
-rw-r--r--test/tsan/java_alloc.cc4
-rw-r--r--test/tsan/java_heap_init.cc2
-rw-r--r--test/tsan/java_lock_move.cc2
-rw-r--r--test/tsan/java_lock_rec.cc8
-rw-r--r--test/tsan/java_lock_rec_race.cc6
-rw-r--r--test/tsan/java_move_overlap.cc2
-rw-r--r--test/tsan/java_move_overlap_race.cc6
-rw-r--r--test/tsan/java_race_pc.cc8
-rw-r--r--test/tsan/java_rwlock.cc2
-rw-r--r--test/tsan/lit.cfg3
-rw-r--r--test/tsan/lit.site.cfg.in5
-rw-r--r--test/tsan/longjmp.cc4
-rw-r--r--test/tsan/longjmp2.cc4
-rw-r--r--test/tsan/longjmp3.cc4
-rw-r--r--test/tsan/longjmp4.cc4
-rw-r--r--test/tsan/lots_of_threads.c30
-rw-r--r--test/tsan/malloc_overflow.cc10
-rw-r--r--test/tsan/mmap_stress.cc5
-rw-r--r--test/tsan/mutex_annotations.cc49
-rw-r--r--test/tsan/mutex_cycle_long.c42
-rw-r--r--test/tsan/mutex_lock_destroyed.cc25
-rw-r--r--test/tsan/pthread_key.cc39
-rw-r--r--test/tsan/race_on_mutex.c32
-rw-r--r--test/tsan/race_on_speculative_load.cc4
-rw-r--r--test/tsan/setuid.c6
-rw-r--r--test/tsan/setuid2.c6
-rw-r--r--test/tsan/signal_sync2.cc77
-rw-r--r--test/tsan/static_init1.cc2
-rw-r--r--test/tsan/static_init2.cc2
-rw-r--r--test/tsan/static_init4.cc2
-rw-r--r--test/tsan/static_init5.cc2
-rw-r--r--test/tsan/static_init6.cc4
-rw-r--r--test/tsan/sunrpc.cc2
-rw-r--r--test/tsan/suppressions_global.cc2
-rw-r--r--test/tsan/suppressions_race.cc2
-rw-r--r--test/tsan/suppressions_race2.cc2
-rw-r--r--test/tsan/test.h35
-rw-r--r--test/tsan/thread_detach.c2
-rw-r--r--test/tsan/thread_detach2.c2
-rw-r--r--test/tsan/thread_leak.c2
-rw-r--r--test/tsan/thread_leak2.c2
-rw-r--r--test/tsan/thread_leak4.c2
-rw-r--r--test/tsan/tsan-vs-gvn.cc2
-rw-r--r--test/tsan/unaligned_norace.cc2
-rw-r--r--test/tsan/vfork.cc5
-rw-r--r--test/tsan/virtual_inheritance_compile_bug.cc2
122 files changed, 2451 insertions, 136 deletions
diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt
index a058602659c1..e05b100f3699 100644
--- a/test/tsan/CMakeLists.txt
+++ b/test/tsan/CMakeLists.txt
@@ -22,6 +22,7 @@ if(APPLE)
endif()
foreach(arch ${TSAN_TEST_ARCH})
+ set(TSAN_TEST_TARGET_ARCH ${arch})
string(TOLOWER "-${arch}" TSAN_TEST_CONFIG_SUFFIX)
if(ANDROID OR ${arch} MATCHES "arm|aarch64")
# This is only true if we are cross-compiling.
@@ -53,4 +54,4 @@ endif()
add_lit_testsuite(check-tsan "Running ThreadSanitizer tests"
${TSAN_TESTSUITES}
DEPENDS ${TSAN_TEST_DEPS})
-set_target_properties(check-tsan PROPERTIES FOLDER "TSan tests")
+set_target_properties(check-tsan PROPERTIES FOLDER "Compiler-RT Tests")
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
diff --git a/test/tsan/Linux/check_preinit.cc b/test/tsan/Linux/check_preinit.cc
new file mode 100644
index 000000000000..8f5bf4033760
--- /dev/null
+++ b/test/tsan/Linux/check_preinit.cc
@@ -0,0 +1,60 @@
+// RUN: %clang_tsan -fno-sanitize=thread -shared -fPIC -O1 -DBUILD_SO=1 %s -o \
+// RUN: %t.so && \
+// RUN: %clang_tsan -O1 %s %t.so -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: llvm-objdump -t %t | FileCheck %s --check-prefix=CHECK-DUMP
+// CHECK-DUMP: {{[.]preinit_array.*__local_tsan_preinit}}
+
+// SANITIZER_CAN_USE_PREINIT_ARRAY is undefined on android.
+// UNSUPPORTED: android
+
+// Test checks if __tsan_init is called from .preinit_array.
+// Without initialization from .preinit_array, __tsan_init will be called from
+// constructors of the binary which are called after constructors of shared
+// library.
+
+#include <stdio.h>
+
+#if BUILD_SO
+
+// "volatile" is needed to avoid compiler optimize-out constructors.
+volatile int counter = 0;
+volatile int lib_constructor_call = 0;
+volatile int tsan_init_call = 0;
+
+__attribute__ ((constructor))
+void LibConstructor() {
+ lib_constructor_call = ++counter;
+};
+
+#else // BUILD_SO
+
+extern int counter;
+extern int lib_constructor_call;
+extern int tsan_init_call;
+
+volatile int bin_constructor_call = 0;
+
+__attribute__ ((constructor))
+void BinConstructor() {
+ bin_constructor_call = ++counter;
+};
+
+namespace __tsan {
+
+void OnInitialize() {
+ tsan_init_call = ++counter;
+}
+
+}
+
+int main() {
+ // CHECK: TSAN_INIT 1
+ // CHECK: LIB_CONSTRUCTOR 2
+ // CHECK: BIN_CONSTRUCTOR 3
+ printf("TSAN_INIT %d\n", tsan_init_call);
+ printf("LIB_CONSTRUCTOR %d\n", lib_constructor_call);
+ printf("BIN_CONSTRUCTOR %d\n", bin_constructor_call);
+ return 0;
+}
+
+#endif // BUILD_SO
diff --git a/test/tsan/Linux/user_malloc.cc b/test/tsan/Linux/user_malloc.cc
index c671bfcdd17a..9c3ce681d748 100644
--- a/test/tsan/Linux/user_malloc.cc
+++ b/test/tsan/Linux/user_malloc.cc
@@ -8,7 +8,7 @@ extern "C" void __interceptor_free(void *p);
extern "C" void *malloc(unsigned long size) {
static int first = 0;
if (__sync_lock_test_and_set(&first, 1) == 0)
- printf("user malloc\n");
+ fprintf(stderr, "user malloc\n");
return __interceptor_malloc(size);
}
diff --git a/test/tsan/Unit/lit.site.cfg.in b/test/tsan/Unit/lit.site.cfg.in
index 9498105653a1..23894a839856 100644
--- a/test/tsan/Unit/lit.site.cfg.in
+++ b/test/tsan/Unit/lit.site.cfg.in
@@ -1,5 +1,4 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
+@LIT_SITE_CFG_IN_HEADER@
# Load common config for all compiler-rt unit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured")
diff --git a/test/tsan/aligned_vs_unaligned_race.cc b/test/tsan/aligned_vs_unaligned_race.cc
index 5c1189f34a4b..fb299da8e72e 100644
--- a/test/tsan/aligned_vs_unaligned_race.cc
+++ b/test/tsan/aligned_vs_unaligned_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
// Race between an aligned access and an unaligned access, which
// touches the same memory region.
#include "test.h"
@@ -28,7 +28,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("Pass\n");
+ fprintf(stderr, "Pass\n");
// CHECK: ThreadSanitizer: data race
// CHECK: Pass
return 0;
diff --git a/test/tsan/benign_race.cc b/test/tsan/benign_race.cc
index 2f72fe1860d0..90722aa93157 100644
--- a/test/tsan/benign_race.cc
+++ b/test/tsan/benign_race.cc
@@ -33,7 +33,7 @@ int main() {
Global = 43;
WTFGlobal = 143;
pthread_join(t, 0);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/blacklist.cc b/test/tsan/blacklist.cc
index d6ca383cb758..c1bcca60d505 100644
--- a/test/tsan/blacklist.cc
+++ b/test/tsan/blacklist.cc
@@ -23,7 +23,7 @@ int main() {
pthread_create(&t[1], NULL, Blacklisted_Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
diff --git a/test/tsan/blacklist2.cc b/test/tsan/blacklist2.cc
index 629b58821bfe..bf6c4eb75b65 100644
--- a/test/tsan/blacklist2.cc
+++ b/test/tsan/blacklist2.cc
@@ -44,6 +44,6 @@ int main() {
pthread_create(&t[1], NULL, Blacklisted_Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
diff --git a/test/tsan/debugging.cc b/test/tsan/debugging.cc
new file mode 100644
index 000000000000..653364404eb0
--- /dev/null
+++ b/test/tsan/debugging.cc
@@ -0,0 +1,108 @@
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test.h"
+
+extern "C" {
+void __tsan_on_report(void *report);
+void *__tsan_get_current_report();
+int __tsan_get_report_data(void *report, const char **description, int *count,
+ int *stack_count, int *mop_count, int *loc_count,
+ int *mutex_count, int *thread_count,
+ int *unique_tid_count, void **sleep_trace,
+ unsigned long trace_size);
+int __tsan_get_report_mop(void *report, unsigned long idx, int *tid,
+ void **addr, int *size, int *write, int *atomic,
+ void **trace, unsigned long trace_size);
+int __tsan_get_report_thread(void *report, unsigned long idx, int *tid,
+ unsigned long *os_id, int *running,
+ const char **name, int *parent_tid, void **trace,
+ unsigned long trace_size);
+}
+
+long my_global;
+
+void *Thread(void *a) {
+ barrier_wait(&barrier);
+ my_global = 42;
+ return NULL;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ fprintf(stderr, "&my_global = %p\n", &my_global);
+ // CHECK: &my_global = [[GLOBAL:0x[0-9a-f]+]]
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ my_global = 41;
+ barrier_wait(&barrier);
+ pthread_join(t, 0);
+ fprintf(stderr, "Done.\n");
+}
+
+void __tsan_on_report(void *report) {
+ fprintf(stderr, "__tsan_on_report(%p)\n", report);
+ fprintf(stderr, "__tsan_get_current_report() = %p\n",
+ __tsan_get_current_report());
+ // CHECK: __tsan_on_report([[REPORT:0x[0-9a-f]+]])
+ // CHECK: __tsan_get_current_report() = [[REPORT]]
+
+ const char *description;
+ int count;
+ int stack_count, mop_count, loc_count, mutex_count, thread_count,
+ unique_tid_count;
+ void *sleep_trace[16] = {0};
+ __tsan_get_report_data(report, &description, &count, &stack_count, &mop_count,
+ &loc_count, &mutex_count, &thread_count,
+ &unique_tid_count, sleep_trace, 16);
+ fprintf(stderr, "report type = '%s', count = %d\n", description, count);
+ // CHECK: report type = 'data-race', count = 0
+
+ fprintf(stderr, "mop_count = %d\n", mop_count);
+ // CHECK: mop_count = 2
+
+ int tid;
+ void *addr;
+ int size, write, atomic;
+ void *trace[16] = {0};
+
+ __tsan_get_report_mop(report, 0, &tid, &addr, &size, &write, &atomic, trace,
+ 16);
+ fprintf(stderr, "tid = %d, addr = %p, size = %d, write = %d, atomic = %d\n",
+ tid, addr, size, write, atomic);
+ // CHECK: tid = 1, addr = [[GLOBAL]], size = 8, write = 1, atomic = 0
+ fprintf(stderr, "trace[0] = %p, trace[1] = %p\n", trace[0], trace[1]);
+ // CHECK: trace[0] = 0x{{[0-9a-f]+}}, trace[1] = {{0x0|\(nil\)|\(null\)}}
+
+ __tsan_get_report_mop(report, 1, &tid, &addr, &size, &write, &atomic, trace,
+ 16);
+ fprintf(stderr, "tid = %d, addr = %p, size = %d, write = %d, atomic = %d\n",
+ tid, addr, size, write, atomic);
+ // CHECK: tid = 0, addr = [[GLOBAL]], size = 8, write = 1, atomic = 0
+ fprintf(stderr, "trace[0] = %p, trace[1] = %p\n", trace[0], trace[1]);
+ // CHECK: trace[0] = 0x{{[0-9a-f]+}}, trace[1] = {{0x0|\(nil\)|\(null\)}}
+
+ fprintf(stderr, "thread_count = %d\n", thread_count);
+ // CHECK: thread_count = 2
+
+ unsigned long os_id;
+ int running;
+ const char *name;
+ int parent_tid;
+
+ __tsan_get_report_thread(report, 0, &tid, &os_id, &running, &name, &parent_tid, trace, 16);
+ fprintf(stderr, "tid = %d\n", tid);
+ // CHECK: tid = 1
+
+ __tsan_get_report_thread(report, 1, &tid, &os_id, &running, &name, &parent_tid, trace, 16);
+ fprintf(stderr, "tid = %d\n", tid);
+ // CHECK: tid = 0
+}
+
+// CHECK: Done.
+// CHECK: ThreadSanitizer: reported 1 warnings
diff --git a/test/tsan/dl_iterate_phdr.cc b/test/tsan/dl_iterate_phdr.cc
index b9ce615f82fe..3c9821bf458a 100644
--- a/test/tsan/dl_iterate_phdr.cc
+++ b/test/tsan/dl_iterate_phdr.cc
@@ -47,7 +47,7 @@ int main(int argc, char *argv[]) {
dlclose(lib);
}
pthread_join(th, 0);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return 0;
}
diff --git a/test/tsan/dtls.c b/test/tsan/dtls.c
new file mode 100644
index 000000000000..51697565f1f1
--- /dev/null
+++ b/test/tsan/dtls.c
@@ -0,0 +1,62 @@
+// RUN: %clang_tsan %s -o %t
+// RUN: %clang_tsan %s -DBUILD_SO -fPIC -o %t-so.so -shared
+// RUN: %run %t 2>&1 | FileCheck %s
+
+// Test that tsan cleans up dynamic TLS memory between reuse.
+
+#include "test.h"
+
+#ifndef BUILD_SO
+#include <assert.h>
+#include <dlfcn.h>
+
+typedef volatile long *(* get_t)();
+get_t GetTls;
+
+void *Thread1(void *arg) {
+ pthread_detach(pthread_self());
+ volatile long *x = GetTls();
+ *x = 42;
+ fprintf(stderr, "stack: %p dtls: %p\n", &x, x);
+ barrier_wait(&barrier);
+ return 0;
+}
+
+void *Thread2(void *arg) {
+ volatile long *x = GetTls();
+ *x = 42;
+ fprintf(stderr, "stack: %p dtls: %p\n", &x, x);
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ char path[4096];
+ snprintf(path, sizeof(path), "%s-so.so", argv[0]);
+
+ void *handle = dlopen(path, RTLD_LAZY);
+ if (!handle) fprintf(stderr, "%s\n", dlerror());
+ assert(handle != 0);
+ GetTls = (get_t)dlsym(handle, "GetTls");
+ assert(dlerror() == 0);
+
+ barrier_init(&barrier, 2);
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ barrier_wait(&barrier);
+ // Wait for actual thread termination without using pthread_join,
+ // which would synchronize threads.
+ sleep(1);
+ pthread_create(&t[1], 0, Thread2, 0);
+ pthread_join(t[1], 0);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+#else // BUILD_SO
+__thread long huge_thread_local_array[1 << 17];
+long *GetTls() {
+ return &huge_thread_local_array[0];
+}
+#endif
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/fd_close_norace.cc b/test/tsan/fd_close_norace.cc
index 1b52c20f990c..7d9d491f1dcc 100644
--- a/test/tsan/fd_close_norace.cc
+++ b/test/tsan/fd_close_norace.cc
@@ -25,7 +25,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_close_norace2.cc b/test/tsan/fd_close_norace2.cc
index bf94fd5512b3..382ae5f34a83 100644
--- a/test/tsan/fd_close_norace2.cc
+++ b/test/tsan/fd_close_norace2.cc
@@ -23,7 +23,7 @@ int main() {
while (write(pipes[1], &t, 1) != 1) {
}
pthread_join(t, 0);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_dup_norace.cc b/test/tsan/fd_dup_norace.cc
index 5045325b22b5..e5995175bc0f 100644
--- a/test/tsan/fd_dup_norace.cc
+++ b/test/tsan/fd_dup_norace.cc
@@ -28,7 +28,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_dup_norace2.cc b/test/tsan/fd_dup_norace2.cc
index 662c686f33a8..31aaed9d356c 100644
--- a/test/tsan/fd_dup_norace2.cc
+++ b/test/tsan/fd_dup_norace2.cc
@@ -53,7 +53,7 @@ int main() {
exit(printf("close failed\n"));
if (close(fd2) == -1)
exit(printf("close failed\n"));
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_dup_race.cc b/test/tsan/fd_dup_race.cc
index a1aee5500753..d665eebff987 100644
--- a/test/tsan/fd_dup_race.cc
+++ b/test/tsan/fd_dup_race.cc
@@ -27,7 +27,7 @@ int main() {
exit(printf("dup2 failed\n"));
barrier_wait(&barrier);
pthread_join(th, 0);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
}
// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_pipe_norace.cc b/test/tsan/fd_pipe_norace.cc
index b434703d782a..01c4490c6c89 100644
--- a/test/tsan/fd_pipe_norace.cc
+++ b/test/tsan/fd_pipe_norace.cc
@@ -27,7 +27,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_socket_connect_norace.cc b/test/tsan/fd_socket_connect_norace.cc
index ab2a950f17d6..b9fb4340ad78 100644
--- a/test/tsan/fd_socket_connect_norace.cc
+++ b/test/tsan/fd_socket_connect_norace.cc
@@ -38,7 +38,7 @@ int main() {
pthread_join(t, 0);
close(c);
close(s);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_socket_norace.cc b/test/tsan/fd_socket_norace.cc
index 0f41c4357354..07b0cb356b8c 100644
--- a/test/tsan/fd_socket_norace.cc
+++ b/test/tsan/fd_socket_norace.cc
@@ -45,7 +45,7 @@ int main() {
close(c);
close(s);
pthread_join(t, 0);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_socketpair_norace.cc b/test/tsan/fd_socketpair_norace.cc
index a455d44a3965..bee030dd3249 100644
--- a/test/tsan/fd_socketpair_norace.cc
+++ b/test/tsan/fd_socketpair_norace.cc
@@ -31,7 +31,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fork_atexit.cc b/test/tsan/fork_atexit.cc
index 51a64fc264d1..15cf0a2485ca 100644
--- a/test/tsan/fork_atexit.cc
+++ b/test/tsan/fork_atexit.cc
@@ -1,5 +1,4 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=50 %run %t 2>&1 | FileCheck %s
-// UNSUPPORTED: darwin
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/test/tsan/fork_deadlock.cc b/test/tsan/fork_deadlock.cc
index 22bed086f7d0..32006e2ae530 100644
--- a/test/tsan/fork_deadlock.cc
+++ b/test/tsan/fork_deadlock.cc
@@ -1,5 +1,4 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=50 %run %t 2>&1 | FileCheck %s
-// UNSUPPORTED: darwin
#include "test.h"
#include <errno.h>
#include <sys/types.h>
@@ -13,18 +12,10 @@ static void *incrementer(void *p) {
return 0;
}
-static void *watchdog(void *p) {
- sleep(100); // is not intended to exit
- fprintf(stderr, "timed out after 100 seconds\n");
- exit(1);
- return 0;
-}
-
int main() {
barrier_init(&barrier, 2);
- pthread_t th1, th2;
+ pthread_t th1;
pthread_create(&th1, 0, incrementer, 0);
- pthread_create(&th2, 0, watchdog, 0);
for (int i = 0; i < 10; i++) {
switch (fork()) {
default: // parent
diff --git a/test/tsan/fork_multithreaded.cc b/test/tsan/fork_multithreaded.cc
index b345f58ad0c3..faf407b95656 100644
--- a/test/tsan/fork_multithreaded.cc
+++ b/test/tsan/fork_multithreaded.cc
@@ -1,13 +1,12 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-DIE
// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=die_after_fork=0 %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-NODIE
-// UNSUPPORTED: darwin
#include "test.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
static void *sleeper(void *p) {
- sleep(10); // not intended to exit during test
+ sleep(1000); // not intended to exit during test
return 0;
}
diff --git a/test/tsan/fork_multithreaded3.cc b/test/tsan/fork_multithreaded3.cc
index 5b8c13eb8b85..a651b3c18b4e 100644
--- a/test/tsan/fork_multithreaded3.cc
+++ b/test/tsan/fork_multithreaded3.cc
@@ -1,5 +1,4 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
-// UNSUPPORTED: darwin
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
diff --git a/test/tsan/ignore_lib4.cc b/test/tsan/ignore_lib4.cc
new file mode 100644
index 000000000000..193df11d2b2a
--- /dev/null
+++ b/test/tsan/ignore_lib4.cc
@@ -0,0 +1,48 @@
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -shared -o %T/libignore_lib4.so
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: echo "called_from_lib:libignore_lib4.so" > %t.supp
+// RUN: %env_tsan_opts=suppressions='%t.supp' %run %t 2>&1 | FileCheck %s
+
+// Longjmp assembly has not been implemented for mips64 yet
+// XFAIL: mips64
+// powerpc64 big endian bots failed with "FileCheck error: '-' is empty" due
+// to a segmentation fault.
+// UNSUPPORTED: powerpc64-unknown-linux-gnu
+// aarch64 bots failed with "called_from_lib suppression 'libignore_lib4.so'
+// is matched against 2 libraries".
+// UNSUPPORTED: aarch64
+
+// Test longjmp in ignored lib.
+// It used to crash since we jumped out of ScopedInterceptor scope.
+
+#include "test.h"
+#include <setjmp.h>
+#include <string.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string>
+
+#ifdef LIB
+
+extern "C" void myfunc() {
+ for (int i = 0; i < (1 << 20); i++) {
+ jmp_buf env;
+ if (!setjmp(env))
+ longjmp(env, 1);
+ }
+}
+
+#else
+
+int main(int argc, char **argv) {
+ std::string lib = std::string(dirname(argv[0])) + "/libignore_lib4.so";
+ void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW);
+ void (*func)() = (void(*)())dlsym(h, "myfunc");
+ func();
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+#endif
+
+// CHECK: DONE
diff --git a/test/tsan/ignore_race.cc b/test/tsan/ignore_race.cc
index cc33b66b27d4..e410006ddc72 100644
--- a/test/tsan/ignore_race.cc
+++ b/test/tsan/ignore_race.cc
@@ -25,7 +25,7 @@ int main() {
barrier_wait(&barrier);
Global = 43;
pthread_join(t, 0);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/ignored-interceptors-mmap.cc b/test/tsan/ignored-interceptors-mmap.cc
new file mode 100644
index 000000000000..8715883238e2
--- /dev/null
+++ b/test/tsan/ignored-interceptors-mmap.cc
@@ -0,0 +1,61 @@
+// RUN: %clangxx_tsan -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NORMAL
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-IGNORE
+
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "test.h"
+
+extern "C" {
+void AnnotateIgnoreReadsBegin(const char *f, int l);
+void AnnotateIgnoreReadsEnd(const char *f, int l);
+void AnnotateIgnoreWritesBegin(const char *f, int l);
+void AnnotateIgnoreWritesEnd(const char *f, int l);
+}
+
+void *global_p;
+
+int mmap_and_ignore_reads_and_writes() {
+ const size_t kSize = sysconf(_SC_PAGESIZE);
+ void *p = mmap(0, kSize, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANON, -1, 0);
+ if (p == MAP_FAILED)
+ return printf("mmap failed with %d\n", errno);
+ munmap(p, kSize);
+
+ void *new_p = mmap(p, kSize, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANON, -1, 0);
+ if (p == MAP_FAILED || p != new_p)
+ return printf("second mmap failed with %d\n", errno);
+
+ AnnotateIgnoreWritesBegin(__FILE__, __LINE__);
+ global_p = p;
+ AnnotateIgnoreWritesEnd(__FILE__, __LINE__);
+ barrier_wait(&barrier);
+ return 0;
+}
+
+void *Thread(void *a) {
+ barrier_wait(&barrier);
+
+ ((int*)global_p)[1] = 10;
+ printf("Read the zero value from mmapped memory %d\n", ((int*)global_p)[1]);
+ return 0;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ if (mmap_and_ignore_reads_and_writes())
+ return 1;
+ pthread_join(t, 0);
+ printf("OK\n");
+ return 0;
+}
+
+// CHECK-NORMAL: WARNING: ThreadSanitizer: data race
+// CHECK-NORMAL: OK
+// CHECK-IGNORE_NOT: WARNING: ThreadSanitizer: data race
+// CHECK-IGNORE: OK
diff --git a/test/tsan/inlined_memcpy_race.cc b/test/tsan/inlined_memcpy_race.cc
index 720f2bfcac8c..4d085893aae0 100644
--- a/test/tsan/inlined_memcpy_race.cc
+++ b/test/tsan/inlined_memcpy_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
#include "test.h"
#include <string.h>
@@ -24,7 +24,7 @@ int main() {
pthread_create(&t[1], NULL, MemSetThread, x);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
diff --git a/test/tsan/inlined_memcpy_race2.cc b/test/tsan/inlined_memcpy_race2.cc
index 37414ba5d3db..906a52bd32e4 100644
--- a/test/tsan/inlined_memcpy_race2.cc
+++ b/test/tsan/inlined_memcpy_race2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
#include "test.h"
#include <string.h>
@@ -25,7 +25,7 @@ int main() {
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
@@ -33,5 +33,5 @@ int main() {
// CHECK: #0 memset
// CHECK: #1 MemSetThread
// CHECK: Previous write
-// CHECK: #0 memmove
+// CHECK: #0 {{(memcpy|memmove)}}
// CHECK: #1 MemMoveThread
diff --git a/test/tsan/interface_atomic_test.c b/test/tsan/interface_atomic_test.c
index 18d860ea02e2..b7dfc86afa39 100644
--- a/test/tsan/interface_atomic_test.c
+++ b/test/tsan/interface_atomic_test.c
@@ -1,5 +1,5 @@
// Test that we can include header with TSan atomic interface.
-// RUN: %clang_tsan %s -o %t && %run %t | FileCheck %s
+// RUN: %clang_tsan %s -o %t && %run %t 2>&1 | FileCheck %s
#include <sanitizer/tsan_interface_atomic.h>
#include <stdio.h>
@@ -9,7 +9,7 @@ int main() {
int res = __tsan_atomic32_load(&a, __tsan_memory_order_acquire);
if (res == 100) {
// CHECK: PASS
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
return 1;
diff --git a/test/tsan/java_alloc.cc b/test/tsan/java_alloc.cc
index 4a606f7940d3..94919a4373a4 100644
--- a/test/tsan/java_alloc.cc
+++ b/test/tsan/java_alloc.cc
@@ -26,10 +26,10 @@ int main() {
stress(jheap);
pthread_join(th, 0);
if (__tsan_java_fini() != 0) {
- printf("FAILED\n");
+ fprintf(stderr, "FAILED\n");
return 1;
}
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return 0;
}
diff --git a/test/tsan/java_heap_init.cc b/test/tsan/java_heap_init.cc
index bb7357c25b42..47ec5dbad28e 100644
--- a/test/tsan/java_heap_init.cc
+++ b/test/tsan/java_heap_init.cc
@@ -20,7 +20,7 @@ int main() {
return printf("second mmap failed with %d\n", errno);
__tsan_java_init(jheap, kHeapSize);
__tsan_java_move(jheap + 16, jheap, 16);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/java_lock_move.cc b/test/tsan/java_lock_move.cc
index fe5491dc2aa0..66599f8b7081 100644
--- a/test/tsan/java_lock_move.cc
+++ b/test/tsan/java_lock_move.cc
@@ -35,7 +35,7 @@ int main() {
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(varaddr2, kBlockSize);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/java_lock_rec.cc b/test/tsan/java_lock_rec.cc
index f0bf40196e9f..aa8de97a148b 100644
--- a/test/tsan/java_lock_rec.cc
+++ b/test/tsan/java_lock_rec.cc
@@ -10,14 +10,14 @@ void *Thread(void *p) {
*(int*)varaddr = 42;
int rec = __tsan_java_mutex_unlock_rec(lockaddr);
if (rec != 2) {
- printf("FAILED 0 rec=%d\n", rec);
+ fprintf(stderr, "FAILED 0 rec=%d\n", rec);
exit(1);
}
barrier_wait(&barrier);
barrier_wait(&barrier);
__tsan_java_mutex_lock_rec(lockaddr, rec);
if (*(int*)varaddr != 43) {
- printf("FAILED 3 var=%d\n", *(int*)varaddr);
+ fprintf(stderr, "FAILED 3 var=%d\n", *(int*)varaddr);
exit(1);
}
__tsan_java_mutex_unlock(lockaddr);
@@ -40,7 +40,7 @@ int main() {
barrier_wait(&barrier);
__tsan_java_mutex_lock(lockaddr);
if (*(int*)varaddr != 42) {
- printf("FAILED 1 var=%d\n", *(int*)varaddr);
+ fprintf(stderr, "FAILED 1 var=%d\n", *(int*)varaddr);
exit(1);
}
*(int*)varaddr = 43;
@@ -48,7 +48,7 @@ int main() {
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(jheap, kBlockSize);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/java_lock_rec_race.cc b/test/tsan/java_lock_rec_race.cc
index 3da8ad076990..bf56eef2022c 100644
--- a/test/tsan/java_lock_rec_race.cc
+++ b/test/tsan/java_lock_rec_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
#include "java.h"
jptr varaddr;
@@ -10,7 +10,7 @@ void *Thread(void *p) {
__tsan_java_mutex_lock(lockaddr);
int rec = __tsan_java_mutex_unlock_rec(lockaddr);
if (rec != 3) {
- printf("FAILED 0 rec=%d\n", rec);
+ fprintf(stderr, "FAILED 0 rec=%d\n", rec);
exit(1);
}
*(int*)varaddr = 42;
@@ -42,7 +42,7 @@ int main() {
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(jheap, kBlockSize);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/java_move_overlap.cc b/test/tsan/java_move_overlap.cc
index 7ed98ef1a210..bf8d1e1550fc 100644
--- a/test/tsan/java_move_overlap.cc
+++ b/test/tsan/java_move_overlap.cc
@@ -66,7 +66,7 @@ int main(int argc, char **argv) {
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(varaddr1_new, kBlockSize);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/java_move_overlap_race.cc b/test/tsan/java_move_overlap_race.cc
index 874b90b26341..fbbcf2c8a33f 100644
--- a/test/tsan/java_move_overlap_race.cc
+++ b/test/tsan/java_move_overlap_race.cc
@@ -1,6 +1,6 @@
// RUN: %clangxx_tsan -O1 %s -o %t
-// RUN: %deflake %run %t | FileCheck %s
-// RUN: %deflake %run %t arg | FileCheck %s
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
+// RUN: %deflake %run %t arg 2>&1 | FileCheck %s
#include "java.h"
jptr varaddr1_old;
@@ -46,7 +46,7 @@ int main(int argc, char **argv) {
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(varaddr1_new, kBlockSize);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/java_race_pc.cc b/test/tsan/java_race_pc.cc
index 0745ade6c479..be1c5f26a3b1 100644
--- a/test/tsan/java_race_pc.cc
+++ b/test/tsan/java_race_pc.cc
@@ -1,8 +1,8 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
-// This test fails on powerpc64 on both VMA (44 and 46).
+// This test fails on powerpc64 big endian.
// The Tsan report is returning wrong information about
// the location of the race.
-// XFAIL: powerpc64
+// XFAIL: powerpc64-unknown-linux-gnu
#include "java.h"
void foobar() {
@@ -13,7 +13,7 @@ void barbaz() {
void *Thread(void *p) {
barrier_wait(&barrier);
- __tsan_read1_pc((jptr)p, (jptr)foobar + 1);
+ __tsan_read1_pc((jptr)p, (jptr)foobar + kPCInc);
return 0;
}
@@ -26,7 +26,7 @@ int main() {
__tsan_java_alloc(jheap, kBlockSize);
pthread_t th;
pthread_create(&th, 0, Thread, (void*)jheap);
- __tsan_write1_pc((jptr)jheap, (jptr)barbaz + 1);
+ __tsan_write1_pc((jptr)jheap, (jptr)barbaz + kPCInc);
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(jheap, kBlockSize);
diff --git a/test/tsan/java_rwlock.cc b/test/tsan/java_rwlock.cc
index a4cc92a13635..aa77273a41b5 100644
--- a/test/tsan/java_rwlock.cc
+++ b/test/tsan/java_rwlock.cc
@@ -29,7 +29,7 @@ int main() {
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(jheap, kBlockSize);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg
index d141fc228512..1fc1eccd15ea 100644
--- a/test/tsan/lit.cfg
+++ b/test/tsan/lit.cfg
@@ -50,11 +50,12 @@ clang_tsan_cxxflags = config.cxx_mode_flags + clang_tsan_cflags
if config.has_libcxx and config.host_os != 'Darwin':
# FIXME: Dehardcode this path somehow.
libcxx_path = os.path.join(config.compiler_rt_obj_root, "lib",
- "tsan", "libcxx_tsan_" + config.arch)
+ "tsan", "libcxx_tsan_" + config.target_arch)
libcxx_incdir = os.path.join(libcxx_path, "include", "c++", "v1")
libcxx_libdir = os.path.join(libcxx_path, "lib")
libcxx_so = os.path.join(libcxx_libdir, "libc++.so")
clang_tsan_cxxflags += ["-std=c++11",
+ "-nostdinc++",
"-I%s" % libcxx_incdir,
libcxx_so,
"-Wl,-rpath=%s" % libcxx_libdir]
diff --git a/test/tsan/lit.site.cfg.in b/test/tsan/lit.site.cfg.in
index 08d4c1e00c7b..a87e8d25d6b2 100644
--- a/test/tsan/lit.site.cfg.in
+++ b/test/tsan/lit.site.cfg.in
@@ -1,10 +1,9 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
+@LIT_SITE_CFG_IN_HEADER@
config.name_suffix = "@TSAN_TEST_CONFIG_SUFFIX@"
-config.arch = "@arch@"
config.has_libcxx = @TSAN_HAS_LIBCXX@
config.target_cflags = "@TSAN_TEST_TARGET_CFLAGS@"
+config.target_arch = "@TSAN_TEST_TARGET_ARCH@"
# Load common config for all compiler-rt lit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
diff --git a/test/tsan/longjmp.cc b/test/tsan/longjmp.cc
index d642067391fd..61d285c11bf2 100644
--- a/test/tsan/longjmp.cc
+++ b/test/tsan/longjmp.cc
@@ -14,11 +14,11 @@ int foo(jmp_buf env) {
int main() {
jmp_buf env;
if (setjmp(env) == 42) {
- printf("JUMPED\n");
+ fprintf(stderr, "JUMPED\n");
return 0;
}
foo(env);
- printf("FAILED\n");
+ fprintf(stderr, "FAILED\n");
return 0;
}
diff --git a/test/tsan/longjmp2.cc b/test/tsan/longjmp2.cc
index eee423dc5fbe..2b2775a8ca1e 100644
--- a/test/tsan/longjmp2.cc
+++ b/test/tsan/longjmp2.cc
@@ -16,11 +16,11 @@ int main() {
sigjmp_buf env;
printf("env=%p\n", env);
if (sigsetjmp(env, 1) == 42) {
- printf("JUMPED\n");
+ fprintf(stderr, "JUMPED\n");
return 0;
}
foo(env);
- printf("FAILED\n");
+ fprintf(stderr, "FAILED\n");
return 0;
}
diff --git a/test/tsan/longjmp3.cc b/test/tsan/longjmp3.cc
index 79965c4193d3..197b91e1cdc3 100644
--- a/test/tsan/longjmp3.cc
+++ b/test/tsan/longjmp3.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
// Longjmp assembly has not been implemented for mips64 yet
// XFAIL: mips64
@@ -34,7 +34,7 @@ void mymain() {
return;
}
foo(env);
- printf("FAILED\n");
+ fprintf(stderr, "FAILED\n");
}
int main() {
diff --git a/test/tsan/longjmp4.cc b/test/tsan/longjmp4.cc
index c8583997331e..3785a0f07261 100644
--- a/test/tsan/longjmp4.cc
+++ b/test/tsan/longjmp4.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
// Longjmp assembly has not been implemented for mips64 yet
// XFAIL: mips64
@@ -37,7 +37,7 @@ void mymain() {
return;
}
foo(env);
- printf("FAILED\n");
+ fprintf(stderr, "FAILED\n");
}
int main() {
diff --git a/test/tsan/lots_of_threads.c b/test/tsan/lots_of_threads.c
new file mode 100644
index 000000000000..eef9b1cb036c
--- /dev/null
+++ b/test/tsan/lots_of_threads.c
@@ -0,0 +1,30 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+
+void *thr(void *arg) {
+ // Create a sync object on stack, so there is something to free on thread end.
+ volatile int x;
+ __atomic_fetch_add(&x, 1, __ATOMIC_SEQ_CST);
+ barrier_wait(&barrier);
+ return 0;
+}
+
+int main() {
+ const int kThreads = 10;
+ barrier_init(&barrier, kThreads + 1);
+ pthread_t t[kThreads];
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 16 << 20);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ for (int i = 0; i < kThreads; i++)
+ pthread_create(&t[i], &attr, thr, 0);
+ pthread_attr_destroy(&attr);
+ barrier_wait(&barrier);
+ sleep(1);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK: DONE
+
diff --git a/test/tsan/malloc_overflow.cc b/test/tsan/malloc_overflow.cc
index b2f9b0f57798..3db412978d04 100644
--- a/test/tsan/malloc_overflow.cc
+++ b/test/tsan/malloc_overflow.cc
@@ -6,17 +6,17 @@
int main() {
void *p = malloc((size_t)-1);
if (p != 0)
- printf("FAIL malloc(-1) = %p\n", p);
+ fprintf(stderr, "FAIL malloc(-1) = %p\n", p);
p = malloc((size_t)-1 / 2);
if (p != 0)
- printf("FAIL malloc(-1/2) = %p\n", p);
+ fprintf(stderr, "FAIL malloc(-1/2) = %p\n", p);
p = calloc((size_t)-1, (size_t)-1);
if (p != 0)
- printf("FAIL calloc(-1, -1) = %p\n", p);
+ fprintf(stderr, "FAIL calloc(-1, -1) = %p\n", p);
p = calloc((size_t)-1 / 2, (size_t)-1 / 2);
if (p != 0)
- printf("FAIL calloc(-1/2, -1/2) = %p\n", p);
- printf("OK\n");
+ fprintf(stderr, "FAIL calloc(-1/2, -1/2) = %p\n", p);
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: FAIL
diff --git a/test/tsan/mmap_stress.cc b/test/tsan/mmap_stress.cc
index e01e7e92b8f9..f272779a49b9 100644
--- a/test/tsan/mmap_stress.cc
+++ b/test/tsan/mmap_stress.cc
@@ -47,6 +47,10 @@ void *Worker(void *arg) {
}
int main() {
+ // This test is flaky on several builders:
+ // https://groups.google.com/d/msg/llvm-dev/KUFPdLhBN3Q/L75rwW9xBgAJ
+ // The cause is unknown (lit hides test output on failures).
+#if 0
pthread_t th[4];
for (int i = 0; i < 4; i++) {
if (pthread_create(&th[i], 0, Worker, 0))
@@ -56,6 +60,7 @@ int main() {
if (pthread_join(th[i], 0))
exit(printf("pthread_join failed: %d\n", errno));
}
+#endif
fprintf(stderr, "DONE\n");
}
diff --git a/test/tsan/mutex_annotations.cc b/test/tsan/mutex_annotations.cc
new file mode 100644
index 000000000000..59fa452c0a76
--- /dev/null
+++ b/test/tsan/mutex_annotations.cc
@@ -0,0 +1,49 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+
+// Test that a linker-initialized mutex can be created/destroyed while in use.
+
+// Stub for testing, just invokes annotations.
+// Meant to be synchronized externally with test barrier.
+class Mutex {
+ public:
+ void Create(bool linker_initialized = false) {
+ if (linker_initialized)
+ ANNOTATE_RWLOCK_CREATE_STATIC(&state_);
+ else
+ ANNOTATE_RWLOCK_CREATE(&state_);
+ }
+
+ void Destroy() {
+ ANNOTATE_RWLOCK_DESTROY(&state_);
+ }
+
+ void Lock() {
+ ANNOTATE_RWLOCK_ACQUIRED(&state_, true);
+ }
+
+ void Unlock() {
+ ANNOTATE_RWLOCK_RELEASED(&state_, true);
+ }
+
+ private:
+ long long state_;
+};
+
+int main() {
+ Mutex m;
+
+ m.Lock();
+ m.Create(true);
+ m.Unlock();
+
+ m.Lock();
+ m.Destroy();
+ m.Unlock();
+
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: DONE
diff --git a/test/tsan/mutex_cycle_long.c b/test/tsan/mutex_cycle_long.c
new file mode 100644
index 000000000000..b5d67c16c321
--- /dev/null
+++ b/test/tsan/mutex_cycle_long.c
@@ -0,0 +1,42 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: not %run %t 5 2>&1 | FileCheck %s
+// RUN: not %run %t 10 2>&1 | FileCheck %s
+// RUN: not %run %t 15 2>&1 | FileCheck %s
+// RUN: not %run %t 20 2>&1 | FileCheck %s
+// RUN: %run %t 30 2>&1 | FileCheck %s --check-prefix=CHECK-TOO-LONG-CYCLE
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+ int num_mutexes = 5;
+ if (argc > 1) num_mutexes = atoi(argv[1]);
+
+ pthread_mutex_t m[num_mutexes];
+ for (int i = 0; i < num_mutexes; ++i)
+ pthread_mutex_init(&m[i], NULL);
+
+ for (int i = 0; i < num_mutexes - 1; ++i) {
+ pthread_mutex_lock(&m[i]);
+ pthread_mutex_lock(&m[i + 1]);
+
+ pthread_mutex_unlock(&m[i]);
+ pthread_mutex_unlock(&m[i + 1]);
+ }
+
+ pthread_mutex_lock(&m[num_mutexes - 1]);
+ pthread_mutex_lock(&m[0]);
+
+ pthread_mutex_unlock(&m[num_mutexes - 1]);
+ pthread_mutex_unlock(&m[0]);
+
+ for (int i = 0; i < num_mutexes; ++i)
+ pthread_mutex_destroy(&m[i]);
+
+ fprintf(stderr, "PASS\n");
+}
+
+// CHECK: ThreadSanitizer: lock-order-inversion (potential deadlock)
+// CHECK-TOO-LONG-CYCLE: WARNING: too long mutex cycle found
+// CHECK: PASS
diff --git a/test/tsan/mutex_lock_destroyed.cc b/test/tsan/mutex_lock_destroyed.cc
new file mode 100644
index 000000000000..52d6be6210a6
--- /dev/null
+++ b/test/tsan/mutex_lock_destroyed.cc
@@ -0,0 +1,25 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %deflake %run %t | FileCheck %s
+// RUN: %deflake %run %t 1 | FileCheck %s
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+ pthread_mutex_t *m = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
+ pthread_mutex_init(m, 0);
+ pthread_mutex_lock(m);
+ pthread_mutex_unlock(m);
+ pthread_mutex_destroy(m);
+
+ if (argc > 1 && argv[1][0] == '1')
+ free(m);
+
+ pthread_mutex_lock(m);
+ // CHECK: WARNING: ThreadSanitizer: use of an invalid mutex (e.g. uninitialized or destroyed)
+ // CHECK: #0 pthread_mutex_lock
+ // CHECK: #1 main {{.*}}mutex_lock_destroyed.cc:[[@LINE-3]]
+
+ return 0;
+}
diff --git a/test/tsan/pthread_key.cc b/test/tsan/pthread_key.cc
new file mode 100644
index 000000000000..798caa4aba86
--- /dev/null
+++ b/test/tsan/pthread_key.cc
@@ -0,0 +1,39 @@
+// RUN: %clangxx_tsan -O1 %s -DBUILD_SO -fPIC -shared -o %t-so.so
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// Extracted from:
+// https://bugs.chromium.org/p/v8/issues/detail?id=4995
+
+#include "test.h"
+
+void* thr(void* arg) {
+ const int N = 32;
+ pthread_key_t keys_[N];
+ for (size_t i = 0; i < N; ++i) {
+ int err = pthread_key_create(&keys_[i], 0);
+ if (err) {
+ fprintf(stderr, "pthread_key_create failed with %d\n", err);
+ exit(1);
+ }
+ }
+ for (size_t i = 0; i < N; i++)
+ pthread_setspecific(keys_[i], (void*)(long)i);
+ for (size_t i = 0; i < N; i++)
+ pthread_key_delete(keys_[i]);
+ return 0;
+}
+
+int main() {
+ for (int i = 0; i < 10; i++) {
+ pthread_t th;
+ pthread_create(&th, 0, thr, 0);
+ pthread_join(th, 0);
+ }
+ pthread_t th[2];
+ pthread_create(&th[0], 0, thr, 0);
+ pthread_create(&th[1], 0, thr, 0);
+ pthread_join(th[0], 0);
+ pthread_join(th[1], 0);
+ fprintf(stderr, "DONE\n");
+ // CHECK: DONE
+}
diff --git a/test/tsan/race_on_mutex.c b/test/tsan/race_on_mutex.c
index d998fdca2df3..c7f5e06392c5 100644
--- a/test/tsan/race_on_mutex.c
+++ b/test/tsan/race_on_mutex.c
@@ -1,26 +1,30 @@
// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
-// This test fails on powerpc64 (VMA=46).
-// The size of the write reported by Tsan for T1 is 8 instead of 1.
-// XFAIL: powerpc64-unknown-linux-gnu
#include "test.h"
pthread_mutex_t Mtx;
int Global;
-void *Thread1(void *x) {
- pthread_mutex_init(&Mtx, 0);
+void *Thread2(void *x) {
+ barrier_wait(&barrier);
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT: Atomic read of size 1 at {{.*}} by thread T2:
+// CHECK-NEXT: #0 pthread_mutex_lock
+// CHECK-NEXT: #1 Thread2{{.*}} {{.*}}race_on_mutex.c:[[@LINE+1]]{{(:3)?}} ({{.*}})
pthread_mutex_lock(&Mtx);
- Global = 42;
+ Global = 43;
pthread_mutex_unlock(&Mtx);
- barrier_wait(&barrier);
return NULL;
}
-void *Thread2(void *x) {
- barrier_wait(&barrier);
+void *Thread1(void *x) {
+// CHECK: Previous write of size {{[0-9]+}} at {{.*}} by thread T1:
+// CHECK: #{{[0-9]+}} {{.*}}pthread_mutex_init {{.*}} ({{.*}})
+// CHECK-NEXT: #{{[0-9]+}} Thread1{{.*}} {{.*}}race_on_mutex.c:[[@LINE+1]]{{(:3)?}} ({{.*}})
+ pthread_mutex_init(&Mtx, 0);
pthread_mutex_lock(&Mtx);
- Global = 43;
+ Global = 42;
pthread_mutex_unlock(&Mtx);
+ barrier_wait(&barrier);
return NULL;
}
@@ -34,11 +38,3 @@ int main() {
pthread_mutex_destroy(&Mtx);
return 0;
}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NEXT: Atomic read of size 1 at {{.*}} by thread T2:
-// CHECK-NEXT: #0 pthread_mutex_lock
-// CHECK-NEXT: #1 Thread2{{.*}} {{.*}}race_on_mutex.c:21{{(:3)?}} ({{.*}})
-// CHECK: Previous write of size 1 at {{.*}} by thread T1:
-// CHECK-NEXT: #0 pthread_mutex_init {{.*}} ({{.*}})
-// CHECK-NEXT: #1 Thread1{{.*}} {{.*}}race_on_mutex.c:11{{(:3)?}} ({{.*}})
diff --git a/test/tsan/race_on_speculative_load.cc b/test/tsan/race_on_speculative_load.cc
index dd40daeb5c19..5a9d698ca9a6 100644
--- a/test/tsan/race_on_speculative_load.cc
+++ b/test/tsan/race_on_speculative_load.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
// Regtest for https://github.com/google/sanitizers/issues/447
// This is a correct program and tsan should not report a race.
#include "test.h"
@@ -24,7 +24,7 @@ int main() {
g = 1;
barrier_wait(&barrier);
pthread_join(t, 0);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
// CHECK-NOT: ThreadSanitizer: data race
// CHECK: PASS
}
diff --git a/test/tsan/setuid.c b/test/tsan/setuid.c
index bc9c8ca3abaa..2d6b7c866df8 100644
--- a/test/tsan/setuid.c
+++ b/test/tsan/setuid.c
@@ -1,4 +1,10 @@
// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+//
+// setuid(0) hangs on powerpc64 big endian. When this is fixed remove
+// the unsupported flag.
+// https://llvm.org/bugs/show_bug.cgi?id=25799
+//
+// UNSUPPORTED: powerpc64-unknown-linux-gnu
#include "test.h"
#include <sys/types.h>
#include <unistd.h>
diff --git a/test/tsan/setuid2.c b/test/tsan/setuid2.c
index 9dbb6577e1c6..3ea897802cc5 100644
--- a/test/tsan/setuid2.c
+++ b/test/tsan/setuid2.c
@@ -1,4 +1,10 @@
// RUN: %clang_tsan -O1 %s -o %t && %env_tsan_opts=flush_memory_ms=1:memory_limit_mb=1 %run %t 2>&1 | FileCheck %s
+//
+// setuid(0) hangs on powerpc64 big endian. When this is fixed remove
+// the unsupported flag.
+// https://llvm.org/bugs/show_bug.cgi?id=25799
+//
+// UNSUPPORTED: powerpc64-unknown-linux-gnu
#include "test.h"
#include <sys/types.h>
#include <unistd.h>
diff --git a/test/tsan/signal_sync2.cc b/test/tsan/signal_sync2.cc
new file mode 100644
index 000000000000..163f20650756
--- /dev/null
+++ b/test/tsan/signal_sync2.cc
@@ -0,0 +1,77 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// UNSUPPORTED: darwin
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <errno.h>
+
+// Test synchronization in signal handled within IgnoreSync region.
+
+extern "C" void AnnotateIgnoreSyncBegin(const char *f, int l);
+extern "C" void AnnotateIgnoreSyncEnd(const char *f, int l);
+
+const int kSignalCount = 500;
+
+__thread int process_signals;
+int signals_handled;
+int done;
+int ready[kSignalCount];
+long long data[kSignalCount];
+
+static void handler(int sig) {
+ if (!__atomic_load_n(&process_signals, __ATOMIC_RELAXED))
+ return;
+ int pos = signals_handled++;
+ if (pos >= kSignalCount)
+ return;
+ data[pos] = pos;
+ __atomic_store_n(&ready[pos], 1, __ATOMIC_RELEASE);
+}
+
+static void* thr(void *p) {
+ AnnotateIgnoreSyncBegin(__FILE__, __LINE__);
+ __atomic_store_n(&process_signals, 1, __ATOMIC_RELAXED);
+ while (!__atomic_load_n(&done, __ATOMIC_RELAXED)) {
+ }
+ AnnotateIgnoreSyncEnd(__FILE__, __LINE__);
+ return 0;
+}
+
+int main() {
+ struct sigaction act = {};
+ act.sa_handler = handler;
+ if (sigaction(SIGPROF, &act, 0)) {
+ perror("sigaction");
+ exit(1);
+ }
+ itimerval t;
+ t.it_value.tv_sec = 0;
+ t.it_value.tv_usec = 10;
+ t.it_interval = t.it_value;
+ if (setitimer(ITIMER_PROF, &t, 0)) {
+ perror("setitimer");
+ exit(1);
+ }
+
+ pthread_t th;
+ pthread_create(&th, 0, thr, 0);
+ for (int pos = 0; pos < kSignalCount; pos++) {
+ while (__atomic_load_n(&ready[pos], __ATOMIC_ACQUIRE) == 0) {
+ }
+ if (data[pos] != pos) {
+ printf("at pos %d, expect %d, got %lld\n", pos, pos, data[pos]);
+ exit(1);
+ }
+ }
+ __atomic_store_n(&done, 1, __ATOMIC_RELAXED);
+ pthread_join(th, 0);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: DONE
diff --git a/test/tsan/static_init1.cc b/test/tsan/static_init1.cc
index 3e5fb14ba44b..3e6e4f9dfec1 100644
--- a/test/tsan/static_init1.cc
+++ b/test/tsan/static_init1.cc
@@ -21,7 +21,7 @@ int main() {
pthread_create(&t[1], 0, Thread, 0);
pthread_join(t[0], 0);
pthread_join(t[1], 0);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/static_init2.cc b/test/tsan/static_init2.cc
index 667aed1343dc..ca2300ae6801 100644
--- a/test/tsan/static_init2.cc
+++ b/test/tsan/static_init2.cc
@@ -27,7 +27,7 @@ int main() {
pthread_create(&t[1], 0, Thread, 0);
pthread_join(t[0], 0);
pthread_join(t[1], 0);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/static_init4.cc b/test/tsan/static_init4.cc
index 85835a2520f7..c8da78364c5c 100644
--- a/test/tsan/static_init4.cc
+++ b/test/tsan/static_init4.cc
@@ -31,7 +31,7 @@ int main() {
pthread_create(&t[1], 0, Thread1, 0);
pthread_join(t[0], 0);
pthread_join(t[1], 0);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/static_init5.cc b/test/tsan/static_init5.cc
index 961e3a3b6329..b334981e85b0 100644
--- a/test/tsan/static_init5.cc
+++ b/test/tsan/static_init5.cc
@@ -36,7 +36,7 @@ int main() {
pthread_create(&t[1], 0, Thread1, 0);
pthread_join(t[0], 0);
pthread_join(t[1], 0);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/static_init6.cc b/test/tsan/static_init6.cc
index 77253eac173f..fd22e0a02e6a 100644
--- a/test/tsan/static_init6.cc
+++ b/test/tsan/static_init6.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -static-libstdc++ -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -stdlib=libstdc++ -static-libstdc++ -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
@@ -36,7 +36,7 @@ int main() {
pthread_create(&t[1], 0, Thread1, 0);
pthread_join(t[0], 0);
pthread_join(t[1], 0);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/sunrpc.cc b/test/tsan/sunrpc.cc
index 579816d64098..5cfb5344ec10 100644
--- a/test/tsan/sunrpc.cc
+++ b/test/tsan/sunrpc.cc
@@ -19,7 +19,7 @@ int main(int argc, char *argv[]) {
pthread_create(&th[1], 0, thr, 0);
pthread_join(th[0], 0);
pthread_join(th[1], 0);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
// CHECK: DONE
return 0;
}
diff --git a/test/tsan/suppressions_global.cc b/test/tsan/suppressions_global.cc
index 8928162cfb8a..282d261c19ef 100644
--- a/test/tsan/suppressions_global.cc
+++ b/test/tsan/suppressions_global.cc
@@ -20,7 +20,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
return 0;
}
diff --git a/test/tsan/suppressions_race.cc b/test/tsan/suppressions_race.cc
index 7a88434db820..d0aeeda95e36 100644
--- a/test/tsan/suppressions_race.cc
+++ b/test/tsan/suppressions_race.cc
@@ -22,7 +22,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
return 0;
}
diff --git a/test/tsan/suppressions_race2.cc b/test/tsan/suppressions_race2.cc
index b6566a80178d..6f8ca736d8ae 100644
--- a/test/tsan/suppressions_race2.cc
+++ b/test/tsan/suppressions_race2.cc
@@ -22,7 +22,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
return 0;
}
diff --git a/test/tsan/test.h b/test/tsan/test.h
index a681daa32906..e3affdc0837d 100644
--- a/test/tsan/test.h
+++ b/test/tsan/test.h
@@ -67,3 +67,38 @@ unsigned long long monotonic_clock_ns() {
return (unsigned long long)t.tv_sec * 1000000000ull + t.tv_nsec;
}
#endif
+
+//The const kPCInc must be in sync with StackTrace::GetPreviousInstructionPc
+#if defined(__powerpc64__)
+// PCs are always 4 byte aligned.
+const int kPCInc = 4;
+#elif defined(__sparc__) || defined(__mips__)
+const int kPCInc = 8;
+#else
+const int kPCInc = 1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void AnnotateRWLockCreate(const char *f, int l, void *m);
+void AnnotateRWLockCreateStatic(const char *f, int l, void *m);
+void AnnotateRWLockDestroy(const char *f, int l, void *m);
+void AnnotateRWLockAcquired(const char *f, int l, void *m, long is_w);
+void AnnotateRWLockReleased(const char *f, int l, void *m, long is_w);
+
+#ifdef __cplusplus
+}
+#endif
+
+#define ANNOTATE_RWLOCK_CREATE(m) \
+ AnnotateRWLockCreate(__FILE__, __LINE__, m)
+#define ANNOTATE_RWLOCK_CREATE_STATIC(m) \
+ AnnotateRWLockCreateStatic(__FILE__, __LINE__, m)
+#define ANNOTATE_RWLOCK_DESTROY(m) \
+ AnnotateRWLockDestroy(__FILE__, __LINE__, m)
+#define ANNOTATE_RWLOCK_ACQUIRED(m, is_w) \
+ AnnotateRWLockAcquired(__FILE__, __LINE__, m, is_w)
+#define ANNOTATE_RWLOCK_RELEASED(m, is_w) \
+ AnnotateRWLockReleased(__FILE__, __LINE__, m, is_w)
diff --git a/test/tsan/thread_detach.c b/test/tsan/thread_detach.c
index 802d8ded0fad..2a95742b7cd8 100644
--- a/test/tsan/thread_detach.c
+++ b/test/tsan/thread_detach.c
@@ -12,7 +12,7 @@ int main() {
pthread_create(&t, 0, Thread, 0);
barrier_wait(&barrier);
pthread_detach(t);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
diff --git a/test/tsan/thread_detach2.c b/test/tsan/thread_detach2.c
index 8133980ba5a1..5ee94e9a967b 100644
--- a/test/tsan/thread_detach2.c
+++ b/test/tsan/thread_detach2.c
@@ -20,7 +20,7 @@ int main() {
pthread_create(&t, 0, Thread, 0);
pthread_detach(t);
barrier_wait(&barrier);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
diff --git a/test/tsan/thread_leak.c b/test/tsan/thread_leak.c
index 9b850dd4b567..9b42b16b72a4 100644
--- a/test/tsan/thread_leak.c
+++ b/test/tsan/thread_leak.c
@@ -10,7 +10,7 @@ int main() {
pthread_t t;
pthread_create(&t, 0, Thread, 0);
pthread_join(t, 0);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
diff --git a/test/tsan/thread_leak2.c b/test/tsan/thread_leak2.c
index fc2942b2a05d..c3cac7a49284 100644
--- a/test/tsan/thread_leak2.c
+++ b/test/tsan/thread_leak2.c
@@ -10,7 +10,7 @@ int main() {
pthread_t t;
pthread_create(&t, 0, Thread, 0);
pthread_detach(t);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
diff --git a/test/tsan/thread_leak4.c b/test/tsan/thread_leak4.c
index 1ebca58871ac..1d0636f1a4c0 100644
--- a/test/tsan/thread_leak4.c
+++ b/test/tsan/thread_leak4.c
@@ -9,7 +9,7 @@ void *Thread(void *x) {
int main() {
pthread_t t;
pthread_create(&t, 0, Thread, 0);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return 0;
}
diff --git a/test/tsan/tsan-vs-gvn.cc b/test/tsan/tsan-vs-gvn.cc
index 950f5d30d4da..efd81ef502fd 100644
--- a/test/tsan/tsan-vs-gvn.cc
+++ b/test/tsan/tsan-vs-gvn.cc
@@ -31,7 +31,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/unaligned_norace.cc b/test/tsan/unaligned_norace.cc
index 94df1cf74cc1..7e360cf87042 100644
--- a/test/tsan/unaligned_norace.cc
+++ b/test/tsan/unaligned_norace.cc
@@ -77,7 +77,7 @@ int main() {
pthread_create(&th, 0, Thread, 0);
Test(true);
pthread_join(th, 0);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer:
diff --git a/test/tsan/vfork.cc b/test/tsan/vfork.cc
index 98a82623ee65..2d669b305a9d 100644
--- a/test/tsan/vfork.cc
+++ b/test/tsan/vfork.cc
@@ -1,5 +1,4 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
-// UNSUPPORTED: darwin
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
@@ -27,7 +26,7 @@ int main() {
pipe(fds);
int pid = vfork();
if (pid < 0) {
- printf("FAIL to vfork\n");
+ fprintf(stderr, "FAIL to vfork\n");
exit(1);
}
if (pid == 0) { // child
@@ -44,7 +43,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/virtual_inheritance_compile_bug.cc b/test/tsan/virtual_inheritance_compile_bug.cc
index 7da581d80601..3b1e08b1689b 100644
--- a/test/tsan/virtual_inheritance_compile_bug.cc
+++ b/test/tsan/virtual_inheritance_compile_bug.cc
@@ -10,6 +10,6 @@ struct DDD: CCC, BBB { DDD(); }; // NOLINT
DDD::DDD() { }
int main() {
DDD d;
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK: OK