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

ruby-changes:50929

From: nobu <ko1@a...>
Date: Thu, 12 Apr 2018 12:48:53 +0900 (JST)
Subject: [ruby-changes:50929] nobu:r63136 (trunk): error.c: super in method_missing

nobu	2018-04-12 12:48:48 +0900 (Thu, 12 Apr 2018)

  New Revision: 63136

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

  Log:
    error.c: super in method_missing
    
    * error.c (nometh_err_initialize): do not shirtcut rb_call_super,
      to push proper control frame.  [ruby-dev:50522] [Bug #14670]
    
    * error.c (rb_nomethod_err_new): allocate and initialize a new
      NoMethodError instance.
    
    * vm_eval.c (rb_make_no_method_exception): create a new exception
      instance directly without method calls, to prevent influence of
      ruby level method definitions, which can cause an unpredictable
      behavior, e.g., infinite recursion.

  Modified files:
    trunk/error.c
    trunk/internal.h
    trunk/test/ruby/test_exception.rb
    trunk/vm_eval.c
Index: internal.h
===================================================================
--- internal.h	(revision 63135)
+++ internal.h	(revision 63136)
@@ -1220,6 +1220,7 @@ VALUE rb_name_err_new(VALUE mesg, VALUE https://github.com/ruby/ruby/blob/trunk/internal.h#L1220
     rb_exc_raise(rb_name_err_new(mesg, recv, name))
 #define rb_name_err_raise(mesg, recv, name) \
     rb_name_err_raise_str(rb_fstring_cstr(mesg), (recv), (name))
+VALUE rb_nomethod_err_new(VALUE mesg, VALUE recv, VALUE method, VALUE args, int priv);
 VALUE rb_key_err_new(VALUE mesg, VALUE recv, VALUE name);
 #define rb_key_err_raise(mesg, recv, name) \
     rb_exc_raise(rb_key_err_new(mesg, recv, name))
Index: test/ruby/test_exception.rb
===================================================================
--- test/ruby/test_exception.rb	(revision 63135)
+++ test/ruby/test_exception.rb	(revision 63136)
@@ -1320,4 +1320,20 @@ $stderr = $stdout; raise "\x82\xa0"') do https://github.com/ruby/ruby/blob/trunk/test/ruby/test_exception.rb#L1320
     end;
     assert_in_out_err([], code, [], /Bug14566/, success: false, timeout: 1)
   end
+
+  def test_super_in_method_missing
+    assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+    begin;
+      class Object
+        def method_missing(name, *args, &block)
+          super
+        end
+      end
+
+      bug14670 = '[ruby-dev:50522] [Bug #14670]'
+      assert_raise_with_message(NoMethodError, /`foo'/, bug14670) do
+        Object.new.foo
+      end
+    end;
+  end
 end
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 63135)
+++ vm_eval.c	(revision 63136)
@@ -643,26 +643,18 @@ MJIT_FUNC_EXPORTED VALUE https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L643
 rb_make_no_method_exception(VALUE exc, VALUE format, VALUE obj,
 			    int argc, const VALUE *argv, int priv)
 {
-    int n = 0;
-    enum {
-	arg_mesg,
-	arg_name,
-	arg_args,
-	arg_priv,
-	args_size
-    };
-    VALUE args[args_size];
+    VALUE name = argv[0];
 
     if (!format) {
 	format = rb_fstring_cstr("undefined method `%s' for %s%s%s");
     }
-    args[n++] = rb_name_err_mesg_new(format, obj, argv[0]);
-    args[n++] = argv[0];
     if (exc == rb_eNoMethodError) {
-	args[n++] = rb_ary_new4(argc - 1, argv + 1);
-	args[n++] = priv ? Qtrue : Qfalse;
+	VALUE args = rb_ary_new4(argc - 1, argv + 1);
+	return rb_nomethod_err_new(format, obj, name, args, priv);
+    }
+    else {
+	return rb_name_err_new(format, obj, name);
     }
-    return rb_class_new_instance(n, args, exc);
 }
 
 #endif /* #ifndef MJIT_HEADER */
Index: error.c
===================================================================
--- error.c	(revision 63135)
+++ error.c	(revision 63136)
@@ -916,6 +916,15 @@ rb_exc_new_str(VALUE etype, VALUE str) https://github.com/ruby/ruby/blob/trunk/error.c#L916
     return rb_class_new_instance(1, &str, etype);
 }
 
