Skip to content

Commit 3546ced

Browse files
committed
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
1 parent a18fa86 commit 3546ced

File tree

4 files changed

+39
-31
lines changed

4 files changed

+39
-31
lines changed

test/ruby/test_backtrace.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,4 +460,10 @@ def test_backtrace_internal_frame
460460
assert_equal(__FILE__, backtrace[1].path) # not "<internal:kernel>"
461461
assert_equal("Kernel#tap", backtrace[1].label)
462462
end
463+
464+
def test_backtrace_on_argument_error
465+
lineno = __LINE__; [1, 2].inject(:tap)
466+
rescue ArgumentError
467+
assert_equal("#{ __FILE__ }:#{ lineno }:in 'Kernel#tap'", $!.backtrace[0].to_s)
468+
end
463469
end

test/ruby/test_method.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1612,7 +1612,7 @@ def test_argument_error_location
16121612
begin
16131613
foo(1)
16141614
rescue ArgumentError => e
1615-
assert_equal "main.rb:#{$line_method}:in 'foo'", e.backtrace.first
1615+
assert_equal "main.rb:#{$line_method}:in 'Object#foo'", e.backtrace.first
16161616
end
16171617
EOS
16181618
END_OF_BODY

vm_args.c

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
99
**********************************************************************/
1010

11-
NORETURN(static void raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const VALUE exc));
12-
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));
13-
NORETURN(static void argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const char *error, const VALUE keys));
11+
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));
12+
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));
13+
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));
1414
VALUE rb_keyword_error_new(const char *error, VALUE keys); /* class.c */
1515
static VALUE method_missing(rb_execution_context_t *ec, VALUE obj, ID id, int argc, const VALUE *argv,
1616
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
321321
#define KW_SPECIFIED_BITS_MAX (32-1) /* TODO: 32 -> Fixnum's max bits */
322322

323323
static void
324-
args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq,
324+
args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme,
325325
VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
326326
VALUE *const locals)
327327
{
@@ -345,7 +345,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons
345345
}
346346
}
347347

348-
if (missing) argument_kw_error(ec, iseq, "missing", missing);
348+
if (missing) argument_kw_error(ec, iseq, cme, "missing", missing);
349349

350350
for (di=0; i<key_num; i++, di++) {
351351
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
386386
else {
387387
if (found != passed_keyword_len) {
388388
VALUE keys = make_unknown_kw_hash(passed_keywords, passed_keyword_len, passed_values);
389-
argument_kw_error(ec, iseq, "unknown", keys);
389+
argument_kw_error(ec, iseq, cme, "unknown", keys);
390390
}
391391
}
392392

@@ -397,7 +397,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons
397397
}
398398

399399
static void
400-
args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb_iseq_t *const iseq,
400+
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,
401401
VALUE keyword_hash, VALUE *const locals, bool remove_hash_value)
402402
{
403403
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
430430
}
431431
}
432432

433-
if (missing) argument_kw_error(ec, iseq, "missing", missing);
433+
if (missing) argument_kw_error(ec, iseq, cme, "missing", missing);
434434

435435
for (di=0; i<key_num; i++, di++) {
436436
VALUE key = ID2SYM(acceptable_keywords[i]);
@@ -485,11 +485,11 @@ args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb
485485
* This is simpler than writing code to check which entries in the hash do not match.
486486
* This will raise an exception, so the additional performance impact shouldn't be material.
487487
*/
488-
args_setup_kw_parameters_from_kwsplat(ec, iseq, rb_hash_dup(keyword_hash), locals, true);
488+
args_setup_kw_parameters_from_kwsplat(ec, iseq, cme, rb_hash_dup(keyword_hash), locals, true);
489489
}
490490
}
491491
else if (!RHASH_EMPTY_P(keyword_hash)) {
492-
argument_kw_error(ec, iseq, "unknown", rb_hash_keys(keyword_hash));
492+
argument_kw_error(ec, iseq, cme, "unknown", rb_hash_keys(keyword_hash));
493493
}
494494
}
495495

@@ -607,6 +607,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
607607
VALUE splat_flagged_keyword_hash = 0;
608608
VALUE converted_keyword_hash = 0;
609609
VALUE rest_last = 0;
610+
const rb_callable_method_entry_t *cme = calling->cc ? vm_cc_cme(calling->cc) : NULL;
610611

