Skip to content

Commit 9168cad

Browse files
rwstaunerXrXr
authored andcommitted
YJIT: Bail out if proc would be stored above stack top
Fixes [Bug #21266].
1 parent f3b9509 commit 9168cad

File tree

4 files changed

+28
-0
lines changed

4 files changed

+28
-0
lines changed

bootstraptest/test_yjit.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4889,6 +4889,16 @@ def tests
48894889
tests
48904890
}
48914891

4892+
# regression test for splat with &proc{} when the target has rest (Bug #21266)
4893+
assert_equal '[]', %q{
4894+
def foo(args) = bar(*args, &proc { _1 })
4895+
def bar(_, _, _, _, *rest) = yield rest
4896+
4897+
GC.stress = true
4898+
foo([1,2,3,4])
4899+
foo([1,2,3,4])
4900+
}
4901+
48924902
# regression test for invalidating an empty block
48934903
assert_equal '0', %q{
48944904
def foo = (* = 1).pred

test/ruby/test_yjit.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,18 @@ def req2kws = yield a: 1, b: 2
17721772
RUBY
17731773
end
17741774

1775+
def test_proc_block_with_kwrest
1776+
# When the bug was present this required --yjit-stats to trigger.
1777+
assert_compiles(<<~RUBY, result: {extra: 5})
1778+
def foo = bar(w: 1, x: 2, y: 3, z: 4, extra: 5, &proc { _1 })
1779+
def bar(w:, x:, y:, z:, **kwrest) = yield kwrest
1780+
1781+
GC.stress = true
1782+
foo
1783+
foo
1784+
RUBY
1785+
end
1786+
17751787
private
17761788

17771789
def code_gc_helpers

yjit/src/codegen.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7896,6 +7896,11 @@ fn gen_send_iseq(
78967896
gen_counter_incr(jit, asm, Counter::send_iseq_clobbering_block_arg);
78977897
return None;
78987898
}
7899+
if iseq_has_rest || has_kwrest {
7900+
// The proc would be stored above the current stack top, where GC can't see it
7901+
gen_counter_incr(jit, asm, Counter::send_iseq_block_arg_gc_unsafe);
7902+
return None;
7903+
}
78997904
let proc = asm.stack_pop(1); // Pop first, as argc doesn't account for the block arg
79007905
let callee_specval = asm.ctx.sp_opnd(callee_specval);
79017906
asm.store(callee_specval, proc);

yjit/src/stats.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ make_counters! {
354354
send_iseq_arity_error,
355355
send_iseq_block_arg_type,
356356
send_iseq_clobbering_block_arg,
357+
send_iseq_block_arg_gc_unsafe,
357358
send_iseq_complex_discard_extras,
358359
send_iseq_leaf_builtin_block_arg_block_param,
359360
send_iseq_kw_splat_non_nil,

0 commit comments

Comments
 (0)