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
@@ -164,6 +164,7 @@ struct rb_method_definition_struct { BITFIELD(rb_method_type_t, type, VM_METHOD_TYPE_MINIMUM_BITS); int alias_count : 28; 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 33fb82e1d7..1acf12f7f3 100644 --- a/test/ruby/test_alias.rb +++ b/test/ruby/test_alias.rb @@ -227,4 +227,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 @@ -2,7 +2,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 6 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 214 +#define RUBY_PATCHLEVEL 215 #define RUBY_RELEASE_YEAR 2022 #define RUBY_RELEASE_MONTH 3 diff --git a/vm_method.c b/vm_method.c index 3c087841dc..270334ea1b 100644 --- a/vm_method.c +++ b/vm_method.c @@ -584,6 +584,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 && @@ -698,7 +699,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; } |