Skip to content

Commit eac3e97

Browse files
committed
Add a rb_bug() in mutex_free
1 parent e6bc5b4 commit eac3e97

1 file changed

Lines changed: 29 additions & 0 deletions

File tree

thread_sync.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,34 @@ mutex_free(void *ptr)
133133
{
134134
rb_mutex_t *mutex = ptr;
135135
if (mutex_locked_p(mutex)) {
136+
/* A *locked* mutex is being swept. Its owner (mutex->th) must be a
137+
* live thread that is keeping it in keeping_mutexes. Validate the
138+
* owner against the VM's authoritative live-thread set BEFORE
139+
* dereferencing it, so a dangling/garbage owner pointer (heap
140+
* corruption or a freed owner) is caught here with a backtrace
141+
* instead of segfaulting deeper inside thread_mutex_remove(). */
142+
rb_vm_t *vm = GET_VM();
143+
rb_ractor_t *r;
144+
rb_thread_t *i;
145+
int owner_is_live = 0;
146+
ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
147+
ccan_list_for_each(&r->threads.set, i, lt_node) {
148+
if (i == mutex->th) { owner_is_live = 1; break; }
149+
}
150+
if (owner_is_live) break;
151+
}
152+
if (!owner_is_live) {
153+
/* Is the VM tearing down? The main thread is set THREAD_KILLED at
154+
* the very start of rb_ec_cleanup (eval.c) and never reverted, so
155+
* this is a monotonic "shutdown in progress" signal readable from
156+
* any thread without touching mutex->th. */
157+
int in_shutdown = (vm->ractor.main_thread->status == THREAD_KILLED);
158+
rb_bug("mutex_free: locked mutex=%p has dangling owner th=%p "
159+
"(ec_serial=%llu) not in the live-thread set (%s)",
160+
(void *)mutex, (void *)mutex->th,
161+
(unsigned long long)mutex->ec_serial,
162+
in_shutdown ? "VM shutdown in progress" : "not shutdown");
163+
}
136164
thread_mutex_remove(mutex->th, mutex);
137165
}
138166
ruby_xfree(ptr);
@@ -479,6 +507,7 @@ rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t *th, rb_serial_t ec_serial)
479507
struct sync_waiter *cur = 0, *next;
480508

481509
mutex->ec_serial = 0;
510+
mutex->th = 0;
482511
thread_mutex_remove(th, mutex);
483512

484513
ccan_list_for_each_safe(&mutex->waitq, cur, next, node) {

0 commit comments

Comments
 (0)