diff options
| author | Samuel Williams <samuel.williams@shopify.com> | 2026-05-11 16:56:09 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-05-11 07:56:09 +0000 |
| commit | d0ea61cb87ea3a3d40ef6f90a5ff8dea75fa6f3a (patch) | |
| tree | ebe68ace8c4cdbfbbf84384a01cb2e4c6221be9f | |
| parent | eb053e7446607f5e70215bf508499ef6bab3aa4a (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.c | 8 |
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; |
