holey-bytes/hbvm/src/validate.rs

86 lines
2.8 KiB
Rust
Raw Normal View History

2023-06-24 17:18:31 -05:00
//! Validate if program is sound to execute
2023-06-24 17:16:14 -05:00
/// Program validation error kind
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ErrorKind {
2023-06-24 17:16:14 -05:00
/// Unknown opcode
InvalidInstruction,
2023-06-24 17:16:14 -05:00
/// VM doesn't implement this valid opcode
Unimplemented,
2023-06-24 17:16:14 -05:00
/// Attempted to copy over register boundary
RegisterArrayOverflow,
2023-07-13 04:05:41 -05:00
/// Program is not validly terminated
InvalidEnd,
}
2023-06-24 17:16:14 -05:00
/// Error
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Error {
2023-06-24 17:16:14 -05:00
/// Kind
2023-07-07 08:22:03 -05:00
pub kind: ErrorKind,
2023-06-24 17:16:14 -05:00
/// Location in bytecode
pub index: usize,
}
2023-06-24 17:16:14 -05:00
/// Perform bytecode validation. If it passes, the program should be
/// sound to execute.
pub fn validate(mut program: &[u8]) -> Result<(), Error> {
use hbbytecode::opcode::*;
2023-07-13 04:05:41 -05:00
if program.len() < 12 {
return Err(Error {
kind: ErrorKind::InvalidEnd,
index: 0,
});
}
for (index, item) in program.iter().enumerate().skip(program.len() - 12) {
if *item != 0 {
return Err(Error {
kind: ErrorKind::InvalidEnd,
index,
});
}
}
let start = program;
loop {
2023-06-24 17:16:14 -05:00
// Match on instruction types and perform necessary checks
program = match program {
[] => return Ok(()),
2023-07-24 13:41:10 -05:00
[LD..=ST, reg, _, _, _, _, _, _, _, _, count_0, count_1, ..]
if usize::from(*reg) * 8
2023-07-25 12:10:00 -05:00
+ usize::from(u16::from_le_bytes([*count_1, *count_0]))
2023-07-24 13:41:10 -05:00
> 2048 =>
{
return Err(Error {
2023-07-07 08:22:03 -05:00
kind: ErrorKind::RegisterArrayOverflow,
index: (program.as_ptr() as usize) - (start.as_ptr() as usize),
})
}
[BRC, src, dst, count, ..]
if src.checked_add(*count).is_none() || dst.checked_add(*count).is_none() =>
{
return Err(Error {
2023-07-07 08:22:03 -05:00
kind: ErrorKind::RegisterArrayOverflow,
index: (program.as_ptr() as usize) - (start.as_ptr() as usize),
})
}
2023-07-13 04:05:41 -05:00
[UN | NOP | ECALL, rest @ ..]
| [DIR | DIRF, _, _, _, _, rest @ ..]
| [ADD..=CMPU | BRC | ADDF..=MULF, _, _, _, rest @ ..]
2023-07-07 08:22:03 -05:00
| [NEG..=NOT | CP..=SWA | NEGF..=FTI, _, _, rest @ ..]
2023-07-12 05:45:50 -05:00
| [LI, _, _, _, _, _, _, _, _, _, rest @ ..]
2023-07-24 11:48:42 -05:00
| [ADDI..=XORI | CMPI..=CMPUI | BMC | JAL..=JGTU | ADDFI..=MULFI, _, _, _, _, _, _, _, _, _, _, rest @ ..]
| [SLI..=SRSI, _, _, _, _, rest @ ..]
| [LD..=ST, _, _, _, _, _, _, _, _, _, _, _, _, rest @ ..] => rest,
_ => {
return Err(Error {
2023-07-07 08:22:03 -05:00
kind: ErrorKind::InvalidInstruction,
index: (program.as_ptr() as usize) - (start.as_ptr() as usize),
})
}
}
}
}