From 2dbcc123f4f605b51a3698d38ccd53ba6ef482ac Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Fri, 22 Mar 2024 15:29:13 -0700 Subject: [PATCH] Do not apply anon_rest optimization when passed array uses keyword-flagged hash The optimization sets args->rest_dupped to avoid allocating an array, but this is not safe if the splat array ends in a keyword flagged hash. Unset args->rest_dupped in this case. Fixes [Bug #20388] --- test/ruby/test_keyword.rb | 13 +++++++++++++ vm_args.c | 3 +++ 2 files changed, 16 insertions(+) diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index 5d0262a449..34a80c3729 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -2835,6 +2835,19 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal({a: 1}, kw) end + def test_anon_splat_ruby2_keywords_bug_20388 + extend(Module.new{def process(action, ...) 1 end}) + extend(Module.new do + def process(action, *args) + args.freeze + super + end + ruby2_keywords :process + end) + + assert_equal(1, process(:foo, bar: :baz)) + end + def test_top_ruby2_keywords assert_in_out_err([], <<-INPUT, ["[1, 2, 3]", "{:k=>1}"], []) def bar(*a, **kw) diff --git a/vm_args.c b/vm_args.c index aa800319df..9df175eaa9 100644 --- a/vm_args.c +++ b/vm_args.c @@ -687,6 +687,9 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co rest_last = rb_hash_dup(rest_last); kw_flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT; + // Unset rest_dupped set by anon_rest as we may need to modify splat in this case + args->rest_dupped = false; + if (ignore_keyword_hash_p(rest_last, iseq, &kw_flag, &converted_keyword_hash)) { arg_rest_dup(args); rb_ary_pop(args->rest);