diff options
| author | Stan Lo <stan.lo@shopify.com> | 2025-09-23 20:46:04 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-23 19:46:04 +0000 |
| commit | 39d764ed800fa6c930ff23067de323fd2fde4c2a (patch) | |
| tree | 41477470c7cb02e437885a425b9921dca28d6244 | |
| parent | 990ec01e7ddf4e465d08a69b76dff33aaa3d9e1d (diff) | |
ZJIT: Add stack overflow check to `gen_ccall_variadic` (#14636)
ZJIT: Add stack overflow check to gen_ccall_variadic
| -rw-r--r-- | zjit/src/codegen.rs | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index bd7ab84786..2db30448a3 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -661,6 +661,9 @@ fn gen_ccall_variadic( ) -> lir::Opnd { gen_prepare_non_leaf_call(jit, asm, state); + let stack_growth = state.stack_size(); + gen_stack_overflow_check(jit, asm, state, stack_growth); + gen_push_frame(asm, args.len(), state, ControlFrame { recv, iseq: None, @@ -1109,17 +1112,8 @@ fn gen_send_without_block_direct( state: &FrameState, ) -> lir::Opnd { let local_size = unsafe { get_iseq_body_local_table_size(iseq) }.as_usize(); - // Stack overflow check: fails if CFP<=SP at any point in the callee. - asm_comment!(asm, "stack overflow check"); let stack_growth = state.stack_size() + local_size + unsafe { get_iseq_body_stack_max(iseq) }.as_usize(); - // vm_push_frame() checks it against a decremented cfp, and CHECK_VM_STACK_OVERFLOW0 - // adds to the margin another control frame with `&bounds[1]`. - const { assert!(RUBY_SIZEOF_CONTROL_FRAME % SIZEOF_VALUE == 0, "sizeof(rb_control_frame_t) is a multiple of sizeof(VALUE)"); } - let cfp_growth = 2 * (RUBY_SIZEOF_CONTROL_FRAME / SIZEOF_VALUE); - let peak_offset = SIZEOF_VALUE * (stack_growth + cfp_growth); - let stack_limit = asm.add(SP, peak_offset.into()); - asm.cmp(CFP, stack_limit); - asm.jbe(side_exit(jit, state, StackOverflow)); + gen_stack_overflow_check(jit, asm, state, stack_growth); // Save cfp->pc and cfp->sp for the caller frame 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 asm.mov(cfp_opnd(RUBY_OFFSET_CFP_BLOCK_CODE), 0.into()); } +/// Stack overflow check: fails if CFP<=SP at any point in the callee. +fn gen_stack_overflow_check(jit: &mut JITState, asm: &mut Assembler, state: &FrameState, stack_growth: usize) { + asm_comment!(asm, "stack overflow check"); + // vm_push_frame() checks it against a decremented cfp, and CHECK_VM_STACK_OVERFLOW0 + // adds to the margin another control frame with `&bounds[1]`. + const { assert!(RUBY_SIZEOF_CONTROL_FRAME % SIZEOF_VALUE == 0, "sizeof(rb_control_frame_t) is a multiple of sizeof(VALUE)"); } + let cfp_growth = 2 * (RUBY_SIZEOF_CONTROL_FRAME / SIZEOF_VALUE); + let peak_offset = (cfp_growth + stack_growth) * SIZEOF_VALUE; + let stack_limit = asm.lea(Opnd::mem(64, SP, peak_offset as i32)); + asm.cmp(CFP, stack_limit); + asm.jbe(side_exit(jit, state, StackOverflow)); +} + /// Return an operand we use for the basic block argument at a given index fn param_opnd(idx: usize) -> Opnd { // To simplify the implementation, allocate a fixed register or a stack slot for each basic block argument for now. |
