Fix segfault in EOWNERDEAD handling - remove incorrect ref count manipulation

Root cause: The previous code incorrectly called shm_->sub_ref() when handling
EOWNERDEAD, which could cause the shared memory to be freed prematurely while
the mutex pointer was still in use, leading to segmentation fault.

Fix: Remove the shm_->sub_ref() call. When EOWNERDEAD is returned, it means
we have successfully acquired the lock. We only need to call pthread_mutex_consistent()
to make the mutex usable again, then return success. The shared memory reference
count should not be modified in this path.

This fixes the segfault in MutexTest.TryLockExceptionSafety on FreeBSD 15.
This commit is contained in:
木头云 2025-12-06 06:21:38 +00:00
parent a82e3faf63
commit 47fa303455

View File

@ -206,19 +206,15 @@ public:
case ETIMEDOUT:
return false;
case EOWNERDEAD: {
if (shm_->ref() > 1) {
shm_->sub_ref();
}
// EOWNERDEAD means we have successfully acquired the lock,
// but the previous owner died. We need to make it consistent.
int eno2 = ::pthread_mutex_consistent(mutex_);
if (eno2 != 0) {
ipc::error("fail pthread_mutex_lock[%d], pthread_mutex_consistent[%d]\n", eno, eno2);
return false;
}
// EOWNERDEAD means we have successfully acquired the lock,
// but the previous owner died. After calling pthread_mutex_consistent(),
// the mutex is now in a consistent state and we hold the lock.
// We should return success here, not unlock and retry.
// This avoids issues with FreeBSD's robust mutex list management.
// After calling pthread_mutex_consistent(), the mutex is now in a
// consistent state and we hold the lock. Return success.
return true;
}
default:
@ -238,15 +234,15 @@ public:
case ETIMEDOUT:
return false;
case EOWNERDEAD: {
if (shm_->ref() > 1) {
shm_->sub_ref();
}
// EOWNERDEAD means we have successfully acquired the lock,
// but the previous owner died. We need to make it consistent.
int eno2 = ::pthread_mutex_consistent(mutex_);
if (eno2 != 0) {
ipc::error("fail pthread_mutex_timedlock[%d], pthread_mutex_consistent[%d]\n", eno, eno2);
throw std::system_error{eno2, std::system_category()};
}
// Successfully acquired the lock after making it consistent
// After calling pthread_mutex_consistent(), the mutex is now in a
// consistent state and we hold the lock. Return success.
return true;
}
default: