<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/156829>156829</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
TSan CHECK failure in `ThreadRegistry::ConsumeThreadUserId` on `AArch64` when intercepting `pthread_detach()` (thread created/managed inside closed-source .so)
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
Katze719
</td>
</tr>
</table>
<pre>
Component: ThreadSanitizer (compiler-rt)
Toolchain & versions
```txt
Clang: Ubuntu clang version 19.1.7 (++20250804090312+cd708029e0b2-1~exp1~20250804210325.79)
Target triple used for build: aarch64-linux-gnu
Linker: lld-19
TSan runtime: libclang_rt.tsan-aarch64.{a,so} from LLVM 19 packages
```
**Runtime environment**
- Hardware: Raspberry Pi Compute Module 4 (ARMv8, AArch64)
- Kernel: Linux 5.15, configured with CONFIG_ARM64_VA_BITS_48=y (/proc/config confirms ARM64_VA_BITS=48)
- Page size: 4096
- Distro/userspace: Yocto
- ASLR: kernel.randomize_va_space=2
- vm.mmap_rnd_bits: tested values 30, 28, 27, 26 (no change)
- ulimit -v: unlimited
- Execution is native on AArch64
**Build Flags**
```txt
-fsanitize=thread -fPIE -pie -g -O1
```
**What happens**
Running the instrumented app and invoking a specific code path that calls into a closed-source shared library (which internally creates and manages threads) reliably aborts with a TSan CHECK:
```txt
ThreadSanitizer: CHECK failed: sanitizer_thread_registry.cpp:348
"((t)) != (0)" (0x0, 0x0) (tid=3351)
#0 __tsan::CheckUnwind() crtstuff.c (some+0x528840) (BuildId: 50d2cc61e1c5...)
#1 __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long)
crtstuff.c (some+0x499844) (BuildId: 50d2cc61e1c5...)
#2 __sanitizer::ThreadRegistry::ConsumeThreadUserId(unsigned long)
crtstuff.c (some+0x498598) (BuildId: 50d2cc61e1c5...)
#3 pthread_detach <null> (some+0x4b74c0) (BuildId: 50d2cc61e1c5...)
#4 PtUtilsLib::Thread::WaitUntilSignaled() (application frame)
...
```
With `TSAN_OPTIONS=verbosity=2` I also see (right before the CHECK) repeated lines like:
```txt
__tls_get_addr: DTLS_Destroy 0x...
__tls_get_addr: DTLS_Destroy 0x...
```
- so the detach seems to happen during thread exit / a TLS destructor path.
**Minimal reproducer?**
I don’t have the library’s sources. However, the symptom is consistent with either:
- a double pthread_detach (or detach after join), or
- a detach in a TLS destructor after TSan has already "consumed" the thread id, or
- a thread created in non-instrumented code such that TSan never registered it, but later intercepts pthread_detach on its pthread_t.
A synthetic mini test that double-detaches does not crash glibc (second call returns EINVAL), so a TSan CHECK here seems unexpected:
```c++
// build: clang -fsanitize=thread -fPIE -pie -O1 -g dd.c -o dd
#include <pthread.h>
#include <stdio.h>
void* fn(void*) { return NULL; }
int main() {
pthread_t th;
int rc = pthread_create(&th, 0, fn, 0);
if (rc) return rc;
int rc1 = pthread_detach(th); // expected 0
int rc2 = pthread_detach(th); // expected EINVAL; with TSan I hit the CHECK above
printf("detach rc1=%d rc2=%d\n", rc1, rc2);
return 0;
}
```
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJyUV0tv27oS_jXMZmBDpvyQFl44dnxP0PSBPFrclUGRY4snEimQlJN0cX77xZByGjenuC1g2BJnOO_5Ziy81weDuGSzSzbbXIg-1NYtP4jwHReT8qKy6mW5tm1nDZrA8hXc1w6FuhNGB_0dHTBeSNt2ukE3coHxkmUrlq3urW1kLbQBxudwROe1NZ5o8yx9wnNg2WrdCHMguQ9Vb0IPkt5P_DApx5PxgnQwfsn4Jc_4LCuyaVZm-YQzfinVIisyXmJW8dHkH3zuJv-cmPgky_lsvCiTUffCHTBAcLprEHqPCvbWQdXrRpEBQjhZz6ejRpv-eXQwPctWN9o8oiNq06jRJIq5EwZcb4JuMRJ0FW3euTAOXpjRIGfMFpeC8bW3bLGBvbMt3Nx8_QiTEjohH8UBz6KRosY4fW6TdEBz1M6aliIfCSxbjeAv4dSTcFH5rfBdhc69wBcNlKY-IHy0qm8QphS21e3HY8H4GlaraFUKxQg-oDPYkIgbchdm48mM2KQ1e33oHSp40qGG9edP2-v_7Fa3H-fT3dfV7vL6_m43LVi-eUlZ2XbOSsa36WK671oPZzdYvpkWJ9VfxAHB6-_RAZhm5Tweb7QPzjK-7T063wkZ6f-1MthIX93d3NLJY7R87IRRttXfcXcUu4F9wyPnsR23reh2zqhdpYOnWwF9QAVH0fToIc_IVx4Dwxfxe07uGAuyFuaAJ1v7Rrc6wOhIMnoT31BF0tUzyj5QkWoPRgR9RLDmNc5v0nlJFQbbRhz8axp_6oLR3g8NxfJNiB0Go_2X6ysYdRphdIDR58mvyuVbLQLUouvQ_FBw2xujzQFCjaCND66nMkIFoutAGAXaHO0jcQjwHUq91xKkVQidCDUEkilF03jQJlgQIBvrUY287Z1E8LWgGml05YSLpfBUa1kTMzojmuYFpEMR0EdlrTBU8JBc84yX4LDRompeQFTWBZ_KTUBsr_VfV-sPLP-XQP2EPpSWyAx7oRuMfXyKpNslbTuHB6qtl7HsOpav8mkRQ8dj_RYRsngJjE9YviFPsnjC4-NzrJT4QyxF0IrlmzyfTVKJAAAwnmew21Hzk835al2jfHwwT9qoqKME6YIP_X4_liTE2xYZv8yeZ7wopifRsUyuowuzTHEp5xOcyNl4PD5TNYHdzr_x_6RvmwLAC1kLR33oE2isKSextX8-703EfgWNNYf49avTk3qAX3kyLctiOv0zT_h7T1J6b4eEDd5Z4_sWE-nBo7smL8_M_D0Li1lZ_JmFOXRDDSkMQtbA8rXpm4blV-eyq8VU_mEep_AlPATd-BtdvXU-PX8TOjyYoJs7fTAiJZbkkwLRdY2WImLP3okWf8glJe9Q4ht1Fptn93erT7vPX-6vP38iRD6iq6zX4SUC5zyDaxCNt-ARSYvThzpAhXvrMKJIasrYuR11NnW_QQ-NfsR_7dXdLjR-d8CwE0rFVt3c39ztNkhA_wLZc7L2N9neOjUCb6NNQ1o8Yush2AEFQfUuYV8EUnzWARjfErrc3IEiwb0M1kWoG7-F0o_a6FY05KKzqpdUl9tXTL0GZQ274qzIWFkS5h5TaAYYfCV5SDDpx_CXfcIjOuos4vQvbRdsSzODWlH7gCYk7EMd6tQH5KAAZfuqwXcVyAvrTn6LfUAHf1ttImStwbrT5cSgzXun06WIs7XwIBoSTxDOZeo0ReBHxg7x0-pM9HCa4J3mCBhrRmczJs4R38thjkRdhsIACYuRZoeOqFT1ARpBFsXRIbEL_mefaca-OQ1DylbgX0yoMWgJrTY6DvmkMcVulO6jB2XRg7EBpBO-hgMtbbGDUVqj4qADh6F3xsPV9aevq5shoN6ezSSo0eFQbr3B5w5liFPnbYHKtKvGotpS3b2umGm5_X_D_vOEBr5SYwkjC0pFQbk2sukVEgQNgRjXLL96R_RBaXsiHS0lbwV7w3gxvESYWlwO_sKnh5sbll8CW2xYttImQCuonoqBLyLLa-gh1CxPZ8TqJNDQPJFTTcS781DHyUlfpD0-lq939xFiZIKTaIeT54InZ5JTJmkA10lMBNEY3VMWIHtzm__x7SHt-WXqxpjza6h1-AF-tKocMQXEaRP20VM-VKmTtEAwPlOkf3hks7WJq8Y60uMPfxOIwfksvaccvBbShVrmqsxLcYHLyWI2LxezeV5e1Eu-L3ie81kxWczzXCzUXFW84GWlclFWubrQy_gnqMymWTFdTMqxWMwln_FyP53OZvliyqYZtkI346Y5tmPrDhfa-x6Xk9m84OVFIypsfPxTyLnBJ4hUcmS2uXBLujSq-oNn06zRPvgfYoIODS7fdAwtZr2jJTTOoN8c8POMup7Ns9M-Pc_gqUbzAyUI4Nk8e5diCu48i7vaGVAxvk1bKEGW1wp_2mjH3jJeXvSuWdYhdPSvIZXIQYe6r8bStoxvyc_hZ9Q5-zfKwPg2Rsczvh3Cd1zy_wUAAP__Y5W5Fw">