Skip to content

Commit 11b1b5e

Browse files
jbachorikclaude
andcommitted
Fix pthread_key_t sentinel for musl (key 0 is valid)
On musl, pthread_key_create returns key 0 as the first valid key. The key != 0 sentinel in currentSignalSafe() and release() treated this as "uninitialized", causing currentSignalSafe() to always return nullptr on musl. This broke cachedIsJavaThread() caching and crash protection tracking in signal handlers. Replace with an explicit _tls_key_initialized volatile bool flag. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4b7ea59 commit 11b1b5e

2 files changed

Lines changed: 15 additions & 6 deletions

File tree

ddprof-lib/src/main/cpp/thread.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <time.h>
77

88
pthread_key_t ProfiledThread::_tls_key;
9+
volatile bool ProfiledThread::_tls_key_initialized = false;
910
int ProfiledThread::_buffer_size = 0;
1011
volatile int ProfiledThread::_running_buffer_pos = 0;
1112
ProfiledThread** ProfiledThread::_buffer = nullptr;
@@ -17,7 +18,13 @@ void ProfiledThread::initTLSKey() {
1718
pthread_once(&tls_initialized, doInitTLSKey);
1819
}
1920

20-
void ProfiledThread::doInitTLSKey() { pthread_key_create(&_tls_key, freeKey); }
21+
void ProfiledThread::doInitTLSKey() {
22+
pthread_key_create(&_tls_key, freeKey);
23+
// Must be set AFTER pthread_key_create so signal handlers see a valid key.
24+
// volatile write provides sufficient ordering for single-writer (init thread)
25+
// multi-reader (signal handlers on other threads) on all supported architectures.
26+
_tls_key_initialized = true;
27+
}
2128

2229
inline void ProfiledThread::freeKey(void *key) {
2330
ProfiledThread *tls_ref = (ProfiledThread *)(key);
@@ -51,10 +58,10 @@ void ProfiledThread::initCurrentThread() {
5158
}
5259

5360
void ProfiledThread::release() {
54-
pthread_key_t key = _tls_key;
55-
if (key == 0) {
61+
if (!_tls_key_initialized) {
5662
return;
5763
}
64+
pthread_key_t key = _tls_key;
5865
ProfiledThread *tls = (ProfiledThread *)pthread_getspecific(key);
5966
if (tls != NULL) {
6067
pthread_setspecific(key, NULL);
@@ -119,9 +126,10 @@ ProfiledThread *ProfiledThread::current() {
119126
}
120127

121128
ProfiledThread *ProfiledThread::currentSignalSafe() {
122-
// Signal-safe: never allocate, just return existing TLS or null
123-
pthread_key_t key = _tls_key;
124-
return key != 0 ? (ProfiledThread *)pthread_getspecific(key) : nullptr;
129+
// Signal-safe: never allocate, just return existing TLS or null.
130+
// Use _tls_key_initialized instead of key != 0 because pthread_key_create
131+
// can legitimately return key 0 (common on musl where keys start at 0).
132+
return _tls_key_initialized ? (ProfiledThread *)pthread_getspecific(_tls_key) : nullptr;
125133
}
126134

127135
int ProfiledThread::popFreeSlot() {

ddprof-lib/src/main/cpp/thread.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class ProfiledThread : public ThreadLocalData {
3030
// Even with 5 levels cap we will need any highly recursing signal handlers
3131
static constexpr u32 CRASH_HANDLER_NESTING_LIMIT = 5;
3232
static pthread_key_t _tls_key;
33+
static volatile bool _tls_key_initialized;
3334
static int _buffer_size;
3435
static volatile int _running_buffer_pos;
3536
static ProfiledThread** _buffer;

0 commit comments

Comments
 (0)