Fix GC compaction safety and write barriers in worker_pool.c#172
Open
samuel-williams-shopify wants to merge 1 commit intomainfrom
Open
Fix GC compaction safety and write barriers in worker_pool.c#172samuel-williams-shopify wants to merge 1 commit intomainfrom
samuel-williams-shopify wants to merge 1 commit intomainfrom
Conversation
8e19e94 to
40ceaca
Compare
40ceaca to
e620883
Compare
1. RB_GC_GUARD(_blocking_operation) in worker_pool_call The _blocking_operation VALUE argument is on the calling fiber's C stack. The GC finds it via conservative scan, marks the underlying TypedData object, and prevents collection — keeping the raw C pointer extracted before the fiber switch valid throughout the worker's execution. RB_GC_GUARD ensures the compiler doesn't treat the VALUE as dead before the end of the function. 2. RUBY_TYPED_WB_PROTECTED + compact function Without WB_PROTECTED, RB_OBJ_WRITE (used at worker creation) installed no write barrier. A new compact function updates worker->thread via rb_gc_location for proper compacting GC support. 3. rb_gc_mark_movable for thread objects Changed from rb_gc_mark (which pins) to rb_gc_mark_movable so threads can be relocated by the compacting GC. Co-authored-by: Cursor <cursoragent@cursor.com>
e620883 to
2e301ec
Compare
samuel-williams-shopify
added a commit
to samuel-williams-shopify/ruby
that referenced
this pull request
May 10, 2026
Extract the raw operation pointer before rb_funcall so it is obtained while the GVL is held and no fiber switch has occurred yet. Place RB_GC_GUARD(blocking_operation) after the last implicit use of the VALUE — all accesses via the derived `operation` pointer — so the compiler cannot treat blocking_operation as dead before this point, keeping it reachable as a GC root through rb_funcall and through all subsequent uses of the raw pointer. See: socketry/io-event#172 Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Main bug: stale raw C pointer after GC compaction
worker_pool_callextracted a raw C pointer (rb_fiber_scheduler_blocking_operation_t *) from theblocking_operationTypedData object before yielding the fiber. The compacting GC can move that TypedData object while the calling fiber is suspended, leaving a stale pointer that the worker thread then dereferences — crashing.Fix: store the Ruby VALUE alongside the raw pointer and register all four
Workstruct VALUEs (blocking_operation_value,scheduler,blocker,fiber) as precise GC roots viarb_gc_register_address. The compacting GC updates these in-place when objects move. The worker thread re-extracts the raw pointer from the (now-updated) VALUE right before use.Additional: RUBY_TYPED_WB_PROTECTED + compact function
Without
WB_PROTECTED,RB_OBJ_WRITE(already present at worker creation) installed no write barrier. Adding the flag makes it functional. A newworker_pool_compactfunction updatesworker->threadviarb_gc_locationso thread objects can be moved by the compacting GC.Additional: rb_gc_mark_movable for thread objects
Changed from
rb_gc_mark(which pins objects, preventing compaction) torb_gc_mark_movableso thread objects are eligible for compaction.