Skip to content

Commit

Permalink
ObjectSpace::WeakMap: fix compaction support
Browse files Browse the repository at this point in the history
[Bug #19529]

`rb_gc_update_tbl_refs` can't be used on `w->obj2wmap` because it's
not a `VALUE -> VALUE` table, but a `VALUE -> VALUE *` table, so
we need some dedicated iterator.
  • Loading branch information
byroot committed Mar 14, 2023
1 parent ac65ce1 commit 548086b
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
8 changes: 8 additions & 0 deletions test/ruby/test_weakmap.rb
Expand Up @@ -176,4 +176,12 @@ def test_no_memory_leak
end
end;
end

def test_compaction_bug_19529
obj = Object.new
100.times do |i|
GC.compact
@wm[i] = obj
end
end
end
37 changes: 36 additions & 1 deletion weakmap.c
Expand Up @@ -12,12 +12,47 @@ struct weakmap {
VALUE final;
};

static int
wmap_replace_ref(st_data_t *key, st_data_t *value, st_data_t _argp, int existing)
{
*key = rb_gc_location((VALUE)*key);

VALUE *values = (VALUE *)value;
VALUE size = values[0];

for (VALUE index = 1; index <= size; index++) {
values[index] = rb_gc_location(values[index]);
}

return ST_CONTINUE;
}

static int
wmap_foreach_replace(st_data_t key, st_data_t value, st_data_t _argp, int error)
{
if (rb_gc_location((VALUE)key) != (VALUE)key) {
return ST_REPLACE;
}

VALUE *values = (VALUE *)value;
VALUE size = values[0];

for (VALUE index = 1; index <= size; index++) {
VALUE val = values[index];
if (rb_gc_location(val) != val) {
return ST_REPLACE;
}
}

return ST_CONTINUE;
}

static void
wmap_compact(void *ptr)
{
struct weakmap *w = ptr;
if (w->wmap2obj) rb_gc_update_tbl_refs(w->wmap2obj);
if (w->obj2wmap) rb_gc_update_tbl_refs(w->obj2wmap);
if (w->obj2wmap) st_foreach_with_replace(w->obj2wmap, wmap_foreach_replace, wmap_replace_ref, (st_data_t)NULL);
w->final = rb_gc_location(w->final);
}

Expand Down

0 comments on commit 548086b

Please sign in to comment.