Skip to content

Commit 8aebe2c

Browse files
bneradtclaude
andauthored
Fix intermittent cache unit test segfault in Fedora CI (#13527)
The Fedora CI job fails every so often with a SIGSEGV in one of the cache unit tests, always with the same stack: strrchr() called from SourceLocation::str(), from lock_waiting(), from Mutex_trylock(). In DEBUG builds a thread that fails to acquire a mutex reports the holder's srcloc and handler, but those fields belong to whichever thread holds the mutex, and a waiter that just failed to acquire it holds nothing. That read races with the holder publishing the fields on acquire and clearing them in Mutex_unlock(). Because SourceLocation::str() loads file once for valid() and again for strrchr(), and because the clear happens before the mutex is released, a waiter can pass the validity check and then dereference a null file. The cache unit tests are the only ones that enable the locks debug tag, so they are the only ones that reach this code at all. This patch addresses this by reporting the waiting site rather than the holder's. That SourceLocation is a MakeSourceLocation() temporary owned by the caller, so nothing else can mutate it, and a holder snapshot is stale the instant it is taken in any case. The holder is still reported by lock_holding(), which runs from Mutex_unlock() where the caller owns those fields. Fixes: #13524 Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent f869b9c commit 8aebe2c

1 file changed

Lines changed: 7 additions & 1 deletion

File tree

  • include/iocore/eventsystem

include/iocore/eventsystem/Lock.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,13 @@ Mutex_trylock(
261261
if (m->thread_holding != t) {
262262
if (!ink_mutex_try_acquire(&m->the_mutex)) {
263263
#ifdef DEBUG
264-
lock_waiting(m->srcloc, m->handler);
264+
// Report the waiting site, not the holder's. m->srcloc and m->handler
265+
// belong to whichever thread holds the mutex, and this thread just failed
266+
// to acquire it, so reading them races with the holder publishing them
267+
// below and clearing them in Mutex_unlock(). Any holder snapshot is stale
268+
// the instant it is taken anyway; lock_holding() still reports the holder
269+
// from Mutex_unlock(), where the fields are owned by the caller.
270+
lock_waiting(location, ahandler);
265271
#ifdef LOCK_CONTENTION_PROFILING
266272
m->unsuccessful_nonblocking_acquires++;
267273
m->nonblocking_acquires++;

0 commit comments

Comments
 (0)