611612
vm_check_canary(ec, orig_sp);
612613
/*
@@ -861,7 +862,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
861862
args_extend(args, min_argc);
862863
}
863864
else {
864-
argument_arity_error(ec, iseq, given_argc, min_argc, max_argc);
865+
argument_arity_error(ec, iseq, cme, given_argc, min_argc, max_argc);
865866
}
866867
}
867868

@@ -872,7 +873,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
872873
given_argc = max_argc;
873874
}
874875
else {
875-
argument_arity_error(ec, iseq, given_argc, min_argc, max_argc);
876+
argument_arity_error(ec, iseq, cme, given_argc, min_argc, max_argc);
876877
}
877878
}
878879

@@ -918,15 +919,15 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
918919

919920
if (args->kw_argv != NULL) {
920921
const struct rb_callinfo_kwarg *kw_arg = args->kw_arg;
921-
args_setup_kw_parameters(ec, iseq, args->kw_argv, kw_arg->keyword_len, kw_arg->keywords, klocals);
922+
args_setup_kw_parameters(ec, iseq, cme, args->kw_argv, kw_arg->keyword_len, kw_arg->keywords, klocals);
922923
}
923924
else if (!NIL_P(keyword_hash)) {
924925
bool remove_hash_value = false;
925926
if (ISEQ_BODY(iseq)->param.flags.has_kwrest) {
926927
keyword_hash = check_kwrestarg(keyword_hash, &kw_flag);
927928
remove_hash_value = true;
928929
}
929-
args_setup_kw_parameters_from_kwsplat(ec, iseq, keyword_hash, klocals, remove_hash_value);
930+
args_setup_kw_parameters_from_kwsplat(ec, iseq, cme, keyword_hash, klocals, remove_hash_value);
930931
}
931932
else {
932933
#if VM_CHECK_MODE > 0
@@ -941,15 +942,15 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
941942
VM_ASSERT(args_argc(args) == 1);
942943
}
943944
#endif
944-
args_setup_kw_parameters(ec, iseq, NULL, 0, NULL, klocals);
945+
args_setup_kw_parameters(ec, iseq, cme, NULL, 0, NULL, klocals);
945946
}
946947
}
947948
else if (ISEQ_BODY(iseq)->param.flags.has_kwrest) {
948949
args_setup_kw_rest_parameter(keyword_hash, locals + ISEQ_BODY(iseq)->param.keyword->rest_start,
949950
kw_flag, ISEQ_BODY(iseq)->param.flags.anon_kwrest);
950951
}
951952
else if (!NIL_P(keyword_hash) && RHASH_SIZE(keyword_hash) > 0 && arg_setup_type == arg_setup_method) {
952-
argument_kw_error(ec, iseq, "unknown", rb_hash_keys(keyword_hash));
953+
argument_kw_error(ec, iseq, cme, "unknown", rb_hash_keys(keyword_hash));
953954
}
954955

955956
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
975976
}
976977

977978
static void
978-
raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const VALUE exc)
979+
raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc)
979980
{
980981
VALUE at;
981982

982983
if (iseq) {
983984
vm_push_frame(ec, iseq, VM_FRAME_MAGIC_DUMMY | VM_ENV_FLAG_LOCAL, Qnil /* self */,
984-
VM_BLOCK_HANDLER_NONE /* specval*/, Qfalse /* me or cref */,
985+
VM_BLOCK_HANDLER_NONE /* specval*/, (VALUE) cme /* me or cref */,
985986
ISEQ_BODY(iseq)->iseq_encoded,
986987
ec->cfp->sp, 0, 0 /* stack_max */);
987988
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
997998
}
998999

9991000
static void
1000-
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)
1001+
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)
10011002
{
10021003
VALUE exc = rb_arity_error_new(miss_argc, min_argc, max_argc);
10031004
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
10181019
RSTRING_PTR(mesg)[RSTRING_LEN(mesg)-1] = ')';
10191020
}
10201021
}
1021-
raise_argument_error(ec, iseq, exc);
1022+
raise_argument_error(ec, iseq, cme, exc);
10221023
}
10231024

10241025
static void
1025-
argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const char *error, const VALUE keys)
1026+
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)
10261027
{
1027-
raise_argument_error(ec, iseq, rb_keyword_error_new(error, keys));
1028+
raise_argument_error(ec, iseq, cme, rb_keyword_error_new(error, keys));
10281029
}
10291030

10301031
static VALUE

