From 62430c19c9f1ab49429cebe65f30588472648c95 Mon Sep 17 00:00:00 2001 From: Luke Gruber Date: Mon, 18 Aug 2025 10:47:40 -0400 Subject: Properly unlock locked mutexes on thread cleanup. Mutexes were being improperly unlocked on thread cleanup. This bug was introduced in 050a8954395. We must keep a reference from the mutex to the thread, because if the fiber is collected before the mutex is, then we cannot unlink it from the thread in `mutex_free`. If it's not unlinked from the the thread when it's freed, it causes bugs in `rb_thread_unlock_all_locking_mutexes`. We now mark the fiber when a mutex is locked, and the thread is marked as well. However, a fiber can still be freed in the same GC cycle as the mutex, so the reference to the thread is still needed. The reason we need to mark the fiber is that `mutex_owned_p()` has an ABA issue where if the fiber is collected while it's locked, a new fiber could be allocated at the same memory address and we could get false positives. Fixes [Bug #21342] Co-authored-by: John Hawthorn --- thread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'thread.c') diff --git a/thread.c b/thread.c index bab615b9ed..5556100102 100644 --- a/thread.c +++ b/thread.c @@ -442,7 +442,7 @@ rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th) th->keeping_mutexes = mutex->next_mutex; // rb_warn("mutex #<%p> was not unlocked by thread #<%p>", (void *)mutex, (void*)th); - + VM_ASSERT(mutex->fiber); const char *error_message = rb_mutex_unlock_th(mutex, th, mutex->fiber); if (error_message) rb_bug("invalid keeping_mutexes: %s", error_message); } -- cgit v1.2.3