fix(vm): verify function should never allocate
This commit is contained in:
parent
582f0435a1
commit
668fc0d6fa
|
@ -43,19 +43,19 @@ impl fmt::Display for Error {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct VerifyError {
|
||||
pub struct VerifyError<'m> {
|
||||
pub from: usize,
|
||||
pub kind: VerifyErrorKind,
|
||||
pub kind: VerifyErrorKind<'m>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum VerifyErrorKind {
|
||||
pub enum VerifyErrorKind<'m> {
|
||||
InvalidJumpTarget { invoked_by: &'static str, to: usize },
|
||||
InstrpOutOfBounds,
|
||||
UnparsableInstruction(Vec<u8>),
|
||||
UnparsableInstruction(&'m [u8]),
|
||||
}
|
||||
|
||||
impl fmt::Display for VerifyError {
|
||||
impl fmt::Display for VerifyError<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use VerifyErrorKind as K;
|
||||
write!(f, "at instruction {}: ", self.from)?;
|
||||
|
@ -72,31 +72,32 @@ impl fmt::Display for VerifyError {
|
|||
/// this should be called before attempting to run an opcode stream to ensure
|
||||
/// that jump targets are valid (this makes it possible to avoid unnecessary
|
||||
/// checks during tight loops)
|
||||
pub fn verify(m: &[u8]) -> Result<(), VerifyError> {
|
||||
let check_jump = |jinstr: &'static str, from: usize, to: u64| -> Result<(), VerifyError> {
|
||||
match usize::try_from(to) {
|
||||
Ok(to) if to == 0 => Ok(()),
|
||||
Ok(to) if matches!(next_instr(m, to), Some(Ok((_, Instr::Label)))) => Ok(()),
|
||||
Ok(to) => Err(VerifyError {
|
||||
from,
|
||||
kind: VerifyErrorKind::InvalidJumpTarget {
|
||||
invoked_by: jinstr,
|
||||
to,
|
||||
},
|
||||
}),
|
||||
Err(_) => Err(VerifyError {
|
||||
from,
|
||||
kind: VerifyErrorKind::InstrpOutOfBounds,
|
||||
}),
|
||||
}
|
||||
};
|
||||
pub fn verify(m: &[u8]) -> Result<(), VerifyError<'_>> {
|
||||
let check_jump =
|
||||
|jinstr: &'static str, from: usize, to: u64| -> Result<(), VerifyError<'static>> {
|
||||
match usize::try_from(to) {
|
||||
Ok(to) if to == 0 => Ok(()),
|
||||
Ok(to) if matches!(next_instr(m, to), Some(Ok((_, Instr::Label)))) => Ok(()),
|
||||
Ok(to) => Err(VerifyError {
|
||||
from,
|
||||
kind: VerifyErrorKind::InvalidJumpTarget {
|
||||
invoked_by: jinstr,
|
||||
to,
|
||||
},
|
||||
}),
|
||||
Err(_) => Err(VerifyError {
|
||||
from,
|
||||
kind: VerifyErrorKind::InstrpOutOfBounds,
|
||||
}),
|
||||
}
|
||||
};
|
||||
|
||||
let mut instrp = 0;
|
||||
|
||||
while let Some(nxti) = next_instr(m, instrp) {
|
||||
let (nxtidelta, nxti) = nxti.map_err(|code| VerifyError {
|
||||
from: instrp,
|
||||
kind: VerifyErrorKind::UnparsableInstruction(code.to_vec()),
|
||||
kind: VerifyErrorKind::UnparsableInstruction(code),
|
||||
})?;
|
||||
assert_ne!(nxtidelta, 0);
|
||||
instrp += nxtidelta;
|
||||
|
|
Loading…
Reference in a new issue