[前][次][番号順一覧][スレッド一覧]

ruby-changes:37425

From: nobu <ko1@a...>
Date: Thu, 5 Feb 2015 13:41:14 +0900 (JST)
Subject: [ruby-changes:37425] nobu:r49506 (trunk): convert method name to a Symbol

nobu	2015-02-05 13:41:05 +0900 (Thu, 05 Feb 2015)

  New Revision: 49506

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=49506

  Log:
    convert method name to a Symbol
    
    * vm_eval.c (send_internal), vm_insnhelper.c (vm_call_opt_send):
      convert String method name into a Symbol, as method_missing
      method expects its first argument to be a Symbol.  [Bug #10828]

  Modified files:
    trunk/ChangeLog
    trunk/test/-ext-/symbol/test_inadvertent_creation.rb
    trunk/vm_eval.c
    trunk/vm_insnhelper.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 49505)
+++ ChangeLog	(revision 49506)
@@ -1,4 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
-Thu Feb  5 12:31:05 2015  Nobuyoshi Nakada  <nobu@r...>
+Thu Feb  5 13:41:01 2015  Nobuyoshi Nakada  <nobu@r...>
+
+	* vm_eval.c (send_internal), vm_insnhelper.c (vm_call_opt_send):
+	  convert String method name into a Symbol, as method_missing
+	  method expects its first argument to be a Symbol.  [Bug #10828]
 
 	* vm_insnhelper.c (ci_missing_reason): return the reason of method
 	  missing in call info.
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 49505)
+++ vm_eval.c	(revision 49506)
@@ -865,12 +865,22 @@ rb_funcall_with_block(VALUE recv, ID mid https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L865
     return rb_call(recv, mid, argc, argv, CALL_PUBLIC);
 }
 
+static VALUE *
+current_vm_stack_arg(rb_thread_t *th, const VALUE *argv)
+{
+    rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
+    if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, prev_cfp)) return NULL;
+    if (prev_cfp->sp + 1 != argv) return NULL;
+    return prev_cfp->sp + 1;
+}
+
 static VALUE
 send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope)
 {
     ID id;
     VALUE vid;
     VALUE self;
+    VALUE ret, vargv = 0;
     rb_thread_t *th = GET_THREAD();
 
     if (scope == CALL_PUBLIC) {
@@ -893,12 +903,31 @@ send_internal(int argc, const VALUE *arg https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L903
 						 recv, argc, argv);
 	    rb_exc_raise(exc);
 	}
+	if (!SYMBOL_P(*argv)) {
+	    VALUE *tmp_argv = current_vm_stack_arg(th, argv);
+	    vid = rb_str_intern(vid);
+	    if (tmp_argv) {
+		tmp_argv[0] = vid;
+	    }
+	    else if (argc > 1) {
+		tmp_argv = ALLOCV_N(VALUE, vargv, argc);
+		tmp_argv[0] = vid;
+		MEMCPY(tmp_argv+1, argv+1, VALUE, argc-1);
+		argv = tmp_argv;
+	    }
+	    else {
+		argv = &vid;
+	    }
+	}
 	id = idMethodMissing;
-    } else {
+    }
+    else {
 	argv++; argc--;
     }
     PASS_PASSED_BLOCK_TH(th);
-    return rb_call0(recv, id, argc, argv, scope, self);
+    ret = rb_call0(recv, id, argc, argv, scope, self);
+    ALLOCV_END(vargv);
+    return ret;
 }
 
 /*
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 49505)
+++ vm_insnhelper.c	(revision 49506)
@@ -1544,6 +1544,7 @@ vm_call_opt_send(rb_thread_t *th, rb_con https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1544
 	    VALUE exc = make_no_method_exception(rb_eNoMethodError, NULL, ci->recv, rb_long2int(ci->argc), &TOPN(i));
 	    rb_exc_raise(exc);
 	}
+	TOPN(i) = rb_str_intern(sym);
 	ci->mid = idMethodMissing;
 	th->method_missing_reason = ci->aux.missing_reason = ci_missing_reason(ci);
     }
Index: test/-ext-/symbol/test_inadvertent_creation.rb
===================================================================
--- test/-ext-/symbol/test_inadvertent_creation.rb	(revision 49505)
+++ test/-ext-/symbol/test_inadvertent_creation.rb	(revision 49506)
@@ -379,17 +379,17 @@ module Test_Symbol https://github.com/ruby/ruby/blob/trunk/test/-ext-/symbol/test_inadvertent_creation.rb#L379
 
     def test_send_leak_string_custom_method_missing
       x = Object.new
-      def x.method_missing(*); end
+      def x.method_missing(*); super; end
       assert_no_immortal_symbol_created("send should not leak - str mm") do |name|
-        assert_nothing_raised(NoMethodError) {x.send(name)}
+        assert_raise(NoMethodError) {x.send(name)}
       end
     end
 
     def test_send_leak_symbol_custom_method_missing
       x = Object.new
-      def x.method_missing(*); end
+      def x.method_missing(*); super; end
       assert_no_immortal_symbol_created("send should not leak - sym mm") do |name|
-        assert_nothing_raised(NoMethodError) {x.send(name.to_sym)}
+        assert_raise(NoMethodError) {x.send(name.to_sym)}
       end
     end
 
@@ -407,17 +407,17 @@ module Test_Symbol https://github.com/ruby/ruby/blob/trunk/test/-ext-/symbol/test_inadvertent_creation.rb#L407
 
     def test_send_leak_string_custom_method_missing_no_optimization
       x = Object.new
-      def x.method_missing(*); end
+      def x.method_missing(*); super; end
       assert_no_immortal_symbol_created("send should not leak - str mm slow") do |name|
-        assert_nothing_raised(NoMethodError) {x.method(:send).call(name)}
+        assert_raise(NoMethodError) {x.method(:send).call(name)}
       end
     end
 
     def test_send_leak_symbol_custom_method_missing_no_optimization
       x = Object.new
-      def x.method_missing(*); end
+      def x.method_missing(*); super; end
       assert_no_immortal_symbol_created("send should not leak - sym mm slow") do |name|
-        assert_nothing_raised(NoMethodError) {x.method(:send).call(name.to_sym)}
+        assert_raise(NoMethodError) {x.method(:send).call(name.to_sym)}
       end
     end
   end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]