Skip to content

Commit 8e8ad73

Browse files
authored
pulley: Fix interpreter push/pop (#9644)
* Add stack-overflow checking to `push` and other decrements of `sp`. * Fix the up/down direction of push/pop (`push` goes down, `pop` goes up). * Fix the order of operation sin `push`, first decrement then write. * Move methods to `Interpreter` to use `ControlFlow` more heavily.
1 parent 438fc93 commit 8e8ad73

File tree

1 file changed

+83
-28
lines changed

1 file changed

+83
-28
lines changed

pulley/src/interp.rs

Lines changed: 83 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -571,21 +571,6 @@ impl MachineState {
571571

572572
state
573573
}
574-
575-
/// `*sp = val; sp += size_of::<T>()`
576-
fn push<T>(&mut self, val: T) {
577-
let sp = self[XReg::sp].get_ptr::<T>();
578-
unsafe { sp.write_unaligned(val) }
579-
self[XReg::sp].set_ptr(sp.wrapping_add(1));
580-
}
581-
582-
/// `ret = *sp; sp -= size_of::<T>()`
583-
fn pop<T>(&mut self) -> T {
584-
let sp = self[XReg::sp].get_ptr::<T>();
585-
let val = unsafe { sp.read_unaligned() };
586-
self[XReg::sp].set_ptr(sp.wrapping_sub(1));
587-
val
588-
}
589574
}
590575

591576
/// The reason the interpreter loop terminated.
@@ -614,6 +599,76 @@ impl Interpreter<'_> {
614599
self.pc = unsafe { self.pc.offset(offset - inst_size) };
615600
ControlFlow::Continue(())
616601
}
602+
603+
/// `sp -= size_of::<T>(); *sp = val;`
604+
#[must_use]
605+
fn push<T>(&mut self, val: T) -> ControlFlow<Done> {
606+
let new_sp = self.state[XReg::sp].get_ptr::<T>().wrapping_sub(1);
607+
self.set_sp(new_sp)?;
608+
unsafe {
609+
new_sp.write_unaligned(val);
610+
}
611+
ControlFlow::Continue(())
612+
}
613+
614+
/// `ret = *sp; sp -= size_of::<T>()`
615+
fn pop<T>(&mut self) -> T {
616+
let sp = self.state[XReg::sp].get_ptr::<T>();
617+
let val = unsafe { sp.read_unaligned() };
618+
self.set_sp_unchecked(sp.wrapping_add(1));
619+
val
620+
}
621+
622+
/// Sets the stack pointer to the `sp` provided.
623+
///
624+
/// Returns a trap if this would result in stack overflow, or if `sp` is
625+
/// beneath the base pointer of `self.state.stack`.
626+
#[must_use]
627+
fn set_sp<T>(&mut self, sp: *mut T) -> ControlFlow<Done> {
628+
let sp_raw = sp as usize;
629+
let base_raw = self.state.stack.as_ptr() as usize;
630+
if sp_raw < base_raw {
631+
return ControlFlow::Break(Done::Trap(self.pc.as_ptr()));
632+
}
633+
self.set_sp_unchecked(sp);
634+
ControlFlow::Continue(())
635+
}
636+
637+
/// Same as `set_sp` but does not check to see if `sp` is in-bounds. Should
638+
/// only be used with stack increment operations such as `pop`.
639+
fn set_sp_unchecked<T>(&mut self, sp: *mut T) {
640+
if cfg!(debug_assertions) {
641+
let sp_raw = sp as usize;
642+
let base = self.state.stack.as_ptr() as usize;
643+
let end = base + self.state.stack.len();
644+
assert!(base <= sp_raw && sp_raw <= end);
645+
}
646+
self.state[XReg::sp].set_ptr(sp);
647+
}
648+
}
649+
650+
#[test]
651+
fn simple_push_pop() {
652+
let mut state = MachineState::with_stack(vec![0; 16]);
653+
unsafe {
654+
let mut i = Interpreter {
655+
state: &mut state,
656+
// this isn't actually read so just manufacture a dummy one
657+
pc: UnsafeBytecodeStream::new((&mut 0).into()),
658+
};
659+
assert!(i.push(0_i32).is_continue());
660+
assert_eq!(i.pop::<i32>(), 0_i32);
661+
assert!(i.push(1_i32).is_continue());
662+
assert!(i.push(2_i32).is_continue());
663+
assert!(i.push(3_i32).is_continue());
664+
assert!(i.push(4_i32).is_continue());
665+
assert!(i.push(5_i32).is_break());
666+
assert!(i.push(6_i32).is_break());
667+
assert_eq!(i.pop::<i32>(), 4_i32);
668+
assert_eq!(i.pop::<i32>(), 3_i32);
669+
assert_eq!(i.pop::<i32>(), 2_i32);
670+
assert_eq!(i.pop::<i32>(), 1_i32);
671+
}
617672
}
618673

