summaryrefslogtreecommitdiff
path: root/test/tsan
diff options
context:
space:
mode:
Diffstat (limited to 'test/tsan')
-rw-r--r--test/tsan/CMakeLists.txt4
-rw-r--r--test/tsan/Darwin/xpc-race.mm53
-rw-r--r--test/tsan/Linux/double_race.cc52
-rw-r--r--test/tsan/Linux/user_malloc.cc7
-rw-r--r--test/tsan/allocator_returns_null.cc12
-rw-r--r--test/tsan/atexit3.cc41
-rw-r--r--test/tsan/cond_cancel.c2
-rw-r--r--test/tsan/custom_mutex.h10
-rw-r--r--test/tsan/custom_mutex4.cc33
-rw-r--r--test/tsan/custom_mutex5.cc33
-rw-r--r--test/tsan/lit.cfg11
-rw-r--r--test/tsan/map32bit.cc5
-rw-r--r--test/tsan/signal_pause.cc35
-rw-r--r--test/tsan/strerror_r.cc3
-rw-r--r--test/tsan/thread_name.cc8
-rw-r--r--test/tsan/thread_name2.cc10
-rw-r--r--test/tsan/tls_race.cc1
-rw-r--r--test/tsan/tls_race2.cc1
18 files changed, 275 insertions, 46 deletions
diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt
index a689086129521..2b1d3004b1def 100644
--- a/test/tsan/CMakeLists.txt
+++ b/test/tsan/CMakeLists.txt
@@ -7,9 +7,9 @@ endif()
if(NOT COMPILER_RT_STANDALONE_BUILD)
list(APPEND TSAN_TEST_DEPS tsan)
endif()
-if(COMPILER_RT_HAS_LIBCXX_SOURCES AND
+if(COMPILER_RT_LIBCXX_PATH AND
COMPILER_RT_TEST_COMPILER_ID STREQUAL "Clang"
- AND NOT APPLE)
+ AND NOT APPLE AND NOT ANDROID)
list(APPEND TSAN_TEST_DEPS libcxx_tsan)
set(TSAN_HAS_LIBCXX True)
else()
diff --git a/test/tsan/Darwin/xpc-race.mm b/test/tsan/Darwin/xpc-race.mm
index a1e214c12b7df..872c9ee73e138 100644
--- a/test/tsan/Darwin/xpc-race.mm
+++ b/test/tsan/Darwin/xpc-race.mm
@@ -1,22 +1,26 @@
-// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %clangxx_tsan %s -o %t -framework Foundation
// RUN: %deflake %run %t 2>&1 | FileCheck %s
// UNSUPPORTED: ios
#import <Foundation/Foundation.h>
#import <xpc/xpc.h>
+#import <stdatomic.h>
#import "../test.h"
long global;
-long received_msgs;
+_Atomic(long) msg_counter;
+_Atomic(long) processed_msgs;
xpc_connection_t server_conn;
xpc_connection_t client_conns[2];
int main(int argc, const char *argv[]) {
@autoreleasepool {
- NSLog(@"Hello world.");
+ fprintf(stderr, "Hello world.\n");
+ // CHECK: Hello world.
+
barrier_init(&barrier, 2);
dispatch_queue_t server_q = dispatch_queue_create("server.queue", DISPATCH_QUEUE_CONCURRENT);
@@ -24,21 +28,34 @@ int main(int argc, const char *argv[]) {
server_conn = xpc_connection_create(NULL, server_q);
xpc_connection_set_event_handler(server_conn, ^(xpc_object_t client) {
- NSLog(@"server event handler, client = %@", client);
+ fprintf(stderr, "server event handler, client = %p\n", client);
if (client == XPC_ERROR_CONNECTION_INTERRUPTED || client == XPC_ERROR_CONNECTION_INVALID) {
return;
}
xpc_connection_set_event_handler(client, ^(xpc_object_t object) {
- NSLog(@"received message: %@", object);
+ fprintf(stderr, "received message: %p\n", object);
- barrier_wait(&barrier);
- global = 42;
+ long msg_number = atomic_fetch_add_explicit(&msg_counter, 1, memory_order_relaxed);
- dispatch_sync(dispatch_get_main_queue(), ^{
- received_msgs++;
+ if (msg_number == 0)
+ barrier_wait(&barrier);
+
+ global++;
+ // CHECK: WARNING: ThreadSanitizer: data race
+ // CHECK: Write of size 8
+ // CHECK: #0 {{.*}}xpc-race.mm:[[@LINE-3]]
+ // CHECK: Previous write of size 8
+ // CHECK: #0 {{.*}}xpc-race.mm:[[@LINE-5]]
+ // CHECK: Location is global 'global'
+
+ if (msg_number == 1)
+ barrier_wait(&barrier);
- if (received_msgs >= 2) {
+ atomic_fetch_add(&processed_msgs, 1);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ if (processed_msgs >= 2) {
xpc_connection_cancel(client_conns[0]);
xpc_connection_cancel(client_conns[1]);
xpc_connection_cancel(server_conn);
@@ -55,12 +72,12 @@ int main(int argc, const char *argv[]) {
for (int i = 0; i < 2; i++) {
client_conns[i] = xpc_connection_create_from_endpoint(endpoint);
xpc_connection_set_event_handler(client_conns[i], ^(xpc_object_t event) {
- NSLog(@"client event handler, event = %@", event);
+ fprintf(stderr, "client event handler, event = %p\n", event);
});
xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(msg, "hello", "world");
- NSLog(@"sending message: %@", msg);
+ fprintf(stderr, "sending message: %p\n", msg);
xpc_connection_send_message(client_conns[i], msg);
xpc_connection_resume(client_conns[i]);
@@ -68,16 +85,8 @@ int main(int argc, const char *argv[]) {
CFRunLoopRun();
- NSLog(@"Done.");
+ fprintf(stderr, "Done.\n");
+ // CHECK: Done.
}
return 0;
}
-
-// CHECK: Hello world.
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 8
-// CHECK: #0 {{.*}}xpc-race.mm:36
-// CHECK: Previous write of size 8
-// CHECK: #0 {{.*}}xpc-race.mm:36
-// CHECK: Location is global 'global'
-// CHECK: Done.
diff --git a/test/tsan/Linux/double_race.cc b/test/tsan/Linux/double_race.cc
new file mode 100644
index 0000000000000..2b4af35a2676e
--- /dev/null
+++ b/test/tsan/Linux/double_race.cc
@@ -0,0 +1,52 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
+#include "../test.h"
+#include <memory.h>
+
+// A reproducer for a known issue.
+// See reference to double_race.cc in tsan_rtl_report.cc for an explanation.
+
+char buf[16];
+volatile int nreport;
+
+void __sanitizer_report_error_summary(const char *summary) {
+ nreport++;
+}
+
+const int kEventPCBits = 61;
+
+extern "C" bool __tsan_symbolize_external(unsigned long pc, char *func_buf,
+ unsigned long func_siz,
+ char *file_buf,
+ unsigned long file_siz, int *line,
+ int *col) {
+ if (pc >> kEventPCBits) {
+ printf("bad PC passed to __tsan_symbolize_external: %lx\n", pc);
+ _exit(1);
+ }
+ return true;
+}
+
+void *Thread(void *arg) {
+ barrier_wait(&barrier);
+ memset(buf, 2, sizeof(buf));
+ return 0;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ memset(buf, 1, sizeof(buf));
+ barrier_wait(&barrier);
+ pthread_join(t, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 8 at {{.*}} by thread T1:
+// CHECK: #0 memset
+// CHECK: #1 Thread
+// CHECK-NOT: bad PC passed to __tsan_symbolize_external
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 8 at {{.*}} by thread T1:
+// CHECK: #0 Thread
diff --git a/test/tsan/Linux/user_malloc.cc b/test/tsan/Linux/user_malloc.cc
index 6d51a9dd7d9b2..b470e6c543f87 100644
--- a/test/tsan/Linux/user_malloc.cc
+++ b/test/tsan/Linux/user_malloc.cc
@@ -1,5 +1,12 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
// UNSUPPORTED: powerpc64le
+
+// FIXME: Remove the test or find how to fix this.
+// On some distributions, probably with newer glibc, tsan initialization calls
+// dlsym which then calls malloc and crashes because of tsan is not initialized.
+// UNSUPPORTED: linux
+
#include <stdio.h>
// Defined by tsan.
diff --git a/test/tsan/allocator_returns_null.cc b/test/tsan/allocator_returns_null.cc
index 852dda035f23a..5e2e2e9a53c73 100644
--- a/test/tsan/allocator_returns_null.cc
+++ b/test/tsan/allocator_returns_null.cc
@@ -37,9 +37,10 @@
// RUN: | FileCheck %s --check-prefix=CHECK-nnNULL
#include <assert.h>
-#include <string.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <limits>
#include <new>
@@ -51,6 +52,7 @@ int main(int argc, char **argv) {
const char *action = argv[1];
fprintf(stderr, "%s:\n", action);
+ // The limit enforced in tsan_mman.cc, user_alloc_internal function.
static const size_t kMaxAllowedMallocSizePlusOne = (1ULL << 40) + 1;
void *x = 0;
@@ -78,10 +80,13 @@ int main(int argc, char **argv) {
assert(0);
}
+ fprintf(stderr, "errno: %d\n", errno);
+
// The NULL pointer is printed differently on different systems, while (long)0
// is always the same.
fprintf(stderr, "x: %lx\n", (long)x);
free(x);
+
return x != 0;
}
@@ -101,14 +106,19 @@ int main(int argc, char **argv) {
// CHECK-nnCRASH: ThreadSanitizer's allocator is terminating the process
// CHECK-mNULL: malloc:
+// CHECK-mNULL: errno: 12
// CHECK-mNULL: x: 0
// CHECK-cNULL: calloc:
+// CHECK-cNULL: errno: 12
// CHECK-cNULL: x: 0
// CHECK-coNULL: calloc-overflow:
+// CHECK-coNULL: errno: 12
// CHECK-coNULL: x: 0
// CHECK-rNULL: realloc:
+// CHECK-rNULL: errno: 12
// CHECK-rNULL: x: 0
// CHECK-mrNULL: realloc-after-malloc:
+// CHECK-mrNULL: errno: 12
// CHECK-mrNULL: x: 0
// CHECK-nnNULL: new-nothrow:
// CHECK-nnNULL: x: 0
diff --git a/test/tsan/atexit3.cc b/test/tsan/atexit3.cc
new file mode 100644
index 0000000000000..43ba5bbf6919f
--- /dev/null
+++ b/test/tsan/atexit3.cc
@@ -0,0 +1,41 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static void atexit5() {
+ fprintf(stderr, "5");
+}
+
+static void atexit4() {
+ fprintf(stderr, "4");
+}
+
+static void atexit3() {
+ fprintf(stderr, "3");
+}
+
+static void atexit2() {
+ fprintf(stderr, "2");
+}
+
+static void atexit1() {
+ fprintf(stderr, "1");
+}
+
+static void atexit0() {
+ fprintf(stderr, "\n");
+}
+
+int main() {
+ atexit(atexit0);
+ atexit(atexit1);
+ atexit(atexit2);
+ atexit(atexit3);
+ atexit(atexit4);
+ atexit(atexit5);
+}
+
+// CHECK-NOT: FATAL: ThreadSanitizer
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: 54321
diff --git a/test/tsan/cond_cancel.c b/test/tsan/cond_cancel.c
index fb6a66136b8af..5c497155cb69e 100644
--- a/test/tsan/cond_cancel.c
+++ b/test/tsan/cond_cancel.c
@@ -8,7 +8,7 @@
// (defined in sanitizer_thread_registry.cc). It might seem a bug on glibc,
// however the same version GLIBC-2.17 will not make fail the test on
// powerpc64 BE (VMA=46)
-// XFAIL: powerpc64-unknown-linux-gnu
+// UNSUPPORTED: powerpc64-unknown-linux-gnu
#include "test.h"
diff --git a/test/tsan/custom_mutex.h b/test/tsan/custom_mutex.h
index e3ac7a9a52a7f..8e226a170ec4f 100644
--- a/test/tsan/custom_mutex.h
+++ b/test/tsan/custom_mutex.h
@@ -6,15 +6,16 @@
// A very primitive mutex annotated with tsan annotations.
class Mutex {
public:
- Mutex(bool prof, unsigned flags)
+ Mutex(bool prof, unsigned create_flags, unsigned destroy_flags=0)
: prof_(prof)
, locked_(false)
- , seq_(0) {
- __tsan_mutex_create(this, flags);
+ , seq_(0)
+ , destroy_flags_(destroy_flags) {
+ __tsan_mutex_create(this, create_flags);
}
~Mutex() {
- __tsan_mutex_destroy(this, 0);
+ __tsan_mutex_destroy(this, destroy_flags_);
}
void Lock() {
@@ -57,6 +58,7 @@ class Mutex {
const bool prof_;
std::atomic<bool> locked_;
int seq_;
+ unsigned destroy_flags_;
// This models mutex profiling subsystem.
static Mutex prof_mu_;
diff --git a/test/tsan/custom_mutex4.cc b/test/tsan/custom_mutex4.cc
new file mode 100644
index 0000000000000..539a8be803c60
--- /dev/null
+++ b/test/tsan/custom_mutex4.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 --std=c++11 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "custom_mutex.h"
+
+#include <type_traits>
+
+// Test that the destruction events of a mutex are ignored when the
+// annotations request this.
+//
+// Use after destruction is UB, but __tsan_mutex_linker_init and
+// __tsan_mutex_not_static exist to support global variables of mutex type,
+// which might be accessed during program shutdown after the class's destructor
+// has run.
+
+int main() {
+ std::aligned_storage<sizeof(Mutex), alignof(Mutex)>::type mu1_store;
+ Mutex* mu1 = reinterpret_cast<Mutex*>(&mu1_store);
+ new(&mu1_store) Mutex(false, __tsan_mutex_linker_init);
+ mu1->Lock();
+ mu1->~Mutex();
+ mu1->Unlock();
+
+ std::aligned_storage<sizeof(Mutex), alignof(Mutex)>::type mu2_store;
+ Mutex* mu2 = reinterpret_cast<Mutex*>(&mu2_store);
+ new(&mu2_store) Mutex(false, 0, __tsan_mutex_not_static);
+ mu2->Lock();
+ mu2->~Mutex();
+ mu2->Unlock();
+
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK: DONE
diff --git a/test/tsan/custom_mutex5.cc b/test/tsan/custom_mutex5.cc
new file mode 100644
index 0000000000000..ad906e38aeb19
--- /dev/null
+++ b/test/tsan/custom_mutex5.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 --std=c++11 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
+#include "custom_mutex.h"
+
+#include <type_traits>
+
+// Test that we detect the destruction of an in-use mutex when the
+// thread annotations don't otherwise disable the check.
+
+int main() {
+ std::aligned_storage<sizeof(Mutex), alignof(Mutex)>::type mu1_store;
+ Mutex* mu1 = reinterpret_cast<Mutex*>(&mu1_store);
+ new(&mu1_store) Mutex(false, 0);
+ mu1->Lock();
+ mu1->~Mutex();
+ mu1->Unlock();
+
+ std::aligned_storage<sizeof(Mutex), alignof(Mutex)>::type mu2_store;
+ Mutex* mu2 = reinterpret_cast<Mutex*>(&mu2_store);
+ new(&mu2_store)
+ Mutex(false, __tsan_mutex_not_static, __tsan_mutex_not_static);
+ mu2->Lock();
+ mu2->~Mutex();
+ mu2->Unlock();
+
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
+// CHECK: main {{.*}}custom_mutex5.cc:14
+// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
+// CHECK: main {{.*}}custom_mutex5.cc:22
+// CHECK: DONE
diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg
index 0ab62db0907fd..fdbafefbc66fd 100644
--- a/test/tsan/lit.cfg
+++ b/test/tsan/lit.cfg
@@ -66,7 +66,7 @@ if config.has_libcxx and config.host_os != 'Darwin':
"-Wl,-rpath=%s" % libcxx_libdir]
def build_invocation(compile_flags):
- return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " "
+ return " " + " ".join([config.clang] + compile_flags) + " "
config.substitutions.append( ("%clang_tsan ", build_invocation(clang_tsan_cflags)) )
config.substitutions.append( ("%clangxx_tsan ", build_invocation(clang_tsan_cxxflags)) )
@@ -79,14 +79,11 @@ config.substitutions.append( ("%deflake ", os.path.join(os.path.dirname(__file__
# Default test suffixes.
config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm']
-# ThreadSanitizer tests are currently supported on FreeBSD, Linux and Darwin.
-if config.host_os not in ['FreeBSD', 'Linux', 'Darwin']:
+if config.host_os not in ['FreeBSD', 'Linux', 'Darwin', 'NetBSD']:
config.unsupported = True
-# Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL
-# because the test hangs.
-if config.target_arch != 'aarch64':
- config.available_features.add('stable-runtime')
+if config.android:
+ config.unsupported = True
if config.host_os == 'Darwin' and config.target_arch in ["x86_64", "x86_64h"]:
config.parallelism_group = "darwin-64bit-sanitizer"
diff --git a/test/tsan/map32bit.cc b/test/tsan/map32bit.cc
index 3b4f8990016e8..8aef27bc1900d 100644
--- a/test/tsan/map32bit.cc
+++ b/test/tsan/map32bit.cc
@@ -12,8 +12,8 @@
// XFAIL: aarch64
// XFAIL: powerpc64
-// MAP_32BIT doesn't exist on OS X.
-// UNSUPPORTED: darwin
+// MAP_32BIT doesn't exist on OS X and NetBSD.
+// UNSUPPORTED: darwin,netbsd
void *Thread(void *ptr) {
*(int*)ptr = 42;
@@ -45,4 +45,3 @@ int main() {
// CHECK: WARNING: ThreadSanitizer: data race
// CHECK: DONE
-
diff --git a/test/tsan/signal_pause.cc b/test/tsan/signal_pause.cc
new file mode 100644
index 0000000000000..cbcef9491e9e4
--- /dev/null
+++ b/test/tsan/signal_pause.cc
@@ -0,0 +1,35 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// Test that pause loop handles signals.
+
+#include "test.h"
+#include <signal.h>
+#include <errno.h>
+
+void handler(int signum) {
+ write(2, "DONE\n", 5);
+ _exit(0);
+}
+
+void *thread(void *arg) {
+ for (;;)
+ pause();
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ struct sigaction act = {};
+ act.sa_handler = &handler;
+ if (sigaction(SIGUSR1, &act, 0)) {
+ fprintf(stderr, "sigaction failed %d\n", errno);
+ return 1;
+ }
+ pthread_t th;
+ pthread_create(&th, 0, thread, 0);
+ sleep(1); // give it time to block in pause
+ pthread_kill(th, SIGUSR1);
+ sleep(10); // signal handler must exit the process while we are here
+ return 0;
+}
+
+// CHECK: DONE
diff --git a/test/tsan/strerror_r.cc b/test/tsan/strerror_r.cc
index 06c92d3bb641d..ad482013012c2 100644
--- a/test/tsan/strerror_r.cc
+++ b/test/tsan/strerror_r.cc
@@ -11,7 +11,8 @@
char buffer[1000];
void *Thread(void *p) {
- return strerror_r(TEST_ERROR, buffer, sizeof(buffer));
+ strerror_r(TEST_ERROR, buffer, sizeof(buffer));
+ return buffer;
}
int main() {
diff --git a/test/tsan/thread_name.cc b/test/tsan/thread_name.cc
index 80d30b82d8b5f..17caa62ef4401 100644
--- a/test/tsan/thread_name.cc
+++ b/test/tsan/thread_name.cc
@@ -3,10 +3,14 @@
#if defined(__linux__)
#define USE_PTHREAD_SETNAME_NP __GLIBC_PREREQ(2, 12)
+#define tsan_pthread_setname_np pthread_setname_np
#elif defined(__FreeBSD__)
#include <pthread_np.h>
#define USE_PTHREAD_SETNAME_NP 1
-#define pthread_setname_np pthread_set_name_np
+#define tasn_pthread_setname_np pthread_set_name_np
+#elif defined(__NetBSD__)
+#define USE_PTHREAD_SETNAME_NP 1
+#define tsan_pthread_setname_np(a, b) pthread_setname_np((a), "%s", (void *)(b))
#else
#define USE_PTHREAD_SETNAME_NP 0
#endif
@@ -24,7 +28,7 @@ void *Thread1(void *x) {
void *Thread2(void *x) {
#if USE_PTHREAD_SETNAME_NP
- pthread_setname_np(pthread_self(), "Thread2");
+ tsan_pthread_setname_np(pthread_self(), "Thread2");
#else
AnnotateThreadName(__FILE__, __LINE__, "Thread2");
#endif
diff --git a/test/tsan/thread_name2.cc b/test/tsan/thread_name2.cc
index d7ed0f0d1952f..9ebac29ddb5ed 100644
--- a/test/tsan/thread_name2.cc
+++ b/test/tsan/thread_name2.cc
@@ -6,7 +6,11 @@
#if defined(__FreeBSD__)
#include <pthread_np.h>
-#define pthread_setname_np pthread_set_name_np
+#define tsan_pthread_setname_np pthread_set_name_np
+#elif defined(__NetBSD__)
+#define tsan_pthread_setname_np(a, b) pthread_setname_np((a), "%s", (void *)(b))
+#else
+#define tsan_pthread_setname_np pthread_setname_np
#endif
long long Global;
@@ -18,7 +22,7 @@ void *Thread1(void *x) {
}
void *Thread2(void *x) {
- pthread_setname_np(pthread_self(), "foobar2");
+ tsan_pthread_setname_np(pthread_self(), "foobar2");
Global--;
barrier_wait(&barrier);
return 0;
@@ -29,7 +33,7 @@ int main() {
pthread_t t[2];
pthread_create(&t[0], 0, Thread1, 0);
pthread_create(&t[1], 0, Thread2, 0);
- pthread_setname_np(t[0], "foobar1");
+ tsan_pthread_setname_np(t[0], "foobar1");
barrier_wait(&barrier);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
diff --git a/test/tsan/tls_race.cc b/test/tsan/tls_race.cc
index b43a514cc8aa8..dd37ff01d9751 100644
--- a/test/tsan/tls_race.cc
+++ b/test/tsan/tls_race.cc
@@ -20,4 +20,5 @@ int main() {
// CHECK: WARNING: ThreadSanitizer: data race
// CHECK-Linux: Location is TLS of main thread.
// CHECK-FreeBSD: Location is TLS of main thread.
+// CHECK-NetBSD: Location is TLS of main thread.
// CHECK-Darwin: Location is heap block of size 4
diff --git a/test/tsan/tls_race2.cc b/test/tsan/tls_race2.cc
index b04ff67881009..f3139b69fc082 100644
--- a/test/tsan/tls_race2.cc
+++ b/test/tsan/tls_race2.cc
@@ -27,4 +27,5 @@ int main() {
// CHECK: WARNING: ThreadSanitizer: data race
// CHECK-Linux: Location is TLS of thread T1.
// CHECK-FreeBSD: Location is TLS of thread T1.
+// CHECK-NetBSD: Location is TLS of thread T1.
// CHECK-Darwin: Location is heap block of size 4