diff --git a/src/libipc/platform/posix/mutex.h b/src/libipc/platform/posix/mutex.h index 0df842b..8a4ac5f 100644 --- a/src/libipc/platform/posix/mutex.h +++ b/src/libipc/platform/posix/mutex.h @@ -150,6 +150,17 @@ public: void close() noexcept { if ((ref_ != nullptr) && (shm_ != nullptr) && (mutex_ != nullptr)) { + // Try to unlock the mutex before destroying it. + // This is important for robust mutexes on FreeBSD, which maintain + // a per-thread robust list. If we destroy a mutex while it's in + // the robust list (even if not locked), FreeBSD may encounter + // dangling pointers later, leading to segfaults. + // We ignore any errors from unlock() since: + // 1. If we don't hold the lock, EPERM is expected and harmless + // 2. If the mutex is already unlocked, this is a no-op + // 3. If there's an error, we still want to proceed with cleanup + ::pthread_mutex_unlock(mutex_); + if (shm_->name() != nullptr) { release_mutex(shm_->name(), [this] { auto self_ref = ref_->fetch_sub(1, std::memory_order_relaxed); @@ -171,6 +182,9 @@ public: void clear() noexcept { if ((shm_ != nullptr) && (mutex_ != nullptr)) { + // Try to unlock before destroying, same reasoning as in close() + ::pthread_mutex_unlock(mutex_); + if (shm_->name() != nullptr) { release_mutex(shm_->name(), [this] { int eno;