Skip to content

Commit

Permalink
YJIT: Fix out of bounds access when splatting empty array
Browse files Browse the repository at this point in the history
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]
  • Loading branch information
XrXr committed Jun 3, 2024
1 parent c9bec74 commit b861fc9
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 13 deletions.
11 changes: 11 additions & 0 deletions bootstraptest/test_yjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4454,3 +4454,14 @@ def body
body
}

# regression test for splatting empty array to cfunc
assert_normal_exit %q{
def test_body(args) = Array(1, *args)
test_body([])
0x100.times do
array = Array.new(100)
array.clear
test_body(array)
end
}
26 changes: 13 additions & 13 deletions yjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5814,20 +5814,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");

// 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)));
// Check last element of array if present
if required_args > 0 {
asm_comment!(asm, "Check last argument is not ruby2keyword hash");

guard_object_is_not_ruby2_keyword_hash(
asm,
last_array_value,
Counter::guard_send_splatarray_last_ruby_2_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_ruby_2_keywords,
);
}

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

0 comments on commit b861fc9

Please sign in to comment.