aboutsummaryrefslogtreecommitdiff
path: root/test/tsan
diff options
context:
space:
mode:
Diffstat (limited to 'test/tsan')
-rw-r--r--test/tsan/CMakeLists.txt4
-rw-r--r--test/tsan/cond_cancel.c7
-rw-r--r--test/tsan/cond_destruction.cc53
-rw-r--r--test/tsan/cond_race.cc2
-rw-r--r--test/tsan/deadlock_detector_stress_test.cc2
-rw-r--r--test/tsan/dl_iterate_phdr.cc56
-rw-r--r--test/tsan/fd_dup_norace2.cc60
-rw-r--r--test/tsan/fd_dup_race.cc33
-rw-r--r--test/tsan/heap_race.cc4
-rw-r--r--test/tsan/ignore_free.cc2
-rw-r--r--test/tsan/ignore_malloc.cc2
-rw-r--r--test/tsan/java.h5
-rw-r--r--test/tsan/java_heap_init.cc28
-rw-r--r--test/tsan/java_race.cc3
-rw-r--r--test/tsan/java_race_pc.cc36
-rw-r--r--test/tsan/java_symbolization.cc44
-rw-r--r--test/tsan/large_malloc_meta.cc28
-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/malloc_stack.cc2
-rw-r--r--test/tsan/mmap_large.cc7
-rw-r--r--test/tsan/mmap_stress.cc47
-rw-r--r--test/tsan/mop1.c40
-rw-r--r--test/tsan/race_top_suppression.cc29
-rw-r--r--test/tsan/race_top_suppression1.cc32
-rw-r--r--test/tsan/setuid.c26
-rw-r--r--test/tsan/setuid2.c21
-rw-r--r--test/tsan/signal_cond.cc51
-rw-r--r--test/tsan/signal_longjmp.cc3
-rw-r--r--test/tsan/signal_recursive.cc2
-rw-r--r--test/tsan/signal_segv_handler.cc39
-rw-r--r--test/tsan/test.h10
-rw-r--r--test/tsan/thread_detach2.c28
35 files changed, 674 insertions, 48 deletions
diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt
index 5a9542fd76fc..2996c1d80fbd 100644
--- a/test/tsan/CMakeLists.txt
+++ b/test/tsan/CMakeLists.txt
@@ -1,5 +1,7 @@
set(TSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
-list(APPEND TSAN_TEST_DEPS GotsanRuntimeCheck)
+if(NOT ${LLVM_NATIVE_ARCH} STREQUAL "Mips")
+ list(APPEND TSAN_TEST_DEPS GotsanRuntimeCheck)
+endif()
if(NOT COMPILER_RT_STANDALONE_BUILD)
list(APPEND TSAN_TEST_DEPS tsan)
endif()
diff --git a/test/tsan/cond_cancel.c b/test/tsan/cond_cancel.c
index e744570b12fc..ddfb745174f6 100644
--- a/test/tsan/cond_cancel.c
+++ b/test/tsan/cond_cancel.c
@@ -8,9 +8,14 @@ pthread_mutex_t m;
pthread_cond_t c;
int x;
+static void my_cleanup(void *arg) {
+ printf("my_cleanup\n");
+ pthread_mutex_unlock((pthread_mutex_t*)arg);
+}
+
void *thr1(void *p) {
pthread_mutex_lock(&m);
- pthread_cleanup_push((void(*)(void *arg))pthread_mutex_unlock, &m);
+ pthread_cleanup_push(my_cleanup, &m);
barrier_wait(&barrier);
while (x == 0)
pthread_cond_wait(&c, &m);
diff --git a/test/tsan/cond_destruction.cc b/test/tsan/cond_destruction.cc
new file mode 100644
index 000000000000..f56b30c4f0a2
--- /dev/null
+++ b/test/tsan/cond_destruction.cc
@@ -0,0 +1,53 @@
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+// RUN: %run %t arg 2>&1 | FileCheck %s
+// RUN: %run %t arg arg 2>&1 | FileCheck %s
+#include "test.h"
+
+// Test for destruction of pthread_cond_t.
+// POSIX states that it is safe to destroy a condition variable upon which no
+// threads are currently blocked. That is, it is not necessary to wait untill
+// other threads return from pthread_cond_wait, they just need to be unblocked.
+
+pthread_mutex_t m;
+pthread_cond_t c;
+bool done1, done2;
+
+void *thr(void *p) {
+ pthread_mutex_lock(&m);
+ done1 = true;
+ pthread_cond_signal(&c);
+ while (!done2)
+ pthread_cond_wait(&c, &m);
+ pthread_mutex_unlock(&m);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ pthread_t th;
+ pthread_mutex_init(&m, 0);
+ pthread_cond_init(&c, 0);
+ pthread_create(&th, 0, thr, 0);
+ pthread_mutex_lock(&m);
+ while (!done1)
+ pthread_cond_wait(&c, &m);
+ done2 = true;
+ // Any of these sequences is legal.
+ if (argc == 1) {
+ pthread_cond_signal(&c);
+ pthread_mutex_unlock(&m);
+ pthread_cond_destroy(&c);
+ } else if (argc == 2) {
+ pthread_mutex_unlock(&m);
+ pthread_cond_signal(&c);
+ pthread_cond_destroy(&c);
+ } else {
+ pthread_cond_signal(&c);
+ pthread_cond_destroy(&c);
+ pthread_mutex_unlock(&m);
+ }
+ pthread_join(th, 0);
+ fprintf(stderr, "DONE\n");
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
diff --git a/test/tsan/cond_race.cc b/test/tsan/cond_race.cc
index 52654f16e85c..4daf37f85414 100644
--- a/test/tsan/cond_race.cc
+++ b/test/tsan/cond_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
// CHECK-NOT: unlock of unlocked mutex
// CHECK: ThreadSanitizer: data race
// CHECK: pthread_cond_signal
diff --git a/test/tsan/deadlock_detector_stress_test.cc b/test/tsan/deadlock_detector_stress_test.cc
index e02a9123f5af..c77ffe555ce5 100644
--- a/test/tsan/deadlock_detector_stress_test.cc
+++ b/test/tsan/deadlock_detector_stress_test.cc
@@ -1,6 +1,6 @@
// RUN: %clangxx_tsan %s -o %t -DLockType=PthreadMutex
// RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOT-SECOND
-// TSAN_OPTIONS="detect_deadlocks=1 second_deadlock_stack=1" %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-SECOND
+// RUN: TSAN_OPTIONS="detect_deadlocks=1 second_deadlock_stack=1" %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-SECOND
// RUN: %clangxx_tsan %s -o %t -DLockType=PthreadSpinLock
// RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s
// RUN: %clangxx_tsan %s -o %t -DLockType=PthreadRWLock
diff --git a/test/tsan/dl_iterate_phdr.cc b/test/tsan/dl_iterate_phdr.cc
new file mode 100644
index 000000000000..b230a920ac4f
--- /dev/null
+++ b/test/tsan/dl_iterate_phdr.cc
@@ -0,0 +1,56 @@
+// 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
+
+// If we mention TSAN_OPTIONS, the test won't run from test_output.sh script.
+
+#ifdef BUILD_SO
+
+#include "test.h"
+
+int exported_var = 0;
+
+#else // BUILD_SO
+
+#include "test.h"
+#include <dlfcn.h>
+#include <link.h>
+#include <string.h>
+#include <string>
+
+static int callback(struct dl_phdr_info *info, size_t size, void *data) {
+ if (info->dlpi_name[0] == '\0')
+ info->dlpi_name = "/proc/self/exe";
+ return !strcmp(info->dlpi_name, "non existent module");
+}
+
+void *thread(void *unused) {
+ for (int i = 0; i < 1000; i++) {
+ barrier_wait(&barrier);
+ dl_iterate_phdr(callback, 0);
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ barrier_init(&barrier, 2);
+ std::string path = std::string(argv[0]) + std::string("-so.so");
+ pthread_t th;
+ pthread_create(&th, 0, thread, 0);
+ for (int i = 0; i < 1000; i++) {
+ barrier_wait(&barrier);
+ void *lib = dlopen(path.c_str(), RTLD_NOW);
+ if (!lib) {
+ printf("error in dlopen: %s\n", dlerror());
+ return 1;
+ }
+ dlclose(lib);
+ }
+ pthread_join(th, 0);
+ printf("DONE\n");
+ return 0;
+}
+
+#endif // BUILD_SO
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/fd_dup_norace2.cc b/test/tsan/fd_dup_norace2.cc
new file mode 100644
index 000000000000..662c686f33a8
--- /dev/null
+++ b/test/tsan/fd_dup_norace2.cc
@@ -0,0 +1,60 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+// dup2(oldfd, newfd) races with read(newfd).
+// This is not reported as race because:
+// 1. Some software dups a closed pipe in place of a socket before closing
+// the socket (to prevent races actually).
+// 2. Some daemons dup /dev/null in place of stdin/stdout.
+
+int fd;
+
+void *Thread(void *x) {
+ char buf;
+ int n = read(fd, &buf, 1);
+ if (n != 1) {
+ // This read can "legitimately" fail regadless of the fact that glibc claims
+ // that "there is no instant in the middle of calling dup2 at which new is
+ // closed and not yet a duplicate of old". Strace of the failing runs
+ // looks as follows:
+ //
+ // [pid 122196] open("/dev/urandom", O_RDONLY) = 3
+ // [pid 122196] open("/dev/urandom", O_RDONLY) = 4
+ // Process 122382 attached
+ // [pid 122382] read(3, <unfinished ...>
+ // [pid 122196] dup2(4, 3 <unfinished ...>
+ // [pid 122382] <... read resumed> 0x7fcd139960b7, 1) = -1 EBADF (Bad file descriptor)
+ // [pid 122196] <... dup2 resumed> ) = 3
+ // read failed: n=-1 errno=9
+ //
+ // The failing read does not interfere with what this test tests,
+ // so we just ignore the failure.
+ //
+ // exit(printf("read failed: n=%d errno=%d\n", n, errno));
+ }
+ return 0;
+}
+
+int main() {
+ fd = open("/dev/urandom", O_RDONLY);
+ int fd2 = open("/dev/urandom", O_RDONLY);
+ if (fd == -1 || fd2 == -1)
+ exit(printf("open failed\n"));
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ if (dup2(fd2, fd) == -1)
+ exit(printf("dup2 failed\n"));
+ pthread_join(th, 0);
+ if (close(fd) == -1)
+ exit(printf("close failed\n"));
+ if (close(fd2) == -1)
+ exit(printf("close failed\n"));
+ printf("DONE\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/fd_dup_race.cc b/test/tsan/fd_dup_race.cc
new file mode 100644
index 000000000000..a1aee5500753
--- /dev/null
+++ b/test/tsan/fd_dup_race.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
+#include "test.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+// dup2(oldfd, newfd) races with close(newfd).
+
+int fd;
+
+void *Thread(void *x) {
+ barrier_wait(&barrier);
+ if (close(fd) == -1)
+ exit(printf("close failed\n"));
+ return 0;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ fd = open("/dev/random", O_RDONLY);
+ int fd2 = open("/dev/random", O_RDONLY);
+ if (fd == -1 || fd2 == -1)
+ exit(printf("open failed\n"));
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ if (dup2(fd2, fd) == -1)
+ exit(printf("dup2 failed\n"));
+ barrier_wait(&barrier);
+ pthread_join(th, 0);
+ printf("DONE\n");
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/heap_race.cc b/test/tsan/heap_race.cc
index c3da68f42658..0201ea9a2e7f 100644
--- a/test/tsan/heap_race.cc
+++ b/test/tsan/heap_race.cc
@@ -1,17 +1,21 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include "test.h"
#include <pthread.h>
#include <stdio.h>
#include <stddef.h>
void *Thread(void *a) {
((int*)a)[0]++;
+ barrier_wait(&barrier);
return NULL;
}
int main() {
+ barrier_init(&barrier, 2);
int *p = new int(42);
pthread_t t;
pthread_create(&t, NULL, Thread, p);
+ barrier_wait(&barrier);
p[0]++;
pthread_join(t, NULL);
delete p;
diff --git a/test/tsan/ignore_free.cc b/test/tsan/ignore_free.cc
index bb6c6ee14364..4e678952c7aa 100644
--- a/test/tsan/ignore_free.cc
+++ b/test/tsan/ignore_free.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %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"
extern "C" {
diff --git a/test/tsan/ignore_malloc.cc b/test/tsan/ignore_malloc.cc
index 1f633f062d0e..100b4e5dc808 100644
--- a/test/tsan/ignore_malloc.cc
+++ b/test/tsan/ignore_malloc.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %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"
extern "C" {
diff --git a/test/tsan/java.h b/test/tsan/java.h
index 35fdbc1e7bb1..565a7a7fdabf 100644
--- a/test/tsan/java.h
+++ b/test/tsan/java.h
@@ -18,4 +18,9 @@ int __tsan_java_mutex_unlock_rec(jptr addr);
int __tsan_java_acquire(jptr addr);
int __tsan_java_release(jptr addr);
int __tsan_java_release_store(jptr addr);
+
+void __tsan_read1_pc(jptr addr, jptr pc);
+void __tsan_write1_pc(jptr addr, jptr pc);
}
+
+const jptr kExternalPCBit = 1ULL << 60;
diff --git a/test/tsan/java_heap_init.cc b/test/tsan/java_heap_init.cc
new file mode 100644
index 000000000000..bb7357c25b42
--- /dev/null
+++ b/test/tsan/java_heap_init.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "java.h"
+#include <errno.h>
+#include <sys/mman.h>
+
+int main() {
+ // Test that munmap interceptor resets meta shadow for the memory range.
+ // Previously __tsan_java_move failed because it encountered non-zero meta
+ // shadow for the destination.
+ int const kHeapSize = 1024 * 1024;
+ jptr jheap = (jptr)mmap(0, kHeapSize, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+ if (jheap == (jptr)MAP_FAILED)
+ return printf("mmap failed with %d\n", errno);
+ __atomic_store_n((int*)jheap, 1, __ATOMIC_RELEASE);
+ munmap((void*)jheap, kHeapSize);
+ jheap = (jptr)mmap((void*)jheap, kHeapSize, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+ if (jheap == (jptr)MAP_FAILED)
+ return printf("second mmap failed with %d\n", errno);
+ __tsan_java_init(jheap, kHeapSize);
+ __tsan_java_move(jheap + 16, jheap, 16);
+ printf("DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/java_race.cc b/test/tsan/java_race.cc
index ede058e85d8a..140a2a3c19d3 100644
--- a/test/tsan/java_race.cc
+++ b/test/tsan/java_race.cc
@@ -2,11 +2,13 @@
#include "java.h"
void *Thread(void *p) {
+ barrier_wait(&barrier);
*(int*)p = 42;
return 0;
}
int main() {
+ barrier_init(&barrier, 2);
int const kHeapSize = 1024 * 1024;
jptr jheap = (jptr)malloc(kHeapSize + 8) + 8;
__tsan_java_init(jheap, kHeapSize);
@@ -15,6 +17,7 @@ int main() {
pthread_t th;
pthread_create(&th, 0, Thread, (void*)jheap);
*(int*)jheap = 43;
+ barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(jheap, kBlockSize);
fprintf(stderr, "DONE\n");
diff --git a/test/tsan/java_race_pc.cc b/test/tsan/java_race_pc.cc
new file mode 100644
index 000000000000..015a0b1f43c6
--- /dev/null
+++ b/test/tsan/java_race_pc.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include "java.h"
+
+void foobar() {
+}
+
+void barbaz() {
+}
+
+void *Thread(void *p) {
+ barrier_wait(&barrier);
+ __tsan_read1_pc((jptr)p, (jptr)foobar + 1);
+ return 0;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ int const kHeapSize = 1024 * 1024;
+ jptr jheap = (jptr)malloc(kHeapSize + 8) + 8;
+ __tsan_java_init(jheap, kHeapSize);
+ const int kBlockSize = 16;
+ __tsan_java_alloc(jheap, kBlockSize);
+ pthread_t th;
+ pthread_create(&th, 0, Thread, (void*)jheap);
+ __tsan_write1_pc((jptr)jheap, (jptr)barbaz + 1);
+ barrier_wait(&barrier);
+ pthread_join(th, 0);
+ __tsan_java_free(jheap, kBlockSize);
+ fprintf(stderr, "DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: #0 foobar
+// CHECK: #0 barbaz
+// CHECK: DONE
diff --git a/test/tsan/java_symbolization.cc b/test/tsan/java_symbolization.cc
new file mode 100644
index 000000000000..aa5ec0c37558
--- /dev/null
+++ b/test/tsan/java_symbolization.cc
@@ -0,0 +1,44 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include "java.h"
+#include <memory.h>
+
+extern "C" bool __tsan_symbolize_external(jptr pc,
+ char *func_buf, jptr func_siz,
+ char *file_buf, jptr file_siz,
+ int *line, int *col) {
+ if (pc == (1234 | kExternalPCBit)) {
+ memcpy(func_buf, "MyFunc", sizeof("MyFunc"));
+ memcpy(file_buf, "MyFile.java", sizeof("MyFile.java"));
+ *line = 1234;
+ *col = 56;
+ return true;
+ }
+ return false;
+}
+
+void *Thread(void *p) {
+ barrier_wait(&barrier);
+ __tsan_write1_pc((jptr)p, 1234 | kExternalPCBit);
+ return 0;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ int const kHeapSize = 1024 * 1024;
+ jptr jheap = (jptr)malloc(kHeapSize + 8) + 8;
+ __tsan_java_init(jheap, kHeapSize);
+ const int kBlockSize = 16;
+ __tsan_java_alloc(jheap, kBlockSize);
+ pthread_t th;
+ pthread_create(&th, 0, Thread, (void*)jheap);
+ __tsan_write1_pc((jptr)jheap, 1234 | kExternalPCBit);
+ barrier_wait(&barrier);
+ pthread_join(th, 0);
+ __tsan_java_free(jheap, kBlockSize);
+ fprintf(stderr, "DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: #0 MyFunc MyFile.java:1234:56
+// CHECK: DONE
diff --git a/test/tsan/large_malloc_meta.cc b/test/tsan/large_malloc_meta.cc
new file mode 100644
index 000000000000..e83004824a3a
--- /dev/null
+++ b/test/tsan/large_malloc_meta.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+#include <sys/mman.h>
+
+// Test for previously unbounded memory consumption for large mallocs.
+// Code allocates a large memory block (that is handled by LargeMmapAllocator),
+// and forces allocation of meta shadow for the block. Then freed the block.
+// But meta shadow was not unmapped. Then code occupies the virtual memory
+// range of the block with something else (that does not need meta shadow).
+// And repeats. As the result meta shadow growed infinitely.
+// This program used to consume >2GB. Now it consumes <50MB.
+
+int main() {
+ for (int i = 0; i < 1000; i++) {
+ const int kSize = 1 << 20;
+ const int kPageSize = 4 << 10;
+ volatile int *p = new int[kSize];
+ for (int j = 0; j < kSize; j += kPageSize / sizeof(*p))
+ __atomic_store_n(&p[i], 1, __ATOMIC_RELEASE);
+ delete[] p;
+ mmap(0, kSize * sizeof(*p) + kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANON,
+ -1, 0);
+ }
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK: DONE
diff --git a/test/tsan/longjmp.cc b/test/tsan/longjmp.cc
index d7371c5e4069..d642067391fd 100644
--- a/test/tsan/longjmp.cc
+++ b/test/tsan/longjmp.cc
@@ -1,4 +1,8 @@
// 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 546019b2d11a..eee423dc5fbe 100644
--- a/test/tsan/longjmp2.cc
+++ b/test/tsan/longjmp2.cc
@@ -1,4 +1,8 @@
// 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 71d964dbbed9..79965c4193d3 100644
--- a/test/tsan/longjmp3.cc
+++ b/test/tsan/longjmp3.cc
@@ -1,4 +1,8 @@
// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | 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 15330f5d83c8..c8583997331e 100644
--- a/test/tsan/longjmp4.cc
+++ b/test/tsan/longjmp4.cc
@@ -1,4 +1,8 @@
// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | 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/malloc_stack.cc b/test/tsan/malloc_stack.cc
index ba1d62bcd9e7..f0c6f9354a5f 100644
--- a/test/tsan/malloc_stack.cc
+++ b/test/tsan/malloc_stack.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
#include "test.h"
_Atomic(int*) p;
diff --git a/test/tsan/mmap_large.cc b/test/tsan/mmap_large.cc
index 4ae4c0863501..098530475df5 100644
--- a/test/tsan/mmap_large.cc
+++ b/test/tsan/mmap_large.cc
@@ -4,6 +4,13 @@
#include <errno.h>
#include <sys/mman.h>
+#if defined(__FreeBSD__)
+// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
+// that, it was never implemented. So just define it to zero.
+#undef MAP_NORESERVE
+#define MAP_NORESERVE 0
+#endif
+
int main() {
#ifdef __x86_64__
const size_t kLog2Size = 39;
diff --git a/test/tsan/mmap_stress.cc b/test/tsan/mmap_stress.cc
new file mode 100644
index 000000000000..5e3904adf90b
--- /dev/null
+++ b/test/tsan/mmap_stress.cc
@@ -0,0 +1,47 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+#include <errno.h>
+#include <sys/mman.h>
+
+void *SubWorker(void *arg) {
+ (void)arg;
+ const int kMmapSize = 65536;
+ for (int i = 0; i < 500; i++) {
+ int *ptr = (int*)mmap(0, kMmapSize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ *ptr = 42;
+ munmap(ptr, kMmapSize);
+ }
+ return 0;
+}
+
+void *Worker1(void *arg) {
+ (void)arg;
+ pthread_t th[4];
+ for (int i = 0; i < 4; i++)
+ pthread_create(&th[i], 0, SubWorker, 0);
+ for (int i = 0; i < 4; i++)
+ pthread_join(th[i], 0);
+ return 0;
+}
+
+void *Worker(void *arg) {
+ (void)arg;
+ pthread_t th[4];
+ for (int i = 0; i < 4; i++)
+ pthread_create(&th[i], 0, Worker1, 0);
+ for (int i = 0; i < 4; i++)
+ pthread_join(th[i], 0);
+ return 0;
+}
+
+int main() {
+ pthread_t th[4];
+ for (int i = 0; i < 4; i++)
+ pthread_create(&th[i], 0, Worker, 0);
+ for (int i = 0; i < 4; i++)
+ pthread_join(th[i], 0);
+ fprintf(stderr, "DONE\n");
+}
+
+// CHECK: DONE
diff --git a/test/tsan/mop1.c b/test/tsan/mop1.c
new file mode 100644
index 000000000000..e61c5b8caac9
--- /dev/null
+++ b/test/tsan/mop1.c
@@ -0,0 +1,40 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include "test.h"
+
+// We want to establish the following sequence of accesses to X:
+// - main thread writes X
+// - thread2 reads X, this read happens-before the write in main thread
+// - thread1 reads X, this read is concurrent with the write in main thread
+// Write in main thread and read in thread1 should be detected as a race.
+// Previously tsan replaced write by main thread with read by thread1,
+// as the result the race was not detected.
+
+volatile long X, Y, Z;
+
+void *Thread1(void *x) {
+ barrier_wait(&barrier);
+ barrier_wait(&barrier);
+ Y = X;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Z = X;
+ barrier_wait(&barrier);
+ return NULL;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ X = 42;
+ barrier_wait(&barrier);
+ pthread_create(&t[1], 0, Thread2, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+
diff --git a/test/tsan/race_top_suppression.cc b/test/tsan/race_top_suppression.cc
new file mode 100644
index 000000000000..7d42dbf3b4bf
--- /dev/null
+++ b/test/tsan/race_top_suppression.cc
@@ -0,0 +1,29 @@
+// RUN: echo "race_top:TopFunction" > %t.supp
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%t.supp'" %run %t 2>&1 | FileCheck %s
+// RUN: rm %t.supp
+#include "test.h"
+
+int Global;
+
+void TopFunction(int *p) {
+ *p = 1;
+}
+
+void *Thread(void *x) {
+ barrier_wait(&barrier);
+ TopFunction(&Global);
+ return 0;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ Global--;
+ barrier_wait(&barrier);
+ pthread_join(t, 0);
+ fprintf(stderr, "DONE\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/race_top_suppression1.cc b/test/tsan/race_top_suppression1.cc
new file mode 100644
index 000000000000..881e661ba789
--- /dev/null
+++ b/test/tsan/race_top_suppression1.cc
@@ -0,0 +1,32 @@
+// RUN: echo "race_top:TopFunction" > %t.supp
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%t.supp'" %deflake %run %t 2>&1 | FileCheck %s
+// RUN: rm %t.supp
+#include "test.h"
+
+int Global;
+
+void AnotherFunction(int *p) {
+ *p = 1;
+}
+
+void TopFunction(int *p) {
+ AnotherFunction(p);
+}
+
+void *Thread(void *x) {
+ barrier_wait(&barrier);
+ TopFunction(&Global);
+ return 0;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ Global--;
+ barrier_wait(&barrier);
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/setuid.c b/test/tsan/setuid.c
new file mode 100644
index 000000000000..bc9c8ca3abaa
--- /dev/null
+++ b/test/tsan/setuid.c
@@ -0,0 +1,26 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+#include <sys/types.h>
+#include <unistd.h>
+
+// Setuid call used to hang because the background tsan thread did not handle
+// SIGSETXID signal. Note that we don't care whether setuid call succeeds
+// or not.
+
+static void *thread(void *arg) {
+ (void)arg;
+ sleep(1);
+ return 0;
+}
+
+int main() {
+ // Create another thread just for completeness of the picture.
+ pthread_t th;
+ pthread_create(&th, 0, thread, 0);
+ setuid(0);
+ pthread_join(th, 0);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK: DONE
diff --git a/test/tsan/setuid2.c b/test/tsan/setuid2.c
new file mode 100644
index 000000000000..67a6fd14dbcb
--- /dev/null
+++ b/test/tsan/setuid2.c
@@ -0,0 +1,21 @@
+// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="flush_memory_ms=1 memory_limit_mb=1" %run %t 2>&1 | FileCheck %s
+#include "test.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+
+// Test that setuid call works in presence of stoptheworld.
+
+int main() {
+ struct timespec tp0, tp1;
+ clock_gettime(CLOCK_MONOTONIC, &tp0);
+ clock_gettime(CLOCK_MONOTONIC, &tp1);
+ while (tp1.tv_sec - tp0.tv_sec < 3) {
+ clock_gettime(CLOCK_MONOTONIC, &tp1);
+ setuid(0);
+ }
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK: DONE
diff --git a/test/tsan/signal_cond.cc b/test/tsan/signal_cond.cc
new file mode 100644
index 000000000000..f5eae745d407
--- /dev/null
+++ b/test/tsan/signal_cond.cc
@@ -0,0 +1,51 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <semaphore.h>
+
+// Test that signals can be delivered to blocked pthread_cond_wait.
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=91
+
+int g_thread_run = 1;
+pthread_mutex_t mutex;
+pthread_cond_t cond;
+sem_t sem;
+
+void sig_handler(int sig) {
+ (void)sig;
+ write(1, "SIGNAL\n", sizeof("SIGNAL\n") - 1);
+ sem_post(&sem);
+}
+
+void* my_thread(void* arg) {
+ pthread_mutex_lock(&mutex);
+ while (g_thread_run)
+ pthread_cond_wait(&cond, &mutex);
+ pthread_mutex_unlock(&mutex);
+ return 0;
+}
+
+int main() {
+ sem_init(&sem, 0, 0);
+ signal(SIGUSR1, &sig_handler);
+ pthread_t thr;
+ pthread_create(&thr, 0, &my_thread, 0);
+ // wait for thread to get inside pthread_cond_wait
+ // (can't use barrier_wait for that)
+ sleep(1);
+ pthread_kill(thr, SIGUSR1);
+ while (sem_wait(&sem) == -1 && errno == EINTR) {
+ }
+ pthread_mutex_lock(&mutex);
+ g_thread_run = 0;
+ pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ pthread_join(thr, 0);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK: SIGNAL
+// CHECK: DONE
diff --git a/test/tsan/signal_longjmp.cc b/test/tsan/signal_longjmp.cc
index 84b0682dcbaf..2525c898887b 100644
--- a/test/tsan/signal_longjmp.cc
+++ b/test/tsan/signal_longjmp.cc
@@ -3,6 +3,9 @@
// Test case for longjumping out of signal handler:
// https://code.google.com/p/thread-sanitizer/issues/detail?id=75
+// Longjmp assembly has not been implemented for mips64 yet
+// XFAIL: mips64
+
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
diff --git a/test/tsan/signal_recursive.cc b/test/tsan/signal_recursive.cc
index 825338de9fba..67fc9c0ec9a3 100644
--- a/test/tsan/signal_recursive.cc
+++ b/test/tsan/signal_recursive.cc
@@ -3,6 +3,8 @@
// Test case for recursive signal handlers, adopted from:
// https://code.google.com/p/thread-sanitizer/issues/detail?id=71
+// REQUIRES: disabled
+
#include "test.h"
#include <semaphore.h>
#include <signal.h>
diff --git a/test/tsan/signal_segv_handler.cc b/test/tsan/signal_segv_handler.cc
deleted file mode 100644
index 2d806eef6764..000000000000
--- a/test/tsan/signal_segv_handler.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="flush_memory_ms=1 memory_limit_mb=1" %run %t 2>&1 | FileCheck %s
-
-// JVM uses SEGV to preempt threads. All threads do a load from a known address
-// periodically. When runtime needs to preempt threads, it unmaps the page.
-// Threads start triggering SEGV one by one. The signal handler blocks
-// threads while runtime does its thing. Then runtime maps the page again
-// and resumes the threads.
-// Previously this pattern conflicted with stop-the-world machinery,
-// because it briefly reset SEGV handler to SIG_DFL.
-// As the consequence JVM just silently died.
-
-// This test sets memory flushing rate to maximum, then does series of
-// "benign" SEGVs that are handled by signal handler, and ensures that
-// the process survive.
-
-#include "test.h"
-#include <signal.h>
-#include <sys/mman.h>
-
-void *guard;
-
-void handler(int signo, siginfo_t *info, void *uctx) {
- mprotect(guard, 4096, PROT_READ | PROT_WRITE);
-}
-
-int main() {
- struct sigaction a;
- a.sa_sigaction = handler;
- a.sa_flags = SA_SIGINFO;
- sigaction(SIGSEGV, &a, 0);
- guard = mmap(0, 4096, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
- for (int i = 0; i < 1000000; i++) {
- mprotect(guard, 4096, PROT_NONE);
- *(int*)guard = 1;
- }
- fprintf(stderr, "DONE\n");
-}
-
-// CHECK: DONE
diff --git a/test/tsan/test.h b/test/tsan/test.h
index bb861b07745e..4e877f6d8dfd 100644
--- a/test/tsan/test.h
+++ b/test/tsan/test.h
@@ -11,10 +11,16 @@
__typeof(pthread_barrier_wait) *barrier_wait;
void barrier_init(pthread_barrier_t *barrier, unsigned count) {
+#if defined(__FreeBSD__)
+ static const char libpthread_name[] = "libpthread.so";
+#else
+ static const char libpthread_name[] = "libpthread.so.0";
+#endif
+
if (barrier_wait == 0) {
- void *h = dlopen("libpthread.so.0", RTLD_LAZY);
+ void *h = dlopen(libpthread_name, RTLD_LAZY);
if (h == 0) {
- fprintf(stderr, "failed to dlopen libpthread.so.0, exiting\n");
+ fprintf(stderr, "failed to dlopen %s, exiting\n", libpthread_name);
exit(1);
}
barrier_wait = (__typeof(barrier_wait))dlsym(h, "pthread_barrier_wait");
diff --git a/test/tsan/thread_detach2.c b/test/tsan/thread_detach2.c
new file mode 100644
index 000000000000..8133980ba5a1
--- /dev/null
+++ b/test/tsan/thread_detach2.c
@@ -0,0 +1,28 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+
+// Test for https://llvm.org/bugs/show_bug.cgi?id=23235
+// The bug was that synchronization between thread creation and thread start
+// is not established if pthread_create is followed by pthread_detach.
+
+int x;
+
+void *Thread(void *a) {
+ x = 42;
+ barrier_wait(&barrier);
+ return 0;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ pthread_t t;
+ x = 43;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_detach(t);
+ barrier_wait(&barrier);
+ printf("PASS\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: PASS