diff --git a/crates/interpreter/src/interpreter/analysis.rs b/crates/interpreter/src/interpreter/analysis.rs index def92c9ab3..1a46b5a794 100644 --- a/crates/interpreter/src/interpreter/analysis.rs +++ b/crates/interpreter/src/interpreter/analysis.rs @@ -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; @@ -163,6 +163,18 @@ impl From 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, @@ -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.