619674
impl OpVisitor for Interpreter<'_> {
@@ -1083,68 +1138,68 @@ impl OpVisitor for Interpreter<'_> {
10831138
}
10841139

10851140
fn xpush32(&mut self, src: XReg) -> ControlFlow<Done> {
1086-
self.state.push(self.state[src].get_u32());
1141+
self.push(self.state[src].get_u32())?;
10871142
ControlFlow::Continue(())
10881143
}
10891144

10901145
fn xpush32_many(&mut self, srcs: RegSet<XReg>) -> ControlFlow<Done> {
10911146
for src in srcs {
1092-
self.state.push(self.state[src].get_u32());
1147+
self.xpush32(src)?;
10931148
}
10941149
ControlFlow::Continue(())
10951150
}
10961151

10971152
fn xpush64(&mut self, src: XReg) -> ControlFlow<Done> {
1098-
self.state.push(self.state[src].get_u64());
1153+
self.push(self.state[src].get_u64())?;
10991154
ControlFlow::Continue(())
11001155
}
11011156

11021157
fn xpush64_many(&mut self, srcs: RegSet<XReg>) -> ControlFlow<Done> {
11031158
for src in srcs {
1104-
self.state.push(self.state[src].get_u64());
1159+
self.xpush64(src)?;
11051160
}
11061161
ControlFlow::Continue(())
11071162
}
11081163

11091164
fn xpop32(&mut self, dst: XReg) -> ControlFlow<Done> {
1110-
let val = self.state.pop();
1165+
let val = self.pop();
11111166
self.state[dst].set_u32(val);
11121167
ControlFlow::Continue(())
11131168
}
11141169

11151170
fn xpop32_many(&mut self, dsts: RegSet<XReg>) -> ControlFlow<Done> {
11161171
for dst in dsts.into_iter().rev() {
1117-
let val = self.state.pop();
1172+
let val = self.pop();
11181173
self.state[dst].set_u32(val);
11191174
}
11201175
ControlFlow::Continue(())
11211176
}
11221177

11231178
fn xpop64(&mut self, dst: XReg) -> ControlFlow<Done> {
1124-
let val = self.state.pop();
1179+
let val = self.pop();
11251180
self.state[dst].set_u64(val);
11261181
ControlFlow::Continue(())
11271182
}
11281183

11291184
fn xpop64_many(&mut self, dsts: RegSet<XReg>) -> ControlFlow<Done> {
11301185
for dst in dsts.into_iter().rev() {
1131-
let val = self.state.pop();
1186+
let val = self.pop();
11321187
self.state[dst].set_u64(val);
11331188
}
11341189
ControlFlow::Continue(())
11351190
}
11361191

11371192
fn push_frame(&mut self) -> ControlFlow<Done> {
1138-
self.state.push(self.state[XReg::lr].get_ptr::<u8>());
1139-
self.state.push(self.state[XReg::fp].get_ptr::<u8>());
1193+
self.push(self.state[XReg::lr].get_ptr::<u8>())?;
1194+
self.push(self.state[XReg::fp].get_ptr::<u8>())?;
11401195
self.state[XReg::fp] = self.state[XReg::sp];
11411196
ControlFlow::Continue(())
11421197
}
11431198

11441199
fn pop_frame(&mut self) -> ControlFlow<Done> {
1145-
self.state[XReg::sp] = self.state[XReg::fp];
1146-
let fp = self.state.pop();
1147-
let lr = self.state.pop();
1200+
self.set_sp_unchecked(self.state[XReg::fp].get_ptr::<u8>());
1201+
let fp = self.pop();
1202+
let lr = self.pop();
11481203
self.state[XReg::fp].set_ptr::<u8>(fp);
11491204
self.state[XReg::lr].set_ptr::<u8>(lr);
11501205
ControlFlow::Continue(())

0 commit comments

Comments
 (0)