From 6462c1a042fec4017f7e3bf2c13ec6a29efd23d6 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 14 Mar 2023 03:42:47 +0900 Subject: `Hash#dup` for kwsplat arguments On `f(*a, **kw)` method calls, a rest keyword parameter is identically same Hash object is passed and it should make `#dup`ed Hahs. fix https://bugs.ruby-lang.org/issues/19526 --- vm_args.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'vm_args.c') diff --git a/vm_args.c b/vm_args.c index 1af69cceee..cc7f1e29b5 100644 --- a/vm_args.c +++ b/vm_args.c @@ -450,6 +450,18 @@ ignore_keyword_hash_p(VALUE keyword_hash, const rb_iseq_t * const iseq, unsigned RHASH_EMPTY_P(keyword_hash); } +static VALUE +check_kwrestarg(VALUE keyword_hash, unsigned int *kw_flag) +{ + if (!(*kw_flag & VM_CALL_KW_SPLAT_MUT)) { + *kw_flag |= VM_CALL_KW_SPLAT_MUT; + return rb_hash_dup(keyword_hash); + } + else { + return keyword_hash; + } +} + static int setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * const iseq, struct rb_calling_info *const calling, @@ -528,12 +540,14 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co keyword_hash = Qnil; } else if (UNLIKELY(ISEQ_BODY(iseq)->param.flags.ruby2_keywords)) { - flag_keyword_hash = keyword_hash; - rb_ary_push(args->rest, keyword_hash); + converted_keyword_hash = check_kwrestarg(converted_keyword_hash, &kw_flag); + flag_keyword_hash = converted_keyword_hash; + rb_ary_push(args->rest, converted_keyword_hash); keyword_hash = Qnil; } else if (!ISEQ_BODY(iseq)->param.flags.has_kwrest && !ISEQ_BODY(iseq)->param.flags.has_kw) { - rb_ary_push(args->rest, keyword_hash); + converted_keyword_hash = check_kwrestarg(converted_keyword_hash, &kw_flag); + rb_ary_push(args->rest, converted_keyword_hash); keyword_hash = Qnil; } -- cgit v1.2.3