[compiler-rt] TSAN: Report when thread is not live and referenced in pthread (PR #156921)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 4 09:37:34 PDT 2025
https://github.com/ghostway0 created https://github.com/llvm/llvm-project/pull/156921
fixes #146683 #156829
outputs something like:
==29712==ThreadSanitizer: pthread_detach was called on thread 0 but it is dead.
detach rc1=0 rc2=-22
>From 311b18745e707156a0ff0883265164f5c9bada07 Mon Sep 17 00:00:00 2001
From: ghostway <ghostway at tuta.io>
Date: Thu, 4 Sep 2025 19:26:31 +0300
Subject: [PATCH] TSAN: Report when thread is not live and referenced in
pthread
---
.../sanitizer_thread_registry.cpp | 17 +++++++++----
.../sanitizer_thread_registry.h | 2 +-
.../lib/tsan/rtl/tsan_interceptors_posix.cpp | 24 +++++++++++++++----
compiler-rt/lib/tsan/rtl/tsan_rtl.h | 2 +-
compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp | 4 ++--
5 files changed, 36 insertions(+), 13 deletions(-)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp
index d726d282437ca..b8f32b52c64d8 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp
@@ -274,6 +274,11 @@ void ThreadRegistry::JoinThread(u32 tid, void *arg) {
{
ThreadRegistryLock l(this);
ThreadContextBase *tctx = threads_[tid];
+
+ if (!tctx) {
+ Report("%s: Tried to join thread %u, but it is not live.", SanitizerToolName, tid);
+ }
+
CHECK_NE(tctx, 0);
if (tctx->status == ThreadStatusInvalid) {
Report("%s: Join of non-existent thread\n", SanitizerToolName);
@@ -357,17 +362,19 @@ ThreadContextBase *ThreadRegistry::QuarantinePop() {
return tctx;
}
-u32 ThreadRegistry::ConsumeThreadUserId(uptr user_id) {
+bool ThreadRegistry::ConsumeThreadUserId(uptr user_id, u32 *tid_out) {
ThreadRegistryLock l(this);
- u32 tid;
auto *t = live_.find(user_id);
- CHECK(t);
- tid = t->second;
+ if (!t) {
+ return false;
+ }
+ u32 tid = t->second;
live_.erase(t);
auto *tctx = threads_[tid];
CHECK_EQ(tctx->user_id, user_id);
tctx->user_id = 0;
- return tid;
+ *tid_out = tid;
+ return true;
}
void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) {
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h b/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
index 8adc420c8cce4..83459685fcb53 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -135,7 +135,7 @@ class SANITIZER_MUTEX ThreadRegistry {
// Finishes thread and returns previous status.
ThreadStatus FinishThread(u32 tid);
void StartThread(u32 tid, ThreadID os_id, ThreadType thread_type, void *arg);
- u32 ConsumeThreadUserId(uptr user_id);
+ bool ConsumeThreadUserId(uptr user_id, u32 *tid_out);
void SetThreadUserId(u32 tid, uptr user_id);
// OnFork must be called in the child process after fork to purge old
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index b46a81031258c..4eabea5addd2a 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -1130,7 +1130,11 @@ TSAN_INTERCEPTOR(int, pthread_create,
TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret);
- Tid tid = ThreadConsumeTid(thr, pc, (uptr)th);
+ Tid tid;
+ if (!ThreadConsumeTid(thr, pc, (uptr)th, &tid)) {
+ Report("ThreadSanitizer: pthread_join was called on thread %d but it is dead.\n", thr->tid);
+ return -errno_EINVAL;
+ }
ThreadIgnoreBegin(thr, pc);
int res = BLOCK_REAL(pthread_join)(th, ret);
ThreadIgnoreEnd(thr);
@@ -1155,7 +1159,11 @@ int internal_pthread_join(void *th, void **ret) {
TSAN_INTERCEPTOR(int, pthread_detach, void *th) {
SCOPED_INTERCEPTOR_RAW(pthread_detach, th);
- Tid tid = ThreadConsumeTid(thr, pc, (uptr)th);
+ Tid tid;
+ if (!ThreadConsumeTid(thr, pc, (uptr)th, &tid)) {
+ Report("ThreadSanitizer: pthread_detach was called on thread %d but it is dead.\n", thr->tid);
+ return -errno_EINVAL;
+ }
int res = REAL(pthread_detach)(th);
if (res == 0) {
ThreadDetach(thr, pc, tid);
@@ -1176,7 +1184,11 @@ TSAN_INTERCEPTOR(void, pthread_exit, void *retval) {
#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) {
SCOPED_INTERCEPTOR_RAW(pthread_tryjoin_np, th, ret);
- Tid tid = ThreadConsumeTid(thr, pc, (uptr)th);
+ Tid tid;
+ if (!ThreadConsumeTid(thr, pc, (uptr)th, &tid)) {
+ Report("ThreadSanitizer: pthread_tryjoin_np was called on thread %d but it is dead.\n", thr->tid);
+ return -errno_EINVAL;
+ }
ThreadIgnoreBegin(thr, pc);
int res = REAL(pthread_tryjoin_np)(th, ret);
ThreadIgnoreEnd(thr);
@@ -1190,7 +1202,11 @@ TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) {
TSAN_INTERCEPTOR(int, pthread_timedjoin_np, void *th, void **ret,
const struct timespec *abstime) {
SCOPED_INTERCEPTOR_RAW(pthread_timedjoin_np, th, ret, abstime);
- Tid tid = ThreadConsumeTid(thr, pc, (uptr)th);
+ Tid tid;
+ if (!ThreadConsumeTid(thr, pc, (uptr)th, &tid)) {
+ Report("ThreadSanitizer: pthread_timedjoin_np was called on thread %d but it is dead.\n", thr->tid);
+ return -errno_EINVAL;
+ }
ThreadIgnoreBegin(thr, pc);
int res = BLOCK_REAL(pthread_timedjoin_np)(th, ret, abstime);
ThreadIgnoreEnd(thr);
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index 0b6d5f088b142..03bd4d8de2e28 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -563,7 +563,7 @@ Tid ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached);
void ThreadStart(ThreadState *thr, Tid tid, ThreadID os_id,
ThreadType thread_type);
void ThreadFinish(ThreadState *thr);
-Tid ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid);
+bool ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid, Tid *tid_out);
void ThreadJoin(ThreadState *thr, uptr pc, Tid tid);
void ThreadDetach(ThreadState *thr, uptr pc, Tid tid);
void ThreadFinalize(ThreadState *thr);
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp
index b1464ccfddeb4..fd33dde7e48db 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp
@@ -301,8 +301,8 @@ struct ConsumeThreadContext {
ThreadContextBase *tctx;
};
-Tid ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) {
- return ctx->thread_registry.ConsumeThreadUserId(uid);
+bool ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid, Tid *tid_out) {
+ return ctx->thread_registry.ConsumeThreadUserId(uid, tid_out);
}
struct JoinArg {
More information about the llvm-commits
mailing list