fix(vm): verify function should never allocate

This commit is contained in:
Alain Zscheile 2022-10-22 22:00:34 +02:00
parent 582f0435a1
commit 668fc0d6fa

View file

@ -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;