+static VALUE
+exc_init(VALUE exc, VALUE mesg)
+{
+    rb_ivar_set(exc, id_mesg, mesg);
+    rb_ivar_set(exc, id_bt, Qnil);
+
+    return exc;
+}
+
 /*
  * call-seq:
  *    Exception.new(msg = nil)   ->  exception
@@ -930,10 +939,7 @@ exc_initialize(int argc, VALUE *argv, VA https://github.com/ruby/ruby/blob/trunk/error.c#L939
     VALUE arg;
 
     rb_scan_args(argc, argv, "01", &arg);
-    rb_ivar_set(exc, id_mesg, arg);
-    rb_ivar_set(exc, id_bt, Qnil);
-
-    return exc;
+    return exc_init(exc, arg);
 }
 
 /*
@@ -1421,7 +1427,17 @@ rb_name_error_str(VALUE str, const char https://github.com/ruby/ruby/blob/trunk/error.c#L1427
     rb_exc_raise(exc);
 }
 
-static VALUE name_err_initialize_options(int argc, VALUE *argv, VALUE self, VALUE options);
+static VALUE
+name_err_init_attr(VALUE exc, VALUE recv, VALUE method)
+{
+    const rb_execution_context_t *ec = GET_EC();
+    rb_control_frame_t *cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(ec->cfp);
+    cfp = rb_vm_get_ruby_level_next_cfp(ec, cfp);
+    rb_ivar_set(exc, id_name, method);
+    if (recv != Qundef) rb_ivar_set(exc, id_receiver, recv);
+    if (cfp) rb_ivar_set(exc, id_iseq, rb_iseqw_new(cfp->iseq));
+    return exc;
+}
 
 /*
  * call-seq:
@@ -1435,40 +1451,32 @@ static VALUE name_err_initialize_options https://github.com/ruby/ruby/blob/trunk/error.c#L1451
 static VALUE
 name_err_initialize(int argc, VALUE *argv, VALUE self)
 {
-    VALUE options;
-    argc = rb_scan_args(argc, argv, "*:", NULL, &options);
-    return name_err_initialize_options(argc, argv, self, options);
-}
-
-static VALUE
-name_err_initialize_options(int argc, VALUE *argv, VALUE self, VALUE options)
-{
     ID keywords[1];
-    VALUE values[numberof(keywords)];
-    VALUE name;
-    VALUE iseqw = Qnil;
-    int i;
+    VALUE values[numberof(keywords)], name, options;
 
+    argc = rb_scan_args(argc, argv, "*:", NULL, &options);
     keywords[0] = id_receiver;
     rb_get_kwargs(options, keywords, 0, numberof(values), values);
     name = (argc > 1) ? argv[--argc] : Qnil;
     rb_call_super(argc, argv);
-    rb_ivar_set(self, id_name, name);
-    for (i = 0; i < numberof(keywords); ++i) {
-	if (values[i] != Qundef) {
-	    rb_ivar_set(self, keywords[i], values[i]);
-	}
-    }
-    {
-	const rb_execution_context_t *ec = GET_EC();
-	rb_control_frame_t *cfp =
-	    rb_vm_get_ruby_level_next_cfp(ec, RUBY_VM_PREVIOUS_CONTROL_FRAME(ec->cfp));
-	if (cfp) iseqw = rb_iseqw_new(cfp->iseq);
-    }
-    rb_ivar_set(self, id_iseq, iseqw);
+    name_err_init_attr(self, values[0], name);
     return self;
 }
 
+static VALUE
+name_err_init(VALUE exc, VALUE mesg, VALUE recv, VALUE method)
+{
+    exc_init(exc, rb_name_err_mesg_new(mesg, recv, method));
+    return name_err_init_attr(exc, recv, method);
+}
+
+VALUE
+rb_name_err_new(VALUE mesg, VALUE recv, VALUE method)
+{
+    VALUE exc = rb_obj_alloc(rb_eNameError);
+    return name_err_init(exc, mesg, recv, method);
+}
+
 /*
  *  call-seq:
  *    name_error.name    ->  string or nil
@@ -1506,7 +1514,13 @@ name_err_local_variables(VALUE self) https://github.com/ruby/ruby/blob/trunk/error.c#L1514
     return vars;
 }
 
-static VALUE nometh_err_initialize_options(int argc, VALUE *argv, VALUE self, VALUE options);
+static VALUE
+nometh_err_init_attr(VALUE exc, VALUE args, int priv)
+{
+    rb_ivar_set(exc, id_args, args);
+    rb_ivar_set(exc, id_private_call_p, priv ? Qtrue : Qfalse);
+    return exc;
+}
 
 /*
  * call-seq:
@@ -1521,20 +1535,22 @@ static VALUE nometh_err_initialize_optio https://github.com/ruby/ruby/blob/trunk/error.c#L1535
 static VALUE
 nometh_err_initialize(int argc, VALUE *argv, VALUE self)
 {
-    VALUE options;
+    int priv;
+    VALUE args, options;
     argc = rb_scan_args(argc, argv, "*:", NULL, &options);
-    return nometh_err_initialize_options(argc, argv, self, options);
+    priv = (argc > 3) && (--argc, RTEST(argv[argc]));
+    args = (argc > 2) ? argv[--argc] : Qnil;
+    if (!NIL_P(options)) argv[argc++] = options;
+    rb_call_super(argc, argv);
+    return nometh_err_init_attr(self, args, priv);
 }
 
-static VALUE
-nometh_err_initialize_options(int argc, VALUE *argv, VALUE self, VALUE options)
+VALUE
+rb_nomethod_err_new(VALUE mesg, VALUE recv, VALUE method, VALUE args, int priv)
 {
-    VALUE priv = (argc > 3) && (--argc, RTEST(argv[argc])) ? Qtrue : Qfalse;
-    VALUE args = (argc > 2) ? argv[--argc] : Qnil;
-    name_err_initialize_options(argc, argv, self, options);
-    rb_ivar_set(self, id_args, args);
-    rb_ivar_set(self, id_private_call_p, priv);
-    return self;
+    VALUE exc = rb_obj_alloc(rb_eNoMethodError);
+    name_err_init(exc, mesg, recv, method);
+    return nometh_err_init_attr(exc, args, priv);
 }
 
 /* :nodoc: */
@@ -1584,17 +1600,6 @@ rb_name_err_mesg_new(VALUE mesg, VALUE r https://github.com/ruby/ruby/blob/trunk/error.c#L1600
     return result;
 }
 
-VALUE
-rb_name_err_new(VALUE mesg, VALUE recv, VALUE method)
-{
-    VALUE exc = rb_obj_alloc(rb_eNameError);
-    rb_ivar_set(exc, id_mesg, rb_name_err_mesg_new(mesg, recv, method));
-    rb_ivar_set(exc, id_bt, Qnil);
-    rb_ivar_set(exc, id_name, method);
-    rb_ivar_set(exc, id_receiver, recv);
-    return exc;
-}
-
 /* :nodoc: */
 static VALUE
 name_err_mesg_equal(VALUE obj1, VALUE obj2)

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

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