From 13cd963500106b366c8df9eec5c1b6815e93f07f Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Tue, 21 Nov 2023 09:02:31 -0800 Subject: Prevent modification of splat array inside setup_parameters_complex For the following: ``` def f(*a); a end p f(*a, kw: 3) ``` `setup_parameters_complex` pushes `{kw: 3}` onto `a`. This worked fine back when `concatarray true` was used and `a` was already a copy. It does not work correctly with the optimization to switch to `concatarray false`. This duplicates the array on the callee side in such a case. This affects cases when passing a regular splat and a keyword splat (or literal keywords) in a method call, where the method does not accept keywords. This allocation could probably be avoided, but doing so would make `setup_parameters_complex` more complicated. --- vm_args.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'vm_args.c') diff --git a/vm_args.c b/vm_args.c index 92e141bf6e..14ae550d2f 100644 --- a/vm_args.c +++ b/vm_args.c @@ -542,11 +542,13 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co else if (UNLIKELY(ISEQ_BODY(iseq)->param.flags.ruby2_keywords)) { converted_keyword_hash = check_kwrestarg(converted_keyword_hash, &kw_flag); flag_keyword_hash = converted_keyword_hash; + arg_rest_dup(args); 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) { converted_keyword_hash = check_kwrestarg(converted_keyword_hash, &kw_flag); + arg_rest_dup(args); rb_ary_push(args->rest, converted_keyword_hash); keyword_hash = Qnil; } else { -- cgit v1.2.3