From 75acbd5f0076970d48bc423c2b058adbdb5da9e8 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Sun, 22 Dec 2019 03:31:27 +0900 Subject: compile.c: avoid newarraykwsplat for arguments `foo(*rest, post, **empty_kw)` is compiled like `foo(*rest + [post, **empty_kw])`, and `**empty_kw` is removed by "newarraykwsplat" instruction. However, the method call still has a flag of KW_SPLAT, so "post" is considered as a keyword hash, which caused a segfault. Note that the flag cannot be removed if "empty_kw" is not always empty. This change fixes the issue by compiling arguments with "newarray" instead of "newarraykwsplat". [Bug #16442] --- compile.c | 9 ++++++++- test/ruby/test_keyword.rb | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compile.c b/compile.c index 98ee34afd0..c19112c853 100644 --- a/compile.c +++ b/compile.c @@ -5017,7 +5017,14 @@ setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn, case NODE_ARGSPUSH: { int next_is_list = (nd_type(argn->nd_head) == NODE_LIST); VALUE argc = setup_args_core(iseq, args, argn->nd_head, 1, NULL, NULL); - NO_CHECK(COMPILE(args, "args (cat: splat)", argn->nd_body)); + if (nd_type(argn->nd_body) == NODE_LIST) { + /* This branch is needed to avoid "newarraykwsplat" [Bug #16442] */ + int rest_len = compile_args(iseq, args, argn->nd_body, NULL, NULL); + ADD_INSN1(args, nd_line(argn), newarray, INT2FIX(rest_len)); + } + else { + NO_CHECK(COMPILE(args, "args (cat: splat)", argn->nd_body)); + } if (flag) { *flag |= VM_CALL_ARGS_SPLAT; /* This is a dirty hack. It traverses the AST twice. diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index 3d5cb2dd20..bfdec6fc74 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -4654,6 +4654,12 @@ class TestKeywordArguments < Test::Unit::TestCase def test_splat_empty_hash_with_block_passing assert_valid_syntax("bug15087(**{}, &nil)") end + + def test_do_not_use_newarraykwsplat + assert_equal([42, "foo", 424242], f2(*[], 42, **{})) + a = [1, 2, 3] + assert_equal([[1,2,3,4,5,6], "foo", 424242, {:k=>:k}], f7(*a, 4,5,6, k: :k)) + end end class TestKeywordArgumentsSymProcRefinements < Test::Unit::TestCase -- cgit v1.2.3