Skip to content

Commit b861fc9

Browse files
committed
YJIT: Fix out of bounds access when splatting empty array
This is a backport of 6c8ae44 with a test tailored to crash the 3.3.x branch (from rubyGH-10904). Previously, we read the last element array even when the array was empty, doing an out-of-bounds access. This sometimes caused a SEGV. [Bug #20496]
1 parent c9bec74 commit b861fc9

File tree

2 files changed

+24
-13
lines changed

2 files changed

+24
-13
lines changed

bootstraptest/test_yjit.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4454,3 +4454,14 @@ def body
44544454
44554455
body
44564456
}
4457+
4458+
# regression test for splatting empty array to cfunc
4459+
assert_normal_exit %q{
4460+
def test_body(args) = Array(1, *args)
4461+
test_body([])
4462+
0x100.times do
4463+
array = Array.new(100)
4464+
array.clear
4465+
test_body(array)
4466+
end
4467+
}

yjit/src/codegen.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5814,20 +5814,20 @@ fn push_splat_args(required_args: u32, asm: &mut Assembler) {
58145814
asm.cmp(array_len_opnd, required_args.into());
58155815
asm.jne(Target::side_exit(Counter::guard_send_splatarray_length_not_equal));
58165816

5817-
asm_comment!(asm, "Check last argument is not ruby2keyword hash");
5818-
5819-
// Need to repeat this here to deal with register allocation
5820-
let array_reg = asm.load(asm.stack_opnd(0));
5821-
5822-
let ary_opnd = get_array_ptr(asm, array_reg);
5823-
5824-
let last_array_value = asm.load(Opnd::mem(64, ary_opnd, (required_args as i32 - 1) * (SIZEOF_VALUE as i32)));
5817+
// Check last element of array if present
5818+
if required_args > 0 {
5819+
asm_comment!(asm, "Check last argument is not ruby2keyword hash");
58255820

5826-
guard_object_is_not_ruby2_keyword_hash(
5827-
asm,
5828-
last_array_value,
5829-
Counter::guard_send_splatarray_last_ruby_2_keywords,
5830-
);
5821+
// Need to repeat this here to deal with register allocation
5822+
let array_reg = asm.load(asm.stack_opnd(0));
5823+
let ary_opnd = get_array_ptr(asm, array_reg);
5824+
let last_array_value = asm.load(Opnd::mem(64, ary_opnd, (required_args as i32 - 1) * (SIZEOF_VALUE as i32)));
5825+
guard_object_is_not_ruby2_keyword_hash(
5826+
asm,
5827+
last_array_value,
5828+
Counter::guard_send_splatarray_last_ruby_2_keywords,
5829+
);
5830+
}
58315831

58325832
asm_comment!(asm, "Push arguments from array");
58335833
let array_opnd = asm.stack_pop(1);

0 commit comments

Comments
 (0)