diff --git a/src/core/error.rs b/src/core/error.rs index f74e88dc..43e430a6 100644 --- a/src/core/error.rs +++ b/src/core/error.rs @@ -1,3 +1,6 @@ +use alloc::format; +use alloc::string::{String, ToString}; + use crate::core::indices::GlobalIdx; use crate::validation_stack::LabelKind; use crate::RefType; @@ -25,6 +28,13 @@ pub enum RuntimeError { ExpectedAValueOnTheStack, } +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum StoreInstantiationError { + ActiveDataWriteOutOfBounds, + I64ValueOutOfReach(String), + MissingValueOnTheStack, +} + #[derive(Debug, PartialEq, Eq, Clone)] pub enum Error { /// The magic number at the very start of the given WASM file is invalid. @@ -72,6 +82,7 @@ pub enum Error { FunctionIsNotDefined(FuncIdx), ReferencingAnUnreferencedFunction(FuncIdx), FunctionTypeIsNotDefined(TypeIdx), + StoreInstantiationError(StoreInstantiationError), } impl Display for Error { @@ -196,6 +207,7 @@ impl Display for Error { "C.fn_types[{}] is NOT defined when it should be", func_ty_idx )), + Error::StoreInstantiationError(err) => err.fmt(f), } } } @@ -220,6 +232,26 @@ impl Display for RuntimeError { } } +impl Display for StoreInstantiationError { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + use StoreInstantiationError::*; + match self { + ActiveDataWriteOutOfBounds => { + f.write_str("Active data writing in memory is out of bounds") + } + I64ValueOutOfReach(s) => f.write_fmt(format_args!( + "I64 value {}is out of reach", + if !s.is_empty() { + format!("for {s} ") + } else { + "".to_string() + } + )), + MissingValueOnTheStack => f.write_str(""), + } + } +} + pub type Result = core::result::Result; impl From for Error { @@ -227,3 +259,9 @@ impl From for Error { Self::RuntimeError(value) } } + +impl From for Error { + fn from(value: StoreInstantiationError) -> Self { + Self::StoreInstantiationError(value) + } +} diff --git a/src/execution/mod.rs b/src/execution/mod.rs index 6e65fc07..98bb495c 100644 --- a/src/execution/mod.rs +++ b/src/execution/mod.rs @@ -1,3 +1,4 @@ +use alloc::borrow::ToOwned; use alloc::string::ToString; use alloc::vec; use alloc::vec::Vec; @@ -10,6 +11,7 @@ use store::{DataInst, ElemInst, TableInst}; use value::{ExternAddr, FuncAddr, Ref}; use value_stack::Stack; +use crate::core::error::StoreInstantiationError; use crate::core::reader::types::element::{ElemItems, ElemMode}; use crate::core::reader::types::export::{Export, ExportDesc}; use crate::core::reader::types::FuncType; @@ -20,7 +22,7 @@ use crate::execution::store::{FuncInst, GlobalInst, MemInst, Store}; use crate::execution::value::Value; use crate::validation::code::read_declared_locals; use crate::value::InteropValueList; -use crate::{RefType, RuntimeError, ValType, ValidationInfo}; +use crate::{RefType, Result as CustomResult, RuntimeError, ValType, ValidationInfo}; // TODO pub(crate) mod assert_validated; @@ -48,14 +50,14 @@ where } impl<'b> RuntimeInstance<'b, EmptyHookSet> { - pub fn new(validation_info: &'_ ValidationInfo<'b>) -> Result { + pub fn new(validation_info: &'_ ValidationInfo<'b>) -> CustomResult { Self::new_with_hooks(DEFAULT_MODULE, validation_info, EmptyHookSet) } pub fn new_named( module_name: &str, validation_info: &'_ ValidationInfo<'b>, - ) -> Result { + ) -> CustomResult { Self::new_with_hooks(module_name, validation_info, EmptyHookSet) } } @@ -68,10 +70,10 @@ where module_name: &str, validation_info: &'_ ValidationInfo<'b>, hook_set: H, - ) -> Result { + ) -> CustomResult { trace!("Starting instantiation of bytecode"); - let store = Self::init_store(validation_info); + let store = Self::init_store(validation_info)?; let mut instance = RuntimeInstance { wasm_bytecode: validation_info.wasm, @@ -314,7 +316,8 @@ where } } - fn init_store(validation_info: &ValidationInfo) -> Store { + fn init_store(validation_info: &ValidationInfo) -> CustomResult { + use StoreInstantiationError::*; let function_instances: Vec = { let mut wasm_reader = WasmReader::new(validation_info.wasm); @@ -447,11 +450,7 @@ where wasm.move_start_to(active_data.offset).unwrap_validated(); let mut stack = Stack::new(); run_const(wasm, &mut stack, ()); - let value = stack.peek_unknown_value(); - if value.is_none() { - panic!("No value on the stack for data segment offset"); - } - value.unwrap() + stack.peek_unknown_value().ok_or(MissingValueOnTheStack)? }; // TODO: this shouldn't be a simple value, should it? I mean it can't be, but it can also be any type of ValType @@ -460,7 +459,7 @@ where Value::I32(val) => val, Value::I64(val) => { if val > u32::MAX as u64 { - panic!("i64 value for data segment offset is out of reach") + return Err(I64ValueOutOfReach("data segment".to_owned())); } val as u32 } @@ -472,7 +471,7 @@ where let len = mem_inst.data.len(); if offset as usize + d.init.len() > len { - panic!("Active data writing in memory, out of bounds"); + return Err(ActiveDataWriteOutOfBounds); } let data = mem_inst .data @@ -480,11 +479,11 @@ where .unwrap(); data.copy_from_slice(&d.init); } - DataInst { + Ok(DataInst { data: d.init.clone(), - } + }) }) - .collect(); + .collect::, StoreInstantiationError>>()?; let global_instances: Vec = validation_info .globals @@ -508,7 +507,7 @@ where }) .collect(); - Store { + Ok(Store { funcs: function_instances, mems: memory_instances, globals: global_instances, @@ -516,7 +515,7 @@ where tables, elements, passive_elem_indexes, - } + }) } } @@ -534,7 +533,7 @@ fn get_address_offset(value: Value) -> u32 { match value { Value::I32(val) => val, Value::Ref(rref) => match rref { - Ref::Extern(_) => panic!("Not yet implemented"), + Ref::Extern(_) => todo!("Not yet implemented"), Ref::Func(func_addr) => func_addr.addr.unwrap() as u32, }, // INFO: from wasmtime - implement only global diff --git a/tests/specification/run.rs b/tests/specification/run.rs index 92dd6221..2de8f017 100644 --- a/tests/specification/run.rs +++ b/tests/specification/run.rs @@ -112,7 +112,11 @@ pub fn run_spec_test(filepath: &str) -> WastTestReport { let instance = try_to!(RuntimeInstance::new(&validation_info).map_err(|err| { CompilationError::new( - Box::new(WasmInterpreterError(wasm::Error::RuntimeError(err))), + Box::new(WasmInterpreterError(wasm::Error::RuntimeError(match err { + wasm::Error::RuntimeError(runtime_error) => runtime_error, + // is it unreachable? + _ => unreachable!(""), + }))), filepath, "failed to create runtime instance", )