YJIT: Fix out of bounds access when splatting empty array

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]
This commit is contained in:
Alan Wu 2024-05-31 17:37:21 -04:00
parent bc40d06091
commit 6c8ae44a38
2 changed files with 25 additions and 13 deletions

View File

@ -4980,3 +4980,15 @@ assert_equal '[[:c_call, :x=], [:c_call, :x]]', %q{
events
}
# regression test for splatting empty array
assert_equal '1', %q{
def callee(foo) = foo
def test_body(args) = callee(1, *args)
test_body([])
array = Array.new(100)
array.clear
test_body(array)
}

View File

@ -6953,20 +6953,20 @@ fn push_splat_args(required_args: u32, asm: &mut Assembler) {
asm.cmp(array_len_opnd, required_args.into());
asm.jne(Target::side_exit(Counter::guard_send_splatarray_length_not_equal));
asm_comment!(asm, "Check last argument is not ruby2keyword hash");
// Check last element of array if present
if required_args > 0 {
asm_comment!(asm, "Check last argument is not ruby2keyword hash");
// Need to repeat this here to deal with register allocation
let array_reg = asm.load(asm.stack_opnd(0));
let ary_opnd = get_array_ptr(asm, array_reg);
let last_array_value = asm.load(Opnd::mem(64, ary_opnd, (required_args as i32 - 1) * (SIZEOF_VALUE as i32)));
guard_object_is_not_ruby2_keyword_hash(
asm,
last_array_value,
Counter::guard_send_splatarray_last_ruby2_keywords,
);
// Need to repeat this here to deal with register allocation
let array_reg = asm.load(asm.stack_opnd(0));
let ary_opnd = get_array_ptr(asm, array_reg);
let last_array_value = asm.load(Opnd::mem(64, ary_opnd, (required_args as i32 - 1) * (SIZEOF_VALUE as i32)));
guard_object_is_not_ruby2_keyword_hash(
asm,
last_array_value,
Counter::guard_send_splatarray_last_ruby2_keywords,
);
}
asm_comment!(asm, "Push arguments from array");
let array_opnd = asm.stack_pop(1);