summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndré Luiz Tiago Soares <andre.soares@altxtech.net>2025-10-28 20:48:38 -0300
committerGitHub <noreply@github.com>2025-10-28 23:48:38 +0000
commit80be97e4a2c878d7c5a129b245f1e2430b99b19b (patch)
tree9a9df5328302c96e7105efa534cf1056a87058dd
parent9f4a76ff51530e3ff7a9adf0c689f75f1a1cc6d2 (diff)
ZJIT: Fill `cfp->pc` with trap value for C methods in debug builds
-rw-r--r--zjit/src/codegen.rs18
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());