summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandy Stauner <randy@r4s6.net>2026-01-12 18:35:12 -0700
committernagachika <nagachika@ruby-lang.org>2026-01-25 18:18:10 +0900
commit02eb4eec87cbbb14c24b63678aa0cca625777414 (patch)
tree4faa5e02755b7beb795f3fe66f0f83ccd1863632
parent86e65fa1677180f5108157206edb01cfd25f24b6 (diff)
Add pushtoarray insn to fix segfault with forwarding + splat
Example insns diff for `def x = [3]; def a(...) = b(*x, 2, 3, ...)` == disasm: #<ISeq:a@-e:1 (1,13)-(1,42)> local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1]) [ 1] "..."@0 0000 putself ( 1)[Ca] 0000 putself 0000 opt_send_without_block <calldata!mid:x, argc:0, FCALL|VCALL|ARGS_SIMPLE> 0000 splatarray true 0000 putobject 2 0000 putobject 3 +0000 pushtoarray 2 0000 getlocal_WC_0 "..."@0 0000 sendforward <calldata!mid:b, argc:1, ARGS_SPLAT|ARGS_SPLAT_MUT|FCALL|FORWARDING>, nil 0000 leave [Re] This matches the insns produced by parse.y
-rw-r--r--bootstraptest/test_method.rb15
-rw-r--r--prism_compile.c8
2 files changed, 23 insertions, 0 deletions
diff --git a/bootstraptest/test_method.rb b/bootstraptest/test_method.rb
index 41823b5007..d8a8effbaf 100644
--- a/bootstraptest/test_method.rb
+++ b/bootstraptest/test_method.rb
@@ -1419,3 +1419,18 @@ assert_equal 'ok', %q{
"ok"
end
}
+
+assert_equal '[1, 2, 3]', %q{
+ def target(*args) = args
+ def x = [1]
+ def forwarder(...) = target(*x, 2, ...)
+ forwarder(3).inspect
+}, '[Bug #21832] post-splat args before forwarding'
+
+assert_equal 'ok', <<~RUBY
+ def test(*, kw: false)
+ "ok"
+ end
+
+ test
+RUBY
diff --git a/prism_compile.c b/prism_compile.c
index 79c944d998..9d6a8141bd 100644
--- a/prism_compile.c
+++ b/prism_compile.c
@@ -1821,6 +1821,10 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
// foo(*a, b, c: :d)
// foo(*a, b, **c)
//
+ // If the next node is a forwarding argument:
+ //
+ // foo(*a, b, ...)
+ //
// If the next node is NULL (we have hit the end):
//
// foo(*a, b)
@@ -1843,6 +1847,10 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
PUSH_INSN(ret, location, concatarray);
break;
}
+ case PM_FORWARDING_ARGUMENTS_NODE: {
+ PUSH_INSN1(ret, location, pushtoarray, INT2FIX(post_splat_counter));
+ break;
+ }
default:
break;
}