Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 75 additions & 1 deletion crates/interpreter/src/interpreter/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
OPCODE_INFO_JUMPTABLE, STACK_LIMIT,
};
use core::convert::identity;
use std::{borrow::Cow, sync::Arc, vec, vec::Vec};
use std::{borrow::Cow, fmt, sync::Arc, vec, vec::Vec};

const EOF_NON_RETURNING_FUNCTION: u8 = 0x80;

Expand Down Expand Up @@ -163,6 +163,18 @@ impl From<EofValidationError> for EofError {
}
}

impl fmt::Display for EofError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EofError::Decode(e) => write!(f, "Bytecode decode error: {}", e),
EofError::Validation(e) => write!(f, "Bytecode validation error: {}", e),
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for EofError {}

#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum EofValidationError {
FalsePossitive,
Expand Down Expand Up @@ -229,6 +241,68 @@ pub enum EofValidationError {
NoCodeSections,
}

impl fmt::Display for EofValidationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
EofValidationError::FalsePossitive => "False positive",
EofValidationError::UnknownOpcode => "Opcode is not known",
EofValidationError::OpcodeDisabled => "Opcode is disabled",
EofValidationError::InstructionNotForwardAccessed => "Should have forward jump",
EofValidationError::MissingImmediateBytes => "Bytecode is missing bytes",
EofValidationError::MissingRJUMPVImmediateBytes => {
"Bytecode is missing bytes after RJUMPV opcode"
}
EofValidationError::JumpToImmediateBytes => "Invalid jump",
EofValidationError::BackwardJumpToImmediateBytes => "Invalid backward jump",
EofValidationError::RJUMPVZeroMaxIndex => "Used RJUMPV with zero as MaxIndex",
EofValidationError::JumpZeroOffset => "Used JUMP with zero as offset",
EofValidationError::EOFCREATEInvalidIndex =>
"EOFCREATE points to out of bound index",
EofValidationError::CodeSectionOutOfBounds => "CALLF index is out of bounds",
EofValidationError::CALLFNonReturningFunction => {
"CALLF was used on non-returning function"
}
EofValidationError::StackOverflow => "CALLF stack overflow",
EofValidationError::JUMPFEnoughOutputs => "JUMPF needs more outputs",
EofValidationError::JUMPFStackHigherThanOutputs => {
"JUMPF stack is too high for outputs"
}
EofValidationError::DataLoadOutOfBounds => "DATALOAD is out of bounds",
EofValidationError::RETFBiggestStackNumMoreThenOutputs => {
"RETF biggest stack num is more than outputs"
}
EofValidationError::StackUnderflow =>
"Stack requirement is above smallest stack items",
EofValidationError::TypesStackUnderflow => {
"Smallest stack items is more than output type"
}
EofValidationError::JumpUnderflow => "Jump destination is too low",
EofValidationError::JumpOverflow => "Jump destination is too high",
EofValidationError::BackwardJumpBiggestNumMismatch => {
"Backward jump has different biggest stack item"
}
EofValidationError::BackwardJumpSmallestNumMismatch => {
"Backward jump has different smallest stack item"
}
EofValidationError::LastInstructionNotTerminating => {
"Last instruction of bytecode is not terminating"
}
EofValidationError::CodeSectionNotAccessed => "Code section was not accessed",
EofValidationError::InvalidTypesSection => "Invalid types section",
EofValidationError::InvalidFirstTypesSection => "Invalid first types section",
EofValidationError::MaxStackMismatch => "Max stack element mismatchs",
EofValidationError::NoCodeSections => "No code sections",
}
)
}
}

#[cfg(feature = "std")]
impl std::error::Error for EofValidationError {}

/// Validates that:
/// * All instructions are valid.
/// * It ends with a terminating instruction or RJUMP.
Expand Down