Skip to content

Commit bcef706

Browse files
scheduler: rewind CFP after EC_PUSH_TAG on non-local jumps
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. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent eb053e7 commit bcef706

1 file changed

Lines changed: 8 additions & 0 deletions

File tree

scheduler.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,10 +680,14 @@ rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber)
680680
int saved_interrupt_mask = ec->interrupt_mask;
681681
ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
682682

683+
rb_control_frame_t *volatile cfp = ec->cfp;
683684
EC_PUSH_TAG(ec);
684685
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
685686
result = rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
686687
}
688+
else {
689+
rb_vm_rewind_cfp(ec, cfp);
690+
}
687691
EC_POP_TAG();
688692

689693
ec->interrupt_mask = saved_interrupt_mask;
@@ -1145,10 +1149,14 @@ VALUE rb_fiber_scheduler_fiber_interrupt(VALUE scheduler, VALUE fiber, VALUE exc
11451149
int saved_interrupt_mask = ec->interrupt_mask;
11461150
ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
11471151

1152+
rb_control_frame_t *volatile cfp = ec->cfp;
11481153
EC_PUSH_TAG(ec);
11491154
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
11501155
result = rb_check_funcall(scheduler, id_fiber_interrupt, 2, arguments);
11511156
}
1157+
else {
1158+
rb_vm_rewind_cfp(ec, cfp);
1159+
}
11521160
EC_POP_TAG();
11531161

11541162
ec->interrupt_mask = saved_interrupt_mask;

0 commit comments

Comments
 (0)