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/