[#39548] [Bug #2291] Net::FTPでソケットをオープンする前にbinary=を呼び出すと落ちる — Akira Matsuda <redmine@...>

Bug #2291: Net::FTPでソケットをオープンする前にbinary=を呼び出すと落ちる

10 messages 2009/10/27

[#39592] infinite recursive call to C function — Yusuke ENDOH <mame@...>

遠藤です。

17 messages 2009/10/30
[#39596] Re: infinite recursive call to C function — Yukihiro Matsumoto <matz@...> 2009/10/30

まつもと ゆきひろです

[#39599] Re: infinite recursive call to C function — Nobuyoshi Nakada <nobu@...> 2009/11/02

なかだです。

[#39601] Re: infinite recursive call to C function — Yukihiro Matsumoto <matz@...> 2009/11/02

まつもと ゆきひろです

[ruby-dev:39581] [Bug:trunk] NoMethodError message "no superclass method"

From: Nobuyoshi Nakada <nobu@...>
Date: 2009-10-30 03:43:53 UTC
List: ruby-dev #39581
なかだです。

trunkで組み込みのメソッドからのNoMethodErrorのメッセージが"no
superclass method"になりません。

$ ./ruby -v -e 'module Enumerable;undef min;end; (1..2).min{}'
ruby 1.9.2dev (2009-10-30 trunk 25565) [universal.x86_64-darwin9.0]
-e:1:in `min': undefined method `min' for 1..2:Range (NoMethodError)
	from -e:1:in `<main>'

一方、__send__を使うとsuperとは無関係なのに出てしまいます。

$ ./ruby -e 'Object.new.method(:__send__).call(:foo)'
-e:1:in `call': super: no superclass method `foo' for #<Object:0x000001002f93f0> (NoMethodError)
	from -e:1:in `<main>'

しかも、もう一度同じメソッドを呼ぶと二回目には出ません。

$ ./ruby -e '2.times{begin Object.new.method(:__send__).call(:foo); rescue NoMethodError => e; puts e.message; end}'
super: no superclass method `foo' for #<Object:0x000001002e2f10>
undefined method `foo' for #<Object:0x000001002e2c68>


Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 25565)
+++ vm_eval.c	(working copy)
@@ -22,5 +22,4 @@ static VALUE vm_exec(rb_thread_t *th);
 static void vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref);
 static int vm_collect_local_variables_in_heap(rb_thread_t *th, VALUE *dfp, VALUE ary);
-static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, int scope);
 
 typedef enum call_type {
@@ -30,4 +29,6 @@ typedef enum call_type {
 } call_type;
 
+static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope);
+
 static inline VALUE
 vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
@@ -105,5 +106,5 @@ vm_call0(rb_thread_t* th, VALUE recv, VA
 	klass = RCLASS_SUPER(klass);
 	if (!klass || !(me = rb_method_entry(klass, id))) {
-	    return method_missing(recv, id, argc, argv, 0);
+	    return method_missing(recv, id, argc, argv, NOEX_SUPER);
 	}
 	RUBY_VM_CHECK_INTS();
@@ -122,5 +123,5 @@ vm_call0(rb_thread_t* th, VALUE recv, VA
 	switch (def->body.optimize_type) {
 	  case OPTIMIZED_METHOD_TYPE_SEND:
-	    val = send_internal(argc, argv, recv, NOEX_NOSUPER | NOEX_PRIVATE);
+	    val = send_internal(argc, argv, recv, CALL_FCALL);
 	    break;
 	  case OPTIMIZED_METHOD_TYPE_CALL: {
@@ -176,5 +177,5 @@ vm_call_super(rb_thread_t *th, int argc,
     me = rb_method_entry(klass, id);
     if (!me) {
-	return method_missing(recv, id, argc, argv, 0);
+	return method_missing(recv, id, argc, argv, NOEX_SUPER);
     }
 
@@ -220,5 +221,4 @@ rb_call0(VALUE recv, ID mid, int argc, c
     VALUE klass = CLASS_OF(recv);
     rb_method_entry_t *me;
-    struct cache_entry *ent;
     rb_thread_t *th = GET_THREAD();
     ID oid;
@@ -234,26 +234,10 @@ rb_call0(VALUE recv, ID mid, int argc, c
     }
 
-    /* is it in the method cache? */
-    ent = cache + EXPR1(klass, mid);
-
-    if (ent->mid == mid && ent->klass == klass) {
-	me = ent->me;
-	if (UNDEFINED_METHOD_ENTRY_P(me)) {
-	    return method_missing(recv, mid, argc, argv,
-				  scope == CALL_VCALL ? NOEX_VCALL : 0);
-	}
-	klass = me->klass;
-    }
-    else if ((me = rb_method_entry_without_cache(klass, mid)) != 0 && me->def) {
-	klass = me->klass;
-    }
-    else {
-	if (scope == 3) {
-	    return method_missing(recv, mid, argc, argv, NOEX_SUPER);
-	}
+    me = rb_method_entry(klass, mid);
+    if (UNDEFINED_METHOD_ENTRY_P(me)) {
 	return method_missing(recv, mid, argc, argv,
 			      scope == CALL_VCALL ? NOEX_VCALL : 0);
     }
-
+    klass = me->klass;
     oid = me->def->original_id;
     noex = me->flag;
@@ -580,5 +564,5 @@ rb_funcall_no_recursive(VALUE obj, ID id
 
 static VALUE
-send_internal(int argc, const VALUE *argv, VALUE recv, int scope)
+send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope)
 {
     VALUE vid;
@@ -617,5 +601,5 @@ VALUE
 rb_f_send(int argc, VALUE *argv, VALUE recv)
 {
-    return send_internal(argc, argv, recv, NOEX_NOSUPER | NOEX_PRIVATE);
+    return send_internal(argc, argv, recv, CALL_FCALL);
 }
 
@@ -634,5 +618,5 @@ VALUE
 rb_f_public_send(int argc, VALUE *argv, VALUE recv)
 {
-    return send_internal(argc, argv, recv, NOEX_PUBLIC);
+    return send_internal(argc, argv, recv, CALL_PUBLIC);
 }
 
Index: test/ruby/test_object.rb
===================================================================
--- test/ruby/test_object.rb	(revision 25565)
+++ test/ruby/test_object.rb	(working copy)
@@ -378,4 +378,25 @@ class TestObject < Test::Unit::TestCase
   end
 
+  def test_no_superclass_method
+    o = Object.new
+    e = assert_raise(NoMethodError) {
+      o.method(:__send__).call(:never_defined_test_no_superclass_method)
+    }
+    m1 = e.message
+    assert_no_match(/no superclass method/, m1)
+    e = assert_raise(NoMethodError) {
+      o.method(:__send__).call(:never_defined_test_no_superclass_method)
+    }
+    assert_equal(m1, e.message)
+    e = assert_raise(NoMethodError) {
+      o.never_defined_test_no_superclass_method
+    }
+    assert_equal(m1, e.message)
+  end
+
+  def test_superclass_method
+    assert_in_out_err(["-e", "module Enumerable;undef min;end; (1..2).min{}"], [], [], /no superclass method/)
+  end
+
   def test_specific_eval_with_wrong_arguments
     assert_raise(ArgumentError) do


-- 
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
    中田 伸悦

In This Thread

Prev Next