From ba1cf56464f8e5c3c7bcc2dc75f10aad2cd56e6b Mon Sep 17 00:00:00 2001 From: Henry Date: Sat, 2 May 2026 21:14:02 +0200 Subject: chore: add more tests, fix issues with import types, cleanup doom example Signed-off-by: Henry --- crates/parser/src/conversion.rs | 64 +++++++++++++++++++++++++---------------- crates/parser/src/error.rs | 2 +- crates/parser/src/lib.rs | 20 ++++++++++++- crates/parser/src/module.rs | 10 +++++++ crates/parser/src/visit.rs | 7 ++++- 5 files changed, 76 insertions(+), 27 deletions(-) (limited to 'crates/parser/src') diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 487f992..8a12daa 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -3,7 +3,7 @@ use alloc::sync::Arc; use crate::{Result, module::FunctionCode, visit::process_operators_and_validate}; use alloc::{boxed::Box, format, string::ToString, vec::Vec}; use tinywasm_types::*; -use wasmparser::{FuncValidator, FuncValidatorAllocations, OperatorsReader, ValidatorResources}; +use wasmparser::{CompositeInnerType, FuncValidator, FuncValidatorAllocations, OperatorsReader, ValidatorResources}; pub(crate) fn convert_module_elements<'a, T: IntoIterator>>>( elements: T, @@ -39,7 +39,7 @@ pub(crate) fn convert_module_element(element: wasmparser::Element<'_>) -> Result .collect::>>()? .into_boxed_slice(); - Ok(tinywasm_types::Element { kind, items, ty: convert_reftype(ty), range: element.range }) + Ok(tinywasm_types::Element { kind, items, ty: convert_reftype(ty)?, range: element.range }) } } } @@ -74,7 +74,7 @@ pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result ImportKind::Function(ty), wasmparser::TypeRef::Table(ty) => ImportKind::Table(TableType { - element_type: convert_reftype(ty.element_type), + element_type: convert_reftype(ty.element_type)?, size_initial: ty.initial.try_into().map_err(|_| { crate::ParseError::UnsupportedOperator(format!("Table size initial is too large: {}", ty.initial)) })?, @@ -87,7 +87,7 @@ pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result ImportKind::Memory(convert_module_memory(ty)), wasmparser::TypeRef::Global(ty) => { - ImportKind::Global(GlobalType::new(convert_valtype(&ty.content_type), ty.mutable)) + ImportKind::Global(GlobalType::new(convert_valtype(&ty.content_type)?, ty.mutable)) } wasmparser::TypeRef::Tag(ty) => { return Err(crate::ParseError::UnsupportedOperator(format!("Unsupported import kind: {ty:?}"))); @@ -129,7 +129,7 @@ pub(crate) fn convert_module_table(table: wasmparser::Table<'_>) -> Result Result = ty.params().iter().map(convert_valtype).collect(); - let results: Vec<_> = ty.results().iter().map(convert_valtype).collect(); + let params = params.into_iter().collect::>>()?; + let results = ty.results().iter().map(convert_valtype).collect::>>()?; Ok(FuncType::new(¶ms, &results).into()) } -pub(crate) fn convert_reftype(reftype: wasmparser::RefType) -> WasmType { +pub(crate) fn convert_reftype(reftype: wasmparser::RefType) -> Result { match reftype { - _ if reftype.is_func_ref() => WasmType::RefFunc, - _ if reftype.is_extern_ref() => WasmType::RefExtern, - _ => unimplemented!("Unsupported reference type: {:?}, {:?}", reftype, reftype.heap_type()), + _ if reftype.is_func_ref() => Ok(WasmType::RefFunc), + _ if reftype.is_extern_ref() => Ok(WasmType::RefExtern), + _ => Err(crate::ParseError::UnsupportedOperator(format!( + "Unsupported reference type: {reftype:?}, {:?}", + reftype.heap_type() + ))), } } -pub(crate) fn convert_valtype(valtype: &wasmparser::ValType) -> WasmType { +pub(crate) fn convert_valtype(valtype: &wasmparser::ValType) -> Result { match valtype { - wasmparser::ValType::I32 => WasmType::I32, - wasmparser::ValType::I64 => WasmType::I64, - wasmparser::ValType::F32 => WasmType::F32, - wasmparser::ValType::F64 => WasmType::F64, - wasmparser::ValType::V128 => WasmType::V128, + wasmparser::ValType::I32 => Ok(WasmType::I32), + wasmparser::ValType::I64 => Ok(WasmType::I64), + wasmparser::ValType::F32 => Ok(WasmType::F32), + wasmparser::ValType::F64 => Ok(WasmType::F64), + wasmparser::ValType::V128 => Ok(WasmType::V128), wasmparser::ValType::Ref(r) => convert_reftype(*r), } } @@ -247,10 +257,14 @@ pub(crate) fn process_const_operators(ops: OperatorsReader<'_>) -> Result match convert_heaptype(*hty) { + wasmparser::Operator::RefNull { hty } => match convert_heaptype(*hty)? { WasmType::RefFunc => ConstInstruction::RefFunc(None), WasmType::RefExtern => ConstInstruction::RefExtern(None), - _ => unimplemented!("Unsupported heap type: {:?}", hty), + other => { + return Err(crate::ParseError::UnsupportedOperator(format!( + "Unsupported ref.null heap type lowered to {other:?}" + ))); + } }, wasmparser::Operator::RefFunc { function_index } => ConstInstruction::RefFunc(Some(*function_index)), wasmparser::Operator::I32Const { value } => ConstInstruction::I32Const(*value), @@ -277,12 +291,14 @@ pub(crate) fn process_const_operators(ops: OperatorsReader<'_>) -> Result WasmType { +pub(crate) fn convert_heaptype(heap: wasmparser::HeapType) -> Result { match heap { - wasmparser::HeapType::Abstract { shared: false, ty: wasmparser::AbstractHeapType::Func } => WasmType::RefFunc, + wasmparser::HeapType::Abstract { shared: false, ty: wasmparser::AbstractHeapType::Func } => { + Ok(WasmType::RefFunc) + } wasmparser::HeapType::Abstract { shared: false, ty: wasmparser::AbstractHeapType::Extern } => { - WasmType::RefExtern + Ok(WasmType::RefExtern) } - _ => unimplemented!("Unsupported heap type: {:?}", heap), + _ => Err(crate::ParseError::UnsupportedOperator(format!("Unsupported heap type: {heap:?}"))), } } diff --git a/crates/parser/src/error.rs b/crates/parser/src/error.rs index 22edd39..7b5dc34 100644 --- a/crates/parser/src/error.rs +++ b/crates/parser/src/error.rs @@ -2,7 +2,7 @@ use alloc::string::{String, ToString}; use core::fmt::{Debug, Display}; use wasmparser::Encoding; -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] /// Errors that can occur when parsing a WebAssembly module pub enum ParseError { /// An invalid type was encountered diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index c4f6ff7..c6ae326 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -283,7 +283,25 @@ impl Parser { continue; } - if eof || reader.end_reached { + if reader.end_reached { + if !buffer.is_empty() { + return Err(ParseError::Other("trailing bytes after end of module".into())); + } + + if !eof { + let read_bytes = Self::read_more(&mut stream, &mut buffer, 1)?; + eof = read_bytes == 0; + + if !eof { + return Err(ParseError::Other("trailing bytes after end of module".into())); + } + } + + reader.process_pending_functions(&self.options)?; + return reader.into_module(&self.options); + } + + if eof { reader.process_pending_functions(&self.options)?; return reader.into_module(&self.options); } diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index 02a3297..5f5e5e2 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -377,6 +377,15 @@ impl<'a> ModuleReader<'a> { }; let mut funcs = Vec::with_capacity(self.code.len()); + let mut func_type_idxs = self + .imports + .iter() + .filter_map(|import| match import.kind { + ImportKind::Function(type_idx) => Some(type_idx), + _ => None, + }) + .collect::>(); + func_type_idxs.extend(self.code_type_addrs.iter().copied()); for (code, ty_idx) in self.code.into_iter().zip(self.code_type_addrs) { let ty = self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone(); @@ -402,6 +411,7 @@ impl<'a> ModuleReader<'a> { Ok(ModuleInner { funcs: funcs.into(), func_types: self.func_types.into(), + func_type_idxs: func_type_idxs.into(), globals: self.globals.into(), table_types: self.table_types.into(), imports: self.imports.into(), diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index f8d5cfd..62db307 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -417,7 +417,12 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild // Reference Types fn visit_ref_null(&mut self, ty: wasmparser::HeapType) -> Self::Output { - self.instructions.push(Instruction::RefNull(convert_heaptype(ty))); + match convert_heaptype(ty) { + Ok(ty) => self.instructions.push(Instruction::RefNull(ty)), + Err(err) => { + self.error.get_or_insert(err); + } + }; } fn visit_typed_select_multi(&mut self, tys: Vec) -> Self::Output { -- cgit v1.3.1