summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNARUSE, Yui <naruse@airemix.jp>2022-02-03 08:04:57 +0900
committerNARUSE, Yui <naruse@airemix.jp>2022-02-03 08:04:57 +0900
commit42c9ef769f210d88241a114395dd5ffc27b2fb87 (patch)
treef264115c882c59b101cb8740358b5870f5ca1744
parent7bef8ed183a336b040f051d7c2133b93364920c6 (diff)
merge revision(s) 7ff1bf317887c0d7b21e91ad548d07b9f05c540c,e89d80702bd98a8276243a7fcaa2a158b3bfb659: [Backport #18516]
An alias can suppress method redefinition warning --- test/ruby/test_alias.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) Fix memory leak at the same named alias [Bug #18516] When aliasing a method to the same name method, set a separate bit flag on that method definition, instead of the reference count increment. Although this kind of alias has no actual effect at runtime, is used as the hack to suppress the method re-definition warning. --- method.h | 1 + test/ruby/test_alias.rb | 18 ++++++++++++++++++ vm_method.c | 9 ++++++++- 3 files changed, 27 insertions(+), 1 deletion(-)
-rw-r--r--method.h1
-rw-r--r--test/ruby/test_alias.rb29
-rw-r--r--version.h2
-rw-r--r--vm_method.c9
4 files changed, 39 insertions, 2 deletions
diff --git a/method.h b/method.h
index 815fd9da47..2f4504bfec 100644
--- a/method.h
+++ b/method.h
@@ -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
diff --git a/version.h b/version.h
index fda7b06b3d..74506d4b45 100644
--- a/version.h
+++ b/version.h
@@ -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;
}