summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Williams <samuel.williams@shopify.com>2026-05-11 16:56:09 +0900
committerGitHub <noreply@github.com>2026-05-11 07:56:09 +0000
commitd0ea61cb87ea3a3d40ef6f90a5ff8dea75fa6f3a (patch)
treeebe68ace8c4cdbfbbf84384a01cb2e4c6221be9f
parenteb053e7446607f5e70215bf508499ef6bab3aa4a (diff)
scheduler: rewind CFP after EC_PUSH_TAG on non-local jumps (#16916)
Both rb_fiber_scheduler_unblock and rb_fiber_scheduler_fiber_interrupt used EC_PUSH_TAG but did not capture ec->cfp beforehand nor call rb_vm_rewind_cfp in the non-TAG_NONE branch. Without this, stale call frames can remain on the stack after an exception or other non-local jump, matching the structure rb_protect uses for the same pattern.
-rw-r--r--scheduler.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/scheduler.c b/scheduler.c
index 3205bb3bc9..7efd4274cb 100644
--- a/scheduler.c
+++ b/scheduler.c
@@ -680,10 +680,14 @@ rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber)
int saved_interrupt_mask = ec->interrupt_mask;
ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
+ rb_control_frame_t *volatile cfp = ec->cfp;
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
result = rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
}
+ else {
+ rb_vm_rewind_cfp(ec, cfp);
+ }
EC_POP_TAG();
ec->interrupt_mask = saved_interrupt_mask;
@@ -1145,10 +1149,14 @@ VALUE rb_fiber_scheduler_fiber_interrupt(VALUE scheduler, VALUE fiber, VALUE exc
int saved_interrupt_mask = ec->interrupt_mask;
ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
+ rb_control_frame_t *volatile cfp = ec->cfp;
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
result = rb_check_funcall(scheduler, id_fiber_interrupt, 2, arguments);
}
+ else {
+ rb_vm_rewind_cfp(ec, cfp);
+ }
EC_POP_TAG();
ec->interrupt_mask = saved_interrupt_mask;