variable.c: fix autoload object lifetimes and leak

We must not call normal Hash methods inside GC free callback,
either, however identity hash may be used.

[ruby-core:86935] [Bug #14742]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63389 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
normal 2018-05-10 04:18:28 +00:00
parent 23c74845ed
commit 6726038d76
2 changed files with 19 additions and 6 deletions

View File

@ -335,6 +335,18 @@ p Foo::Bar
end
end
def test_no_leak
assert_no_memory_leak([], '', <<~'end;', 'many autoloads', timeout: 30)
200000.times do |i|
m = Module.new
m.instance_eval do
autoload :Foo, 'x'
autoload :Bar, i.to_s
end
end
end;
end
def add_autoload(path)
(@autoload_paths ||= []) << path
::Object.class_eval {autoload(:AutoloadTest, path)}

View File

@ -1908,6 +1908,7 @@ autoload_c_free(void *ptr)
{
struct autoload_const *ac = ptr;
list_del(&ac->cnode);
xfree(ac);
}
static size_t
@ -1990,7 +1991,7 @@ rb_autoload_str(VALUE mod, ID id, VALUE file)
}
file = rb_fstring(file);
if (!autoload_featuremap) {
autoload_featuremap = rb_hash_new();
autoload_featuremap = rb_hash_new_compare_by_id();
rb_obj_hide(autoload_featuremap);
rb_gc_register_mark_object(autoload_featuremap);
}
@ -2036,13 +2037,13 @@ autoload_delete(VALUE mod, ID id)
ele = get_autoload_data((VALUE)load, &ac);
VM_ASSERT(!list_empty(&ele->constants));
/* list_del_init to make list_del in autoload_c_free idempotent: */
/*
* we must delete here to avoid "already initialized" warnings
* with parallel autoload. list_del_init makes list_del in
* autoload_c_free idempotent
*/
list_del_init(&ac->cnode);
if (list_empty(&ele->constants)) {
rb_hash_delete(autoload_featuremap, ele->feature);
}
if (tbl->num_entries == 0) {
n = autoload;
st_delete(RCLASS_IV_TBL(mod), &n, &val);