run: all
(ulimit -s 8192; ./tsan_test)
- ./output_tests/test_output.sh
+ ./lit_tests/test_output.sh
presubmit:
# Debug build with clang.
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ )
+
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
)
-# Run TSan unit tests.
-if(LLVM_INCLUDE_TESTS)
+if("${CMAKE_HOST_SYSTEM}" STREQUAL "${CMAKE_SYSTEM}")
+ # Run TSan output tests only if we're not cross-compiling,
+ # and can be sure that clang would produce working binaries.
+ set(TSAN_TEST_DEPS
+ clang clang-headers FileCheck count not
+ ${TSAN_RUNTIME_LIBRARIES}
+ )
+ set(TSAN_TEST_PARAMS
+ tsan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ )
+ if(LLVM_INCLUDE_TESTS)
+ list(APPEND ASAN_TEST_DEPS TsanUnitTests)
+ endif()
+ add_lit_testsuite(check-tsan "Running ThreadSanitizer tests"
+ ${CMAKE_CURRENT_BINARY_DIR}
+ PARAMS ${TSAN_TEST_PARAMS}
+ DEPENDS ${TSAN_TEST_DEPS}
+ )
+ set_target_properties(check-tsan PROPERTIES FOLDER "TSan unittests")
+elseif(LLVM_INCLUDE_TESTS)
+ # Otherwise run only TSan unit tests.
add_lit_testsuite(check-tsan "Running ThreadSanitizer tests"
${CMAKE_CURRENT_BINARY_DIR}/Unit
DEPENDS TsanUnitTests)
--- /dev/null
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+int *mem;
+pthread_mutex_t mtx;
+
+void *Thread1(void *x) {
+ pthread_mutex_lock(&mtx);
+ free(mem);
+ pthread_mutex_unlock(&mtx);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ usleep(1000000);
+ pthread_mutex_lock(&mtx);
+ mem[0] = 42;
+ pthread_mutex_unlock(&mtx);
+ return NULL;
+}
+
+int main() {
+ mem = (int*)malloc(100);
+ pthread_mutex_init(&mtx, 0);
+ pthread_t t;
+ pthread_create(&t, NULL, Thread1, NULL);
+ Thread2(0);
+ pthread_join(t, NULL);
+ pthread_mutex_destroy(&mtx);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
+// CHECK: Write of size 4 at {{.*}} by main thread:
+// CHECK: #0 Thread2
+// CHECK: #1 main
+// CHECK: Previous write of size 8 at {{.*}} by thread 1:
+// CHECK: #0 free
+// CHECK: #1 Thread1
--- /dev/null
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+
+void __attribute__((noinline)) foo(int *mem) {
+ free(mem);
+}
+
+void __attribute__((noinline)) bar(int *mem) {
+ mem[0] = 42;
+}
+
+int main() {
+ int *mem = (int*)malloc(100);
+ foo(mem);
+ bar(mem);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
+// CHECK: Write of size 4 at {{.*}} by main thread:
+// CHECK: #0 bar
+// CHECK: #1 main
+// CHECK: Previous write of size 8 at {{.*}} by main thread:
+// CHECK: #0 free
+// CHECK: #1 foo
+// CHECK: #2 main
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+
+void *Thread(void *a) {
+ ((int*)a)[0]++;
+ return NULL;
+}
+
+int main() {
+ int *p = new int(42);
+ pthread_t t;
+ pthread_create(&t, NULL, Thread, p);
+ p[0]++;
+ pthread_join(t, NULL);
+ delete p;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
--- /dev/null
+# -*- Python -*-
+
+import os
+
+# Setup config name.
+config.name = 'ThreadSanitizer'
+
+# Setup source root.
+config.test_source_root = os.path.dirname(__file__)
+
+def DisplayNoConfigMessage():
+ lit.fatal("No site specific configuration available! " +
+ "Try running your test from the build tree or running " +
+ "make check-tsan")
+
+# Figure out LLVM source root.
+llvm_src_root = getattr(config, 'llvm_src_root', None)
+if llvm_src_root is None:
+ # We probably haven't loaded the site-specific configuration: the user
+ # is likely trying to run a test file directly, and the site configuration
+ # wasn't created by the build system.
+ tsan_site_cfg = lit.params.get('tsan_site_config', None)
+ if (tsan_site_cfg) and (os.path.exists(tsan_site_cfg)):
+ lit.load_config(config, tsan_site_cfg)
+ raise SystemExit
+
+ # Try to guess the location of site-specific configuration using llvm-config
+ # util that can point where the build tree is.
+ llvm_config = lit.util.which("llvm-config", config.environment["PATH"])
+ 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",
+ "lib", "tsan", "lit_tests", "lit.site.cfg")
+ if (not tsan_site_cfg) or (not os.path.exists(tsan_site_cfg)):
+ DisplayNoConfigMessage()
+
+ lit.load_config(config, tsan_site_cfg)
+ 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")
+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)
+lit.load_config(config, compiler_rt_lit_cfg)
+
+# Setup environment variables for running ThreadSanitizer.
+config.environment['TSAN_OPTIONS'] = "atexit_sleep_ms=0"
+
+# Setup default compiler flags used with -faddress-sanitizer option.
+# FIXME: Review the set of required flags and check if it can be reduced.
+clang_tsan_cflags = ("-fthread-sanitizer "
+ + "-fPIE "
+ + "-fno-builtin "
+ + "-g "
+ + "-Wall "
+ + "-pie "
+ + "-lpthread "
+ + "-ldl ")
+clang_tsan_cxxflags = "-ccc-clang-cxx -ccc-cxx " + clang_tsan_cflags
+config.substitutions.append( ("%clangxx_tsan ", (" " + config.clang + " " +
+ clang_tsan_cxxflags + " ")) )
+config.substitutions.append( ("%clang_tsan ", (" " + config.clang + " " +
+ clang_tsan_cflags + " ")) )
+
+# Define CHECK-%os to check for OS-dependent output.
+config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os)))
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp']
+
+# ThreadSanitizer tests are currently supported on Linux only.
+if config.host_os not in ['Linux']:
+ config.unsupported = True
--- /dev/null
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+config.clang = "@LLVM_BINARY_DIR@/bin/clang"
+config.host_os = "@HOST_OS@"
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.target_triple = "@TARGET_TRIPLE@"
+
+# 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
+except KeyError,e:
+ key, = e.args
+ lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
+
+# Let the main config do the real work.
+lit.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
--- /dev/null
+// 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>
+
+char *data = new char[10];
+char *data1 = new char[10];
+char *data2 = new char[10];
+
+void *Thread1(void *x) {
+ memcpy(data+5, data1, 1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ usleep(500*1000);
+ memcpy(data+3, data2, 4);
+ return NULL;
+}
+
+int main() {
+ fprintf(stderr, "addr=%p\n", &data[5]);
+ 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);
+ return 0;
+}
+
+// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 1 at [[ADDR]] by thread 2:
+// CHECK: #0 memcpy
+// CHECK: #1 Thread2
+// CHECK: Previous write of size 1 at [[ADDR]] by thread 1:
+// CHECK: #0 memcpy
+// CHECK: #1 Thread1
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void *Thread1(void *x) {
+ int *p = (int*)x;
+ p[0] = 1;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ usleep(500*1000);
+ char *p = (char*)x;
+ p[2] = 1;
+ return NULL;
+}
+
+int main() {
+ int *data = new int(42);
+ fprintf(stderr, "ptr1=%p\n", data);
+ fprintf(stderr, "ptr2=%p\n", (char*)data + 2);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, data);
+ pthread_create(&t[1], NULL, Thread2, data);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ delete data;
+}
+
+// CHECK: ptr1=[[PTR1:0x[0-9,a-f]+]]
+// CHECK: ptr2=[[PTR2:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 1 at [[PTR2]] by thread 2:
+// CHECK: Previous write of size 4 at [[PTR1]] by thread 1:
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void *Thread1(void *x) {
+ usleep(500*1000);
+ int *p = (int*)x;
+ p[0] = 1;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ char *p = (char*)x;
+ p[2] = 1;
+ return NULL;
+}
+
+int main() {
+ int *data = new int(42);
+ fprintf(stderr, "ptr1=%p\n", data);
+ fprintf(stderr, "ptr2=%p\n", (char*)data + 2);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, data);
+ pthread_create(&t[1], NULL, Thread2, data);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ delete data;
+}
+
+// CHECK: ptr1=[[PTR1:0x[0-9,a-f]+]]
+// CHECK: ptr2=[[PTR2:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 4 at [[PTR1]] by thread 1:
+// CHECK: Previous write of size 1 at [[PTR2]] by thread 2:
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *p) {
+ pthread_mutex_lock((pthread_mutex_t*)p);
+ return 0;
+}
+
+int main() {
+ pthread_mutex_t m;
+ pthread_mutex_init(&m, 0);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, &m);
+ usleep(1000*1000);
+ pthread_mutex_destroy(&m);
+ pthread_join(t, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
+// CHECK: #0 pthread_mutex_destroy
+// CHECK: #1 main
+// CHECK: and:
+// CHECK: #0 pthread_mutex_lock
+// CHECK: #1 Thread
+// CHECK: Mutex {{.*}} created at:
+// CHECK: #0 pthread_mutex_init
+// CHECK: #1 main
--- /dev/null
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+pthread_barrier_t B;
+int Global;
+
+void *Thread1(void *x) {
+ pthread_barrier_init(&B, 0, 2);
+ pthread_barrier_wait(&B);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ usleep(1000000);
+ pthread_barrier_wait(&B);
+ return NULL;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, NULL, Thread1, NULL);
+ Thread2(0);
+ pthread_join(t, NULL);
+ pthread_barrier_destroy(&B);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
--- /dev/null
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+pthread_barrier_t B;
+int Global;
+
+void *Thread1(void *x) {
+ if (pthread_barrier_wait(&B) == PTHREAD_BARRIER_SERIAL_THREAD)
+ pthread_barrier_destroy(&B);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ if (pthread_barrier_wait(&B) == PTHREAD_BARRIER_SERIAL_THREAD)
+ pthread_barrier_destroy(&B);
+ return NULL;
+}
+
+int main() {
+ pthread_barrier_init(&B, 0, 2);
+ pthread_t t;
+ pthread_create(&t, NULL, Thread1, NULL);
+ Thread2(0);
+ pthread_join(t, NULL);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+void *Thread1(void *p) {
+ *(int*)p = 42;
+ return 0;
+}
+
+void *Thread2(void *p) {
+ *(int*)p = 44;
+ return 0;
+}
+
+void *alloc() {
+ return malloc(99);
+}
+
+void *AllocThread(void* arg) {
+ return alloc();
+}
+
+int main() {
+ void *p = 0;
+ pthread_t t[2];
+ pthread_create(&t[0], 0, AllocThread, 0);
+ pthread_join(t[0], &p);
+ fprintf(stderr, "addr=%p\n", p);
+ pthread_create(&t[0], 0, Thread1, (char*)p + 16);
+ pthread_create(&t[1], 0, Thread2, (char*)p + 16);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+ return 0;
+}
+
+// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// ...
+// CHECK: Location is heap block of size 99 at [[ADDR]] allocated by thread 1:
+// CHCEKL #0 malloc
+// CHECK: #1 alloc
+// CHECK: #2 AllocThread
+// ...
+// CHECK: Thread 1 (finished) created at:
+// CHECK: #0 pthread_create
+// CHECK: #1 main
--- /dev/null
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+pthread_mutex_t Mtx;
+int Global;
+
+void *Thread1(void *x) {
+ pthread_mutex_init(&Mtx, 0);
+ pthread_mutex_lock(&Mtx);
+ Global = 42;
+ pthread_mutex_unlock(&Mtx);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ usleep(1000000);
+ pthread_mutex_lock(&Mtx);
+ Global = 43;
+ pthread_mutex_unlock(&Mtx);
+ 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);
+ pthread_mutex_destroy(&Mtx);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT: Read of size 1 at {{.*}} by thread 2:
+// 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 1:
+// CHECK-NEXT: #0 pthread_mutex_init {{.*}} ({{.*}})
+// CHECK-NEXT: #1 Thread1{{.*}} {{.*}}race_on_mutex.c:11{{(:3)?}} ({{.*}})
--- /dev/null
+// 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>
+
+// Ensure that we can restore a stack of a finished thread.
+
+int g_data;
+
+void __attribute__((noinline)) foobar(int *p) {
+ *p = 42;
+}
+
+void *Thread1(void *x) {
+ foobar(&g_data);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ usleep(1000*1000);
+ g_data = 43;
+ 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);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 4 at {{.*}} by thread 2:
+// CHECK: Previous write of size 4 at {{.*}} by thread 1:
+// CHECK: #0 foobar
+// CHECK: #1 Thread1
+// CHECK: Thread 1 (finished) created at:
+// CHECK: #0 pthread_create
+// CHECK: #1 main
--- /dev/null
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ Global = 42;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Global = 43;
+ 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);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ Global++;
+ 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
--- /dev/null
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void __attribute__((noinline)) foo1() {
+ Global = 42;
+}
+
+void __attribute__((noinline)) bar1() {
+ volatile int tmp = 42; (void)tmp;
+ foo1();
+}
+
+void __attribute__((noinline)) foo2() {
+ volatile int v = Global; (void)v;
+}
+
+void __attribute__((noinline)) bar2() {
+ volatile int tmp = 42; (void)tmp;
+ foo2();
+}
+
+void *Thread1(void *x) {
+ usleep(1000000);
+ bar1();
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ bar2();
+ return NULL;
+}
+
+void StartThread(pthread_t *t, void *(*f)(void*)) {
+ pthread_create(t, NULL, f, NULL);
+}
+
+int main() {
+ pthread_t t[2];
+ StartThread(&t[0], Thread1);
+ StartThread(&t[1], Thread2);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT: Write of size 4 at {{.*}} by thread 1:
+// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack.c:9{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack.c:14{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack.c:28{{(:3)?}} ({{.*}})
+// CHECK: Previous read of size 4 at {{.*}} by thread 2:
+// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack.c:18{{(:26)?}} ({{.*}})
+// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack.c:23{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 Thread2{{.*}} {{.*}}simple_stack.c:33{{(:3)?}} ({{.*}})
+// CHECK: Thread 1 (running) created at:
+// CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}})
+// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:38{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:43{{(:3)?}} ({{.*}})
+// CHECK: Thread 2 ({{.*}}) created at:
+// CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}})
+// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:38{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:44{{(:3)?}} ({{.*}})
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void __attribute__((noinline)) foo1() {
+ Global = 42;
+}
+
+void __attribute__((noinline)) bar1() {
+ volatile int tmp = 42;
+ int tmp2 = tmp;
+ (void)tmp2;
+ foo1();
+}
+
+void __attribute__((noinline)) foo2() {
+ volatile int tmp = Global;
+ int tmp2 = tmp;
+ (void)tmp2;
+}
+
+void __attribute__((noinline)) bar2() {
+ volatile int tmp = 42;
+ int tmp2 = tmp;
+ (void)tmp2;
+ foo2();
+}
+
+void *Thread1(void *x) {
+ usleep(1000000);
+ bar1();
+ return NULL;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, NULL, Thread1, NULL);
+ bar2();
+ pthread_join(t, NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT: Write of size 4 at {{.*}} by thread 1:
+// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack2.cc:9{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack2.cc:16{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack2.cc:34{{(:3)?}} ({{.*}})
+// CHECK: Previous read of size 4 at {{.*}} by main thread:
+// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack2.cc:20{{(:28)?}} ({{.*}})
+// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack2.cc:29{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack2.cc:41{{(:3)?}} ({{.*}})
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+int X = 0;
+
+void *Thread(void *p) {
+ X = 42;
+ return 0;
+}
+
+void MySleep() {
+ usleep(100*1000);
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ MySleep(); // Assume the thread has done the write.
+ X = 43;
+ pthread_join(t, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// ...
+// CHECK: As if synchronized via sleep:
+// CHECK-NEXT: #0 usleep
+// CHECK-NEXT: #1 MySleep
+// CHECK-NEXT: #2 main
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+int X = 0;
+
+void *Thread(void *p) {
+ X = 42;
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ usleep(100*1000);
+ pthread_create(&t, 0, Thread, 0);
+ X = 43;
+ pthread_join(t, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: As if synchronized via sleep
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+struct P {
+ int x;
+ int y;
+};
+
+void *Thread(void *x) {
+ static P p = {rand(), rand()};
+ if (p.x > RAND_MAX || p.y > RAND_MAX)
+ exit(1);
+ return 0;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread, 0);
+ pthread_create(&t[1], 0, Thread, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+ printf("PASS\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+struct Cache {
+ int x;
+ explicit Cache(int x)
+ : x(x) {
+ }
+};
+
+void foo(Cache *my) {
+ static Cache *c = my ? my : new Cache(rand());
+ if (c->x >= RAND_MAX)
+ exit(1);
+}
+
+void *Thread(void *x) {
+ foo(new Cache(rand()));
+ return 0;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread, 0);
+ pthread_create(&t[1], 0, Thread, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+ printf("PASS\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sched.h>
+
+struct Cache {
+ int x;
+};
+
+Cache g_cache;
+
+Cache *CreateCache() {
+ g_cache.x = rand();
+ return &g_cache;
+}
+
+_Atomic(Cache*) queue;
+
+void *Thread1(void *x) {
+ static Cache *c = CreateCache();
+ __c11_atomic_store(&queue, c, 0);
+ return 0;
+}
+
+void *Thread2(void *x) {
+ Cache *c = 0;
+ for (;;) {
+ c = __c11_atomic_load(&queue, 0);
+ if (c)
+ break;
+ sched_yield();
+ }
+ if (c->x >= RAND_MAX)
+ exit(1);
+ return 0;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ pthread_create(&t[1], 0, Thread2, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sched.h>
+
+struct Cache {
+ int x;
+ explicit Cache(int x)
+ : x(x) {
+ }
+};
+
+int g_other;
+
+Cache *CreateCache() {
+ g_other = rand();
+ return new Cache(rand());
+}
+
+void *Thread1(void *x) {
+ static Cache *c = CreateCache();
+ if (c->x == g_other)
+ exit(1);
+ return 0;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ pthread_create(&t[1], 0, Thread1, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+ printf("PASS\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sched.h>
+
+struct Cache {
+ int x;
+ explicit Cache(int x)
+ : x(x) {
+ }
+};
+
+void *AsyncInit(void *p) {
+ return new Cache((int)(long)p);
+}
+
+Cache *CreateCache() {
+ pthread_t t;
+ pthread_create(&t, 0, AsyncInit, (void*)rand());
+ void *res;
+ pthread_join(t, &res);
+ return (Cache*)res;
+}
+
+void *Thread1(void *x) {
+ static Cache *c = CreateCache();
+ if (c->x >= RAND_MAX)
+ exit(1);
+ return 0;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ pthread_create(&t[1], 0, Thread1, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+ printf("PASS\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+
+int X;
+
+void *Thread1(void *x) {
+ X = 42;
+ X = 66;
+ X = 78;
+ return 0;
+}
+
+void *Thread2(void *x) {
+ X = 11;
+ X = 99;
+ X = 73;
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread1, 0);
+ Thread2(0);
+ pthread_join(t, 0);
+}
+
+// CHECK: ThreadSanitizer: reported 1 warnings
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+
+volatile int N; // Prevent loop unrolling.
+int **data;
+
+void *Thread1(void *x) {
+ for (int i = 0; i < N; i++)
+ data[i][0] = 42;
+ return 0;
+}
+
+int main() {
+ N = 4;
+ data = new int*[N];
+ for (int i = 0; i < N; i++)
+ data[i] = new int;
+ pthread_t t;
+ pthread_create(&t, 0, Thread1, 0);
+ Thread1(0);
+ pthread_join(t, 0);
+ for (int i = 0; i < N; i++)
+ delete data[i];
+ delete[] data;
+}
+
+// CHECK: ThreadSanitizer: reported 1 warnings
--- /dev/null
+#!/bin/bash
+
+ulimit -s 8192
+set -e # fail on any error
+
+ROOTDIR=$(dirname $0)/..
+
+# Assuming clang is in path.
+CC=clang
+CXX=clang++
+
+# TODO: add testing for all of -O0...-O3
+CFLAGS="-fthread-sanitizer -fPIE -O1 -g -fno-builtin -Wall"
+LDFLAGS="-pie -lpthread -ldl $ROOTDIR/rtl/libtsan.a"
+
+test_file() {
+ SRC=$1
+ COMPILER=$2
+ echo ----- TESTING $(basename $1)
+ OBJ=$SRC.o
+ EXE=$SRC.exe
+ $COMPILER $SRC $CFLAGS -c -o $OBJ
+ $COMPILER $OBJ $LDFLAGS -o $EXE
+ RES=$(TSAN_OPTIONS="atexit_sleep_ms=0" $EXE 2>&1 || true)
+ if [ "$3" != "" ]; then
+ printf "%s\n" "$RES"
+ fi
+ printf "%s\n" "$RES" | FileCheck $SRC
+ if [ "$3" == "" ]; then
+ rm -f $EXE $OBJ
+ fi
+}
+
+if [ "$1" == "" ]; then
+ for c in $ROOTDIR/lit_tests/*.{c,cc}; do
+ if [[ $c == */failing_* ]]; then
+ echo SKIPPING FAILING TEST $c
+ continue
+ fi
+ COMPILER=$CXX
+ case $c in
+ *.c) COMPILER=$CC
+ esac
+ test_file $c $COMPILER
+ done
+ wait
+else
+ test_file $ROOTDIR/lit_tests/$1 $CXX "DUMP"
+fi
--- /dev/null
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+void *Thread(void *x) {
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_join(t, 0);
+ printf("PASS\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
--- /dev/null
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+void *Thread(void *x) {
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_detach(t);
+ printf("PASS\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
--- /dev/null
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+
+void *Thread(void *x) {
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: thread leak
--- /dev/null
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+int Global;
+void *Thread1(void *x) {
+ Global = 42;
+ return x;
+}
+int main() {
+ pthread_t t;
+ pthread_create(&t, NULL, Thread1, NULL);
+ Global = 43;
+ pthread_join(t, NULL);
+ return Global;
+}
+// CHECK: WARNING: ThreadSanitizer: data race
--- /dev/null
+// Regression test for http://code.google.com/p/thread-sanitizer/issues/detail?id=3.
+// The C++ variant is much more compact that the LLVM IR equivalent.
+
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <stdio.h>
+struct AAA { virtual long aaa () { return 0; } }; // NOLINT
+struct BBB: virtual AAA { unsigned long bbb; }; // NOLINT
+struct CCC: virtual AAA { };
+struct DDD: CCC, BBB { DDD(); }; // NOLINT
+DDD::DDD() { }
+int main() {
+ DDD d;
+ printf("OK\n");
+}
+// CHECK: OK
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+
+struct A {
+ A() {
+ sem_init(&sem_, 0, 0);
+ }
+ virtual void F() {
+ }
+ void Done() {
+ sem_post(&sem_);
+ }
+ virtual ~A() {
+ }
+ sem_t sem_;
+};
+
+struct B : A {
+ virtual void F() {
+ }
+ virtual ~B() {
+ sem_wait(&sem_);
+ sem_destroy(&sem_);
+ }
+};
+
+static A *obj = new B;
+
+void *Thread1(void *x) {
+ 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);
+ fprintf(stderr, "PASS\n");
+}
+// CHECK: PASS
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
--- /dev/null
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.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) {
+ 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
+++ /dev/null
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-
-int *mem;
-pthread_mutex_t mtx;
-
-void *Thread1(void *x) {
- pthread_mutex_lock(&mtx);
- free(mem);
- pthread_mutex_unlock(&mtx);
- return NULL;
-}
-
-void *Thread2(void *x) {
- usleep(1000000);
- pthread_mutex_lock(&mtx);
- mem[0] = 42;
- pthread_mutex_unlock(&mtx);
- return NULL;
-}
-
-int main() {
- mem = (int*)malloc(100);
- pthread_mutex_init(&mtx, 0);
- pthread_t t;
- pthread_create(&t, NULL, Thread1, NULL);
- Thread2(0);
- pthread_join(t, NULL);
- pthread_mutex_destroy(&mtx);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
-// CHECK: Write of size 4 at {{.*}} by main thread:
-// CHECK: #0 Thread2
-// CHECK: #1 main
-// CHECK: Previous write of size 8 at {{.*}} by thread 1:
-// CHECK: #0 free
-// CHECK: #1 Thread1
-
+++ /dev/null
-#include <stdlib.h>
-
-void __attribute__((noinline)) foo(int *mem) {
- free(mem);
-}
-
-void __attribute__((noinline)) bar(int *mem) {
- mem[0] = 42;
-}
-
-int main() {
- int *mem = (int*)malloc(100);
- foo(mem);
- bar(mem);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
-// CHECK: Write of size 4 at {{.*}} by main thread:
-// CHECK: #0 bar
-// CHECK: #1 main
-// CHECK: Previous write of size 8 at {{.*}} by main thread:
-// CHECK: #0 free
-// CHECK: #1 foo
-// CHECK: #2 main
-
+++ /dev/null
-#include <pthread.h>
-#include <stdio.h>
-#include <stddef.h>
-
-void *Thread(void *a) {
- ((int*)a)[0]++;
- return NULL;
-}
-
-int main() {
- int *p = new int(42);
- pthread_t t;
- pthread_create(&t, NULL, Thread, p);
- p[0]++;
- pthread_join(t, NULL);
- delete p;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
+++ /dev/null
-#include <pthread.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-char *data = new char[10];
-char *data1 = new char[10];
-char *data2 = new char[10];
-
-void *Thread1(void *x) {
- memcpy(data+5, data1, 1);
- return NULL;
-}
-
-void *Thread2(void *x) {
- usleep(500*1000);
- memcpy(data+3, data2, 4);
- return NULL;
-}
-
-int main() {
- fprintf(stderr, "addr=%p\n", &data[5]);
- 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);
- return 0;
-}
-
-// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 1 at [[ADDR]] by thread 2:
-// CHECK: #0 memcpy
-// CHECK: #1 Thread2
-// CHECK: Previous write of size 1 at [[ADDR]] by thread 1:
-// CHECK: #0 memcpy
-// CHECK: #1 Thread1
-
+++ /dev/null
-#include <pthread.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <unistd.h>
-
-void *Thread1(void *x) {
- int *p = (int*)x;
- p[0] = 1;
- return NULL;
-}
-
-void *Thread2(void *x) {
- usleep(500*1000);
- char *p = (char*)x;
- p[2] = 1;
- return NULL;
-}
-
-int main() {
- int *data = new int(42);
- fprintf(stderr, "ptr1=%p\n", data);
- fprintf(stderr, "ptr2=%p\n", (char*)data + 2);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, data);
- pthread_create(&t[1], NULL, Thread2, data);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- delete data;
-}
-
-// CHECK: ptr1=[[PTR1:0x[0-9,a-f]+]]
-// CHECK: ptr2=[[PTR2:0x[0-9,a-f]+]]
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 1 at [[PTR2]] by thread 2:
-// CHECK: Previous write of size 4 at [[PTR1]] by thread 1:
-
+++ /dev/null
-#include <pthread.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <unistd.h>
-
-void *Thread1(void *x) {
- usleep(500*1000);
- int *p = (int*)x;
- p[0] = 1;
- return NULL;
-}
-
-void *Thread2(void *x) {
- char *p = (char*)x;
- p[2] = 1;
- return NULL;
-}
-
-int main() {
- int *data = new int(42);
- fprintf(stderr, "ptr1=%p\n", data);
- fprintf(stderr, "ptr2=%p\n", (char*)data + 2);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, data);
- pthread_create(&t[1], NULL, Thread2, data);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- delete data;
-}
-
-// CHECK: ptr1=[[PTR1:0x[0-9,a-f]+]]
-// CHECK: ptr2=[[PTR2:0x[0-9,a-f]+]]
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 4 at [[PTR1]] by thread 1:
-// CHECK: Previous write of size 1 at [[PTR2]] by thread 2:
-
+++ /dev/null
-#include <pthread.h>
-#include <unistd.h>
-
-void *Thread(void *p) {
- pthread_mutex_lock((pthread_mutex_t*)p);
- return 0;
-}
-
-int main() {
- pthread_mutex_t m;
- pthread_mutex_init(&m, 0);
- pthread_t t;
- pthread_create(&t, 0, Thread, &m);
- usleep(1000*1000);
- pthread_mutex_destroy(&m);
- pthread_join(t, 0);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
-// CHECK: #0 pthread_mutex_destroy
-// CHECK: #1 main
-// CHECK: and:
-// CHECK: #0 pthread_mutex_lock
-// CHECK: #1 Thread
-// CHECK: Mutex {{.*}} created at:
-// CHECK: #0 pthread_mutex_init
-// CHECK: #1 main
-
+++ /dev/null
-#include <pthread.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-
-pthread_barrier_t B;
-int Global;
-
-void *Thread1(void *x) {
- pthread_barrier_init(&B, 0, 2);
- pthread_barrier_wait(&B);
- return NULL;
-}
-
-void *Thread2(void *x) {
- usleep(1000000);
- pthread_barrier_wait(&B);
- return NULL;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, NULL, Thread1, NULL);
- Thread2(0);
- pthread_join(t, NULL);
- pthread_barrier_destroy(&B);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-
+++ /dev/null
-#include <pthread.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-
-pthread_barrier_t B;
-int Global;
-
-void *Thread1(void *x) {
- if (pthread_barrier_wait(&B) == PTHREAD_BARRIER_SERIAL_THREAD)
- pthread_barrier_destroy(&B);
- return NULL;
-}
-
-void *Thread2(void *x) {
- if (pthread_barrier_wait(&B) == PTHREAD_BARRIER_SERIAL_THREAD)
- pthread_barrier_destroy(&B);
- return NULL;
-}
-
-int main() {
- pthread_barrier_init(&B, 0, 2);
- pthread_t t;
- pthread_create(&t, NULL, Thread1, NULL);
- Thread2(0);
- pthread_join(t, NULL);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
+++ /dev/null
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-void *Thread1(void *p) {
- *(int*)p = 42;
- return 0;
-}
-
-void *Thread2(void *p) {
- *(int*)p = 44;
- return 0;
-}
-
-void *alloc() {
- return malloc(99);
-}
-
-void *AllocThread(void* arg) {
- return alloc();
-}
-
-int main() {
- void *p = 0;
- pthread_t t[2];
- pthread_create(&t[0], 0, AllocThread, 0);
- pthread_join(t[0], &p);
- fprintf(stderr, "addr=%p\n", p);
- pthread_create(&t[0], 0, Thread1, (char*)p + 16);
- pthread_create(&t[1], 0, Thread2, (char*)p + 16);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
- return 0;
-}
-
-// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
-// CHECK: WARNING: ThreadSanitizer: data race
-// ...
-// CHECK: Location is heap block of size 99 at [[ADDR]] allocated by thread 1:
-// CHCEKL #0 malloc
-// CHECK: #1 alloc
-// CHECK: #2 AllocThread
-// ...
-// CHECK: Thread 1 (finished) created at:
-// CHECK: #0 pthread_create
-// CHECK: #1 main
+++ /dev/null
-#include <pthread.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-
-pthread_mutex_t Mtx;
-int Global;
-
-void *Thread1(void *x) {
- pthread_mutex_init(&Mtx, 0);
- pthread_mutex_lock(&Mtx);
- Global = 42;
- pthread_mutex_unlock(&Mtx);
- return NULL;
-}
-
-void *Thread2(void *x) {
- usleep(1000000);
- pthread_mutex_lock(&Mtx);
- Global = 43;
- pthread_mutex_unlock(&Mtx);
- 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);
- pthread_mutex_destroy(&Mtx);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NEXT: Read of size 1 at {{.*}} by thread 2:
-// CHECK-NEXT: #0 pthread_mutex_lock
-// CHECK-NEXT: #1 Thread2{{.*}} {{.*}}race_on_mutex.c:19{{(:3)?}} ({{.*}})
-// CHECK: Previous write of size 1 at {{.*}} by thread 1:
-// CHECK-NEXT: #0 pthread_mutex_init {{.*}} ({{.*}})
-// CHECK-NEXT: #1 Thread1{{.*}} {{.*}}race_on_mutex.c:10{{(:3)?}} ({{.*}})
+++ /dev/null
-#include <pthread.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-// Ensure that we can restore a stack of a finished thread.
-
-int g_data;
-
-void __attribute__((noinline)) foobar(int *p) {
- *p = 42;
-}
-
-void *Thread1(void *x) {
- foobar(&g_data);
- return NULL;
-}
-
-void *Thread2(void *x) {
- usleep(1000*1000);
- g_data = 43;
- 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);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 4 at {{.*}} by thread 2:
-// CHECK: Previous write of size 4 at {{.*}} by thread 1:
-// CHECK: #0 foobar
-// CHECK: #1 Thread1
-// CHECK: Thread 1 (finished) created at:
-// CHECK: #0 pthread_create
-// CHECK: #1 main
-
+++ /dev/null
-#include <pthread.h>
-#include <stdio.h>
-
-int Global;
-
-void *Thread1(void *x) {
- Global = 42;
- return NULL;
-}
-
-void *Thread2(void *x) {
- Global = 43;
- 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);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
+++ /dev/null
-#include <pthread.h>
-#include <stdio.h>
-
-int Global;
-
-void *Thread1(void *x) {
- Global++;
- 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
+++ /dev/null
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-
-void __attribute__((noinline)) foo1() {
- Global = 42;
-}
-
-void __attribute__((noinline)) bar1() {
- volatile int tmp = 42; (void)tmp;
- foo1();
-}
-
-void __attribute__((noinline)) foo2() {
- volatile int v = Global; (void)v;
-}
-
-void __attribute__((noinline)) bar2() {
- volatile int tmp = 42; (void)tmp;
- foo2();
-}
-
-void *Thread1(void *x) {
- usleep(1000000);
- bar1();
- return NULL;
-}
-
-void *Thread2(void *x) {
- bar2();
- return NULL;
-}
-
-void StartThread(pthread_t *t, void *(*f)(void*)) {
- pthread_create(t, NULL, f, NULL);
-}
-
-int main() {
- pthread_t t[2];
- StartThread(&t[0], Thread1);
- StartThread(&t[1], Thread2);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NEXT: Write of size 4 at {{.*}} by thread 1:
-// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack.c:8{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack.c:13{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack.c:27{{(:3)?}} ({{.*}})
-// CHECK: Previous read of size 4 at {{.*}} by thread 2:
-// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack.c:17{{(:26)?}} ({{.*}})
-// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack.c:22{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 Thread2{{.*}} {{.*}}simple_stack.c:32{{(:3)?}} ({{.*}})
-// CHECK: Thread 1 (running) created at:
-// CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}})
-// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:37{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:42{{(:3)?}} ({{.*}})
-// CHECK: Thread 2 ({{.*}}) created at:
-// CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}})
-// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:37{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:43{{(:3)?}} ({{.*}})
+++ /dev/null
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-
-void __attribute__((noinline)) foo1() {
- Global = 42;
-}
-
-void __attribute__((noinline)) bar1() {
- volatile int tmp = 42;
- int tmp2 = tmp;
- (void)tmp2;
- foo1();
-}
-
-void __attribute__((noinline)) foo2() {
- volatile int tmp = Global;
- int tmp2 = tmp;
- (void)tmp2;
-}
-
-void __attribute__((noinline)) bar2() {
- volatile int tmp = 42;
- int tmp2 = tmp;
- (void)tmp2;
- foo2();
-}
-
-void *Thread1(void *x) {
- usleep(1000000);
- bar1();
- return NULL;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, NULL, Thread1, NULL);
- bar2();
- pthread_join(t, NULL);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NEXT: Write of size 4 at {{.*}} by thread 1:
-// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack2.cc:8{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack2.cc:15{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack2.cc:33{{(:3)?}} ({{.*}})
-// CHECK: Previous read of size 4 at {{.*}} by main thread:
-// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack2.cc:19{{(:28)?}} ({{.*}})
-// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack2.cc:28{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack2.cc:40{{(:3)?}} ({{.*}})
+++ /dev/null
-#include <pthread.h>
-#include <unistd.h>
-
-int X = 0;
-
-void *Thread(void *p) {
- X = 42;
- return 0;
-}
-
-void MySleep() {
- usleep(100*1000);
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- MySleep(); // Assume the thread has done the write.
- X = 43;
- pthread_join(t, 0);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// ...
-// CHECK: As if synchronized via sleep:
-// CHECK-NEXT: #0 usleep
-// CHECK-NEXT: #1 MySleep
-// CHECK-NEXT: #2 main
-
+++ /dev/null
-#include <pthread.h>
-#include <unistd.h>
-
-int X = 0;
-
-void *Thread(void *p) {
- X = 42;
- return 0;
-}
-
-int main() {
- pthread_t t;
- usleep(100*1000);
- pthread_create(&t, 0, Thread, 0);
- X = 43;
- pthread_join(t, 0);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NOT: As if synchronized via sleep
+++ /dev/null
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-struct P {
- int x;
- int y;
-};
-
-void *Thread(void *x) {
- static P p = {rand(), rand()};
- if (p.x > RAND_MAX || p.y > RAND_MAX)
- exit(1);
- return 0;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread, 0);
- pthread_create(&t[1], 0, Thread, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
+++ /dev/null
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-struct Cache {
- int x;
- explicit Cache(int x)
- : x(x) {
- }
-};
-
-void foo(Cache *my) {
- static Cache *c = my ? my : new Cache(rand());
- if (c->x >= RAND_MAX)
- exit(1);
-}
-
-void *Thread(void *x) {
- foo(new Cache(rand()));
- return 0;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread, 0);
- pthread_create(&t[1], 0, Thread, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
+++ /dev/null
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sched.h>
-
-struct Cache {
- int x;
-};
-
-Cache g_cache;
-
-Cache *CreateCache() {
- g_cache.x = rand();
- return &g_cache;
-}
-
-_Atomic(Cache*) queue;
-
-void *Thread1(void *x) {
- static Cache *c = CreateCache();
- __c11_atomic_store(&queue, c, 0);
- return 0;
-}
-
-void *Thread2(void *x) {
- Cache *c = 0;
- for (;;) {
- c = __c11_atomic_load(&queue, 0);
- if (c)
- break;
- sched_yield();
- }
- if (c->x >= RAND_MAX)
- exit(1);
- return 0;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread1, 0);
- pthread_create(&t[1], 0, Thread2, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
+++ /dev/null
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sched.h>
-
-struct Cache {
- int x;
- explicit Cache(int x)
- : x(x) {
- }
-};
-
-int g_other;
-
-Cache *CreateCache() {
- g_other = rand();
- return new Cache(rand());
-}
-
-void *Thread1(void *x) {
- static Cache *c = CreateCache();
- if (c->x == g_other)
- exit(1);
- return 0;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread1, 0);
- pthread_create(&t[1], 0, Thread1, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
+++ /dev/null
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sched.h>
-
-struct Cache {
- int x;
- explicit Cache(int x)
- : x(x) {
- }
-};
-
-void *AsyncInit(void *p) {
- return new Cache((int)(long)p);
-}
-
-Cache *CreateCache() {
- pthread_t t;
- pthread_create(&t, 0, AsyncInit, (void*)rand());
- void *res;
- pthread_join(t, &res);
- return (Cache*)res;
-}
-
-void *Thread1(void *x) {
- static Cache *c = CreateCache();
- if (c->x >= RAND_MAX)
- exit(1);
- return 0;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread1, 0);
- pthread_create(&t[1], 0, Thread1, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
+++ /dev/null
-#include <pthread.h>
-
-int X;
-
-void *Thread1(void *x) {
- X = 42;
- X = 66;
- X = 78;
- return 0;
-}
-
-void *Thread2(void *x) {
- X = 11;
- X = 99;
- X = 73;
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread1, 0);
- Thread2(0);
- pthread_join(t, 0);
-}
-
-// CHECK: ThreadSanitizer: reported 1 warnings
-
+++ /dev/null
-#include <pthread.h>
-
-volatile int N; // Prevent loop unrolling.
-int **data;
-
-void *Thread1(void *x) {
- for (int i = 0; i < N; i++)
- data[i][0] = 42;
- return 0;
-}
-
-int main() {
- N = 4;
- data = new int*[N];
- for (int i = 0; i < N; i++)
- data[i] = new int;
- pthread_t t;
- pthread_create(&t, 0, Thread1, 0);
- Thread1(0);
- pthread_join(t, 0);
- for (int i = 0; i < N; i++)
- delete data[i];
- delete[] data;
-}
-
-// CHECK: ThreadSanitizer: reported 1 warnings
-
+++ /dev/null
-#!/bin/bash
-
-ulimit -s 8192
-set -e # fail on any error
-
-ROOTDIR=$(dirname $0)/..
-
-# Assuming clang is in path.
-CC=clang
-CXX=clang++
-
-# TODO: add testing for all of -O0...-O3
-CFLAGS="-fthread-sanitizer -fPIE -O1 -g -fno-builtin -Wall"
-LDFLAGS="-pie -lpthread -ldl $ROOTDIR/rtl/libtsan.a"
-
-test_file() {
- SRC=$1
- COMPILER=$2
- echo ----- TESTING $(basename $1)
- OBJ=$SRC.o
- EXE=$SRC.exe
- $COMPILER $SRC $CFLAGS -c -o $OBJ
- $COMPILER $OBJ $LDFLAGS -o $EXE
- RES=$(TSAN_OPTIONS="atexit_sleep_ms=0" $EXE 2>&1 || true)
- if [ "$3" != "" ]; then
- printf "%s\n" "$RES"
- fi
- printf "%s\n" "$RES" | FileCheck $SRC
- if [ "$3" == "" ]; then
- rm -f $EXE $OBJ
- fi
-}
-
-if [ "$1" == "" ]; then
- for c in $ROOTDIR/output_tests/*.{c,cc}; do
- if [[ $c == */failing_* ]]; then
- echo SKIPPING FAILING TEST $c
- continue
- fi
- COMPILER=$CXX
- case $c in
- *.c) COMPILER=$CC
- esac
- test_file $c $COMPILER
- done
- wait
-else
- test_file $ROOTDIR/output_tests/$1 $CXX "DUMP"
-fi
+++ /dev/null
-#include <pthread.h>
-
-void *Thread(void *x) {
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- pthread_join(t, 0);
- return 0;
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
-
+++ /dev/null
-#include <pthread.h>
-
-void *Thread(void *x) {
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- pthread_detach(t);
- return 0;
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
-
+++ /dev/null
-#include <pthread.h>
-
-void *Thread(void *x) {
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: thread leak
-
+++ /dev/null
-#include <pthread.h>
-int Global;
-void *Thread1(void *x) {
- Global = 42;
- return x;
-}
-int main() {
- pthread_t t;
- pthread_create(&t, NULL, Thread1, NULL);
- Global = 43;
- pthread_join(t, NULL);
- return Global;
-}
-// CHECK: WARNING: ThreadSanitizer: data race
+++ /dev/null
-// Regression test for http://code.google.com/p/thread-sanitizer/issues/detail?id=3.
-// The C++ variant is much more compact that the LLVM IR equivalent.
-#include <stdio.h>
-struct AAA { virtual long aaa () { return 0; } }; // NOLINT
-struct BBB: virtual AAA { unsigned long bbb; }; // NOLINT
-struct CCC: virtual AAA { };
-struct DDD: CCC, BBB { DDD(); }; // NOLINT
-DDD::DDD() { }
-int main() {
- DDD d;
- printf("OK\n");
-}
-// CHECK: OK
+++ /dev/null
-#include <pthread.h>
-#include <semaphore.h>
-#include <stdio.h>
-
-struct A {
- A() {
- sem_init(&sem_, 0, 0);
- }
- virtual void F() {
- }
- void Done() {
- sem_post(&sem_);
- }
- virtual ~A() {
- }
- sem_t sem_;
-};
-
-struct B : A {
- virtual void F() {
- }
- virtual ~B() {
- sem_wait(&sem_);
- sem_destroy(&sem_);
- }
-};
-
-static A *obj = new B;
-
-void *Thread1(void *x) {
- 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);
- fprintf(stderr, "PASS\n");
-}
-// CHECK: PASS
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
+++ /dev/null
-#include <pthread.h>
-#include <semaphore.h>
-#include <stdio.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) {
- 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