vm_insnhelper.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ vm_check_frame_detail(VALUE type, int req_block, int req_me, int req_cref, VALUE
170170
}
171171
else { /* cref or Qfalse */
172172
if (cref_or_me != Qfalse && cref_or_me_type != imemo_cref) {
173-
if (((type & VM_FRAME_FLAG_LAMBDA) || magic == VM_FRAME_MAGIC_IFUNC) && (cref_or_me_type == imemo_ment)) {
173+
if (((type & VM_FRAME_FLAG_LAMBDA) || magic == VM_FRAME_MAGIC_IFUNC || magic == VM_FRAME_MAGIC_DUMMY) && (cref_or_me_type == imemo_ment)) {
174174
/* ignore */
175175
}
176176
else {
@@ -2909,7 +2909,7 @@ vm_call_iseq_setup_tailcall_opt_start(rb_execution_context_t *ec, rb_control_fra
29092909
}
29102910

29112911
static void
2912-
args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq,
2912+
args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme,
29132913
VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
29142914
VALUE *const locals);
29152915

@@ -2953,7 +2953,7 @@ vm_call_iseq_setup_kwparm_kwarg(rb_execution_context_t *ec, rb_control_frame_t *
29532953
const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
29542954
VALUE * const ci_kws = ALLOCA_N(VALUE, ci_kw_len);
29552955
MEMCPY(ci_kws, argv + lead_num, VALUE, ci_kw_len);
2956-
args_setup_kw_parameters(ec, iseq, ci_kws, ci_kw_len, ci_keywords, klocals);
2956+
args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), ci_kws, ci_kw_len, ci_keywords, klocals);
29572957

29582958
int param = ISEQ_BODY(iseq)->param.size;
29592959
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,
30843084
CALLER_SETUP_ARG(cfp, calling, ci, lead_num);
30853085

30863086
if (calling->argc != lead_num) {
3087-
argument_arity_error(ec, iseq, calling->argc, lead_num, lead_num);
3087+
argument_arity_error(ec, iseq, vm_cc_cme(cc), calling->argc, lead_num, lead_num);
30883088
}
30893089

30903090
//VM_ASSERT(ci == calling->cd->ci);
@@ -3114,7 +3114,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
31143114
const int opt = argc - lead_num;
31153115

31163116
if (opt < 0 || opt > opt_num) {
3117-
argument_arity_error(ec, iseq, argc, lead_num, lead_num + opt_num);
3117+
argument_arity_error(ec, iseq, vm_cc_cme(cc), argc, lead_num, lead_num + opt_num);
31183118
}
31193119

31203120
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,
31503150
MEMCPY(ci_kws, argv + lead_num, VALUE, ci_kw_len);
31513151

31523152
VALUE *const klocals = argv + kw_param->bits_start - kw_param->num;
3153-
args_setup_kw_parameters(ec, iseq, ci_kws, ci_kw_len, ci_keywords, klocals);
3153+
args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), ci_kws, ci_kw_len, ci_keywords, klocals);
31543154

31553155
CC_SET_FASTPATH(cc, vm_call_iseq_setup_kwparm_kwarg,
31563156
vm_call_cacheable(ci, cc));
@@ -3161,7 +3161,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
31613161
else if (argc == lead_num) {
31623162
/* no kwarg */
31633163
VALUE *const klocals = argv + kw_param->bits_start - kw_param->num;
3164-
args_setup_kw_parameters(ec, iseq, NULL, 0, NULL, klocals);
3164+
args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), NULL, 0, NULL, klocals);
31653165

31663166
if (klocals[kw_param->num] == INT2FIX(0)) {
31673167
/* copy from default_values */
@@ -5207,7 +5207,7 @@ vm_callee_setup_block_arg(rb_execution_context_t *ec, struct rb_calling_info *ca
52075207
}
52085208
}
52095209
else {
5210-
argument_arity_error(ec, iseq, calling->argc, ISEQ_BODY(iseq)->param.lead_num, ISEQ_BODY(iseq)->param.lead_num);
5210+
argument_arity_error(ec, iseq, NULL, calling->argc, ISEQ_BODY(iseq)->param.lead_num, ISEQ_BODY(iseq)->param.lead_num);
52115211
}
52125212
}
52135213

@@ -5229,6 +5229,7 @@ vm_yield_setup_args(rb_execution_context_t *ec, const rb_iseq_t *iseq, const int
52295229
calling->kw_splat = (flags & VM_CALL_KW_SPLAT) ? 1 : 0;
52305230
calling->recv = Qundef;
52315231
calling->heap_argv = 0;
5232+
calling->cc = NULL;
52325233
struct rb_callinfo dummy_ci = VM_CI_ON_STACK(0, flags, 0, 0);
52335234

52345235
return vm_callee_setup_block_arg(ec, calling, &dummy_ci, iseq, argv, arg_setup_type);

0 commit comments

Comments
 (0)