summaryrefslogtreecommitdiff
path: root/lib/tsan/lit_tests
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tsan/lit_tests')
-rw-r--r--lib/tsan/lit_tests/CMakeLists.txt5
-rw-r--r--lib/tsan/lit_tests/SharedLibs/lit.local.cfg4
-rw-r--r--lib/tsan/lit_tests/SharedLibs/load_shared_lib-so.cc22
-rw-r--r--lib/tsan/lit_tests/Unit/lit.cfg5
-rw-r--r--lib/tsan/lit_tests/Unit/lit.site.cfg.in4
-rw-r--r--lib/tsan/lit_tests/aligned_vs_unaligned_race.cc34
-rw-r--r--lib/tsan/lit_tests/atomic_free.cc19
-rw-r--r--lib/tsan/lit_tests/atomic_free2.cc19
-rw-r--r--lib/tsan/lit_tests/atomic_norace.cc61
-rw-r--r--lib/tsan/lit_tests/atomic_race.cc80
-rw-r--r--lib/tsan/lit_tests/atomic_stack.cc29
-rw-r--r--lib/tsan/lit_tests/benign_race.cc39
-rw-r--r--lib/tsan/lit_tests/free_race.c3
-rw-r--r--lib/tsan/lit_tests/free_race2.c4
-rw-r--r--lib/tsan/lit_tests/inlined_memcpy_race.cc55
-rw-r--r--lib/tsan/lit_tests/java.h2
-rw-r--r--lib/tsan/lit_tests/java_lock.cc2
-rw-r--r--lib/tsan/lit_tests/java_lock_rec.cc54
-rw-r--r--lib/tsan/lit_tests/java_lock_rec_race.cc48
-rw-r--r--lib/tsan/lit_tests/java_rwlock.cc2
-rw-r--r--lib/tsan/lit_tests/lit.cfg24
-rw-r--r--lib/tsan/lit_tests/lit.site.cfg.in1
-rw-r--r--lib/tsan/lit_tests/load_shared_lib.cc44
-rw-r--r--lib/tsan/lit_tests/longjmp.cc22
-rw-r--r--lib/tsan/lit_tests/longjmp2.cc24
-rw-r--r--lib/tsan/lit_tests/longjmp3.cc48
-rw-r--r--lib/tsan/lit_tests/longjmp4.cc51
-rw-r--r--lib/tsan/lit_tests/malloc_overflow.cc22
-rw-r--r--lib/tsan/lit_tests/malloc_stack.cc25
-rw-r--r--lib/tsan/lit_tests/memcpy_race.cc6
-rw-r--r--lib/tsan/lit_tests/mutex_destroy_locked.cc1
-rw-r--r--lib/tsan/lit_tests/mutexset7.cc1
-rw-r--r--lib/tsan/lit_tests/mutexset8.cc39
-rw-r--r--lib/tsan/lit_tests/oob_race.cc24
-rw-r--r--lib/tsan/lit_tests/race_on_heap.cc4
-rw-r--r--lib/tsan/lit_tests/race_on_mutex.c2
-rw-r--r--lib/tsan/lit_tests/race_on_mutex2.c24
-rw-r--r--lib/tsan/lit_tests/race_on_write.cc39
-rw-r--r--lib/tsan/lit_tests/signal_errno.cc7
-rw-r--r--lib/tsan/lit_tests/signal_malloc.cc3
-rw-r--r--lib/tsan/lit_tests/simple_race.cc1
-rwxr-xr-xlib/tsan/lit_tests/test_output.sh15
-rw-r--r--lib/tsan/lit_tests/thread_end_with_ignore.cc19
-rw-r--r--lib/tsan/lit_tests/thread_end_with_ignore2.cc9
-rw-r--r--lib/tsan/lit_tests/thread_leak3.c3
-rw-r--r--lib/tsan/lit_tests/thread_leak4.c18
-rw-r--r--lib/tsan/lit_tests/thread_leak5.c19
-rw-r--r--lib/tsan/lit_tests/thread_name.cc4
-rw-r--r--lib/tsan/lit_tests/tsan-vs-gvn.cc38
-rw-r--r--lib/tsan/lit_tests/unaligned_norace.cc84
-rw-r--r--lib/tsan/lit_tests/unaligned_race.cc135
-rw-r--r--lib/tsan/lit_tests/vptr_harmful_race.cc4
-rw-r--r--lib/tsan/lit_tests/vptr_harmful_race2.cc51
53 files changed, 1264 insertions, 38 deletions
diff --git a/lib/tsan/lit_tests/CMakeLists.txt b/lib/tsan/lit_tests/CMakeLists.txt
index ff2508dd75afd..53e5015d1bc4d 100644
--- a/lib/tsan/lit_tests/CMakeLists.txt
+++ b/lib/tsan/lit_tests/CMakeLists.txt
@@ -11,9 +11,8 @@ configure_lit_site_cfg(
if(COMPILER_RT_CAN_EXECUTE_TESTS)
# Run TSan output tests only if we're sure we can produce working binaries.
set(TSAN_TEST_DEPS
- clang clang-headers FileCheck count not llvm-symbolizer
- ${TSAN_RUNTIME_LIBRARIES}
- )
+ ${SANITIZER_COMMON_LIT_TEST_DEPS}
+ ${TSAN_RUNTIME_LIBRARIES})
set(TSAN_TEST_PARAMS
tsan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
)
diff --git a/lib/tsan/lit_tests/SharedLibs/lit.local.cfg b/lib/tsan/lit_tests/SharedLibs/lit.local.cfg
new file mode 100644
index 0000000000000..b3677c17a0f2a
--- /dev/null
+++ b/lib/tsan/lit_tests/SharedLibs/lit.local.cfg
@@ -0,0 +1,4 @@
+# Sources in this directory are compiled as shared libraries and used by
+# tests in parent directory.
+
+config.suffixes = []
diff --git a/lib/tsan/lit_tests/SharedLibs/load_shared_lib-so.cc b/lib/tsan/lit_tests/SharedLibs/load_shared_lib-so.cc
new file mode 100644
index 0000000000000..d05aa6a40d182
--- /dev/null
+++ b/lib/tsan/lit_tests/SharedLibs/load_shared_lib-so.cc
@@ -0,0 +1,22 @@
+//===----------- load_shared_lib-so.cc --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stddef.h>
+
+int GLOB_SHARED = 0;
+
+extern "C"
+void *write_from_so(void *unused) {
+ GLOB_SHARED++;
+ return NULL;
+}
diff --git a/lib/tsan/lit_tests/Unit/lit.cfg b/lib/tsan/lit_tests/Unit/lit.cfg
index 6688697c0c1b1..0a0dbbfa54950 100644
--- a/lib/tsan/lit_tests/Unit/lit.cfg
+++ b/lib/tsan/lit_tests/Unit/lit.cfg
@@ -11,9 +11,8 @@ def get_required_attr(config, attr_name):
return attr_value
# Setup attributes common for all compiler-rt projects.
-llvm_src_root = get_required_attr(config, 'llvm_src_root')
-compiler_rt_lit_unit_cfg = os.path.join(llvm_src_root, "projects",
- "compiler-rt", "lib",
+compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root')
+compiler_rt_lit_unit_cfg = os.path.join(compiler_rt_src_root, "lib",
"lit.common.unit.cfg")
lit.load_config(config, compiler_rt_lit_unit_cfg)
diff --git a/lib/tsan/lit_tests/Unit/lit.site.cfg.in b/lib/tsan/lit_tests/Unit/lit.site.cfg.in
index 23654b9be2eee..6eedc21808765 100644
--- a/lib/tsan/lit_tests/Unit/lit.site.cfg.in
+++ b/lib/tsan/lit_tests/Unit/lit.site.cfg.in
@@ -1,15 +1,17 @@
## Autogenerated by LLVM/Clang configuration.
# Do not edit!
-config.build_type = "@CMAKE_BUILD_TYPE@"
config.llvm_obj_root = "@LLVM_BINARY_DIR@"
config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.llvm_build_mode = "@LLVM_BUILD_MODE@"
# LLVM tools dir can be passed in lit parameters, so try to
# apply substitution.
try:
config.llvm_tools_dir = config.llvm_tools_dir % lit.params
+ config.llvm_build_mode = config.llvm_build_mode % lit.params
except KeyError,e:
key, = e.args
lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
diff --git a/lib/tsan/lit_tests/aligned_vs_unaligned_race.cc b/lib/tsan/lit_tests/aligned_vs_unaligned_race.cc
new file mode 100644
index 0000000000000..f4533d08306c5
--- /dev/null
+++ b/lib/tsan/lit_tests/aligned_vs_unaligned_race.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// Race between an aligned access and an unaligned access, which
+// touches the same memory region.
+// This is a real race which is not detected by tsan.
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=17
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+
+uint64_t Global[2];
+
+void *Thread1(void *x) {
+ Global[1]++;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ char *p1 = reinterpret_cast<char *>(&Global[0]);
+ uint64_t *p4 = reinterpret_cast<uint64_t *>(p1 + 1);
+ (*p4)++;
+ return NULL;
+}
+
+int main() {
+ 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);
+ printf("Pass\n");
+ // CHECK-NOT: ThreadSanitizer: data race
+ // CHECK: Pass
+ return 0;
+}
diff --git a/lib/tsan/lit_tests/atomic_free.cc b/lib/tsan/lit_tests/atomic_free.cc
new file mode 100644
index 0000000000000..ba9bd5ac4aedd
--- /dev/null
+++ b/lib/tsan/lit_tests/atomic_free.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *a) {
+ __atomic_fetch_add((int*)a, 1, __ATOMIC_SEQ_CST);
+ return 0;
+}
+
+int main() {
+ int *a = new int(0);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, a);
+ sleep(1);
+ delete a;
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/atomic_free2.cc b/lib/tsan/lit_tests/atomic_free2.cc
new file mode 100644
index 0000000000000..5517bf7ce9029
--- /dev/null
+++ b/lib/tsan/lit_tests/atomic_free2.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *a) {
+ sleep(1);
+ __atomic_fetch_add((int*)a, 1, __ATOMIC_SEQ_CST);
+ return 0;
+}
+
+int main() {
+ int *a = new int(0);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, a);
+ delete a;
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
diff --git a/lib/tsan/lit_tests/atomic_norace.cc b/lib/tsan/lit_tests/atomic_norace.cc
new file mode 100644
index 0000000000000..265459b0758e1
--- /dev/null
+++ b/lib/tsan/lit_tests/atomic_norace.cc
@@ -0,0 +1,61 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+const int kTestCount = 4;
+typedef long long T;
+T atomics[kTestCount * 2];
+
+void Test(int test, T *p, bool main_thread) {
+ volatile T sink;
+ if (test == 0) {
+ if (main_thread)
+ __atomic_fetch_add(p, 1, __ATOMIC_RELAXED);
+ else
+ __atomic_fetch_add(p, 1, __ATOMIC_RELAXED);
+ } else if (test == 1) {
+ if (main_thread)
+ __atomic_exchange_n(p, 1, __ATOMIC_ACQ_REL);
+ else
+ __atomic_exchange_n(p, 1, __ATOMIC_ACQ_REL);
+ } else if (test == 2) {
+ if (main_thread)
+ sink = __atomic_load_n(p, __ATOMIC_SEQ_CST);
+ else
+ __atomic_store_n(p, 1, __ATOMIC_SEQ_CST);
+ } else if (test == 3) {
+ if (main_thread)
+ sink = __atomic_load_n(p, __ATOMIC_SEQ_CST);
+ else
+ sink = *p;
+ }
+}
+
+void *Thread(void *p) {
+ for (int i = 0; i < kTestCount; i++) {
+ Test(i, &atomics[i], false);
+ }
+ sleep(2);
+ for (int i = 0; i < kTestCount; i++) {
+ fprintf(stderr, "Test %d reverse\n", i);
+ Test(i, &atomics[kTestCount + i], false);
+ }
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ sleep(1);
+ for (int i = 0; i < kTestCount; i++) {
+ fprintf(stderr, "Test %d\n", i);
+ Test(i, &atomics[i], true);
+ }
+ for (int i = 0; i < kTestCount; i++) {
+ Test(i, &atomics[kTestCount + i], true);
+ }
+ pthread_join(t, 0);
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/atomic_race.cc b/lib/tsan/lit_tests/atomic_race.cc
new file mode 100644
index 0000000000000..360b81238889d
--- /dev/null
+++ b/lib/tsan/lit_tests/atomic_race.cc
@@ -0,0 +1,80 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+
+const int kTestCount = 4;
+typedef long long T;
+T atomics[kTestCount * 2];
+
+void Test(int test, T *p, bool main_thread) {
+ volatile T sink;
+ if (test == 0) {
+ if (main_thread)
+ __atomic_fetch_add(p, 1, __ATOMIC_RELAXED);
+ else
+ *p = 42;
+ } else if (test == 1) {
+ if (main_thread)
+ __atomic_fetch_add(p, 1, __ATOMIC_RELAXED);
+ else
+ sink = *p;
+ } else if (test == 2) {
+ if (main_thread)
+ sink = __atomic_load_n(p, __ATOMIC_SEQ_CST);
+ else
+ *p = 42;
+ } else if (test == 3) {
+ if (main_thread)
+ __atomic_store_n(p, 1, __ATOMIC_SEQ_CST);
+ else
+ sink = *p;
+ }
+}
+
+void *Thread(void *p) {
+ for (int i = 0; i < kTestCount; i++) {
+ Test(i, &atomics[i], false);
+ }
+ sleep(2);
+ for (int i = 0; i < kTestCount; i++) {
+ fprintf(stderr, "Test %d reverse\n", i);
+ Test(i, &atomics[kTestCount + i], false);
+ }
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ sleep(1);
+ for (int i = 0; i < kTestCount; i++) {
+ fprintf(stderr, "Test %d\n", i);
+ Test(i, &atomics[i], true);
+ }
+ for (int i = 0; i < kTestCount; i++) {
+ Test(i, &atomics[kTestCount + i], true);
+ }
+ pthread_join(t, 0);
+}
+
+// CHECK: Test 0
+// CHECK: ThreadSanitizer: data race
+// CHECK-NOT: SUMMARY{{.*}}tsan_interface_atomic
+// CHECK: Test 1
+// CHECK: ThreadSanitizer: data race
+// CHECK-NOT: SUMMARY{{.*}}tsan_interface_atomic
+// CHECK: Test 2
+// CHECK: ThreadSanitizer: data race
+// CHECK-NOT: SUMMARY{{.*}}tsan_interface_atomic
+// CHECK: Test 3
+// CHECK: ThreadSanitizer: data race
+// CHECK-NOT: SUMMARY{{.*}}tsan_interface_atomic
+// CHECK: Test 0 reverse
+// CHECK: ThreadSanitizer: data race
+// CHECK: Test 1 reverse
+// CHECK: ThreadSanitizer: data race
+// CHECK: Test 2 reverse
+// CHECK: ThreadSanitizer: data race
+// CHECK: Test 3 reverse
+// CHECK: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/atomic_stack.cc b/lib/tsan/lit_tests/atomic_stack.cc
new file mode 100644
index 0000000000000..50f6a8a889ca8
--- /dev/null
+++ b/lib/tsan/lit_tests/atomic_stack.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ sleep(1);
+ __atomic_fetch_add(&Global, 1, __ATOMIC_RELAXED);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Global++;
+ return NULL;
+}
+
+int main() {
+ 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);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Atomic write of size 4
+// CHECK: #0 __tsan_atomic32_fetch_add
+// CHECK: #1 Thread1
diff --git a/lib/tsan/lit_tests/benign_race.cc b/lib/tsan/lit_tests/benign_race.cc
new file mode 100644
index 0000000000000..a4d4d23c362af
--- /dev/null
+++ b/lib/tsan/lit_tests/benign_race.cc
@@ -0,0 +1,39 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+int WTFGlobal;
+
+extern "C" {
+void AnnotateBenignRaceSized(const char *f, int l,
+ void *mem, unsigned int size, const char *desc);
+void WTFAnnotateBenignRaceSized(const char *f, int l,
+ void *mem, unsigned int size,
+ const char *desc);
+}
+
+
+void *Thread(void *x) {
+ Global = 42;
+ WTFGlobal = 142;
+ return 0;
+}
+
+int main() {
+ AnnotateBenignRaceSized(__FILE__, __LINE__,
+ &Global, sizeof(Global), "Race on Global");
+ WTFAnnotateBenignRaceSized(__FILE__, __LINE__,
+ &WTFGlobal, sizeof(WTFGlobal),
+ "Race on WTFGlobal");
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ sleep(1);
+ Global = 43;
+ WTFGlobal = 143;
+ pthread_join(t, 0);
+ printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/free_race.c b/lib/tsan/lit_tests/free_race.c
index 7a2ec0cdbed0c..ff71a4d2116b4 100644
--- a/lib/tsan/lit_tests/free_race.c
+++ b/lib/tsan/lit_tests/free_race.c
@@ -40,4 +40,5 @@ int main() {
// CHECK: #1 main
// CHECK: Previous write of size 8 at {{.*}} by thread T1{{.*}}:
// CHECK: #0 free
-// CHECK: #1 Thread1
+// CHECK: #{{(1|2)}} Thread1
+// CHECK: SUMMARY: ThreadSanitizer: heap-use-after-free{{.*}}Thread2
diff --git a/lib/tsan/lit_tests/free_race2.c b/lib/tsan/lit_tests/free_race2.c
index 095f82ea08188..f20774b2d8d4a 100644
--- a/lib/tsan/lit_tests/free_race2.c
+++ b/lib/tsan/lit_tests/free_race2.c
@@ -22,5 +22,5 @@ int main() {
// CHECK: #1 main
// CHECK: Previous write of size 8 at {{.*}} by main thread:
// CHECK: #0 free
-// CHECK: #1 foo
-// CHECK: #2 main
+// CHECK: #{{1|2}} foo
+// CHECK: #{{2|3}} main
diff --git a/lib/tsan/lit_tests/inlined_memcpy_race.cc b/lib/tsan/lit_tests/inlined_memcpy_race.cc
new file mode 100644
index 0000000000000..6efe5a956e9db
--- /dev/null
+++ b/lib/tsan/lit_tests/inlined_memcpy_race.cc
@@ -0,0 +1,55 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int x[4], y[4], z[4];
+
+void *MemCpyThread(void *a) {
+ memcpy((int*)a, z, 16);
+ return NULL;
+}
+
+void *MemMoveThread(void *a) {
+ memmove((int*)a, z, 16);
+ return NULL;
+}
+
+void *MemSetThread(void *a) {
+ sleep(1);
+ memset((int*)a, 0, 16);
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ // Race on x between memcpy and memset
+ pthread_create(&t[0], NULL, MemCpyThread, x);
+ pthread_create(&t[1], NULL, MemSetThread, x);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ // Race on y between memmove and memset
+ pthread_create(&t[0], NULL, MemMoveThread, y);
+ pthread_create(&t[1], NULL, MemSetThread, y);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+
+ printf("PASS\n");
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: #0 memset
+// CHECK: #1 MemSetThread
+// CHECK: Previous write
+// CHECK: #0 memcpy
+// CHECK: #1 MemCpyThread
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: #0 memset
+// CHECK: #1 MemSetThread
+// CHECK: Previous write
+// CHECK: #0 memmove
+// CHECK: #1 MemMoveThread
diff --git a/lib/tsan/lit_tests/java.h b/lib/tsan/lit_tests/java.h
index 7d61f58028645..04094197edb7d 100644
--- a/lib/tsan/lit_tests/java.h
+++ b/lib/tsan/lit_tests/java.h
@@ -14,4 +14,6 @@ void __tsan_java_mutex_lock(jptr addr);
void __tsan_java_mutex_unlock(jptr addr);
void __tsan_java_mutex_read_lock(jptr addr);
void __tsan_java_mutex_read_unlock(jptr addr);
+void __tsan_java_mutex_lock_rec(jptr addr, int rec);
+int __tsan_java_mutex_unlock_rec(jptr addr);
}
diff --git a/lib/tsan/lit_tests/java_lock.cc b/lib/tsan/lit_tests/java_lock.cc
index f66f1e7097fab..d9db103504de1 100644
--- a/lib/tsan/lit_tests/java_lock.cc
+++ b/lib/tsan/lit_tests/java_lock.cc
@@ -1,10 +1,12 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
#include "java.h"
+#include <unistd.h>
jptr varaddr;
jptr lockaddr;
void *Thread(void *p) {
+ sleep(1);
__tsan_java_mutex_lock(lockaddr);
*(int*)varaddr = 42;
__tsan_java_mutex_unlock(lockaddr);
diff --git a/lib/tsan/lit_tests/java_lock_rec.cc b/lib/tsan/lit_tests/java_lock_rec.cc
new file mode 100644
index 0000000000000..5cc80d4a33eff
--- /dev/null
+++ b/lib/tsan/lit_tests/java_lock_rec.cc
@@ -0,0 +1,54 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include "java.h"
+#include <unistd.h>
+
+jptr varaddr;
+jptr lockaddr;
+
+void *Thread(void *p) {
+ __tsan_java_mutex_lock(lockaddr);
+ __tsan_java_mutex_lock(lockaddr);
+ *(int*)varaddr = 42;
+ int rec = __tsan_java_mutex_unlock_rec(lockaddr);
+ if (rec != 2) {
+ printf("FAILED 0 rec=%d\n", rec);
+ exit(1);
+ }
+ sleep(2);
+ __tsan_java_mutex_lock_rec(lockaddr, rec);
+ if (*(int*)varaddr != 43) {
+ printf("FAILED 3 var=%d\n", *(int*)varaddr);
+ exit(1);
+ }
+ __tsan_java_mutex_unlock(lockaddr);
+ __tsan_java_mutex_unlock(lockaddr);
+ return 0;
+}
+
+int main() {
+ int const kHeapSize = 1024 * 1024;
+ void *jheap = malloc(kHeapSize);
+ __tsan_java_init((jptr)jheap, kHeapSize);
+ const int kBlockSize = 16;
+ __tsan_java_alloc((jptr)jheap, kBlockSize);
+ varaddr = (jptr)jheap;
+ *(int*)varaddr = 0;
+ lockaddr = (jptr)jheap + 8;
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ sleep(1);
+ __tsan_java_mutex_lock(lockaddr);
+ if (*(int*)varaddr != 42) {
+ printf("FAILED 1 var=%d\n", *(int*)varaddr);
+ exit(1);
+ }
+ *(int*)varaddr = 43;
+ __tsan_java_mutex_unlock(lockaddr);
+ pthread_join(th, 0);
+ __tsan_java_free((jptr)jheap, kBlockSize);
+ printf("OK\n");
+ return __tsan_java_fini();
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: FAILED
diff --git a/lib/tsan/lit_tests/java_lock_rec_race.cc b/lib/tsan/lit_tests/java_lock_rec_race.cc
new file mode 100644
index 0000000000000..61626aaddc0d3
--- /dev/null
+++ b/lib/tsan/lit_tests/java_lock_rec_race.cc
@@ -0,0 +1,48 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include "java.h"
+#include <unistd.h>
+
+jptr varaddr;
+jptr lockaddr;
+
+void *Thread(void *p) {
+ __tsan_java_mutex_lock(lockaddr);
+ __tsan_java_mutex_lock(lockaddr);
+ __tsan_java_mutex_lock(lockaddr);
+ int rec = __tsan_java_mutex_unlock_rec(lockaddr);
+ if (rec != 3) {
+ printf("FAILED 0 rec=%d\n", rec);
+ exit(1);
+ }
+ *(int*)varaddr = 42;
+ sleep(2);
+ __tsan_java_mutex_lock_rec(lockaddr, rec);
+ __tsan_java_mutex_unlock(lockaddr);
+ __tsan_java_mutex_unlock(lockaddr);
+ __tsan_java_mutex_unlock(lockaddr);
+ return 0;
+}
+
+int main() {
+ int const kHeapSize = 1024 * 1024;
+ void *jheap = malloc(kHeapSize);
+ __tsan_java_init((jptr)jheap, kHeapSize);
+ const int kBlockSize = 16;
+ __tsan_java_alloc((jptr)jheap, kBlockSize);
+ varaddr = (jptr)jheap;
+ *(int*)varaddr = 0;
+ lockaddr = (jptr)jheap + 8;
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ sleep(1);
+ __tsan_java_mutex_lock(lockaddr);
+ *(int*)varaddr = 43;
+ __tsan_java_mutex_unlock(lockaddr);
+ pthread_join(th, 0);
+ __tsan_java_free((jptr)jheap, kBlockSize);
+ printf("OK\n");
+ return __tsan_java_fini();
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: FAILED
diff --git a/lib/tsan/lit_tests/java_rwlock.cc b/lib/tsan/lit_tests/java_rwlock.cc
index 1e8940afd7d08..d1f38733ba035 100644
--- a/lib/tsan/lit_tests/java_rwlock.cc
+++ b/lib/tsan/lit_tests/java_rwlock.cc
@@ -1,10 +1,12 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
#include "java.h"
+#include <unistd.h>
jptr varaddr;
jptr lockaddr;
void *Thread(void *p) {
+ sleep(1);
__tsan_java_mutex_read_lock(lockaddr);
*(int*)varaddr = 42;
__tsan_java_mutex_read_unlock(lockaddr);
diff --git a/lib/tsan/lit_tests/lit.cfg b/lib/tsan/lit_tests/lit.cfg
index 7e2db7b8fd0b0..d483d2fcbdc60 100644
--- a/lib/tsan/lit_tests/lit.cfg
+++ b/lib/tsan/lit_tests/lit.cfg
@@ -2,6 +2,14 @@
import os
+def get_required_attr(config, attr_name):
+ attr_value = getattr(config, attr_name, None)
+ if not attr_value:
+ lit.fatal("No attribute %r in test configuration! You may need to run "
+ "tests from your build directory or add this attribute "
+ "to lit.site.cfg " % attr_name)
+ return attr_value
+
# Setup config name.
config.name = 'ThreadSanitizer'
@@ -30,14 +38,6 @@ if llvm_src_root is None:
if not llvm_config:
DisplayNoConfigMessage()
- # Validate that llvm-config points to the same source tree.
- llvm_src_root = lit.util.capture(["llvm-config", "--src-root"]).strip()
- tsan_test_src_root = os.path.join(llvm_src_root, "projects", "compiler-rt",
- "lib", "tsan", "lit_tests")
- if (os.path.realpath(tsan_test_src_root) !=
- os.path.realpath(config.test_source_root)):
- DisplayNoConfigMessage()
-
# Find out the presumed location of generated site config.
llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip()
tsan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
@@ -49,8 +49,9 @@ if llvm_src_root is None:
raise SystemExit
# Setup attributes common for all compiler-rt projects.
-compiler_rt_lit_cfg = os.path.join(llvm_src_root, "projects", "compiler-rt",
- "lib", "lit.common.cfg")
+compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root')
+compiler_rt_lit_cfg = os.path.join(compiler_rt_src_root, "lib",
+ "lit.common.cfg")
if (not compiler_rt_lit_cfg) or (not os.path.exists(compiler_rt_lit_cfg)):
lit.fatal("Can't find common compiler-rt lit config at: %r"
% compiler_rt_lit_cfg)
@@ -69,11 +70,8 @@ config.environment['TSAN_OPTIONS'] = tsan_options
# Setup default compiler flags used with -fsanitize=thread option.
# FIXME: Review the set of required flags and check if it can be reduced.
clang_tsan_cflags = ("-fsanitize=thread "
- + "-fPIE "
- + "-fno-builtin "
+ "-g "
+ "-Wall "
- + "-pie "
+ "-lpthread "
+ "-ldl ")
clang_tsan_cxxflags = "-ccc-cxx " + clang_tsan_cflags
diff --git a/lib/tsan/lit_tests/lit.site.cfg.in b/lib/tsan/lit_tests/lit.site.cfg.in
index b1c6ccf544ea5..07b521af061f7 100644
--- a/lib/tsan/lit_tests/lit.site.cfg.in
+++ b/lib/tsan/lit_tests/lit.site.cfg.in
@@ -4,6 +4,7 @@
config.clang = "@LLVM_BINARY_DIR@/bin/clang"
config.host_os = "@HOST_OS@"
config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
config.target_triple = "@TARGET_TRIPLE@"
diff --git a/lib/tsan/lit_tests/load_shared_lib.cc b/lib/tsan/lit_tests/load_shared_lib.cc
new file mode 100644
index 0000000000000..dd6fa0964f4af
--- /dev/null
+++ b/lib/tsan/lit_tests/load_shared_lib.cc
@@ -0,0 +1,44 @@
+// Check that if the list of shared libraries changes between the two race
+// reports, the second report occurring in a new shared library is still
+// symbolized correctly.
+
+// RUN: %clangxx_tsan -O1 %p/SharedLibs/load_shared_lib-so.cc \
+// RUN: -fPIC -shared -o %t-so.so
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#include <string>
+
+int GLOB = 0;
+
+void *write_glob(void *unused) {
+ GLOB++;
+ return NULL;
+}
+
+void race_two_threads(void *(*access_callback)(void *unused)) {
+ pthread_t t1, t2;
+ pthread_create(&t1, NULL, access_callback, NULL);
+ pthread_create(&t2, NULL, access_callback, NULL);
+ pthread_join(t1, NULL);
+ pthread_join(t2, NULL);
+}
+
+int main(int argc, char *argv[]) {
+ std::string path = std::string(argv[0]) + std::string("-so.so");
+ race_two_threads(write_glob);
+ // CHECK: write_glob
+ void *lib = dlopen(path.c_str(), RTLD_NOW);
+ if (!lib) {
+ printf("error in dlopen(): %s\n", dlerror());
+ return 1;
+ }
+ void *(*write_from_so)(void *unused);
+ *(void **)&write_from_so = dlsym(lib, "write_from_so");
+ race_two_threads(write_from_so);
+ // CHECK: write_from_so
+ return 0;
+}
diff --git a/lib/tsan/lit_tests/longjmp.cc b/lib/tsan/lit_tests/longjmp.cc
new file mode 100644
index 0000000000000..d9ca4ca5e6e9d
--- /dev/null
+++ b/lib/tsan/lit_tests/longjmp.cc
@@ -0,0 +1,22 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+int foo(jmp_buf env) {
+ longjmp(env, 42);
+}
+
+int main() {
+ jmp_buf env;
+ if (setjmp(env) == 42) {
+ printf("JUMPED\n");
+ return 0;
+ }
+ foo(env);
+ printf("FAILED\n");
+ return 0;
+}
+
+// CHECK-NOT: FAILED
+// CHECK: JUMPED
diff --git a/lib/tsan/lit_tests/longjmp2.cc b/lib/tsan/lit_tests/longjmp2.cc
new file mode 100644
index 0000000000000..0d551fa19d949
--- /dev/null
+++ b/lib/tsan/lit_tests/longjmp2.cc
@@ -0,0 +1,24 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+int foo(sigjmp_buf env) {
+ printf("env=%p\n", env);
+ siglongjmp(env, 42);
+}
+
+int main() {
+ sigjmp_buf env;
+ printf("env=%p\n", env);
+ if (sigsetjmp(env, 1) == 42) {
+ printf("JUMPED\n");
+ return 0;
+ }
+ foo(env);
+ printf("FAILED\n");
+ return 0;
+}
+
+// CHECK-NOT: FAILED
+// CHECK: JUMPED
diff --git a/lib/tsan/lit_tests/longjmp3.cc b/lib/tsan/lit_tests/longjmp3.cc
new file mode 100644
index 0000000000000..87fabd0b3be27
--- /dev/null
+++ b/lib/tsan/lit_tests/longjmp3.cc
@@ -0,0 +1,48 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+void bar(jmp_buf env) {
+ volatile int x = 42;
+ longjmp(env, 42);
+ x++;
+}
+
+void foo(jmp_buf env) {
+ volatile int x = 42;
+ bar(env);
+ x++;
+}
+
+void badguy() {
+ pthread_mutex_t mtx;
+ pthread_mutex_init(&mtx, 0);
+ pthread_mutex_lock(&mtx);
+ pthread_mutex_destroy(&mtx);
+}
+
+void mymain() {
+ jmp_buf env;
+ if (setjmp(env) == 42) {
+ badguy();
+ return;
+ }
+ foo(env);
+ printf("FAILED\n");
+}
+
+int main() {
+ volatile int x = 42;
+ mymain();
+ return x;
+}
+
+// CHECK-NOT: FAILED
+// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
+// CHECK: #0 pthread_mutex_destroy
+// CHECK: #1 badguy
+// CHECK: #2 mymain
+// CHECK: #3 main
+
diff --git a/lib/tsan/lit_tests/longjmp4.cc b/lib/tsan/lit_tests/longjmp4.cc
new file mode 100644
index 0000000000000..a8764dda5a6bd
--- /dev/null
+++ b/lib/tsan/lit_tests/longjmp4.cc
@@ -0,0 +1,51 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <string.h>
+
+void bar(jmp_buf env) {
+ volatile int x = 42;
+ jmp_buf env2;
+ memcpy(env2, env, sizeof(jmp_buf));
+ longjmp(env2, 42);
+ x++;
+}
+
+void foo(jmp_buf env) {
+ volatile int x = 42;
+ bar(env);
+ x++;
+}
+
+void badguy() {
+ pthread_mutex_t mtx;
+ pthread_mutex_init(&mtx, 0);
+ pthread_mutex_lock(&mtx);
+ pthread_mutex_destroy(&mtx);
+}
+
+void mymain() {
+ jmp_buf env;
+ if (setjmp(env) == 42) {
+ badguy();
+ return;
+ }
+ foo(env);
+ printf("FAILED\n");
+}
+
+int main() {
+ volatile int x = 42;
+ mymain();
+ return x;
+}
+
+// CHECK-NOT: FAILED
+// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
+// CHECK: #0 pthread_mutex_destroy
+// CHECK: #1 badguy
+// CHECK: #2 mymain
+// CHECK: #3 main
+
diff --git a/lib/tsan/lit_tests/malloc_overflow.cc b/lib/tsan/lit_tests/malloc_overflow.cc
new file mode 100644
index 0000000000000..19423c5f93f14
--- /dev/null
+++ b/lib/tsan/lit_tests/malloc_overflow.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+ void *p = malloc((size_t)-1);
+ if (p != 0)
+ printf("FAIL malloc(-1) = %p\n", p);
+ p = malloc((size_t)-1 / 2);
+ if (p != 0)
+ printf("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);
+ 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");
+}
+
+// CHECK-NOT: FAIL
+// CHECK-NOT: failed to allocate
diff --git a/lib/tsan/lit_tests/malloc_stack.cc b/lib/tsan/lit_tests/malloc_stack.cc
new file mode 100644
index 0000000000000..c185623ff5ca0
--- /dev/null
+++ b/lib/tsan/lit_tests/malloc_stack.cc
@@ -0,0 +1,25 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+_Atomic(int*) p;
+
+void *thr(void *a) {
+ sleep(1);
+ int *pp = __c11_atomic_load(&p, __ATOMIC_RELAXED);
+ *pp = 42;
+ return 0;
+}
+
+int main() {
+ pthread_t th;
+ pthread_create(&th, 0, thr, p);
+ __c11_atomic_store(&p, new int, __ATOMIC_RELAXED);
+ pthread_join(th, 0);
+}
+
+// CHECK: data race
+// CHECK: Previous write
+// CHECK: #0 operator new
+// CHECK: Location is heap block
+// CHECK: #0 operator new
diff --git a/lib/tsan/lit_tests/memcpy_race.cc b/lib/tsan/lit_tests/memcpy_race.cc
index 806740dda2418..857728ba05400 100644
--- a/lib/tsan/lit_tests/memcpy_race.cc
+++ b/lib/tsan/lit_tests/memcpy_race.cc
@@ -10,13 +10,15 @@ char *data1 = new char[10];
char *data2 = new char[10];
void *Thread1(void *x) {
- memcpy(data+5, data1, 1);
+ static volatile int size = 1;
+ memcpy(data+5, data1, size);
return NULL;
}
void *Thread2(void *x) {
+ static volatile int size = 4;
sleep(1);
- memcpy(data+3, data2, 4);
+ memcpy(data+3, data2, size);
return NULL;
}
diff --git a/lib/tsan/lit_tests/mutex_destroy_locked.cc b/lib/tsan/lit_tests/mutex_destroy_locked.cc
index 991eaf5426e22..27a04248b172b 100644
--- a/lib/tsan/lit_tests/mutex_destroy_locked.cc
+++ b/lib/tsan/lit_tests/mutex_destroy_locked.cc
@@ -19,3 +19,4 @@ int main() {
// CHECK: Mutex {{.*}} created at:
// CHECK: #0 pthread_mutex_init
// CHECK: #1 main
+// CHECK: SUMMARY: ThreadSanitizer: destroy of a locked mutex{{.*}}main
diff --git a/lib/tsan/lit_tests/mutexset7.cc b/lib/tsan/lit_tests/mutexset7.cc
index 141bde2b5015e..3ec1b52029836 100644
--- a/lib/tsan/lit_tests/mutexset7.cc
+++ b/lib/tsan/lit_tests/mutexset7.cc
@@ -4,6 +4,7 @@
#include <unistd.h>
int Global;
+__thread int huge[1024*1024];
void *Thread1(void *x) {
sleep(1);
diff --git a/lib/tsan/lit_tests/mutexset8.cc b/lib/tsan/lit_tests/mutexset8.cc
new file mode 100644
index 0000000000000..6db63f7d16dbd
--- /dev/null
+++ b/lib/tsan/lit_tests/mutexset8.cc
@@ -0,0 +1,39 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+pthread_mutex_t *mtx;
+
+void *Thread1(void *x) {
+ sleep(1);
+ pthread_mutex_lock(mtx);
+ Global++;
+ pthread_mutex_unlock(mtx);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Global--;
+ return NULL;
+}
+
+int main() {
+ // CHECK: WARNING: ThreadSanitizer: data race
+ // CHECK: Write of size 4 at {{.*}} by thread T1
+ // CHECK: (mutexes: write [[M1:M[0-9]+]]):
+ // CHECK: Previous write of size 4 at {{.*}} by thread T2:
+ // CHECK: Mutex [[M1]] created at:
+ // CHECK: #0 pthread_mutex_init
+ // CHECK: #1 main {{.*}}/mutexset8.cc
+ mtx = new pthread_mutex_t;
+ pthread_mutex_init(mtx, 0);
+ 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);
+ pthread_mutex_destroy(mtx);
+ delete mtx;
+}
diff --git a/lib/tsan/lit_tests/oob_race.cc b/lib/tsan/lit_tests/oob_race.cc
new file mode 100644
index 0000000000000..2e7f0593fd8d9
--- /dev/null
+++ b/lib/tsan/lit_tests/oob_race.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+const long kOffset = 64*1024;
+
+void *Thread(void *p) {
+ ((char*)p)[-kOffset] = 43;
+ return 0;
+}
+
+int main() {
+ char *volatile p0 = new char[16];
+ delete[] p0;
+ char *p = new char[32];
+ pthread_t th;
+ pthread_create(&th, 0, Thread, p);
+ p[-kOffset] = 42;
+ pthread_join(th, 0);
+}
+
+// Used to crash with CHECK failed.
+// CHECK: WARNING: ThreadSanitizer: data race
+
diff --git a/lib/tsan/lit_tests/race_on_heap.cc b/lib/tsan/lit_tests/race_on_heap.cc
index dc679e8bf3f96..35434eac18506 100644
--- a/lib/tsan/lit_tests/race_on_heap.cc
+++ b/lib/tsan/lit_tests/race_on_heap.cc
@@ -39,8 +39,8 @@ int main() {
// ...
// CHECK: Location is heap block of size 99 at [[ADDR]] allocated by thread T1:
// CHCEKL #0 malloc
-// CHECK: #1 alloc
-// CHECK: #2 AllocThread
+// CHECK: #{{1|2}} alloc
+// CHECK: #{{2|3}} AllocThread
// ...
// CHECK: Thread T1 (tid={{.*}}, finished) created by main thread at:
// CHECK: #0 pthread_create
diff --git a/lib/tsan/lit_tests/race_on_mutex.c b/lib/tsan/lit_tests/race_on_mutex.c
index de1c2d4160a60..aff32f9bb1a2d 100644
--- a/lib/tsan/lit_tests/race_on_mutex.c
+++ b/lib/tsan/lit_tests/race_on_mutex.c
@@ -34,7 +34,7 @@ int main() {
}
// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NEXT: Read of size 1 at {{.*}} by thread T2:
+// 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:20{{(:3)?}} ({{.*}})
// CHECK: Previous write of size 1 at {{.*}} by thread T1:
diff --git a/lib/tsan/lit_tests/race_on_mutex2.c b/lib/tsan/lit_tests/race_on_mutex2.c
new file mode 100644
index 0000000000000..84bef75a34499
--- /dev/null
+++ b/lib/tsan/lit_tests/race_on_mutex2.c
@@ -0,0 +1,24 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+void *Thread(void *x) {
+ pthread_mutex_lock((pthread_mutex_t*)x);
+ pthread_mutex_unlock((pthread_mutex_t*)x);
+ return 0;
+}
+
+int main() {
+ pthread_mutex_t Mtx;
+ pthread_mutex_init(&Mtx, 0);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, &Mtx);
+ sleep(1);
+ pthread_mutex_destroy(&Mtx);
+ pthread_join(t, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/race_on_write.cc b/lib/tsan/lit_tests/race_on_write.cc
new file mode 100644
index 0000000000000..f1b0bb1cbd6ee
--- /dev/null
+++ b/lib/tsan/lit_tests/race_on_write.cc
@@ -0,0 +1,39 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int fd;
+char buf;
+
+void *Thread1(void *x) {
+ buf = 1;
+ sleep(1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ write(fd, &buf, 1);
+ return NULL;
+}
+
+int main() {
+ fd = open("/dev/null", O_WRONLY);
+ if (fd < 0) return 1;
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ sleep(1);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ close(fd);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Read of size 1
+// CHECK: #0 write
+// CHECK: Previous write of size 1
+// CHECK: #0 Thread1
diff --git a/lib/tsan/lit_tests/signal_errno.cc b/lib/tsan/lit_tests/signal_errno.cc
index af9ccce9045a7..8181555f6f639 100644
--- a/lib/tsan/lit_tests/signal_errno.cc
+++ b/lib/tsan/lit_tests/signal_errno.cc
@@ -10,7 +10,7 @@
pthread_t mainth;
volatile int done;
-static void handler(int, siginfo_t *s, void *c) {
+static void MyHandler(int, siginfo_t *s, void *c) {
errno = 1;
done = 1;
}
@@ -23,7 +23,7 @@ static void* sendsignal(void *p) {
int main() {
mainth = pthread_self();
struct sigaction act = {};
- act.sa_sigaction = &handler;
+ act.sa_sigaction = &MyHandler;
sigaction(SIGPROF, &act, 0);
pthread_t th;
pthread_create(&th, 0, sendsignal, 0);
@@ -38,5 +38,6 @@ int main() {
}
// CHECK: WARNING: ThreadSanitizer: signal handler spoils errno
-// CHECK: #0 handler(int, siginfo*, void*) {{.*}}signal_errno.cc
+// CHECK: #0 MyHandler(int, siginfo{{(_t)?}}*, void*) {{.*}}signal_errno.cc
+// CHECK: SUMMARY: ThreadSanitizer: signal handler spoils errno{{.*}}MyHandler
diff --git a/lib/tsan/lit_tests/signal_malloc.cc b/lib/tsan/lit_tests/signal_malloc.cc
index cee997cdb7635..4dbc2f78ab17a 100644
--- a/lib/tsan/lit_tests/signal_malloc.cc
+++ b/lib/tsan/lit_tests/signal_malloc.cc
@@ -8,7 +8,8 @@
static void handler(int, siginfo_t*, void*) {
// CHECK: WARNING: ThreadSanitizer: signal-unsafe call inside of a signal
// CHECK: #0 malloc
- // CHECK: #1 handler(int, siginfo*, void*) {{.*}}signal_malloc.cc:[[@LINE+1]]
+ // CHECK: #{{(1|2)}} handler(int, siginfo{{(_t)?}}*, void*) {{.*}}signal_malloc.cc:[[@LINE+2]]
+ // CHECK: SUMMARY: ThreadSanitizer: signal-unsafe call inside of a signal{{.*}}handler
volatile char *p = (char*)malloc(1);
p[0] = 0;
free((void*)p);
diff --git a/lib/tsan/lit_tests/simple_race.cc b/lib/tsan/lit_tests/simple_race.cc
index ec29c92ee1a83..99cf228ac2f2b 100644
--- a/lib/tsan/lit_tests/simple_race.cc
+++ b/lib/tsan/lit_tests/simple_race.cc
@@ -23,3 +23,4 @@ int main() {
}
// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: SUMMARY: ThreadSanitizer: data race{{.*}}Thread
diff --git a/lib/tsan/lit_tests/test_output.sh b/lib/tsan/lit_tests/test_output.sh
index d21c9a797ad3f..1eedf6eb20a32 100755
--- a/lib/tsan/lit_tests/test_output.sh
+++ b/lib/tsan/lit_tests/test_output.sh
@@ -6,12 +6,13 @@ set -e # fail on any error
ROOTDIR=$(dirname $0)/..
BLACKLIST=$ROOTDIR/lit_tests/Helpers/blacklist.txt
-# Assuming clang is in path.
-CC=clang
-CXX=clang++
+# Assume clang and clang++ are in path.
+: ${CC:=clang}
+: ${CXX:=clang++}
+: ${FILECHECK:=FileCheck}
# TODO: add testing for all of -O0...-O3
-CFLAGS="-fsanitize=thread -fsanitize-blacklist=$BLACKLIST -fPIE -O1 -g -fno-builtin -Wall"
+CFLAGS="-fsanitize=thread -fsanitize-blacklist=$BLACKLIST -fPIE -O1 -g -Wall"
LDFLAGS="-pie -lpthread -ldl $ROOTDIR/rtl/libtsan.a"
test_file() {
@@ -23,7 +24,7 @@ test_file() {
$COMPILER $SRC $CFLAGS -c -o $OBJ
$COMPILER $OBJ $LDFLAGS -o $EXE
RES=$($EXE 2>&1 || true)
- printf "%s\n" "$RES" | FileCheck $SRC
+ printf "%s\n" "$RES" | $FILECHECK $SRC
if [ "$3" == "" ]; then
rm -f $EXE $OBJ
fi
@@ -35,6 +36,10 @@ if [ "$1" == "" ]; then
echo SKIPPING FAILING TEST $c
continue
fi
+ if [[ $c == */load_shared_lib.cc ]]; then
+ echo TEST $c is not supported
+ continue
+ fi
COMPILER=$CXX
case $c in
*.c) COMPILER=$CC
diff --git a/lib/tsan/lit_tests/thread_end_with_ignore.cc b/lib/tsan/lit_tests/thread_end_with_ignore.cc
new file mode 100644
index 0000000000000..960a477c5ad33
--- /dev/null
+++ b/lib/tsan/lit_tests/thread_end_with_ignore.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+extern "C" void AnnotateIgnoreReadsBegin(const char *f, int l);
+
+void *Thread(void *x) {
+ AnnotateIgnoreReadsBegin("", 0);
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_join(t, 0);
+}
+
+// CHECK: ThreadSanitizer: thread T1 finished with ignores enabled
+
diff --git a/lib/tsan/lit_tests/thread_end_with_ignore2.cc b/lib/tsan/lit_tests/thread_end_with_ignore2.cc
new file mode 100644
index 0000000000000..8f743ae2f4a4a
--- /dev/null
+++ b/lib/tsan/lit_tests/thread_end_with_ignore2.cc
@@ -0,0 +1,9 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+extern "C" void AnnotateIgnoreWritesBegin(const char *f, int l);
+
+int main() {
+ AnnotateIgnoreWritesBegin("", 0);
+}
+
+// CHECK: ThreadSanitizer: thread T0 finished with ignores enabled
+
diff --git a/lib/tsan/lit_tests/thread_leak3.c b/lib/tsan/lit_tests/thread_leak3.c
index c48219fe73fae..3577164cad4a7 100644
--- a/lib/tsan/lit_tests/thread_leak3.c
+++ b/lib/tsan/lit_tests/thread_leak3.c
@@ -1,5 +1,6 @@
// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
#include <pthread.h>
+#include <unistd.h>
void *Thread(void *x) {
return 0;
@@ -8,7 +9,9 @@ void *Thread(void *x) {
int main() {
pthread_t t;
pthread_create(&t, 0, Thread, 0);
+ sleep(1);
return 0;
}
// CHECK: WARNING: ThreadSanitizer: thread leak
+// CHECK: SUMMARY: ThreadSanitizer: thread leak{{.*}}main
diff --git a/lib/tsan/lit_tests/thread_leak4.c b/lib/tsan/lit_tests/thread_leak4.c
new file mode 100644
index 0000000000000..f9fad0360d34b
--- /dev/null
+++ b/lib/tsan/lit_tests/thread_leak4.c
@@ -0,0 +1,18 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+
+void *Thread(void *x) {
+ sleep(10);
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ printf("OK\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
diff --git a/lib/tsan/lit_tests/thread_leak5.c b/lib/tsan/lit_tests/thread_leak5.c
new file mode 100644
index 0000000000000..fc72b149ec250
--- /dev/null
+++ b/lib/tsan/lit_tests/thread_leak5.c
@@ -0,0 +1,19 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *x) {
+ return 0;
+}
+
+int main() {
+ for (int i = 0; i < 5; i++) {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ }
+ sleep(1);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: thread leak
+// CHECK: And 4 more similar thread leaks
diff --git a/lib/tsan/lit_tests/thread_name.cc b/lib/tsan/lit_tests/thread_name.cc
index 0ca0b17699765..37f308ffbc0cf 100644
--- a/lib/tsan/lit_tests/thread_name.cc
+++ b/lib/tsan/lit_tests/thread_name.cc
@@ -15,7 +15,11 @@ void *Thread1(void *x) {
}
void *Thread2(void *x) {
+#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 12)
pthread_setname_np(pthread_self(), "Thread2");
+#else
+ AnnotateThreadName(__FILE__, __LINE__, "Thread2");
+#endif
Global--;
return NULL;
}
diff --git a/lib/tsan/lit_tests/tsan-vs-gvn.cc b/lib/tsan/lit_tests/tsan-vs-gvn.cc
new file mode 100644
index 0000000000000..40ae724b78e12
--- /dev/null
+++ b/lib/tsan/lit_tests/tsan-vs-gvn.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O2 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O3 %s -o %t && %t 2>&1 | FileCheck %s
+//
+// Check that load widening is not tsan-hostile.
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+struct {
+ int i;
+ char c1, c2, c3, c4;
+} S;
+
+int G;
+
+void *Thread1(void *x) {
+ G = S.c1 + S.c3;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ S.c2 = 1;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ memset(&S, 123, sizeof(S));
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("PASS\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: PASS
diff --git a/lib/tsan/lit_tests/unaligned_norace.cc b/lib/tsan/lit_tests/unaligned_norace.cc
new file mode 100644
index 0000000000000..792224b80126b
--- /dev/null
+++ b/lib/tsan/lit_tests/unaligned_norace.cc
@@ -0,0 +1,84 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+uint64_t objs[8*3*3*2][3];
+
+extern "C" {
+uint16_t __tsan_unaligned_read2(void *addr);
+uint32_t __tsan_unaligned_read4(void *addr);
+uint64_t __tsan_unaligned_read8(void *addr);
+void __tsan_unaligned_write2(void *addr, uint16_t v);
+void __tsan_unaligned_write4(void *addr, uint32_t v);
+void __tsan_unaligned_write8(void *addr, uint64_t v);
+}
+
+static void access(char *p, int sz, int rw) {
+ if (rw) {
+ switch (sz) {
+ case 0: __tsan_unaligned_write2(p, 0); break;
+ case 1: __tsan_unaligned_write4(p, 0); break;
+ case 2: __tsan_unaligned_write8(p, 0); break;
+ default: exit(1);
+ }
+ } else {
+ switch (sz) {
+ case 0: __tsan_unaligned_read2(p); break;
+ case 1: __tsan_unaligned_read4(p); break;
+ case 2: __tsan_unaligned_read8(p); break;
+ default: exit(1);
+ }
+ }
+}
+
+static int accesssize(int sz) {
+ switch (sz) {
+ case 0: return 2;
+ case 1: return 4;
+ case 2: return 8;
+ }
+ exit(1);
+}
+
+void Test(bool main) {
+ uint64_t *obj = objs[0];
+ for (int off = 0; off < 8; off++) {
+ for (int sz1 = 0; sz1 < 3; sz1++) {
+ for (int sz2 = 0; sz2 < 3; sz2++) {
+ for (int rw = 0; rw < 2; rw++) {
+ char *p = (char*)obj + off;
+ if (main) {
+ // printf("thr=%d off=%d sz1=%d sz2=%d rw=%d p=%p\n",
+ // main, off, sz1, sz2, rw, p);
+ access(p, sz1, true);
+ } else {
+ p += accesssize(sz1);
+ // printf("thr=%d off=%d sz1=%d sz2=%d rw=%d p=%p\n",
+ // main, off, sz1, sz2, rw, p);
+ access(p, sz2, rw);
+ }
+ obj += 3;
+ }
+ }
+ }
+ }
+}
+
+void *Thread(void *p) {
+ (void)p;
+ Test(false);
+ return 0;
+}
+
+int main() {
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ Test(true);
+ pthread_join(th, 0);
+ printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: OK
diff --git a/lib/tsan/lit_tests/unaligned_race.cc b/lib/tsan/lit_tests/unaligned_race.cc
new file mode 100644
index 0000000000000..18bed8555cc5e
--- /dev/null
+++ b/lib/tsan/lit_tests/unaligned_race.cc
@@ -0,0 +1,135 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+uint64_t objs[8*2*(2 + 4 + 8)][2];
+
+extern "C" {
+uint16_t __sanitizer_unaligned_load16(void *addr);
+uint32_t __sanitizer_unaligned_load32(void *addr);
+uint64_t __sanitizer_unaligned_load64(void *addr);
+void __sanitizer_unaligned_store16(void *addr, uint16_t v);
+void __sanitizer_unaligned_store32(void *addr, uint32_t v);
+void __sanitizer_unaligned_store64(void *addr, uint64_t v);
+}
+
+// All this mess is to generate unique stack for each race,
+// otherwise tsan will suppress similar stacks.
+
+static void access(char *p, int sz, int rw) {
+ if (rw) {
+ switch (sz) {
+ case 0: __sanitizer_unaligned_store16(p, 0); break;
+ case 1: __sanitizer_unaligned_store32(p, 0); break;
+ case 2: __sanitizer_unaligned_store64(p, 0); break;
+ default: exit(1);
+ }
+ } else {
+ switch (sz) {
+ case 0: __sanitizer_unaligned_load16(p); break;
+ case 1: __sanitizer_unaligned_load32(p); break;
+ case 2: __sanitizer_unaligned_load64(p); break;
+ default: exit(1);
+ }
+ }
+}
+
+static int accesssize(int sz) {
+ switch (sz) {
+ case 0: return 2;
+ case 1: return 4;
+ case 2: return 8;
+ }
+ exit(1);
+}
+
+template<int off, int off2>
+static void access3(bool main, int sz1, bool rw, char *p) {
+ p += off;
+ if (main) {
+ access(p, sz1, true);
+ } else {
+ p += off2;
+ if (rw) {
+ *p = 42;
+ } else {
+ if (*p == 42)
+ printf("bingo!\n");
+ }
+ }
+}
+
+template<int off>
+static void access2(bool main, int sz1, int off2, bool rw, char *obj) {
+ if (off2 == 0)
+ access3<off, 0>(main, sz1, rw, obj);
+ else if (off2 == 1)
+ access3<off, 1>(main, sz1, rw, obj);
+ else if (off2 == 2)
+ access3<off, 2>(main, sz1, rw, obj);
+ else if (off2 == 3)
+ access3<off, 3>(main, sz1, rw, obj);
+ else if (off2 == 4)
+ access3<off, 4>(main, sz1, rw, obj);
+ else if (off2 == 5)
+ access3<off, 5>(main, sz1, rw, obj);
+ else if (off2 == 6)
+ access3<off, 6>(main, sz1, rw, obj);
+ else if (off2 == 7)
+ access3<off, 7>(main, sz1, rw, obj);
+}
+
+static void access1(bool main, int off, int sz1, int off2, bool rw, char *obj) {
+ if (off == 0)
+ access2<0>(main, sz1, off2, rw, obj);
+ else if (off == 1)
+ access2<1>(main, sz1, off2, rw, obj);
+ else if (off == 2)
+ access2<2>(main, sz1, off2, rw, obj);
+ else if (off == 3)
+ access2<3>(main, sz1, off2, rw, obj);
+ else if (off == 4)
+ access2<4>(main, sz1, off2, rw, obj);
+ else if (off == 5)
+ access2<5>(main, sz1, off2, rw, obj);
+ else if (off == 6)
+ access2<6>(main, sz1, off2, rw, obj);
+ else if (off == 7)
+ access2<7>(main, sz1, off2, rw, obj);
+}
+
+void Test(bool main) {
+ uint64_t *obj = objs[0];
+ for (int off = 0; off < 8; off++) {
+ for (int sz1 = 0; sz1 < 3; sz1++) {
+ for (int off2 = 0; off2 < accesssize(sz1); off2++) {
+ for (int rw = 0; rw < 2; rw++) {
+ // printf("thr=%d off=%d sz1=%d off2=%d rw=%d p=%p\n",
+ // main, off, sz1, off2, rw, obj);
+ access1(main, off, sz1, off2, rw, (char*)obj);
+ obj += 2;
+ }
+ }
+ }
+ }
+}
+
+void *Thread(void *p) {
+ (void)p;
+ sleep(1);
+ Test(false);
+ return 0;
+}
+
+int main() {
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ Test(true);
+ pthread_join(th, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: ThreadSanitizer: reported 224 warnings
diff --git a/lib/tsan/lit_tests/vptr_harmful_race.cc b/lib/tsan/lit_tests/vptr_harmful_race.cc
index f51ba7ee57f0b..76d31c00ad4f8 100644
--- a/lib/tsan/lit_tests/vptr_harmful_race.cc
+++ b/lib/tsan/lit_tests/vptr_harmful_race.cc
@@ -2,6 +2,7 @@
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
+#include <unistd.h>
struct A {
A() {
@@ -34,6 +35,7 @@ void *Thread1(void *x) {
}
void *Thread2(void *x) {
+ sleep(1);
delete obj;
return NULL;
}
@@ -46,4 +48,4 @@ int main() {
pthread_join(t[1], NULL);
}
-// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: WARNING: ThreadSanitizer: data race on vptr
diff --git a/lib/tsan/lit_tests/vptr_harmful_race2.cc b/lib/tsan/lit_tests/vptr_harmful_race2.cc
new file mode 100644
index 0000000000000..d7e1d19a11bd3
--- /dev/null
+++ b/lib/tsan/lit_tests/vptr_harmful_race2.cc
@@ -0,0 +1,51 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <unistd.h>
+
+struct A {
+ A() {
+ sem_init(&sem_, 0, 0);
+ }
+ virtual void F() {
+ }
+ void Done() {
+ sem_post(&sem_);
+ }
+ virtual ~A() {
+ sem_wait(&sem_);
+ sem_destroy(&sem_);
+ }
+ sem_t sem_;
+};
+
+struct B : A {
+ virtual void F() {
+ }
+ virtual ~B() { }
+};
+
+static A *obj = new B;
+
+void *Thread1(void *x) {
+ sleep(1);
+ obj->F();
+ obj->Done();
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ delete obj;
+ return NULL;
+}
+
+int main() {
+ 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);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race on vptr