summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Gruber <luke.gruber@shopify.com>2026-02-06 16:08:57 -0500
committerGitHub <noreply@github.com>2026-02-06 16:08:57 -0500
commit954094a910c2dcf459caeb61e20143df0864f914 (patch)
tree5eeb6fcfdd17a10db4062dff5021e6a12421934b
parent7b3370a5579956404d742a2e104d72e7c89480e4 (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.c39
1 files changed, 22 insertions, 17 deletions
diff --git a/gc.c b/gc.c
index 53a65d6acb..4e1bb39e21 100644
--- a/gc.c
+++ b/gc.c
@@ -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;
}
}