diff options
-rw-r--r-- | method.h | 1 | ||||
-rw-r--r-- | test/ruby/test_alias.rb | 18 | ||||
-rw-r--r-- | vm_method.c | 9 |
3 files changed, 27 insertions, 1 deletions
@@ -181,6 +181,7 @@ struct rb_method_definition_struct { unsigned int iseq_overload: 1; int alias_count : 27; int complemented_count : 28; + unsigned int no_redef_warning: 1; union { rb_method_iseq_t iseq; diff --git a/test/ruby/test_alias.rb b/test/ruby/test_alias.rb index c6fad25cc2..99f2223b49 100644 --- a/test/ruby/test_alias.rb +++ b/test/ruby/test_alias.rb @@ -264,4 +264,22 @@ class TestAlias < Test::Unit::TestCase end end; end + + def test_alias_memory_leak + assert_no_memory_leak([], "#{<<~"begin;"}", "#{<<~'end;'}", rss: true) + begin; + class A + 500.times do + 1000.times do |i| + define_method(:"foo_#{i}") {} + + alias :"foo_#{i}" :"foo_#{i}" + + remove_method :"foo_#{i}" + end + GC.start + end + end + end; + end end diff --git a/vm_method.c b/vm_method.c index 6867b5cf8c..b926654bdc 100644 --- a/vm_method.c +++ b/vm_method.c @@ -856,6 +856,7 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil if (RTEST(ruby_verbose) && type != VM_METHOD_TYPE_UNDEF && (old_def->alias_count == 0) && + (!old_def->no_redef_warning) && !make_refined && old_def->type != VM_METHOD_TYPE_UNDEF && old_def->type != VM_METHOD_TYPE_ZSUPER && @@ -1086,7 +1087,13 @@ method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me, rb_method_visibility_t visi, VALUE defined_class) { rb_method_entry_t *newme = rb_method_entry_make(klass, mid, defined_class, visi, - me->def->type, method_definition_addref(me->def), 0, NULL); + me->def->type, me->def, 0, NULL); + if (newme == me) { + me->def->no_redef_warning = TRUE; + } + else { + method_definition_addref(me->def); + } method_added(klass, mid); return newme; } |