Skip to content

Commit 39d764e

Browse files
authored
ZJIT: Add stack overflow check to gen_ccall_variadic (ruby#14636)
ZJIT: Add stack overflow check to gen_ccall_variadic
1 parent 990ec01 commit 39d764e

File tree

1 file changed

+17
-10
lines changed

1 file changed

+17
-10
lines changed

zjit/src/codegen.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,9 @@ fn gen_ccall_variadic(
661661
) -> lir::Opnd {
662662
gen_prepare_non_leaf_call(jit, asm, state);
663663

664+
let stack_growth = state.stack_size();
665+
gen_stack_overflow_check(jit, asm, state, stack_growth);
666+
664667
gen_push_frame(asm, args.len(), state, ControlFrame {
665668
recv,
666669
iseq: None,
@@ -1109,17 +1112,8 @@ fn gen_send_without_block_direct(
11091112
state: &FrameState,
11101113
) -> lir::Opnd {
11111114
let local_size = unsafe { get_iseq_body_local_table_size(iseq) }.as_usize();
1112-
// Stack overflow check: fails if CFP<=SP at any point in the callee.
1113-
asm_comment!(asm, "stack overflow check");
11141115
let stack_growth = state.stack_size() + local_size + unsafe { get_iseq_body_stack_max(iseq) }.as_usize();
1115-
// vm_push_frame() checks it against a decremented cfp, and CHECK_VM_STACK_OVERFLOW0
1116-
// adds to the margin another control frame with `&bounds[1]`.
1117-
const { assert!(RUBY_SIZEOF_CONTROL_FRAME % SIZEOF_VALUE == 0, "sizeof(rb_control_frame_t) is a multiple of sizeof(VALUE)"); }
1118-
let cfp_growth = 2 * (RUBY_SIZEOF_CONTROL_FRAME / SIZEOF_VALUE);
1119-
let peak_offset = SIZEOF_VALUE * (stack_growth + cfp_growth);
1120-
let stack_limit = asm.add(SP, peak_offset.into());
1121-
asm.cmp(CFP, stack_limit);
1122-
asm.jbe(side_exit(jit, state, StackOverflow));
1116+
gen_stack_overflow_check(jit, asm, state, stack_growth);
11231117

11241118
// Save cfp->pc and cfp->sp for the caller frame
11251119
gen_prepare_call_with_gc(asm, state, false);
@@ -1713,6 +1707,19 @@ fn gen_push_frame(asm: &mut Assembler, argc: usize, state: &FrameState, frame: C
17131707
asm.mov(cfp_opnd(RUBY_OFFSET_CFP_BLOCK_CODE), 0.into());
17141708
}
17151709

1710+
/// Stack overflow check: fails if CFP<=SP at any point in the callee.
1711+
fn gen_stack_overflow_check(jit: &mut JITState, asm: &mut Assembler, state: &FrameState, stack_growth: usize) {
1712+
asm_comment!(asm, "stack overflow check");
1713+
// vm_push_frame() checks it against a decremented cfp, and CHECK_VM_STACK_OVERFLOW0
1714+
// adds to the margin another control frame with `&bounds[1]`.
1715+
const { assert!(RUBY_SIZEOF_CONTROL_FRAME % SIZEOF_VALUE == 0, "sizeof(rb_control_frame_t) is a multiple of sizeof(VALUE)"); }
1716+
let cfp_growth = 2 * (RUBY_SIZEOF_CONTROL_FRAME / SIZEOF_VALUE);
1717+
let peak_offset = (cfp_growth + stack_growth) * SIZEOF_VALUE;
1718+
let stack_limit = asm.lea(Opnd::mem(64, SP, peak_offset as i32));
1719+
asm.cmp(CFP, stack_limit);
1720+
asm.jbe(side_exit(jit, state, StackOverflow));
1721+
}
1722+
17161723
/// Return an operand we use for the basic block argument at a given index
17171724
fn param_opnd(idx: usize) -> Opnd {
17181725
// To simplify the implementation, allocate a fixed register or a stack slot for each basic block argument for now.

0 commit comments

Comments
 (0)