Guard fiber target across fiber_store. (#17957)

[Bug #22196]
This commit is contained in:
Samuel Williams 2026-07-18 10:18:24 +12:00 committed by GitHub
parent 0f5e45d8cf
commit 84a27934cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
Notes: git 2026-07-17 22:18:53 +00:00
Merged-By: ioquatix <samuel@codeotaku.com>
2 changed files with 42 additions and 0 deletions

8
cont.c
View File

@ -2869,6 +2869,13 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fi
VM_ASSERT(FIBER_RUNNABLE_P(fiber));
/*
* Keep the target fiber object alive across fiber_store. The raw
* rb_fiber_t pointer is used after the coroutine switch, and GC may run
* while this C frame is suspended.
*/
VALUE fiber_value = fiber->cont.self;
rb_fiber_t *current_fiber = fiber_current();
VM_ASSERT(!current_fiber->resuming_fiber);
@ -2902,6 +2909,7 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fi
}
}
#endif
RB_GC_GUARD(fiber_value);
if (fiber_current()->blocking) {
th->blocking += 1;

View File

@ -497,6 +497,40 @@ class TestFiber < Test::Unit::TestCase
assert_equal :ok, ret, '[Bug #14642]'
end
def test_gc_during_nested_resume_yield
assert_normal_exit <<-'RUBY', '[Bug #22196]', timeout: 10
parent = child1 = child2 = nil
parent = Fiber.new do
child1 = Fiber.new do
parent.resume
end
child2 = Fiber.new do
GC.start
parent.resume
end
Fiber.yield
child1 = nil
Fiber.yield
end
parent.resume
child = child1
child1 = nil
child.resume
child = nil
child = child2
child2 = nil
child.resume
RUBY
end
def test_machine_stack_gc
assert_normal_exit <<-RUBY, '[Bug #14561]', timeout: 60
enum = Enumerator.new { |y| y << 1 }