mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Fix id2ref table build when GC in progress
Previously, if GC was in progress when we're initially building the id2ref table, it could see the empty table and then crash when trying to remove ids from it. This commit fixes the bug by only publishing the table after GC is done. Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
This commit is contained in:
parent
07878ebe78
commit
d80c03d22a
2 changed files with 20 additions and 2 deletions
7
gc.c
7
gc.c
|
@ -1975,14 +1975,17 @@ object_id_to_ref(void *objspace_ptr, VALUE object_id)
|
|||
// GC Must not trigger while we build the table, otherwise if we end
|
||||
// up freeing an object that had an ID, we might try to delete it from
|
||||
// the table even though it wasn't inserted yet.
|
||||
id2ref_tbl = st_init_table(&object_id_hash_type);
|
||||
id2ref_value = TypedData_Wrap_Struct(0, &id2ref_tbl_type, id2ref_tbl);
|
||||
st_table *tmp_id2ref_tbl = st_init_table(&object_id_hash_type);
|
||||
VALUE tmp_id2ref_value = TypedData_Wrap_Struct(0, &id2ref_tbl_type, tmp_id2ref_tbl);
|
||||
|
||||
// build_id2ref_i will most certainly malloc, which could trigger GC and sweep
|
||||
// objects we just added to the table.
|
||||
// By calling rb_gc_disable() we also save having to handle potentially garbage objects.
|
||||
bool gc_disabled = RTEST(rb_gc_disable());
|
||||
{
|
||||
id2ref_tbl = tmp_id2ref_tbl;
|
||||
id2ref_value = tmp_id2ref_value;
|
||||
|
||||
rb_gc_impl_each_object(objspace, build_id2ref_i, (void *)id2ref_tbl);
|
||||
}
|
||||
if (!gc_disabled) rb_gc_enable();
|
||||
|
|
|
@ -284,6 +284,21 @@ End
|
|||
end;
|
||||
end
|
||||
|
||||
def test_id2ref_table_build
|
||||
assert_separately([], <<-End)
|
||||
10.times do
|
||||
Object.new.object_id
|
||||
end
|
||||
|
||||
GC.start(immediate_mark: false)
|
||||
|
||||
obj = Object.new
|
||||
EnvUtil.suppress_warning do
|
||||
assert_equal obj, ObjectSpace._id2ref(obj.object_id)
|
||||
end
|
||||
End
|
||||
end
|
||||
|
||||
def test_each_object_singleton_class
|
||||
assert_separately([], <<-End)
|
||||
class C
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue