Skip to content

Commit f2833e3

Browse files
committed
Fix generational GC for weak references
Fixes issue pointed out in https://bugs.ruby-lang.org/issues/21084#note-7. The following script crashes: wmap = ObjectSpace::WeakMap.new GC.disable # only manual GCs GC.start GC.start retain = [] 50.times do k = Object.new wmap[k] = true retain << k end GC.start # wmap promoted, other objects still young retain.clear GC.start(full_mark: false) wmap.keys.each(&:itself) # call method on keys to cause crash
1 parent c05e106 commit f2833e3

2 files changed

Lines changed: 32 additions & 1 deletion

File tree

gc/default/default.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5329,15 +5329,23 @@ rb_gc_impl_handle_weak_references_alive_p(void *objspace_ptr, VALUE obj)
53295329
{
53305330
rb_objspace_t *objspace = objspace_ptr;
53315331

5332-
return RVALUE_MARKED(objspace, obj);
5332+
bool marked = RVALUE_MARKED(objspace, obj);
5333+
5334+
if (marked) {
5335+
rgengc_check_relation(objspace, obj);
5336+
}
5337+
5338+
return marked;
53335339
}
53345340

53355341
static void
53365342
gc_update_weak_references(rb_objspace_t *objspace)
53375343
{
53385344
VALUE *obj_ptr;
53395345
rb_darray_foreach(objspace->weak_references, i, obj_ptr) {
5346+
gc_mark_set_parent(objspace, *obj_ptr);
53405347
rb_gc_handle_weak_references(*obj_ptr);
5348+
gc_mark_set_parent_invalid(objspace);
53415349
}
53425350

53435351
size_t capa = rb_darray_capa(objspace->weak_references);

test/ruby/test_weakmap.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,4 +265,27 @@ def test_use_after_free_bug_20688
265265
10_000.times { weakmap[Object.new] = Object.new }
266266
RUBY
267267
end
268+
269+
def test_generational_gc
270+
EnvUtil.without_gc do
271+
wmap = ObjectSpace::WeakMap.new
272+
273+
(GC::INTERNAL_CONSTANTS[:RVALUE_OLD_AGE] - 1).times { GC.start }
274+
275+
retain = []
276+
50.times do
277+
k = Object.new
278+
wmap[k] = true
279+
retain << k
280+
end
281+
282+
GC.start # WeakMap promoted, other objects still young
283+
284+
retain.clear
285+
286+
GC.start(full_mark: false)
287+
288+
wmap.keys.each(&:itself) # call method on keys to cause crash
289+
end
290+
end
268291
end

0 commit comments

Comments
 (0)