mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Set up callable_method_entry for DUMMY frame on ArgumentError
Before the patch: ``` $ ./miniruby -e '[1, 2].inject(:tap)' -e:1:in '<main>': wrong number of arguments (given 1, expected 0) (ArgumentError) from -e:1:in 'Enumerable#inject' from -e:1:in '<main>' ``` After the patch: ``` $ ./miniruby -e '[1, 2].inject(:tap)' -e:1:in 'Kernel#tap': wrong number of arguments (given 1, expected 0) (ArgumentError) from -e:1:in 'Enumerable#inject' from -e:1:in '<main>' ``` Fixes https://bugs.ruby-lang.org/issues/20968#change-113811
This commit is contained in:
parent
a18fa86351
commit
3546cedde3
4 changed files with 39 additions and 31 deletions
|
@ -460,4 +460,10 @@ class TestBacktrace < Test::Unit::TestCase
|
|||
assert_equal(__FILE__, backtrace[1].path) # not "<internal:kernel>"
|
||||
assert_equal("Kernel#tap", backtrace[1].label)
|
||||
end
|
||||
|
||||
def test_backtrace_on_argument_error
|
||||
lineno = __LINE__; [1, 2].inject(:tap)
|
||||
rescue ArgumentError
|
||||
assert_equal("#{ __FILE__ }:#{ lineno }:in 'Kernel#tap'", $!.backtrace[0].to_s)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1612,7 +1612,7 @@ class TestMethod < Test::Unit::TestCase
|
|||
begin
|
||||
foo(1)
|
||||
rescue ArgumentError => e
|
||||
assert_equal "main.rb:#{$line_method}:in 'foo'", e.backtrace.first
|
||||
assert_equal "main.rb:#{$line_method}:in 'Object#foo'", e.backtrace.first
|
||||
end
|
||||
EOS
|
||||
END_OF_BODY
|
||||
|
|
45
vm_args.c
45
vm_args.c
|
@ -8,9 +8,9 @@
|
|||
|
||||
**********************************************************************/
|
||||
|
||||
NORETURN(static void raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const VALUE exc));
|
||||
NORETURN(static void argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const int miss_argc, const int min_argc, const int max_argc));
|
||||
NORETURN(static void argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const char *error, const VALUE keys));
|
||||
NORETURN(static void raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc));
|
||||
NORETURN(static void argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const int miss_argc, const int min_argc, const int max_argc));
|
||||
NORETURN(static void argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const char *error, const VALUE keys));
|
||||
VALUE rb_keyword_error_new(const char *error, VALUE keys); /* class.c */
|
||||
static VALUE method_missing(rb_execution_context_t *ec, VALUE obj, ID id, int argc, const VALUE *argv,
|
||||
enum method_missing_reason call_status, int kw_splat);
|
||||
|
@ -321,7 +321,7 @@ args_setup_kw_parameters_lookup(const ID key, VALUE *ptr, const VALUE *const pas
|
|||
#define KW_SPECIFIED_BITS_MAX (32-1) /* TODO: 32 -> Fixnum's max bits */
|
||||
|
||||
static void
|
||||
args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq,
|
||||
args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme,
|
||||
VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
|
||||
VALUE *const locals)
|
||||
{
|
||||
|
@ -345,7 +345,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons
|
|||
}
|
||||
}
|
||||
|
||||
if (missing) argument_kw_error(ec, iseq, "missing", missing);
|
||||
if (missing) argument_kw_error(ec, iseq, cme, "missing", missing);
|
||||
|
||||
for (di=0; i<key_num; i++, di++) {
|
||||
if (args_setup_kw_parameters_lookup(acceptable_keywords[i], &locals[i], passed_keywords, passed_values, passed_keyword_len)) {
|
||||
|
@ -386,7 +386,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons
|
|||
else {
|
||||
if (found != passed_keyword_len) {
|
||||
VALUE keys = make_unknown_kw_hash(passed_keywords, passed_keyword_len, passed_values);
|
||||
argument_kw_error(ec, iseq, "unknown", keys);
|
||||
argument_kw_error(ec, iseq, cme, "unknown", keys);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -397,7 +397,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons
|
|||
}
|
||||
|
||||
static void
|
||||
args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb_iseq_t *const iseq,
|
||||
args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme,
|
||||
VALUE keyword_hash, VALUE *const locals, bool remove_hash_value)
|
||||
{
|
||||
const ID *acceptable_keywords = ISEQ_BODY(iseq)->param.keyword->table;
|
||||
|
@ -430,7 +430,7 @@ args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb
|
|||
}
|
||||
}
|
||||
|
||||
if (missing) argument_kw_error(ec, iseq, "missing", missing);
|
||||
if (missing) argument_kw_error(ec, iseq, cme, "missing", missing);
|
||||
|
||||
for (di=0; i<key_num; i++, di++) {
|
||||
VALUE key = ID2SYM(acceptable_keywords[i]);
|
||||
|
@ -485,11 +485,11 @@ args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb
|
|||
* This is simpler than writing code to check which entries in the hash do not match.
|
||||
* This will raise an exception, so the additional performance impact shouldn't be material.
|
||||
*/
|
||||
args_setup_kw_parameters_from_kwsplat(ec, iseq, rb_hash_dup(keyword_hash), locals, true);
|
||||
args_setup_kw_parameters_from_kwsplat(ec, iseq, cme, rb_hash_dup(keyword_hash), locals, true);
|
||||
}
|
||||
}
|
||||
else if (!RHASH_EMPTY_P(keyword_hash)) {
|
||||
argument_kw_error(ec, iseq, "unknown", rb_hash_keys(keyword_hash));
|
||||
argument_kw_error(ec, iseq, cme, "unknown", rb_hash_keys(keyword_hash));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -607,6 +607,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||
VALUE splat_flagged_keyword_hash = 0;
|
||||
VALUE converted_keyword_hash = 0;
|
||||
VALUE rest_last = 0;
|
||||
const rb_callable_method_entry_t *cme = calling->cc ? vm_cc_cme(calling->cc) : NULL;
|
||||
|
||||
vm_check_canary(ec, orig_sp);
|
||||
/*
|
||||
|
@ -861,7 +862,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||
args_extend(args, min_argc);
|
||||
}
|
||||
else {
|
||||
argument_arity_error(ec, iseq, given_argc, min_argc, max_argc);
|
||||
argument_arity_error(ec, iseq, cme, given_argc, min_argc, max_argc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -872,7 +873,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||
given_argc = max_argc;
|
||||
}
|
||||
else {
|
||||
argument_arity_error(ec, iseq, given_argc, min_argc, max_argc);
|
||||
argument_arity_error(ec, iseq, cme, given_argc, min_argc, max_argc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -918,7 +919,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||
|
||||
if (args->kw_argv != NULL) {
|
||||
const struct rb_callinfo_kwarg *kw_arg = args->kw_arg;
|
||||
args_setup_kw_parameters(ec, iseq, args->kw_argv, kw_arg->keyword_len, kw_arg->keywords, klocals);
|
||||
args_setup_kw_parameters(ec, iseq, cme, args->kw_argv, kw_arg->keyword_len, kw_arg->keywords, klocals);
|
||||
}
|
||||
else if (!NIL_P(keyword_hash)) {
|
||||
bool remove_hash_value = false;
|
||||
|
@ -926,7 +927,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||
keyword_hash = check_kwrestarg(keyword_hash, &kw_flag);
|
||||
remove_hash_value = true;
|
||||
}
|
||||
args_setup_kw_parameters_from_kwsplat(ec, iseq, keyword_hash, klocals, remove_hash_value);
|
||||
args_setup_kw_parameters_from_kwsplat(ec, iseq, cme, keyword_hash, klocals, remove_hash_value);
|
||||
}
|
||||
else {
|
||||
#if VM_CHECK_MODE > 0
|
||||
|
@ -941,7 +942,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||
VM_ASSERT(args_argc(args) == 1);
|
||||
}
|
||||
#endif
|
||||
args_setup_kw_parameters(ec, iseq, NULL, 0, NULL, klocals);
|
||||
args_setup_kw_parameters(ec, iseq, cme, NULL, 0, NULL, klocals);
|
||||
}
|
||||
}
|
||||
else if (ISEQ_BODY(iseq)->param.flags.has_kwrest) {
|
||||
|
@ -949,7 +950,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||
kw_flag, ISEQ_BODY(iseq)->param.flags.anon_kwrest);
|
||||
}
|
||||
else if (!NIL_P(keyword_hash) && RHASH_SIZE(keyword_hash) > 0 && arg_setup_type == arg_setup_method) {
|
||||
argument_kw_error(ec, iseq, "unknown", rb_hash_keys(keyword_hash));
|
||||
argument_kw_error(ec, iseq, cme, "unknown", rb_hash_keys(keyword_hash));
|
||||
}
|
||||
|
||||
if (ISEQ_BODY(iseq)->param.flags.has_block) {
|
||||
|
@ -975,13 +976,13 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||
}
|
||||
|
||||
static void
|
||||
raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const VALUE exc)
|
||||
raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc)
|
||||
{
|
||||
VALUE at;
|
||||
|
||||
if (iseq) {
|
||||
vm_push_frame(ec, iseq, VM_FRAME_MAGIC_DUMMY | VM_ENV_FLAG_LOCAL, Qnil /* self */,
|
||||
VM_BLOCK_HANDLER_NONE /* specval*/, Qfalse /* me or cref */,
|
||||
VM_BLOCK_HANDLER_NONE /* specval*/, (VALUE) cme /* me or cref */,
|
||||
ISEQ_BODY(iseq)->iseq_encoded,
|
||||
ec->cfp->sp, 0, 0 /* stack_max */);
|
||||
at = rb_ec_backtrace_object(ec);
|
||||
|
@ -997,7 +998,7 @@ raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const VA
|
|||
}
|
||||
|
||||
static void
|
||||
argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const int miss_argc, const int min_argc, const int max_argc)
|
||||
argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const int miss_argc, const int min_argc, const int max_argc)
|
||||
{
|
||||
VALUE exc = rb_arity_error_new(miss_argc, min_argc, max_argc);
|
||||
if (ISEQ_BODY(iseq)->param.flags.has_kw) {
|
||||
|
@ -1018,13 +1019,13 @@ argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const in
|
|||
RSTRING_PTR(mesg)[RSTRING_LEN(mesg)-1] = ')';
|
||||
}
|
||||
}
|
||||
raise_argument_error(ec, iseq, exc);
|
||||
raise_argument_error(ec, iseq, cme, exc);
|
||||
}
|
||||
|
||||
static void
|
||||
argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const char *error, const VALUE keys)
|
||||
argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const char *error, const VALUE keys)
|
||||
{
|
||||
raise_argument_error(ec, iseq, rb_keyword_error_new(error, keys));
|
||||
raise_argument_error(ec, iseq, cme, rb_keyword_error_new(error, keys));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
|
|
@ -170,7 +170,7 @@ vm_check_frame_detail(VALUE type, int req_block, int req_me, int req_cref, VALUE
|
|||
}
|
||||
else { /* cref or Qfalse */
|
||||
if (cref_or_me != Qfalse && cref_or_me_type != imemo_cref) {
|
||||
if (((type & VM_FRAME_FLAG_LAMBDA) || magic == VM_FRAME_MAGIC_IFUNC) && (cref_or_me_type == imemo_ment)) {
|
||||
if (((type & VM_FRAME_FLAG_LAMBDA) || magic == VM_FRAME_MAGIC_IFUNC || magic == VM_FRAME_MAGIC_DUMMY) && (cref_or_me_type == imemo_ment)) {
|
||||
/* ignore */
|
||||
}
|
||||
else {
|
||||
|
@ -2909,7 +2909,7 @@ vm_call_iseq_setup_tailcall_opt_start(rb_execution_context_t *ec, rb_control_fra
|
|||
}
|
||||
|
||||
static void
|
||||
args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq,
|
||||
args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme,
|
||||
VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
|
||||
VALUE *const locals);
|
||||
|
||||
|
@ -2953,7 +2953,7 @@ vm_call_iseq_setup_kwparm_kwarg(rb_execution_context_t *ec, rb_control_frame_t *
|
|||
const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
|
||||
VALUE * const ci_kws = ALLOCA_N(VALUE, ci_kw_len);
|
||||
MEMCPY(ci_kws, argv + lead_num, VALUE, ci_kw_len);
|
||||
args_setup_kw_parameters(ec, iseq, ci_kws, ci_kw_len, ci_keywords, klocals);
|
||||
args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), ci_kws, ci_kw_len, ci_keywords, klocals);
|
||||
|
||||
int param = ISEQ_BODY(iseq)->param.size;
|
||||
int local = ISEQ_BODY(iseq)->local_table_size;
|
||||
|
@ -3084,7 +3084,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
|
|||
CALLER_SETUP_ARG(cfp, calling, ci, lead_num);
|
||||
|
||||
if (calling->argc != lead_num) {
|
||||
argument_arity_error(ec, iseq, calling->argc, lead_num, lead_num);
|
||||
argument_arity_error(ec, iseq, vm_cc_cme(cc), calling->argc, lead_num, lead_num);
|
||||
}
|
||||
|
||||
//VM_ASSERT(ci == calling->cd->ci);
|
||||
|
@ -3114,7 +3114,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
|
|||
const int opt = argc - lead_num;
|
||||
|
||||
if (opt < 0 || opt > opt_num) {
|
||||
argument_arity_error(ec, iseq, argc, lead_num, lead_num + opt_num);
|
||||
argument_arity_error(ec, iseq, vm_cc_cme(cc), argc, lead_num, lead_num + opt_num);
|
||||
}
|
||||
|
||||
if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_TAILCALL))) {
|
||||
|
@ -3150,7 +3150,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
|
|||
MEMCPY(ci_kws, argv + lead_num, VALUE, ci_kw_len);
|
||||
|
||||
VALUE *const klocals = argv + kw_param->bits_start - kw_param->num;
|
||||
args_setup_kw_parameters(ec, iseq, ci_kws, ci_kw_len, ci_keywords, klocals);
|
||||
args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), ci_kws, ci_kw_len, ci_keywords, klocals);
|
||||
|
||||
CC_SET_FASTPATH(cc, vm_call_iseq_setup_kwparm_kwarg,
|
||||
vm_call_cacheable(ci, cc));
|
||||
|
@ -3161,7 +3161,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
|
|||
else if (argc == lead_num) {
|
||||
/* no kwarg */
|
||||
VALUE *const klocals = argv + kw_param->bits_start - kw_param->num;
|
||||
args_setup_kw_parameters(ec, iseq, NULL, 0, NULL, klocals);
|
||||
args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), NULL, 0, NULL, klocals);
|
||||
|
||||
if (klocals[kw_param->num] == INT2FIX(0)) {
|
||||
/* copy from default_values */
|
||||
|
@ -5207,7 +5207,7 @@ vm_callee_setup_block_arg(rb_execution_context_t *ec, struct rb_calling_info *ca
|
|||
}
|
||||
}
|
||||
else {
|
||||
argument_arity_error(ec, iseq, calling->argc, ISEQ_BODY(iseq)->param.lead_num, ISEQ_BODY(iseq)->param.lead_num);
|
||||
argument_arity_error(ec, iseq, NULL, calling->argc, ISEQ_BODY(iseq)->param.lead_num, ISEQ_BODY(iseq)->param.lead_num);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5229,6 +5229,7 @@ vm_yield_setup_args(rb_execution_context_t *ec, const rb_iseq_t *iseq, const int
|
|||
calling->kw_splat = (flags & VM_CALL_KW_SPLAT) ? 1 : 0;
|
||||
calling->recv = Qundef;
|
||||
calling->heap_argv = 0;
|
||||
calling->cc = NULL;
|
||||
struct rb_callinfo dummy_ci = VM_CI_ON_STACK(0, flags, 0, 0);
|
||||
|
||||
return vm_callee_setup_block_arg(ec, calling, &dummy_ci, iseq, argv, arg_setup_type);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue