diff options
| author | Luke Gruber <luke.gruber@shopify.com> | 2026-02-06 16:08:57 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-06 16:08:57 -0500 |
| commit | 954094a910c2dcf459caeb61e20143df0864f914 (patch) | |
| tree | 5eeb6fcfdd17a10db4062dff5021e6a12421934b | |
| parent | 7b3370a5579956404d742a2e104d72e7c89480e4 (diff) | |
Take VM Lock during rb_gc_{un}register_address (#16097)
The `Rice` C++ library uses an Anchor class that uses RAII to call
`rb_gc_register_address`, `rb_gc_unregister_address` during init+destruct.
It's unclear if this API is meant to be used at runtime like this, but we can
at least lock the VM so it works safely across Ractors and doesn't mangle the
`global_object_list` table.
| -rw-r--r-- | gc.c | 39 |
1 files changed, 22 insertions, 17 deletions
@@ -3633,9 +3633,11 @@ rb_gc_register_address(VALUE *addr) VALUE obj = *addr; struct global_object_list *tmp = ALLOC(struct global_object_list); - tmp->next = vm->global_object_list; - tmp->varptr = addr; - vm->global_object_list = tmp; + RB_VM_LOCKING() { + tmp->next = vm->global_object_list; + tmp->varptr = addr; + vm->global_object_list = tmp; + } /* * Because some C extensions have assignment-then-register bugs, @@ -3653,22 +3655,25 @@ void rb_gc_unregister_address(VALUE *addr) { rb_vm_t *vm = GET_VM(); - struct global_object_list *tmp = vm->global_object_list; - - if (tmp->varptr == addr) { - vm->global_object_list = tmp->next; - SIZED_FREE(tmp); - return; - } - while (tmp->next) { - if (tmp->next->varptr == addr) { - struct global_object_list *t = tmp->next; + struct global_object_list *tmp; + RB_VM_LOCKING() { + tmp = vm->global_object_list; + if (tmp->varptr == addr) { + vm->global_object_list = tmp->next; + SIZED_FREE(tmp); + } + else { + while (tmp->next) { + if (tmp->next->varptr == addr) { + struct global_object_list *t = tmp->next; - tmp->next = tmp->next->next; - SIZED_FREE(t); - break; + tmp->next = tmp->next->next; + SIZED_FREE(t); + break; + } + tmp = tmp->next; + } } - tmp = tmp->next; } } |
