1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

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.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63136 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2018-04-12 03:48:48 +00:00
parent fe96e87e72
commit a72581d70f
4 changed files with 80 additions and 66 deletions

109
error.c
View file

@ -916,6 +916,15 @@ rb_exc_new_str(VALUE etype, VALUE str)
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, VALUE exc)
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 *fmt, ...)
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:
@ -1434,41 +1450,33 @@ static VALUE name_err_initialize_options(int argc, VALUE *argv, VALUE self, VALU
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)
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_options(int argc, VALUE *argv, VALUE self, VA
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 recv, VALUE method)
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)

View file

@ -1220,6 +1220,7 @@ VALUE rb_name_err_new(VALUE mesg, VALUE recv, VALUE method);
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))

View file

@ -1320,4 +1320,20 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
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

View file

@ -643,26 +643,18 @@ MJIT_FUNC_EXPORTED VALUE
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 */