Skip to content

Commit 588347a

Browse files
committed
Fix id2ref for multi-Ractor
The id2ref table needs to be under a VM lock to ensure there are no race conditions. The following script crashes: o = Object.new ObjectSpace._id2ref(o.object_id) 10.times.map do Ractor.new do 10_000.times do a = Object.new a.object_id end end end.map(&:value) With: [BUG] Object ID seen, but not in _id2ref table: object_id=2800 object=T_OBJECT ruby 4.0.0dev (2025-12-06T15:15:43Z ractor-id2ref-fix e7f9abd) +PRISM [x86_64-linux] -- Control frame information ----------------------------------------------- c:0001 p:---- s:0003 e:000002 l:y b:---- DUMMY [FINISH] -- Threading information --------------------------------------------------- Total ractor count: 5 Ruby thread count for this ractor: 1 -- C level backtrace information ------------------------------------------- miniruby(rb_print_backtrace+0x14) [0x6047d09b2dff] vm_dump.c:1105 miniruby(rb_vm_bugreport) vm_dump.c:1450 miniruby(rb_bug_without_die_internal+0x5f) [0x6047d066bf57] error.c:1098 miniruby(rb_bug) error.c:1116 miniruby(rb_gc_get_ractor_newobj_cache+0x0) [0x6047d066c8dd] gc.c:2052 miniruby(gc_sweep_plane+0xad) [0x6047d079276d] gc/default/default.c:3513 miniruby(gc_sweep_page) gc/default/default.c:3605 miniruby(gc_sweep_step) gc/default/default.c:3886 miniruby(gc_sweep+0x1ba) [0x6047d0794cfa] gc/default/default.c:4154 miniruby(gc_start+0xbf2) [0x6047d0796742] gc/default/default.c:6519 miniruby(heap_prepare+0xcc) [0x6047d079748c] gc/default/default.c:2090 miniruby(heap_next_free_page) gc/default/default.c:2305 miniruby(newobj_cache_miss) gc/default/default.c:2412 miniruby(newobj_alloc+0xd) [0x6047d0798ff5] gc/default/default.c:2436 miniruby(rb_gc_impl_new_obj) gc/default/default.c:2515 miniruby(newobj_of) gc.c:996 miniruby(rb_wb_protected_newobj_of) gc.c:1046 miniruby(str_alloc_embed+0x28) [0x6047d08fda18] string.c:1019 miniruby(str_enc_new) string.c:1069 miniruby(prep_io+0x5) [0x6047d07cda14] io.c:9305 miniruby(prep_stdio) io.c:9347 miniruby(rb_io_prep_stdin) io.c:9365 miniruby(thread_start_func_2+0x77c) [0x6047d093a55c] thread.c:679 miniruby(thread_sched_lock_+0x0) [0x6047d093aacd] thread_pthread.c:2241 miniruby(co_start) thread_pthread_mn.c:469
1 parent 87bc106 commit 588347a

File tree

2 files changed

+20
-1
lines changed

2 files changed

+20
-1
lines changed

bootstraptest/test_ractor.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,23 @@ class C
11161116
end.value
11171117
RUBY
11181118

1119+
# Inserting into the id2ref table should be Ractor-safe
1120+
assert_equal 'ok', <<~'RUBY'
1121+
# Force all calls to Kernel#object_id to insert into the id2ref table
1122+
ObjectSpace._id2ref(Object.new.object_id)
1123+
1124+
10.times.map do
1125+
Ractor.new do
1126+
10_000.times do
1127+
a = Object.new
1128+
a.object_id
1129+
end
1130+
end
1131+
end.map(&:value)
1132+
1133+
:ok
1134+
RUBY
1135+
11191136
# Ractor.make_shareable(obj)
11201137
assert_equal 'true', <<~'RUBY', frozen_string_literal: false
11211138
class C

gc.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1905,7 +1905,9 @@ object_id0(VALUE obj)
19051905
RUBY_ASSERT(rb_shape_obj_has_id(obj));
19061906

19071907
if (RB_UNLIKELY(id2ref_tbl)) {
1908-
st_insert(id2ref_tbl, (st_data_t)id, (st_data_t)obj);
1908+
RB_VM_LOCKING() {
1909+
st_insert(id2ref_tbl, (st_data_t)id, (st_data_t)obj);
1910+
}
19091911
}
19101912
return id;
19111913
}

0 commit comments

Comments
 (0)