Skip to content

Commit fcf6563

Browse files
committed
YJIT: Bail out if proc would be stored above stack top
Fixes [Bug #21266]. Backport of 9168cad to 3.3
1 parent 10876c2 commit fcf6563

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
@@ -4585,3 +4585,13 @@ def foo(&) = self.class.name(&)
45854585
new.foo
45864586
end
45874587
}
4588+
4589+
# regression test for splat with &proc{} when the target has rest (Bug #21266)
4590+
assert_equal '[]', %q{
4591+
def foo(args) = bar(*args, &proc { _1 })
4592+
def bar(_, _, _, _, *rest) = yield rest
4593+
4594+
GC.stress = true
4595+
foo([1,2,3,4])
4596+
foo([1,2,3,4])
4597+
}

test/ruby/test_yjit.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,18 @@ def test_disable_stats
15261526
assert_in_out_err(%w[--yjit-stats --yjit-disable])
15271527
end
15281528

1529+
def test_proc_block_with_kwrest
1530+
# When the bug was present this required --yjit-stats to trigger.
1531+
assert_compiles(<<~RUBY, result: {extra: 5})
1532+
def foo = bar(w: 1, x: 2, y: 3, z: 4, extra: 5, &proc { _1 })
1533+
def bar(w:, x:, y:, z:, **kwrest) = yield kwrest
1534+
1535+
GC.stress = true
1536+
foo
1537+
foo
1538+
RUBY
1539+
end
1540+
15291541
private
15301542

15311543
def code_gc_helpers

yjit/src/codegen.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6338,6 +6338,11 @@ fn gen_send_iseq(
63386338
gen_counter_incr(asm, Counter::send_iseq_clobbering_block_arg);
63396339
return None;
63406340
}
6341+
if iseq_has_rest {
6342+
// The proc would be stored above the current stack top, where GC can't see it
6343+
gen_counter_incr(asm, Counter::send_iseq_block_arg_gc_unsafe);
6344+
return None;
6345+
}
63416346
let proc = asm.stack_pop(1); // Pop first, as argc doesn't account for the block arg
63426347
let callee_specval = asm.ctx.sp_opnd(callee_specval as isize * SIZEOF_VALUE as isize);
63436348
asm.store(callee_specval, proc);

yjit/src/stats.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ make_counters! {
328328
send_attrset_kwargs,
329329
send_iseq_tailcall,
330330
send_iseq_arity_error,
331+
send_iseq_block_arg_gc_unsafe,
331332
send_iseq_clobbering_block_arg,
332333
send_iseq_leaf_builtin_block_arg_block_param,
333334
send_iseq_only_keywords,

0 commit comments

Comments
 (0)