aboutsummaryrefslogtreecommitdiff
path: root/test/tsan
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:18:27 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:18:27 +0000
commit316d58822dada9440bd06ecfc758dcc2364d617c (patch)
treefe72ec2e6ce9a360dda74d9d57f7acdb0e3c39d6 /test/tsan
parent0230fcf22fe7d19f03d981c9c2c59a3db0b72ea5 (diff)
downloadsrc-316d58822dada9440bd06ecfc758dcc2364d617c.tar.gz
src-316d58822dada9440bd06ecfc758dcc2364d617c.zip
Vendor import of compiler-rt trunk r290819:vendor/compiler-rt/compiler-rt-trunk-r290819
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=311120 svn path=/vendor/compiler-rt/compiler-rt-trunk-r290819/; revision=311121; tag=vendor/compiler-rt/compiler-rt-trunk-r290819
Diffstat (limited to 'test/tsan')
-rw-r--r--test/tsan/CMakeLists.txt10
-rw-r--r--test/tsan/Darwin/gcd-apply-race.mm4
-rw-r--r--test/tsan/Darwin/gcd-apply.mm4
-rw-r--r--test/tsan/Darwin/gcd-suspend.mm45
-rw-r--r--test/tsan/Darwin/gcd-target-queue-norace.mm41
-rw-r--r--test/tsan/Darwin/libcxx-call-once.mm34
-rw-r--r--test/tsan/Darwin/libcxx-future.mm30
-rw-r--r--test/tsan/Darwin/norace-objcxx-run-time.mm113
-rw-r--r--test/tsan/Darwin/objc-double-property.mm21
-rw-r--r--test/tsan/Darwin/osatomics-bitops.mm34
-rw-r--r--test/tsan/Darwin/realloc-zero.cc20
-rw-r--r--test/tsan/atomic_free.cc13
-rw-r--r--test/tsan/atomic_store.cc49
-rw-r--r--test/tsan/debug_alloc_stack.cc84
-rw-r--r--test/tsan/debug_locate.cc43
-rw-r--r--test/tsan/exceptions.cc185
-rw-r--r--test/tsan/fork_atexit.cc2
-rw-r--r--test/tsan/global_race.cc13
-rw-r--r--test/tsan/ignore_lib4.cc2
-rw-r--r--test/tsan/ignore_lib5.cc75
-rw-r--r--test/tsan/ignore_lib5.cc.supp2
-rw-r--r--test/tsan/java.h1
-rw-r--r--test/tsan/libcxx/lit.local.cfg4
-rw-r--r--test/tsan/lit.cfg11
-rw-r--r--test/tsan/longjmp.cc3
-rw-r--r--test/tsan/longjmp2.cc3
-rw-r--r--test/tsan/longjmp3.cc3
-rw-r--r--test/tsan/longjmp4.cc3
-rw-r--r--test/tsan/map32bit.cc2
-rw-r--r--test/tsan/pie_test.cc6
-rw-r--r--test/tsan/signal_block.cc60
-rw-r--r--test/tsan/signal_cond.cc2
-rw-r--r--test/tsan/signal_longjmp.cc2
-rw-r--r--test/tsan/simple_stack.c41
-rw-r--r--test/tsan/test.h19
35 files changed, 914 insertions, 70 deletions
diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt
index e05b100f3699..2db6ce0a8c1a 100644
--- a/test/tsan/CMakeLists.txt
+++ b/test/tsan/CMakeLists.txt
@@ -24,15 +24,7 @@ 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.
- # Build all tests with host compiler and use host tools.
- set(TSAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER})
- set(TSAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
- else()
- get_target_flags_for_arch(${arch} TSAN_TEST_TARGET_CFLAGS)
- string(REPLACE ";" " " TSAN_TEST_TARGET_CFLAGS "${TSAN_TEST_TARGET_CFLAGS}")
- endif()
+ get_test_cc_for_arch(${arch} TSAN_TEST_TARGET_CC TSAN_TEST_TARGET_CFLAGS)
string(TOUPPER ${arch} ARCH_UPPER_CASE)
set(CONFIG_NAME ${ARCH_UPPER_CASE}Config)
diff --git a/test/tsan/Darwin/gcd-apply-race.mm b/test/tsan/Darwin/gcd-apply-race.mm
index 13b24e0fdb90..028be1ac5b1c 100644
--- a/test/tsan/Darwin/gcd-apply-race.mm
+++ b/test/tsan/Darwin/gcd-apply-race.mm
@@ -10,6 +10,10 @@ long global;
int main(int argc, const char *argv[]) {
barrier_init(&barrier, 2);
fprintf(stderr, "start\n");
+
+ // Warm up GCD (workaround for macOS Sierra where dispatch_apply might run single-threaded).
+ dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ });
+
dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(2, q, ^(size_t i) {
global = i;
diff --git a/test/tsan/Darwin/gcd-apply.mm b/test/tsan/Darwin/gcd-apply.mm
index e68a4b18205d..a7dc3740dc7b 100644
--- a/test/tsan/Darwin/gcd-apply.mm
+++ b/test/tsan/Darwin/gcd-apply.mm
@@ -17,6 +17,10 @@ void callback(void *context, size_t i) {
int main(int argc, const char *argv[]) {
barrier_init(&barrier, 2);
fprintf(stderr, "start\n");
+
+ // Warm up GCD (workaround for macOS Sierra where dispatch_apply might run single-threaded).
+ dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ });
+
dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
global = 42;
diff --git a/test/tsan/Darwin/gcd-suspend.mm b/test/tsan/Darwin/gcd-suspend.mm
new file mode 100644
index 000000000000..3e8818a2d56e
--- /dev/null
+++ b/test/tsan/Darwin/gcd-suspend.mm
@@ -0,0 +1,45 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long my_global = 0;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ dispatch_queue_t q1 = dispatch_queue_create("queue1", NULL);
+ dispatch_queue_t q2 = dispatch_queue_create("queue2", NULL);
+ dispatch_group_t g = dispatch_group_create();
+
+ dispatch_sync(q1, ^{
+ dispatch_suspend(q1);
+ dispatch_async(q2, ^{
+ my_global++;
+ dispatch_resume(q1);
+ });
+ });
+
+ dispatch_sync(q1, ^{
+ my_global++;
+ });
+
+ dispatch_sync(q1, ^{
+ dispatch_suspend(q1);
+ dispatch_group_enter(g);
+ dispatch_async(q1,^{ my_global++; });
+ dispatch_async(q1,^{ my_global++; });
+ dispatch_async(q1,^{ my_global++; dispatch_group_leave(g); });
+ my_global++;
+ dispatch_resume(q1);
+ });
+
+ dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-target-queue-norace.mm b/test/tsan/Darwin/gcd-target-queue-norace.mm
new file mode 100644
index 000000000000..36cb1b9298de
--- /dev/null
+++ b/test/tsan/Darwin/gcd-target-queue-norace.mm
@@ -0,0 +1,41 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long global;
+
+int main(int argc, const char *argv[]) {
+ dispatch_queue_t target_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
+ dispatch_queue_t q1 = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
+ dispatch_queue_t q2 = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
+ dispatch_set_target_queue(q1, target_queue);
+ dispatch_set_target_queue(q2, target_queue);
+
+ for (int i = 0; i < 100000; i++) {
+ dispatch_async(q1, ^{
+ global++;
+
+ if (global == 200000) {
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ }
+ });
+ dispatch_async(q2, ^{
+ global++;
+
+ if (global == 200000) {
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ }
+ });
+ }
+
+ CFRunLoopRun();
+ NSLog(@"Done.");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/libcxx-call-once.mm b/test/tsan/Darwin/libcxx-call-once.mm
new file mode 100644
index 000000000000..5388e495c9c2
--- /dev/null
+++ b/test/tsan/Darwin/libcxx-call-once.mm
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation -std=c++11
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import <iostream>
+#import <thread>
+
+long my_global;
+std::once_flag once_token;
+
+void thread_func() {
+ std::call_once(once_token, [] {
+ my_global = 17;
+ });
+
+ long val = my_global;
+ fprintf(stderr, "my_global = %ld\n", val);
+}
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ std::thread t1(thread_func);
+ std::thread t2(thread_func);
+ t1.join();
+ t2.join();
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/libcxx-future.mm b/test/tsan/Darwin/libcxx-future.mm
new file mode 100644
index 000000000000..902f267ecb89
--- /dev/null
+++ b/test/tsan/Darwin/libcxx-future.mm
@@ -0,0 +1,30 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#include <iostream>
+#include <future>
+#include <vector>
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ auto my_task = [] { return 42; };
+
+ std::vector<std::thread> threads;
+
+ for (int i = 0; i < 100; i++) {
+ std::packaged_task<int(void)> task(my_task);
+ std::future<int> future = task.get_future();
+ threads.push_back(std::thread(std::move(task)));
+ }
+
+ for (auto &t : threads) {
+ t.join();
+ }
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/norace-objcxx-run-time.mm b/test/tsan/Darwin/norace-objcxx-run-time.mm
new file mode 100644
index 000000000000..0cf729e7f2d8
--- /dev/null
+++ b/test/tsan/Darwin/norace-objcxx-run-time.mm
@@ -0,0 +1,113 @@
+// RUN: %clang_tsan %s -lc++ -fobjc-arc -lobjc -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+// Check that we do not report races between:
+// - Object retain and initialize
+// - Object release and dealloc
+// - Object release and .cxx_destruct
+
+#import <Foundation/Foundation.h>
+#include "../test.h"
+invisible_barrier_t barrier2;
+
+class NeedCleanup {
+ public:
+ int x;
+ NeedCleanup() {
+ x = 1;
+ }
+ ~NeedCleanup() {
+ x = 0;
+ }
+};
+
+@interface TestDeallocObject : NSObject {
+ @public
+ int v;
+ }
+ - (id)init;
+ - (void)accessMember;
+ - (void)dealloc;
+@end
+
+@implementation TestDeallocObject
+ - (id)init {
+ if ([super self]) {
+ v = 1;
+ return self;
+ }
+ return nil;
+ }
+ - (void)accessMember {
+ int local = v;
+ local++;
+ }
+ - (void)dealloc {
+ v = 0;
+ }
+@end
+
+@interface TestCXXDestructObject : NSObject {
+ @public
+ NeedCleanup cxxMemberWithCleanup;
+ }
+ - (void)accessMember;
+@end
+
+@implementation TestCXXDestructObject
+ - (void)accessMember {
+ int local = cxxMemberWithCleanup.x;
+ local++;
+ }
+@end
+
+@interface TestInitializeObject : NSObject
+@end
+
+@implementation TestInitializeObject
+ static long InitializerAccessedGlobal = 0;
+ + (void)initialize {
+ InitializerAccessedGlobal = 42;
+ }
+@end
+
+int main(int argc, const char *argv[]) {
+ // Ensure that there is no race when calling initialize on TestInitializeObject;
+ // otherwise, the locking from ObjC runtime becomes observable. Also ensures that
+ // blocks are dispatched to 2 different threads.
+ barrier_init(&barrier, 2);
+ // Ensure that objects are destructed during block object release.
+ barrier_init(&barrier2, 3);
+
+ TestDeallocObject *tdo = [[TestDeallocObject alloc] init];
+ TestCXXDestructObject *tcxxdo = [[TestCXXDestructObject alloc] init];
+ [tdo accessMember];
+ [tcxxdo accessMember];
+ {
+ dispatch_queue_t q = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
+ dispatch_async(q, ^{
+ [TestInitializeObject new];
+ barrier_wait(&barrier);
+ long local = InitializerAccessedGlobal;
+ local++;
+ [tdo accessMember];
+ [tcxxdo accessMember];
+ barrier_wait(&barrier2);
+ });
+ dispatch_async(q, ^{
+ barrier_wait(&barrier);
+ [TestInitializeObject new];
+ long local = InitializerAccessedGlobal;
+ local++;
+ [tdo accessMember];
+ [tcxxdo accessMember];
+ barrier_wait(&barrier2);
+ });
+ }
+ barrier_wait(&barrier2);
+ NSLog(@"Done.");
+ return 0;
+}
+
+// CHECK: Done.
+// CHECK-NOT: ThreadSanitizer: data race
diff --git a/test/tsan/Darwin/objc-double-property.mm b/test/tsan/Darwin/objc-double-property.mm
new file mode 100644
index 000000000000..51b10f21c9ca
--- /dev/null
+++ b/test/tsan/Darwin/objc-double-property.mm
@@ -0,0 +1,21 @@
+// RUN: %clangxx_tsan -O0 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O2 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O3 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+@interface MyClass : NSObject
+@property float a;
+@property double b;
+@property long double c;
+@end
+
+@implementation MyClass
+@end
+
+int main() {
+ NSLog(@"Hello world");
+}
+
+// CHECK: Hello world
diff --git a/test/tsan/Darwin/osatomics-bitops.mm b/test/tsan/Darwin/osatomics-bitops.mm
new file mode 100644
index 000000000000..68badb792fd6
--- /dev/null
+++ b/test/tsan/Darwin/osatomics-bitops.mm
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation -std=c++11
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <libkern/OSAtomic.h>
+
+int main(int argc, const char *argv[]) {
+ int value = 1;
+ bool ret = OSAtomicTestAndClear(7, &value);
+ fprintf(stderr, "value = %d, ret = %d\n", value, ret);
+ // CHECK: value = 0, ret = 1
+
+ ret = OSAtomicTestAndSet(4, &value);
+ fprintf(stderr, "value = %d, ret = %d\n", value, ret);
+ // CHECK: value = 8, ret = 0
+
+ ret = OSAtomicTestAndClear(4, &value);
+ fprintf(stderr, "value = %d, ret = %d\n", value, ret);
+ // CHECK: value = 0, ret = 1
+
+ ret = OSAtomicTestAndSet(12, &value);
+ fprintf(stderr, "value = %d, ret = %d\n", value, ret);
+ // CHECK: value = 2048, ret = 0
+
+ ret = OSAtomicTestAndSet(13, &value);
+ fprintf(stderr, "value = %d, ret = %d\n", value, ret);
+ // CHECK: value = 3072, ret = 0
+
+ ret = OSAtomicTestAndClear(12, &value);
+ fprintf(stderr, "value = %d, ret = %d\n", value, ret);
+ // CHECK: value = 1024, ret = 1
+
+ return 0;
+}
diff --git a/test/tsan/Darwin/realloc-zero.cc b/test/tsan/Darwin/realloc-zero.cc
new file mode 100644
index 000000000000..98262463cb2d
--- /dev/null
+++ b/test/tsan/Darwin/realloc-zero.cc
@@ -0,0 +1,20 @@
+// Test that realloc(nullptr, 0) return a non-NULL pointer.
+
+// RUN: %clang_tsan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <malloc/malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+int main() {
+ void *p = realloc(NULL, 0);
+ if (!p) {
+ abort();
+ }
+ fprintf(stderr, "Okay.\n");
+ return 0;
+}
+
+// CHECK: Okay.
diff --git a/test/tsan/atomic_free.cc b/test/tsan/atomic_free.cc
index a0d8e426b49f..446949ddb986 100644
--- a/test/tsan/atomic_free.cc
+++ b/test/tsan/atomic_free.cc
@@ -1,4 +1,13 @@
-// 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
+
+// Also check that atomics instrumentation can be configured by either driver or
+// legacy flags:
+
+// RUN: %clangxx_tsan -O1 %s -o %t -fno-sanitize-thread-atomics && not %deflake %run %t 2>&1 \
+// RUN: | FileCheck --allow-empty --check-prefix=CHECK-NO-ATOMICS %s
+// RUN: %clangxx_tsan -O1 %s -o %t -mllvm -tsan-instrument-atomics=0 && not %deflake %run %t 2>&1 \
+// RUN: | FileCheck --allow-empty --check-prefix=CHECK-NO-ATOMICS %s <%t
+
#include "test.h"
void *Thread(void *a) {
@@ -18,3 +27,5 @@ int main() {
}
// CHECK: WARNING: ThreadSanitizer: data race
+
+// CHECK-NO-ATOMICS-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/atomic_store.cc b/test/tsan/atomic_store.cc
new file mode 100644
index 000000000000..7ff4879d3cae
--- /dev/null
+++ b/test/tsan/atomic_store.cc
@@ -0,0 +1,49 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
+#include "test.h"
+
+long long Data;
+long long Sync;
+
+void *Thread1(void *x) {
+ Data++;
+ __atomic_store_n(&Sync, 1, __ATOMIC_RELEASE);
+ barrier_wait(&barrier);
+ barrier_wait(&barrier);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ barrier_wait(&barrier);
+ if (__atomic_load_n(&Sync, __ATOMIC_RELAXED) != 1)
+ exit(0);
+ // This store must terminate release sequence of the store in Thread1,
+ // thus tsan must detect race between Thread1 and main on Data.
+ __atomic_store_n(&Sync, 2, __ATOMIC_RELEASE);
+ barrier_wait(&barrier);
+ return NULL;
+}
+
+int main() {
+ barrier_init(&barrier, 3);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ barrier_wait(&barrier);
+ barrier_wait(&barrier);
+ if (__atomic_load_n(&Sync, __ATOMIC_ACQUIRE) != 2)
+ exit(0);
+ if (Data != 1)
+ exit(0);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Read
+// CHECK: #0 main
+// CHECK: Previous write
+// CHECK: #0 Thread1
+// CHECK: Location is global 'Data'
+// CHECK: DONE
diff --git a/test/tsan/debug_alloc_stack.cc b/test/tsan/debug_alloc_stack.cc
new file mode 100644
index 000000000000..303c103206f8
--- /dev/null
+++ b/test/tsan/debug_alloc_stack.cc
@@ -0,0 +1,84 @@
+// RUN: %clangxx_tsan -O0 %s -o %t
+// RUN: env %env_tsan_opts=stack_trace_format=DEFAULT %deflake %run %t 2>&1 | FileCheck %s
+
+// Until I figure out how to make this test work on Linux
+// REQUIRES: system-darwin
+
+#include "test.h"
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef __APPLE__
+#include <sys/types.h>
+#endif
+
+extern "C" int __tsan_get_alloc_stack(void *addr, void **trace, size_t size,
+ int *thread_id, void *os_id);
+
+char *mem;
+void alloc_func() { mem = (char *)malloc(10); }
+
+void *AllocThread(void *context) {
+ uint64_t tid;
+#ifdef __APPLE__
+ pthread_threadid_np(NULL, &tid);
+#else
+ tid = gettid();
+#endif
+ fprintf(stderr, "alloc stack thread os id = 0x%llx\n", tid);
+ // CHECK: alloc stack thread os id = [[THREAD_OS_ID:0x[0-9a-f]+]]
+ alloc_func();
+ return NULL;
+}
+
+void *RaceThread(void *context) {
+ *mem = 'a';
+ barrier_wait(&barrier);
+ return NULL;
+}
+
+int main() {
+ pthread_t t;
+ barrier_init(&barrier, 2);
+
+ pthread_create(&t, NULL, AllocThread, NULL);
+ pthread_join(t, NULL);
+
+ void *trace[100];
+ size_t num_frames = 100;
+ int thread_id;
+ void *thread_os_id;
+ num_frames =
+ __tsan_get_alloc_stack(mem, trace, num_frames, &thread_id, &thread_os_id);
+
+ fprintf(stderr, "alloc stack retval %s\n",
+ (num_frames > 0 && num_frames < 10) ? "ok" : "");
+ // CHECK: alloc stack retval ok
+ fprintf(stderr, "thread id = %d\n", thread_id);
+ // CHECK: thread id = 1
+ fprintf(stderr, "thread os id = 0x%llx\n", (uint64_t)thread_os_id);
+ // CHECK: thread os id = [[THREAD_OS_ID]]
+ fprintf(stderr, "%p\n", trace[0]);
+ // CHECK: [[ALLOC_FRAME_0:0x[0-9a-f]+]]
+ fprintf(stderr, "%p\n", trace[1]);
+ // CHECK: [[ALLOC_FRAME_1:0x[0-9a-f]+]]
+ fprintf(stderr, "%p\n", trace[2]);
+ // CHECK: [[ALLOC_FRAME_2:0x[0-9a-f]+]]
+
+ pthread_create(&t, NULL, RaceThread, NULL);
+ barrier_wait(&barrier);
+ mem[0] = 'b';
+ pthread_join(t, NULL);
+
+ free(mem);
+
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is heap block of size 10 at {{.*}} allocated by thread T1
+// CHECK: #0 [[ALLOC_FRAME_0]]
+// CHECK: #1 [[ALLOC_FRAME_1]] in alloc_func
+// CHECK: #2 [[ALLOC_FRAME_2]] in AllocThread
diff --git a/test/tsan/debug_locate.cc b/test/tsan/debug_locate.cc
new file mode 100644
index 000000000000..01b0960d85b7
--- /dev/null
+++ b/test/tsan/debug_locate.cc
@@ -0,0 +1,43 @@
+// RUN: %clangxx_tsan -O0 %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C" const char *
+__tsan_locate_address(void *addr, char *name, size_t name_size,
+ void **region_address_ptr, size_t *region_size_ptr);
+
+long global_var;
+
+int main() {
+ long stack_var;
+ void *heap_var = malloc(10);
+
+ fprintf(stderr, "stack_var = %p\n", &stack_var);
+ fprintf(stderr, "global_var = %p\n", &global_var);
+ fprintf(stderr, "heap_var = %p\n", heap_var);
+ // CHECK: stack_var = [[STACK_VAR:0x[0-9a-f]+]]
+ // CHECK: global_var = [[GLOBAL_VAR:0x[0-9a-f]+]]
+ // CHECK: heap_var = [[HEAP_VAR:0x[0-9a-f]+]]
+
+ const char *type;
+ char name[128];
+ void *start;
+ size_t size;
+ type = __tsan_locate_address(&stack_var, name, 128, &start, &size);
+ fprintf(stderr, "type: %s\n", type);
+ // CHECK: type: stack
+
+ type = __tsan_locate_address(&global_var, name, 128, &start, &size);
+ fprintf(stderr, "type: %s, name = %s, start = %p, size = %zu\n", type, name,
+ start, size);
+ // CHECK: type: global, name = global_var, start = [[GLOBAL_VAR]], size = {{8|0}}
+
+ type = __tsan_locate_address(heap_var, name, 128, &start, &size);
+ fprintf(stderr, "type: %s, start = %p, size = %zu\n", type, start, size);
+ // CHECK: type: heap, start = [[HEAP_VAR]], size = 10
+
+ free(heap_var);
+ return 0;
+}
diff --git a/test/tsan/exceptions.cc b/test/tsan/exceptions.cc
new file mode 100644
index 000000000000..193e115f7802
--- /dev/null
+++ b/test/tsan/exceptions.cc
@@ -0,0 +1,185 @@
+// RUN: %clangxx_tsan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include "test.h"
+#include <setjmp.h>
+
+__attribute__((noinline)) void throws_int() {
+ throw 42;
+}
+
+__attribute__((noinline)) void callee_throws() {
+ try {
+ throws_int();
+ } catch (int) { // NOLINT
+ fprintf(stderr, "callee_throws caught exception\n");
+ }
+}
+
+__attribute__((noinline)) void throws_catches_rethrows() {
+ try {
+ throws_int();
+ } catch (int) { // NOLINT
+ fprintf(stderr, "throws_catches_rethrows caught exception\n");
+ throw;
+ }
+}
+
+__attribute__((noinline)) void callee_rethrows() {
+ try {
+ throws_catches_rethrows();
+ } catch (int) { // NOLINT
+ fprintf(stderr, "callee_rethrows caught exception\n");
+ }
+}
+
+__attribute__((noinline)) void throws_and_catches() {
+ try {
+ throws_int();
+ } catch (int) { // NOLINT
+ fprintf(stderr, "throws_and_catches caught exception\n");
+ }
+}
+
+__attribute__((noinline)) void nested_try() {
+ try {
+ try {
+ throws_int();
+ } catch (double) { // NOLINT
+ fprintf(stderr, "nested_try inner block caught exception\n");
+ }
+ } catch (int) { // NOLINT
+ fprintf(stderr, "nested_try outer block caught exception\n");
+ }
+}
+
+__attribute__((noinline)) void nested_try2() {
+ try {
+ try {
+ throws_int();
+ } catch (int) { // NOLINT
+ fprintf(stderr, "nested_try inner block caught exception\n");
+ }
+ } catch (double) { // NOLINT
+ fprintf(stderr, "nested_try outer block caught exception\n");
+ }
+}
+
+class ClassWithDestructor {
+ public:
+ ClassWithDestructor() {
+ fprintf(stderr, "ClassWithDestructor\n");
+ }
+ ~ClassWithDestructor() {
+ fprintf(stderr, "~ClassWithDestructor\n");
+ }
+};
+
+__attribute__((noinline)) void local_object_then_throw() {
+ ClassWithDestructor obj;
+ throws_int();
+}
+
+__attribute__((noinline)) void cpp_object_with_destructor() {
+ try {
+ local_object_then_throw();
+ } catch (int) { // NOLINT
+ fprintf(stderr, "cpp_object_with_destructor caught exception\n");
+ }
+}
+
+__attribute__((noinline)) void recursive_call(long n) {
+ if (n > 0) {
+ recursive_call(n - 1);
+ } else {
+ throws_int();
+ }
+}
+
+__attribute__((noinline)) void multiframe_unwind() {
+ try {
+ recursive_call(5);
+ } catch (int) { // NOLINT
+ fprintf(stderr, "multiframe_unwind caught exception\n");
+ }
+}
+
+__attribute__((noinline)) void longjmp_unwind() {
+ jmp_buf env;
+ int i = setjmp(env);
+ if (i != 0) {
+ fprintf(stderr, "longjmp_unwind jumped\n");
+ return;
+ }
+
+ try {
+ longjmp(env, 42);
+ } catch (int) { // NOLINT
+ fprintf(stderr, "longjmp_unwind caught exception\n");
+ }
+}
+
+__attribute__((noinline)) void recursive_call_longjmp(jmp_buf env, long n) {
+ if (n > 0) {
+ recursive_call_longjmp(env, n - 1);
+ } else {
+ longjmp(env, 42);
+ }
+}
+
+__attribute__((noinline)) void longjmp_unwind_multiple_frames() {
+ jmp_buf env;
+ int i = setjmp(env);
+ if (i != 0) {
+ fprintf(stderr, "longjmp_unwind_multiple_frames jumped\n");
+ return;
+ }
+
+ try {
+ recursive_call_longjmp(env, 5);
+ } catch (int) { // NOLINT
+ fprintf(stderr, "longjmp_unwind_multiple_frames caught exception\n");
+ }
+}
+
+#define CHECK_SHADOW_STACK(val) \
+ fprintf(stderr, (val == __tsan_testonly_shadow_stack_current_size() \
+ ? "OK.\n" \
+ : "Shadow stack leak!\n"));
+
+int main(int argc, const char * argv[]) {
+ fprintf(stderr, "Hello, World!\n");
+ unsigned long shadow_stack_size = __tsan_testonly_shadow_stack_current_size();
+
+ throws_and_catches();
+ CHECK_SHADOW_STACK(shadow_stack_size);
+
+ callee_throws();
+ CHECK_SHADOW_STACK(shadow_stack_size);
+
+ callee_rethrows();
+ CHECK_SHADOW_STACK(shadow_stack_size);
+
+ nested_try();
+ CHECK_SHADOW_STACK(shadow_stack_size);
+
+ nested_try2();
+ CHECK_SHADOW_STACK(shadow_stack_size);
+
+ cpp_object_with_destructor();
+ CHECK_SHADOW_STACK(shadow_stack_size);
+
+ multiframe_unwind();
+ CHECK_SHADOW_STACK(shadow_stack_size);
+
+ longjmp_unwind();
+ CHECK_SHADOW_STACK(shadow_stack_size);
+
+ longjmp_unwind_multiple_frames();
+ CHECK_SHADOW_STACK(shadow_stack_size);
+
+ return 0;
+}
+
+// CHECK: Hello, World!
+// CHECK-NOT: Shadow stack leak
diff --git a/test/tsan/fork_atexit.cc b/test/tsan/fork_atexit.cc
index 15cf0a2485ca..6e3a2f5c4ba7 100644
--- a/test/tsan/fork_atexit.cc
+++ b/test/tsan/fork_atexit.cc
@@ -7,7 +7,7 @@
#include <sys/wait.h>
void foo() {
- printf("CHILD ATEXIT\n");
+ fprintf(stderr, "CHILD ATEXIT\n");
}
void *worker(void *unused) {
diff --git a/test/tsan/global_race.cc b/test/tsan/global_race.cc
index a35299619e9d..ec26b06f5c1c 100644
--- a/test/tsan/global_race.cc
+++ b/test/tsan/global_race.cc
@@ -1,4 +1,14 @@
-// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe && %deflake %run %T/global_race.cc.exe | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe && %deflake %run %T/global_race.cc.exe 2>&1 \
+// RUN: | FileCheck %s
+
+// Also check that memory access instrumentation can be configured by either
+// driver or legacy flags:
+
+// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe -fno-sanitize-thread-memory-access && not %deflake %run %T/global_race.cc.exe 2>&1 \
+// RUN: | FileCheck --allow-empty --check-prefix=CHECK-MEMORY-ACCESS-OFF %s
+// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe -mllvm -tsan-instrument-memory-accesses=0 && not %deflake %run %T/global_race.cc.exe 2>&1 \
+// RUN: | FileCheck --allow-empty --check-prefix=CHECK-MEMORY-ACCESS-OFF %s
+
#include "test.h"
int GlobalData[10];
@@ -23,3 +33,4 @@ int main() {
// CHECK: WARNING: ThreadSanitizer: data race
// CHECK: Location is global 'GlobalData' {{(of size 40 )?}}at [[ADDR]] (global_race.cc.exe+0x{{[0-9,a-f]+}})
+// CHECK-MEMORY-ACCESS-OFF-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/ignore_lib4.cc b/test/tsan/ignore_lib4.cc
index 193df11d2b2a..84d8b2768a94 100644
--- a/test/tsan/ignore_lib4.cc
+++ b/test/tsan/ignore_lib4.cc
@@ -3,8 +3,6 @@
// 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
diff --git a/test/tsan/ignore_lib5.cc b/test/tsan/ignore_lib5.cc
new file mode 100644
index 000000000000..d7cd28500be9
--- /dev/null
+++ b/test/tsan/ignore_lib5.cc
@@ -0,0 +1,75 @@
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib1.so
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: echo running w/o suppressions:
+// RUN: %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOSUPP
+// RUN: echo running with suppressions:
+// RUN: %env_tsan_opts=suppressions='%s.supp' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP
+
+// REQUIRES: stable-runtime
+
+// Previously the test episodically failed with:
+// ThreadSanitizer: called_from_lib suppression '/libignore_lib1.so$' is
+// matched against 2 libraries: '/libignore_lib1.so' and '/libignore_lib1.so'
+// This was caused by non-atomicity of reading of /proc/self/maps.
+
+#ifndef LIB
+
+#include <dlfcn.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string>
+#include "test.h"
+
+#ifndef MAP_32BIT
+# define MAP_32BIT 0
+#endif
+
+#ifdef __APPLE__
+# define TSAN_MAP_ANON MAP_ANON
+#else
+# define TSAN_MAP_ANON MAP_ANONYMOUS
+#endif
+
+void *thr(void *arg) {
+ // This thread creates lots of separate mappings in /proc/self/maps before
+ // the ignored library.
+ for (int i = 0; i < 10000; i++) {
+ if (i == 5000)
+ barrier_wait(&barrier);
+ mmap(0, 4096, PROT_READ, TSAN_MAP_ANON | MAP_PRIVATE | MAP_32BIT, -1 , 0);
+ mmap(0, 4096, PROT_WRITE, TSAN_MAP_ANON | MAP_PRIVATE | MAP_32BIT, -1 , 0);
+ }
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ barrier_init(&barrier, 2);
+ pthread_t th;
+ pthread_create(&th, 0, thr, 0);
+ barrier_wait(&barrier);
+ std::string lib = std::string(dirname(argv[0])) + "/libignore_lib1.so";
+ void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW);
+ if (h == 0)
+ exit(printf("failed to load the library (%d)\n", errno));
+ void (*f)() = (void(*)())dlsym(h, "libfunc");
+ if (f == 0)
+ exit(printf("failed to find the func (%d)\n", errno));
+ pthread_join(th, 0);
+ f();
+}
+
+#else // #ifdef LIB
+
+#include "ignore_lib_lib.h"
+
+#endif // #ifdef LIB
+
+// CHECK-NOSUPP: WARNING: ThreadSanitizer: data race
+// CHECK-NOSUPP: OK
+
+// CHECK-WITHSUPP-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-WITHSUPP: OK
+
diff --git a/test/tsan/ignore_lib5.cc.supp b/test/tsan/ignore_lib5.cc.supp
new file mode 100644
index 000000000000..9f4119ec0bc4
--- /dev/null
+++ b/test/tsan/ignore_lib5.cc.supp
@@ -0,0 +1,2 @@
+called_from_lib:/libignore_lib1.so$
+
diff --git a/test/tsan/java.h b/test/tsan/java.h
index 565a7a7fdabf..e9aa4ee2440b 100644
--- a/test/tsan/java.h
+++ b/test/tsan/java.h
@@ -7,6 +7,7 @@ void __tsan_java_init(jptr heap_begin, jptr heap_size);
int __tsan_java_fini();
void __tsan_java_alloc(jptr ptr, jptr size);
void __tsan_java_free(jptr ptr, jptr size);
+jptr __tsan_java_find(jptr *from_ptr, jptr to);
void __tsan_java_move(jptr src, jptr dst, jptr size);
void __tsan_java_finalize();
void __tsan_java_mutex_lock(jptr addr);
diff --git a/test/tsan/libcxx/lit.local.cfg b/test/tsan/libcxx/lit.local.cfg
index 202b44ee116d..3ee705736e6f 100644
--- a/test/tsan/libcxx/lit.local.cfg
+++ b/test/tsan/libcxx/lit.local.cfg
@@ -5,6 +5,8 @@ def getRoot(config):
root = getRoot(config)
-if not root.has_libcxx:
+# Only run if we have an instrumented libcxx. On Darwin, run always (we have
+# interceptors to support the system-provided libcxx).
+if not root.has_libcxx and root.host_os != 'Darwin':
config.unsupported = True
diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg
index 1fc1eccd15ea..5d82cc9d4921 100644
--- a/test/tsan/lit.cfg
+++ b/test/tsan/lit.cfg
@@ -38,13 +38,15 @@ if config.compiler_id == 'GNU':
else:
extra_cflags = []
+tsan_incdir = config.test_source_root + "/../"
# Setup default compiler flags used with -fsanitize=thread option.
clang_tsan_cflags = (["-fsanitize=thread",
"-Wall"] +
[config.target_cflags] +
config.debug_info_flags +
- extra_cflags)
-clang_tsan_cxxflags = config.cxx_mode_flags + clang_tsan_cflags
+ extra_cflags +
+ ["-I%s" % tsan_incdir])
+clang_tsan_cxxflags = config.cxx_mode_flags + clang_tsan_cflags + ["-std=c++11"] + ["-I%s" % tsan_incdir]
# Add additional flags if we're using instrumented libc++.
# Instrumented libcxx currently not supported on Darwin.
if config.has_libcxx and config.host_os != 'Darwin':
@@ -54,8 +56,7 @@ if config.has_libcxx and config.host_os != 'Darwin':
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++",
+ clang_tsan_cxxflags += ["-nostdinc++",
"-I%s" % libcxx_incdir,
libcxx_so,
"-Wl,-rpath=%s" % libcxx_libdir]
@@ -69,7 +70,7 @@ config.substitutions.append( ("%clangxx_tsan ", build_invocation(clang_tsan_cxxf
# Define CHECK-%os to check for OS-dependent output.
config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os)))
-config.substitutions.append( ("%deflake ", os.path.join(os.path.dirname(__file__), "deflake.bash")) )
+config.substitutions.append( ("%deflake ", os.path.join(os.path.dirname(__file__), "deflake.bash") + " "))
# Default test suffixes.
config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm']
diff --git a/test/tsan/longjmp.cc b/test/tsan/longjmp.cc
index 61d285c11bf2..a8abca601758 100644
--- a/test/tsan/longjmp.cc
+++ b/test/tsan/longjmp.cc
@@ -1,8 +1,5 @@
// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
-// Longjmp assembly has not been implemented for mips64 yet
-// XFAIL: mips64
-
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
diff --git a/test/tsan/longjmp2.cc b/test/tsan/longjmp2.cc
index 2b2775a8ca1e..d396f3fec66e 100644
--- a/test/tsan/longjmp2.cc
+++ b/test/tsan/longjmp2.cc
@@ -1,8 +1,5 @@
// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
-// Longjmp assembly has not been implemented for mips64 yet
-// XFAIL: mips64
-
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
diff --git a/test/tsan/longjmp3.cc b/test/tsan/longjmp3.cc
index 197b91e1cdc3..842cf264c977 100644
--- a/test/tsan/longjmp3.cc
+++ b/test/tsan/longjmp3.cc
@@ -1,8 +1,5 @@
// 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
-
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/test/tsan/longjmp4.cc b/test/tsan/longjmp4.cc
index 3785a0f07261..4c2fbf0c4028 100644
--- a/test/tsan/longjmp4.cc
+++ b/test/tsan/longjmp4.cc
@@ -1,8 +1,5 @@
// 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
-
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/test/tsan/map32bit.cc b/test/tsan/map32bit.cc
index 0411f29a9504..3b4f8990016e 100644
--- a/test/tsan/map32bit.cc
+++ b/test/tsan/map32bit.cc
@@ -8,7 +8,7 @@
// https://github.com/google/sanitizers/issues/412
// MAP_32BIT flag for mmap is supported only for x86_64.
-// XFAIL: mips64
+// XFAIL: mips
// XFAIL: aarch64
// XFAIL: powerpc64
diff --git a/test/tsan/pie_test.cc b/test/tsan/pie_test.cc
index 8635f9cd403f..93d31daf5fd6 100644
--- a/test/tsan/pie_test.cc
+++ b/test/tsan/pie_test.cc
@@ -1,12 +1,6 @@
// Check if tsan work with PIE binaries.
// RUN: %clang_tsan %s -pie -fpic -o %t && %run %t
-// Some kernels might map PIE segments outside the current segment
-// mapping defined for x86 [1].
-// [1] https://git.kernel.org/linus/d1fd836dcf00d2028c700c7e44d2c23404062c90
-
-// UNSUPPORTED: x86
-
int main(void) {
return 0;
}
diff --git a/test/tsan/signal_block.cc b/test/tsan/signal_block.cc
new file mode 100644
index 000000000000..dfd4259c43c9
--- /dev/null
+++ b/test/tsan/signal_block.cc
@@ -0,0 +1,60 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// Test that a signal is not delivered when it is blocked.
+
+#include "test.h"
+#include <semaphore.h>
+#include <signal.h>
+#include <errno.h>
+
+int stop;
+sig_atomic_t signal_blocked;
+
+void handler(int signum) {
+ if (signal_blocked) {
+ fprintf(stderr, "signal arrived when blocked\n");
+ exit(1);
+ }
+}
+
+void *thread(void *arg) {
+ sigset_t myset;
+ sigemptyset(&myset);
+ sigaddset(&myset, SIGUSR1);
+ while (!__atomic_load_n(&stop, __ATOMIC_RELAXED)) {
+ usleep(1);
+ if (pthread_sigmask(SIG_BLOCK, &myset, 0)) {
+ fprintf(stderr, "pthread_sigmask failed %d\n", errno);
+ exit(1);
+ }
+ signal_blocked = 1;
+ usleep(1);
+ signal_blocked = 0;
+ if (pthread_sigmask(SIG_UNBLOCK, &myset, 0)) {
+ fprintf(stderr, "pthread_sigmask failed %d\n", errno);
+ exit(1);
+ }
+ }
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ struct sigaction act = {};
+ act.sa_handler = &handler;
+ if (sigaction(SIGUSR1, &act, 0)) {
+ fprintf(stderr, "sigaction failed %d\n", errno);
+ return 1;
+ }
+ pthread_t th;
+ pthread_create(&th, 0, thread, 0);
+ for (int i = 0; i < 100000; i++)
+ pthread_kill(th, SIGUSR1);
+ __atomic_store_n(&stop, 1, __ATOMIC_RELAXED);
+ pthread_join(th, 0);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK-NOT: ThreadSanitizer CHECK
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: DONE
diff --git a/test/tsan/signal_cond.cc b/test/tsan/signal_cond.cc
index beb2e0266e50..6c20dd8f2e39 100644
--- a/test/tsan/signal_cond.cc
+++ b/test/tsan/signal_cond.cc
@@ -14,7 +14,7 @@ pthread_cond_t cond;
void sig_handler(int sig) {
(void)sig;
- write(1, "SIGNAL\n", sizeof("SIGNAL\n") - 1);
+ write(2, "SIGNAL\n", sizeof("SIGNAL\n") - 1);
barrier_wait(&barrier);
}
diff --git a/test/tsan/signal_longjmp.cc b/test/tsan/signal_longjmp.cc
index 45e24626cbfa..f9fa4f54f507 100644
--- a/test/tsan/signal_longjmp.cc
+++ b/test/tsan/signal_longjmp.cc
@@ -3,8 +3,6 @@
// Test case for longjumping out of signal handler:
// https://github.com/google/sanitizers/issues/482
-// Longjmp assembly has not been implemented for mips64 yet
-// XFAIL: mips64
// This test fails on powerpc64 BE (VMA=44), a segmentation fault
// error happens at the second assignment
// "((volatile int *volatile)mem)[1] = 1".
diff --git a/test/tsan/simple_stack.c b/test/tsan/simple_stack.c
index 6ef92fb46c68..71a3911b39be 100644
--- a/test/tsan/simple_stack.c
+++ b/test/tsan/simple_stack.c
@@ -1,4 +1,3 @@
-// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
#include "test.h"
int Global;
@@ -47,20 +46,40 @@ int main() {
return 0;
}
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
+
+// Also check that functions instrumentation can be configured by either driver
+// or legacy flags:
+
+// RUN: %clangxx_tsan -O1 %s -o %t -fno-sanitize-thread-func-entry-exit && %deflake %run %t 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FUNC-ENTRY-EXIT-OFF %s
+// RUN: %clangxx_tsan -O1 %s -o %t -mllvm -tsan-instrument-func-entry-exit=0 && %deflake %run %t 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FUNC-ENTRY-EXIT-OFF %s
+
// CHECK: WARNING: ThreadSanitizer: data race
// CHECK-NEXT: Write of size 4 at {{.*}} by thread T1:
-// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack.c:7{{(:10)?}} ({{.*}})
-// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack.c:12{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack.c:26{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack.c:6{{(:10)?}} ({{.*}})
+// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack.c:11{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack.c:25{{(:3)?}} ({{.*}})
// CHECK: Previous read of size 4 at {{.*}} by thread T2:
-// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack.c:16{{(:20)?}} ({{.*}})
-// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack.c:21{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 Thread2{{.*}} {{.*}}simple_stack.c:31{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack.c:15{{(:20)?}} ({{.*}})
+// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack.c:20{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 Thread2{{.*}} {{.*}}simple_stack.c:30{{(:3)?}} ({{.*}})
// CHECK: Thread T1 (tid={{.*}}, running) created by main thread at:
// CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}})
-// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:37{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:43{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:36{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:42{{(:3)?}} ({{.*}})
// CHECK: Thread T2 ({{.*}}) created by main thread at:
// CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}})
-// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:37{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:44{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:36{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:43{{(:3)?}} ({{.*}})
+
+// CHECK-FUNC-ENTRY-EXIT-OFF: WARNING: ThreadSanitizer: data race
+// CHECK-FUNC-ENTRY-EXIT-OFF-NEXT: Write of size 4 at {{.*}} by thread T1:
+// CHECK-FUNC-ENTRY-EXIT-OFF-NEXT: #0 foo1{{.*}} {{.*}}simple_stack.c:6{{(:10)?}} ({{.*}})
+// CHECK-FUNC-ENTRY-EXIT-OFF: Previous read of size 4 at {{.*}} by thread T2:
+// CHECK-FUNC-ENTRY-EXIT-OFF-NEXT: #0 foo2{{.*}} {{.*}}simple_stack.c:15{{(:20)?}} ({{.*}})
+// CHECK-FUNC-ENTRY-EXIT-OFF: Thread T1 (tid={{.*}}, running) created by main thread at:
+// CHECK-FUNC-ENTRY-EXIT-OFF-NEXT: #0 pthread_create {{.*}} ({{.*}})
+// CHECK-FUNC-ENTRY-EXIT-OFF: Thread T2 ({{.*}}) created by main thread at:
+// CHECK-FUNC-ENTRY-EXIT-OFF-NEXT: #0 pthread_create {{.*}} ({{.*}})
diff --git a/test/tsan/test.h b/test/tsan/test.h
index e3affdc0837d..6b981c09f53d 100644
--- a/test/tsan/test.h
+++ b/test/tsan/test.h
@@ -6,6 +6,7 @@
#include <stddef.h>
#include <sched.h>
#include <stdarg.h>
+#include "sanitizer_common/print_address.h"
#ifdef __APPLE__
#include <mach/mach_time.h>
@@ -22,6 +23,7 @@ extern "C" {
void __tsan_testonly_barrier_init(invisible_barrier_t *barrier,
unsigned count);
void __tsan_testonly_barrier_wait(invisible_barrier_t *barrier);
+unsigned long __tsan_testonly_shadow_stack_current_size();
#ifdef __cplusplus
}
#endif
@@ -37,23 +39,6 @@ static inline void barrier_wait(invisible_barrier_t *barrier) {
// Default instance of the barrier, but a test can declare more manually.
invisible_barrier_t barrier;
-void print_address(const char *str, int n, ...) {
- fprintf(stderr, "%s", str);
- va_list ap;
- va_start(ap, n);
- while (n--) {
- void *p = va_arg(ap, void *);
-#if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__)
- // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not
- // match to the format used in the diagnotic message.
- fprintf(stderr, "0x%012lx ", (unsigned long) p);
-#elif defined(__mips64)
- fprintf(stderr, "0x%010lx ", (unsigned long) p);
-#endif
- }
- fprintf(stderr, "\n");
-}
-
#ifdef __APPLE__
unsigned long long monotonic_clock_ns() {
static mach_timebase_info_data_t timebase_info;