Skip to content

Commit 8f2cfc0

Browse files
samuel-williams-shopifyXrXr
authored andcommitted
Guard fiber target across fiber_store. (rubyGH-17957) [Backport #22196]
1 parent 41d79e8 commit 8f2cfc0

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

cont.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2791,6 +2791,13 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fi
27912791

27922792
VM_ASSERT(FIBER_RUNNABLE_P(fiber));
27932793

2794+
/*
2795+
* Keep the target fiber object alive across fiber_store. The raw
2796+
* rb_fiber_t pointer is used after the coroutine switch, and GC may run
2797+
* while this C frame is suspended.
2798+
*/
2799+
VALUE fiber_value = fiber->cont.self;
2800+
27942801
rb_fiber_t *current_fiber = fiber_current();
27952802

27962803
VM_ASSERT(!current_fiber->resuming_fiber);
@@ -2824,6 +2831,7 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fi
28242831
}
28252832
}
28262833
#endif
2834+
RB_GC_GUARD(fiber_value);
28272835

28282836
if (fiber_current()->blocking) {
28292837
th->blocking += 1;

test/ruby/test_fiber.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,40 @@ def test_create_fiber_in_new_thread
497497
assert_equal :ok, ret, '[Bug #14642]'
498498
end
499499

500+
def test_gc_during_nested_resume_yield
501+
assert_normal_exit <<-'RUBY', '[Bug #22196]', timeout: 10
502+
parent = child1 = child2 = nil
503+
504+
parent = Fiber.new do
505+
child1 = Fiber.new do
506+
parent.resume
507+
end
508+
509+
child2 = Fiber.new do
510+
GC.start
511+
parent.resume
512+
end
513+
514+
Fiber.yield
515+
516+
child1 = nil
517+
518+
Fiber.yield
519+
end
520+
521+
parent.resume
522+
523+
child = child1
524+
child1 = nil
525+
child.resume
526+
child = nil
527+
528+
child = child2
529+
child2 = nil
530+
child.resume
531+
RUBY
532+
end
533+
500534
def test_machine_stack_gc
501535
assert_normal_exit <<-RUBY, '[Bug #14561]', timeout: 60
502536
enum = Enumerator.new { |y| y << 1 }

0 commit comments

Comments
 (0)