ractor: guard the port VALUE across receive/send

ractor_port_receive/send derive a raw 'struct ractor_port *rp' from self's
embedded (RUBY_TYPED_EMBEDDABLE) data and keep using it across a GC
safepoint: receive parks, and send allocates the basket. self is only kept
alive movably (rb_gc_mark_movable via the VM stack), so a concurrent
GC.compact can relocate the port and leave rp dangling -- the receiver then
polls a stale, reused slot's port id forever (a hang of Ractor#value under
IO + GC.compact). RB_GC_GUARD(self) keeps self on the machine stack, whose
conservative scan pins the port so it cannot move while rp is live.
This commit is contained in:
Koichi Sasada committed 2026-07-14 17:32:41 +09:00
1 parent 6a098a07e5
commit fc6ff6fbcc
1 file changed
+4 -1
Notes: git 2026-07-14 08:33:23 +00:00
+4 -1
View File
@@ -126,7 +126,9 @@ ractor_port_receive(rb_execution_context_t *ec, VALUE self)
rb_raise(rb_eRactorError, "only allowed from the creator Ractor of this port");
}
return ractor_receive(ec, rp);
VALUE v = ractor_receive(ec, rp);
RB_GC_GUARD(self);
return v;
}
static VALUE
@@ -134,6 +136,7 @@ ractor_port_send(rb_execution_context_t *ec, VALUE self, VALUE obj, VALUE move)
{
const struct ractor_port *rp = RACTOR_PORT_PTR(self);
ractor_send(ec, rp, obj, RTEST(move));
RB_GC_GUARD(self);
return self;
}