summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--test/ruby/test_alias.rb47
-rw-r--r--vm_method.c11
3 files changed, 63 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 34303eb..75d731c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Thu Mar 20 12:31:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c (rb_method_entry_get_without_cache): get rid of
+ infinite recursion at aliases in a subclass and a superclass.
+ return actually defined class for other than singleton class.
+ [ruby-core:60431] [Bug #9475]
+
Wed Mar 19 17:13:06 2014 Eric Wong <e@80x24.org>
* time.c (time_mload): freeze and preserve marshal-loaded time zone
diff --git a/test/ruby/test_alias.rb b/test/ruby/test_alias.rb
index 956fdb4..4e1db2e 100644
--- a/test/ruby/test_alias.rb
+++ b/test/ruby/test_alias.rb
@@ -132,4 +132,51 @@ class TestAlias < Test::Unit::TestCase
GC.verify_internal_consistency
}
end
+
+ def test_cyclic_zsuper
+ bug9475 = '[ruby-core:60431] [Bug #9475]'
+
+ a = Module.new do
+ def foo
+ "A"
+ end
+ end
+
+ b = Class.new do
+ include a
+ attr_reader :b
+
+ def foo
+ @b ||= 0
+ raise SystemStackError if (@b += 1) > 1
+ # "foo from B"
+ super + "B"
+ end
+ end
+
+ c = Class.new(b) do
+ alias orig_foo foo
+
+ def foo
+ # "foo from C"
+ orig_foo + "C"
+ end
+ end
+
+ b.class_eval do
+ alias orig_foo foo
+ attr_reader :b2
+
+ def foo
+ @b2 ||= 0
+ raise SystemStackError if (@b2 += 1) > 1
+ # "foo from B (again)"
+ orig_foo + "B2"
+ end
+ end
+
+ assert_nothing_raised(SystemStackError, bug9475) do
+ assert_equal("ABC", c.new.foo, bug9475)
+ end
+ end
end
diff --git a/vm_method.c b/vm_method.c
index ff694ea..2279190 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -578,8 +578,15 @@ rb_method_entry_get_without_cache(VALUE klass, ID id,
VALUE defined_class;
rb_method_entry_t *me = search_method(klass, id, &defined_class);
- if (me && RB_TYPE_P(me->klass, T_ICLASS))
- defined_class = me->klass;
+ if (me) {
+ switch (BUILTIN_TYPE(me->klass)) {
+ case T_CLASS:
+ if (RBASIC(klass)->flags & FL_SINGLETON) break;
+ /* fall through */
+ case T_ICLASS:
+ defined_class = me->klass;
+ }
+ }
if (ruby_running) {
if (OPT_GLOBAL_METHOD_CACHE) {