diff options
| author | André Luiz Tiago Soares <andre.soares@altxtech.net> | 2025-10-28 20:48:38 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-10-28 23:48:38 +0000 |
| commit | 80be97e4a2c878d7c5a129b245f1e2430b99b19b (patch) | |
| tree | 9a9df5328302c96e7105efa534cf1056a87058dd | |
| parent | 9f4a76ff51530e3ff7a9adf0c689f75f1a1cc6d2 (diff) | |
ZJIT: Fill `cfp->pc` with trap value for C methods in debug builds
| -rw-r--r-- | zjit/src/codegen.rs | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 5ead4870df..2ac7ca348a 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -25,6 +25,13 @@ use crate::hir_type::{types, Type}; use crate::options::get_option; use crate::cast::IntoUsize; +/// Sentinel program counter stored in C frames when runtime checks are enabled. +const PC_POISON: Option<*const VALUE> = if cfg!(feature = "runtime_checks") { + Some(usize::MAX as *const VALUE) +} else { + None +}; + /// Ephemeral code generation state struct JITState { /// Instruction sequence for the method being compiled @@ -741,6 +748,7 @@ fn gen_ccall_with_frame( iseq: None, cme, frame_type: VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL, + pc: PC_POISON, specval: block_handler_specval, }); @@ -798,6 +806,7 @@ fn gen_ccall_variadic( cme, frame_type: VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL, specval: VM_BLOCK_HANDLER_NONE.into(), + pc: PC_POISON, }); asm_comment!(asm, "switch to new SP register"); @@ -1205,6 +1214,7 @@ fn gen_send_without_block_direct( iseq: Some(iseq), cme, frame_type, + pc: None, specval, }); @@ -1828,6 +1838,7 @@ struct ControlFrame { /// The [`VM_ENV_DATA_INDEX_SPECVAL`] slot of the frame. /// For the type of frames we push, block handler or the parent EP. specval: lir::Opnd, + pc: Option<*const VALUE>, } /// Compile an interpreter frame @@ -1862,8 +1873,11 @@ fn gen_push_frame(asm: &mut Assembler, argc: usize, state: &FrameState, frame: C // cfp_opnd(RUBY_OFFSET_CFP_SP): written by the callee frame on side-exits or non-leaf calls asm.mov(cfp_opnd(RUBY_OFFSET_CFP_ISEQ), VALUE::from(iseq).into()); } else { - // C frames don't have a PC and ISEQ - asm.mov(cfp_opnd(RUBY_OFFSET_CFP_PC), 0.into()); + // C frames don't have a PC and ISEQ in normal operation. + // When runtime checks are enabled we poison the PC so accidental reads stand out. + if let Some(pc) = frame.pc { + asm.mov(cfp_opnd(RUBY_OFFSET_CFP_PC), Opnd::const_ptr(pc)); + } let new_sp = asm.lea(Opnd::mem(64, SP, (ep_offset + 1) * SIZEOF_VALUE_I32)); asm.mov(cfp_opnd(RUBY_OFFSET_CFP_SP), new_sp); asm.mov(cfp_opnd(RUBY_OFFSET_CFP_ISEQ), 0.into()); |
