diff options
-rw-r--r-- | method.h | 1 | ||||
-rw-r--r-- | test/ruby/test_alias.rb | 29 | ||||
-rw-r--r-- | version.h | 2 | ||||
-rw-r--r-- | vm_method.c | 9 |
4 files changed, 39 insertions, 2 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 271d552bf5..99f2223b49 100644 --- a/test/ruby/test_alias.rb +++ b/test/ruby/test_alias.rb @@ -253,4 +253,33 @@ class TestAlias < Test::Unit::TestCase assert_equal(:foo, k.instance_method(:bar).original_name) assert_equal(:foo, name) end + + def test_alias_suppressing_redefinition + assert_in_out_err(%w[-w], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + class A + def foo; end + alias foo foo + def foo; end + 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 @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 0 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 12 +#define RUBY_PATCHLEVEL 13 #define RUBY_RELEASE_YEAR 2022 #define RUBY_RELEASE_MONTH 2 diff --git a/vm_method.c b/vm_method.c index 38d03fbe2b..d1cfd232e5 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; } |