aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2020-06-09 16:30:55 -0700
committerGitHub <noreply@github.com>2020-06-09 16:30:55 -0700
commitad0eccf840f692694e63ec72c8496dc106e603ed (patch)
treef65375353ae6f7ed357a04356f6b6e3abe9240da
parent9491bd89dace4fa26f1e5333d0ebbca14749eb3e (diff)
downloadruby-ad0eccf840f692694e63ec72c8496dc106e603ed.tar.gz
Work around infinite loop when overriding method visibility in prepended module (#3201)
For ZSUPER methods with no defined class for the method entry, start the next lookup at the superclass of the origin class of the method owner, instead of the superclass of the method owner. Fixes [Bug #16942]
-rw-r--r--proc.c4
-rw-r--r--test/ruby/test_method.rb21
2 files changed, 23 insertions, 2 deletions
diff --git a/proc.c b/proc.c
index 38d4fc6bf7..249bc65a70 100644
--- a/proc.c
+++ b/proc.c
@@ -1572,12 +1572,12 @@ mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass,
}
if (me->def->type == VM_METHOD_TYPE_ZSUPER) {
if (me->defined_class) {
- VALUE klass = RCLASS_SUPER(RCLASS_ORIGIN(me->defined_class));
+ VALUE klass = RCLASS_SUPER(RCLASS_ORIGIN(me->defined_class));
id = me->def->original_id;
me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(klass, id, &iclass);
}
else {
- VALUE klass = RCLASS_SUPER(me->owner);
+ VALUE klass = RCLASS_SUPER(RCLASS_ORIGIN(me->owner));
id = me->def->original_id;
me = rb_method_entry_without_refinements(klass, id, &iclass);
}
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
index 12f6f9aa27..43c6c6d44b 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -1181,6 +1181,27 @@ class TestMethod < Test::Unit::TestCase
assert_separately [], "RubyVM::InstructionSequence.compile_option = {trace_instruction: false}\n" + body
end
+ def test_zsuper_private_override_instance_method
+ assert_separately(%w(--disable-gems), <<-'end;', timeout: 30)
+ # Bug #16942 [ruby-core:98691]
+ module M
+ def x
+ end
+ end
+
+ module M2
+ prepend Module.new
+ include M
+ private :x
+ end
+
+ ::Object.prepend(M2)
+
+ m = Object.instance_method(:x)
+ assert_equal M, m.owner
+ end;
+ end
+
def test_eqq
assert_operator(0.method(:<), :===, 5)
assert_not_operator(0.method(:<), :===, -5)