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:
parent
fe96e87e72
commit
a72581d70f
4 changed files with 80 additions and 66 deletions
109
error.c
109
error.c
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
20
vm_eval.c
20
vm_eval.c
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue