diff --git a/crates/wasm-encoder/src/core/code.rs b/crates/wasm-encoder/src/core/code.rs index 16ac59caa6..0cfc07b2bb 100644 --- a/crates/wasm-encoder/src/core/code.rs +++ b/crates/wasm-encoder/src/core/code.rs @@ -87,9 +87,10 @@ impl CodeSection { /// into a new code section encoder: /// /// ``` - /// # use wasmparser::{BinaryReader, CodeSectionReader}; + /// # use wasmparser::{BinaryReader, CodeSectionReader, InMemData}; /// // id, size, # entries, entry /// let code_section = [10, 6, 1, 4, 0, 65, 0, 11]; + /// let code_section = InMemData::new(&code_section); /// /// // Parse the code section. /// let reader = BinaryReader::new(&code_section, 0); @@ -100,7 +101,7 @@ impl CodeSection { /// // Add the body to a new code section encoder by copying bytes rather /// // than re-parsing and re-encoding it. /// let mut encoder = wasm_encoder::CodeSection::new(); - /// encoder.raw(&code_section[body_range.start..body_range.end]); + /// encoder.raw(&code_section[body_range]); /// ``` pub fn raw(&mut self, data: &[u8]) -> &mut Self { data.encode(&mut self.bytes); diff --git a/crates/wasm-encoder/src/reencode.rs b/crates/wasm-encoder/src/reencode.rs index c954ab5b4b..52e58dbe31 100644 --- a/crates/wasm-encoder/src/reencode.rs +++ b/crates/wasm-encoder/src/reencode.rs @@ -661,6 +661,7 @@ pub mod utils { use crate::{CoreTypeEncoder, Encode, Imports}; use alloc::vec::Vec; use core::ops::Range; + use wasmparser::InMemData; pub fn parse_core_module( reencoder: &mut T, @@ -685,9 +686,10 @@ pub mod utils { // give us here) and recurse with that. This means that // users overriding `parse_code_section` always get that // function called. - let orig_offset = parser.offset() as usize; - let get_original_section = |range: Range| { - data.get(range.start - orig_offset..range.end - orig_offset) + let orig_offset = parser.offset(); + let get_original_section = |range: Range| { + InMemData::new(data) + .get(range.start - orig_offset..range.end - orig_offset) .ok_or(Error::InvalidCodeSectionSize) }; let mut last_section = None; diff --git a/crates/wasm-encoder/src/reencode/component.rs b/crates/wasm-encoder/src/reencode/component.rs index fe081040c9..ed278a1a57 100644 --- a/crates/wasm-encoder/src/reencode/component.rs +++ b/crates/wasm-encoder/src/reencode/component.rs @@ -390,6 +390,7 @@ pub mod component_utils { use crate::reencode::Error; use alloc::boxed::Box; use alloc::vec::Vec; + use wasmparser::InMemData; pub fn parse_component( reencoder: &mut T, @@ -414,7 +415,8 @@ pub mod component_utils { | wasmparser::Payload::ModuleSection { unchecked_range, .. } => { - remaining = &remaining[unchecked_range.len()..]; + let skipped_len = InMemData::range_len(unchecked_range); + remaining = &remaining[skipped_len..]; } _ => {} } @@ -430,6 +432,7 @@ pub mod component_utils { payload: wasmparser::Payload<'_>, whole_component: &[u8], ) -> Result<(), Error> { + let whole_component = InMemData::new(whole_component); match payload { wasmparser::Payload::Version { encoding: wasmparser::Encoding::Component, @@ -515,7 +518,7 @@ pub mod component_utils { component, parser, &whole_component[unchecked_range], - whole_component, + whole_component.data, )?; } wasmparser::Payload::ComponentStartSection { start, range: _ } => { diff --git a/crates/wasm-metadata/src/add_metadata.rs b/crates/wasm-metadata/src/add_metadata.rs index c5c65bf4c6..b800fcb67c 100644 --- a/crates/wasm-metadata/src/add_metadata.rs +++ b/crates/wasm-metadata/src/add_metadata.rs @@ -1,6 +1,7 @@ use crate::{Producers, rewrite_wasm}; use anyhow::Result; use std::fmt::Debug; +use wasmparser::InMemData; /// Add metadata (module name, producers) to a WebAssembly file. /// @@ -57,7 +58,7 @@ impl AddMetadata { /// section created. pub fn to_wasm(&self, input: &[u8]) -> Result> { let add_producers = Producers::from_meta(self); - rewrite_wasm(self, &add_producers, input) + rewrite_wasm(self, &add_producers, InMemData::new(input)) } } diff --git a/crates/wasm-metadata/src/metadata.rs b/crates/wasm-metadata/src/metadata.rs index 1951f9438e..6c902cd493 100644 --- a/crates/wasm-metadata/src/metadata.rs +++ b/crates/wasm-metadata/src/metadata.rs @@ -28,7 +28,7 @@ pub struct Metadata { /// Version of the packaged software pub version: Option, /// Byte range of the module in the parent binary - pub range: Range, + pub range: Range, /// Dependencies of the component pub dependencies: Option, } diff --git a/crates/wasm-metadata/src/names/component.rs b/crates/wasm-metadata/src/names/component.rs index 530ca56dfe..c184cc61f5 100644 --- a/crates/wasm-metadata/src/names/component.rs +++ b/crates/wasm-metadata/src/names/component.rs @@ -30,7 +30,7 @@ impl<'a> ComponentNames<'a> { } /// Read a component-name section from a WebAssembly binary. Records the component name, as /// well as all other component name fields for later serialization. - pub fn from_bytes(bytes: &'a [u8], offset: usize) -> Result> { + pub fn from_bytes(bytes: &'a [u8], offset: u64) -> Result> { let reader = BinaryReader::new(bytes, offset); let section = ComponentNameSectionReader::new(reader); let mut s = Self::empty(); diff --git a/crates/wasm-metadata/src/names/module.rs b/crates/wasm-metadata/src/names/module.rs index fcb107ab22..66e984f85b 100644 --- a/crates/wasm-metadata/src/names/module.rs +++ b/crates/wasm-metadata/src/names/module.rs @@ -30,7 +30,7 @@ impl<'a> ModuleNames<'a> { } /// Read a name section from a WebAssembly binary. Records the module name, and all other /// contents of name section, for later serialization. - pub fn from_bytes(bytes: &'a [u8], offset: usize) -> Result> { + pub fn from_bytes(bytes: &'a [u8], offset: u64) -> Result> { let reader = BinaryReader::new(bytes, offset); let section = NameSectionReader::new(reader); let mut s = Self::empty(); diff --git a/crates/wasm-metadata/src/payload.rs b/crates/wasm-metadata/src/payload.rs index 853070094b..ec11dfb1ed 100644 --- a/crates/wasm-metadata/src/payload.rs +++ b/crates/wasm-metadata/src/payload.rs @@ -2,7 +2,7 @@ use std::ops::Range; use anyhow::Result; use serde_derive::Serialize; -use wasmparser::{KnownCustom, Parser, Payload::*}; +use wasmparser::{InMemData, KnownCustom, Parser, Payload::*}; use crate::{ Authors, ComponentNames, Description, Homepage, Licenses, Metadata, ModuleNames, Producers, @@ -40,10 +40,10 @@ impl Payload { if output.is_empty() { match encoding { wasmparser::Encoding::Module => { - output.push(Self::empty_module(0..input.len())) + output.push(Self::empty_module(InMemData::new(input).range())) } wasmparser::Encoding::Component => { - output.push(Self::empty_component(0..input.len())) + output.push(Self::empty_component(InMemData::new(input).range())) } } } @@ -191,7 +191,7 @@ impl Payload { } } - fn empty_component(range: Range) -> Self { + fn empty_component(range: Range) -> Self { let mut this = Self::Component { metadata: Metadata::default(), children: vec![], @@ -200,7 +200,7 @@ impl Payload { this } - fn empty_module(range: Range) -> Self { + fn empty_module(range: Range) -> Self { let mut this = Self::Module(Metadata::default()); this.metadata_mut().range = range; this diff --git a/crates/wasm-metadata/src/producers.rs b/crates/wasm-metadata/src/producers.rs index 5a5f793767..747c5b4645 100644 --- a/crates/wasm-metadata/src/producers.rs +++ b/crates/wasm-metadata/src/producers.rs @@ -1,7 +1,7 @@ use anyhow::Result; use indexmap::{IndexMap, map::Entry}; use wasm_encoder::Encode; -use wasmparser::{BinaryReader, KnownCustom, Parser, ProducersSectionReader}; +use wasmparser::{BinaryReader, InMemData, KnownCustom, Parser, ProducersSectionReader}; use crate::{AddMetadata, rewrite_wasm}; /// A representation of a WebAssembly producers section. @@ -58,7 +58,7 @@ impl Producers { Ok(None) } /// Read the producers section from a Wasm binary. - pub fn from_bytes(bytes: &[u8], offset: usize) -> Result { + pub fn from_bytes(bytes: &[u8], offset: u64) -> Result { let reader = BinaryReader::new(bytes, offset); let section = ProducersSectionReader::new(reader)?; let mut fields = IndexMap::new(); @@ -150,7 +150,7 @@ impl Producers { /// Merge into an existing wasm module. Rewrites the module with this producers section /// merged into its existing one, or adds this producers section if none is present. pub fn add_to_wasm(&self, input: &[u8]) -> Result> { - rewrite_wasm(&Default::default(), self, input) + rewrite_wasm(&Default::default(), self, InMemData::new(input)) } } diff --git a/crates/wasm-metadata/src/rewrite.rs b/crates/wasm-metadata/src/rewrite.rs index 358dc3895a..c94c2dff0a 100644 --- a/crates/wasm-metadata/src/rewrite.rs +++ b/crates/wasm-metadata/src/rewrite.rs @@ -4,12 +4,12 @@ use anyhow::Result; use std::mem; use wasm_encoder::ComponentSection as _; use wasm_encoder::{ComponentSectionId, Encode, Section}; -use wasmparser::{KnownCustom, Parser, Payload::*}; +use wasmparser::{InMemData, KnownCustom, Parser, Payload::*}; pub(crate) fn rewrite_wasm( metadata: &AddMetadata, add_producers: &Producers, - input: &[u8], + input: InMemData, ) -> Result> { let mut producers_found = false; let mut names_found = false; diff --git a/crates/wasm-mutate/src/info.rs b/crates/wasm-mutate/src/info.rs index d8f81d391a..8dd6414d1f 100644 --- a/crates/wasm-mutate/src/info.rs +++ b/crates/wasm-mutate/src/info.rs @@ -5,7 +5,7 @@ use crate::{ use std::collections::HashSet; use std::ops::Range; use wasm_encoder::{RawSection, SectionId}; -use wasmparser::{BinaryReader, Chunk, Parser, Payload}; +use wasmparser::{BinaryReader, Chunk, InMemData, Parser, Payload}; /// Provides module information for future usage during mutation /// an instance of ModuleInfo could be user to determine which mutation could be applied @@ -54,7 +54,7 @@ pub struct ModuleInfo<'a> { // raw_sections pub raw_sections: Vec>, - pub input_wasm: &'a [u8], + pub input_wasm: InMemData<'a>, } impl<'a> ModuleInfo<'a> { @@ -63,7 +63,7 @@ impl<'a> ModuleInfo<'a> { let mut parser = Parser::new(0); let mut info = ModuleInfo::default(); let mut wasm = input_wasm; - info.input_wasm = wasm; + info.input_wasm = InMemData::new(wasm); loop { let (payload, consumed) = match parser.parse(wasm, true)? { @@ -79,16 +79,16 @@ impl<'a> ModuleInfo<'a> { size: _, } => { info.code = Some(info.raw_sections.len()); - info.section(SectionId::Code.into(), range.clone(), input_wasm); + info.section(SectionId::Code.into(), range.clone()); parser.skip_section(); // update slice, bypass the section - wasm = &input_wasm[range.end..]; + wasm = info.input_wasm.index(range.end..); continue; } Payload::TypeSection(reader) => { info.types = Some(info.raw_sections.len()); - info.section(SectionId::Type.into(), reader.range(), input_wasm); + info.section(SectionId::Type.into(), reader.range()); // Save function types for ty in reader.into_iter_err_on_gc_types() { @@ -97,7 +97,7 @@ impl<'a> ModuleInfo<'a> { } Payload::ImportSection(reader) => { info.imports = Some(info.raw_sections.len()); - info.section(SectionId::Import.into(), reader.range(), input_wasm); + info.section(SectionId::Import.into(), reader.range()); for ty in reader.into_imports() { match ty?.ty { @@ -130,7 +130,7 @@ impl<'a> ModuleInfo<'a> { } Payload::FunctionSection(reader) => { info.functions = Some(info.raw_sections.len()); - info.section(SectionId::Function.into(), reader.range(), input_wasm); + info.section(SectionId::Function.into(), reader.range()); for ty in reader { info.function_map.push(ty?); @@ -139,7 +139,7 @@ impl<'a> ModuleInfo<'a> { Payload::TableSection(reader) => { info.tables = Some(info.raw_sections.len()); info.table_count += reader.count(); - info.section(SectionId::Table.into(), reader.range(), input_wasm); + info.section(SectionId::Table.into(), reader.range()); for table in reader { let table = table?; @@ -149,7 +149,7 @@ impl<'a> ModuleInfo<'a> { Payload::MemorySection(reader) => { info.memories = Some(info.raw_sections.len()); info.memory_count += reader.count(); - info.section(SectionId::Memory.into(), reader.range(), input_wasm); + info.section(SectionId::Memory.into(), reader.range()); for ty in reader { info.memory_types.push(ty?); @@ -157,7 +157,7 @@ impl<'a> ModuleInfo<'a> { } Payload::GlobalSection(reader) => { info.globals = Some(info.raw_sections.len()); - info.section(SectionId::Global.into(), reader.range(), input_wasm); + info.section(SectionId::Global.into(), reader.range()); for ty in reader { let ty = ty?; @@ -174,36 +174,36 @@ impl<'a> ModuleInfo<'a> { info.export_names.insert(entry?.name.into()); } - info.section(SectionId::Export.into(), reader.range(), input_wasm); + info.section(SectionId::Export.into(), reader.range()); } Payload::StartSection { func, range } => { info.start = Some(info.raw_sections.len()); info.start_function = Some(func); - info.section(SectionId::Start.into(), range, input_wasm); + info.section(SectionId::Start.into(), range); } Payload::ElementSection(reader) => { info.elements = Some(info.raw_sections.len()); info.elements_count = reader.count(); - info.section(SectionId::Element.into(), reader.range(), input_wasm); + info.section(SectionId::Element.into(), reader.range()); } Payload::DataSection(reader) => { info.data = Some(info.raw_sections.len()); info.data_segments_count = reader.count(); - info.section(SectionId::Data.into(), reader.range(), input_wasm); + info.section(SectionId::Data.into(), reader.range()); } Payload::CustomSection(c) => { - info.section(SectionId::Custom.into(), c.range(), input_wasm); + info.section(SectionId::Custom.into(), c.range()); } Payload::UnknownSection { id, contents: _, range, } => { - info.section(id, range, input_wasm); + info.section(id, range); } Payload::DataCountSection { count: _, range } => { info.data_count = Some(info.raw_sections.len()); - info.section(SectionId::DataCount.into(), range, input_wasm); + info.section(SectionId::DataCount.into(), range); } Payload::Version { .. } => {} Payload::End(_) => { @@ -241,10 +241,10 @@ impl<'a> ModuleInfo<'a> { } /// Registers a new raw_section in the ModuleInfo - pub fn section(&mut self, id: u8, range: Range, full_wasm: &'a [u8]) { + pub fn section(&mut self, id: u8, range: Range) { self.raw_sections.push(RawSection { id, - data: &full_wasm[range], + data: self.input_wasm.index(range), }); } diff --git a/crates/wasm-mutate/src/mutators.rs b/crates/wasm-mutate/src/mutators.rs index 621ca2c2aa..fd92e609fe 100644 --- a/crates/wasm-mutate/src/mutators.rs +++ b/crates/wasm-mutate/src/mutators.rs @@ -105,7 +105,7 @@ pub trait Mutator { } /// Type helper to wrap operator and the byte offset in the code section of a Wasm module -pub type OperatorAndByteOffset<'a> = (Operator<'a>, usize); +pub type OperatorAndByteOffset<'a> = (Operator<'a>, u64); #[cfg(test)] fn match_mutation(original: &str, mutator: T, expected: &str) diff --git a/crates/wasm-mutate/src/mutators/codemotion.rs b/crates/wasm-mutate/src/mutators/codemotion.rs index 74fac3e193..1d3f5a129f 100644 --- a/crates/wasm-mutate/src/mutators/codemotion.rs +++ b/crates/wasm-mutate/src/mutators/codemotion.rs @@ -33,7 +33,7 @@ use crate::{ }; use rand::{RngExt, prelude::*}; use wasm_encoder::{CodeSection, Function, Module, ValType}; -use wasmparser::{CodeSectionReader, FunctionBody}; +use wasmparser::{CodeSectionReader, FunctionBody, InMemData}; /// Code motion meta mutator, it groups all code motion mutators and select a /// valid random one when an input Wasm binary is passed to it. @@ -62,8 +62,10 @@ impl CodemotionMutator { config: &mut WasmMutate, mutators: &[Box], ) -> crate::Result<(Function, u32)> { - let original_code_section = config.info().code.unwrap(); - let reader = config.info().get_binary_reader(original_code_section); + let info = config.info(); + let original_code_section = info.code.unwrap(); + let reader = info.get_binary_reader(original_code_section); + let input_code_section = InMemData::new(info.get_code_section().data); let sectionreader = CodeSectionReader::new(reader)?; let function_count = sectionreader.count(); let function_to_mutate = config.rng().random_range(0..function_count); @@ -100,7 +102,7 @@ impl CodemotionMutator { &ast, &self.copy_locals(reader)?, &operators, - config.info().raw_sections[original_code_section].data, + input_code_section, )?; return Ok((newfunc, fidx)); } @@ -120,7 +122,7 @@ pub trait AstMutator { ast: &Ast, locals: &[(u32, ValType)], operators: &Vec, - input_wasm: &'a [u8], + input_code_section: InMemData<'a>, ) -> Result; /// Checks if this mutator can be applied to the passed `ast` diff --git a/crates/wasm-mutate/src/mutators/codemotion/if_complement.rs b/crates/wasm-mutate/src/mutators/codemotion/if_complement.rs index f3d8be44e0..aac8750ba5 100644 --- a/crates/wasm-mutate/src/mutators/codemotion/if_complement.rs +++ b/crates/wasm-mutate/src/mutators/codemotion/if_complement.rs @@ -4,6 +4,7 @@ //! in the stack is written. The "negation" is encoded with a `i32.eqz` operator. use rand::prelude::*; use wasm_encoder::{Function, ValType}; +use wasmparser::InMemData; use crate::{ WasmMutate, @@ -38,7 +39,7 @@ impl IfComplementWriter { alternative: &Option>, newfunc: &mut wasm_encoder::Function, operators: &Vec, - input_wasm: &'a [u8], + input_wasm: InMemData<'a>, ty: &wasmparser::BlockType, ) -> crate::Result<()> { // negate the value on the stack @@ -74,7 +75,7 @@ impl AstWriter for IfComplementWriter { alternative: &Option>, newfunc: &mut wasm_encoder::Function, operators: &Vec, - input_wasm: &'a [u8], + input_wasm: InMemData<'a>, ty: &wasmparser::BlockType, ) -> crate::Result<()> { if self.if_to_mutate == nodeidx { @@ -115,7 +116,7 @@ impl AstMutator for IfComplementMutator { ast: &Ast, locals: &[(u32, ValType)], operators: &Vec, - input_wasm: &'a [u8], + input_wasm: InMemData<'a>, ) -> crate::Result { // Select the if index let mut newfunc = Function::new(locals.to_vec()); diff --git a/crates/wasm-mutate/src/mutators/codemotion/ir.rs b/crates/wasm-mutate/src/mutators/codemotion/ir.rs index 8bd2e45167..198128c19c 100644 --- a/crates/wasm-mutate/src/mutators/codemotion/ir.rs +++ b/crates/wasm-mutate/src/mutators/codemotion/ir.rs @@ -6,7 +6,7 @@ use crate::{ }; use std::ops::Range; use wasm_encoder::Function; -use wasmparser::{BlockType, Operator}; +use wasmparser::{BlockType, InMemData, Operator}; use self::parse_context::{Ast, Node, State}; @@ -29,7 +29,7 @@ pub trait AstWriter { body: &[usize], newfunc: &mut Function, operators: &Vec, - input_wasm: &'a [u8], + input_wasm: InMemData<'a>, ty: &BlockType, ) -> crate::Result<()> { self.write_loop_default(ast, nodeidx, body, newfunc, operators, input_wasm, ty) @@ -46,7 +46,7 @@ pub trait AstWriter { body: &[usize], newfunc: &mut Function, operators: &Vec, - input_wasm: &'a [u8], + input_wasm: InMemData<'a>, ty: &BlockType, ) -> crate::Result<()> { newfunc.instructions().loop_(map_block_type(*ty)?); @@ -68,7 +68,7 @@ pub trait AstWriter { body: &[usize], newfunc: &mut Function, operators: &Vec, - input_wasm: &'a [u8], + input_wasm: InMemData<'a>, ty: &BlockType, ) -> crate::Result<()> { newfunc.instructions().block(map_block_type(*ty)?); @@ -94,7 +94,7 @@ pub trait AstWriter { body: &[usize], newfunc: &mut Function, operators: &Vec, - input_wasm: &'a [u8], + input_wasm: InMemData<'a>, ty: &BlockType, ) -> crate::Result<()> { self.write_block_default(ast, nodeidx, body, newfunc, operators, input_wasm, ty) @@ -114,7 +114,7 @@ pub trait AstWriter { alternative: &Option>, newfunc: &mut Function, operators: &Vec, - input_wasm: &'a [u8], + input_wasm: InMemData<'a>, ty: &BlockType, ) -> crate::Result<()> { self.write_if_else_default( @@ -141,7 +141,7 @@ pub trait AstWriter { alternative: &Option>, newfunc: &mut Function, operators: &Vec, - input_wasm: &'a [u8], + input_wasm: InMemData<'a>, ty: &BlockType, ) -> crate::Result<()> { newfunc.instructions().if_(map_block_type(*ty)?); @@ -174,7 +174,7 @@ pub trait AstWriter { range: Range, newfunc: &mut Function, operators: &Vec, - input_wasm: &'a [u8], + input_wasm: InMemData<'a>, ) -> crate::Result<()> { let operator_range = (range.start, range.end); let bytes_range = ( @@ -195,7 +195,7 @@ pub trait AstWriter { nodeidx: usize, newfunc: &mut Function, operators: &Vec, - input_wasm: &'a [u8], + input_wasm: InMemData<'a>, ) -> crate::Result<()> { let node = &ast.get_nodes()[nodeidx]; diff --git a/crates/wasm-mutate/src/mutators/codemotion/loop_unrolling.rs b/crates/wasm-mutate/src/mutators/codemotion/loop_unrolling.rs index 1ac91394e6..eb0f9138fe 100644 --- a/crates/wasm-mutate/src/mutators/codemotion/loop_unrolling.rs +++ b/crates/wasm-mutate/src/mutators/codemotion/loop_unrolling.rs @@ -4,7 +4,7 @@ use std::{collections::HashMap, slice::Iter}; use rand::prelude::*; use wasm_encoder::{Function, Instruction, ValType}; -use wasmparser::{BlockType, Operator}; +use wasmparser::{BlockType, InMemData, Operator}; use crate::{ Error, WasmMutate, @@ -36,7 +36,7 @@ impl LoopUnrollWriter { chunk: Iter, to_fix: &HashMap, newfunc: &mut Function, - input_wasm: &'a [u8], + input_code_section: InMemData<'a>, ) -> crate::Result<()> { for (idx, ((_, curr_offset), (_, next_offset))) in chunk.clone().zip(chunk.skip(1)).enumerate() @@ -44,7 +44,7 @@ impl LoopUnrollWriter { if to_fix.contains_key(&idx) { newfunc.instruction(&to_fix[&idx]); } else { - let piece = &input_wasm[*curr_offset..*next_offset]; + let piece = &input_code_section[*curr_offset..*next_offset]; newfunc.raw(piece.to_vec()); } } @@ -57,7 +57,7 @@ impl LoopUnrollWriter { nodeidx: usize, newfunc: &mut Function, operators: &Vec, - input_wasm: &'a [u8], + input_code_section: InMemData<'a>, ) -> crate::Result<()> { let nodes = ast.get_nodes(); @@ -128,7 +128,12 @@ impl LoopUnrollWriter { let including_chunk = operators[range.start + 1 /* skip the loop instruction */..range.end + 1] .iter(); - self.write_and_fix_loop_body(including_chunk, &to_fix, newfunc, input_wasm)?; + self.write_and_fix_loop_body( + including_chunk, + &to_fix, + newfunc, + input_code_section, + )?; // Write A' br B' newfunc.instructions().br(1); @@ -140,7 +145,12 @@ impl LoopUnrollWriter { let including_chunk = operators[range.start + 1 /* skip the loop instruction */..range.end + 1] .iter(); - self.write_and_fix_loop_body(including_chunk, &to_fix, newfunc, input_wasm)?; + self.write_and_fix_loop_body( + including_chunk, + &to_fix, + newfunc, + input_code_section, + )?; // Closing loop newfunc.instructions().end(); @@ -162,13 +172,21 @@ impl AstWriter for LoopUnrollWriter { body: &[usize], newfunc: &mut Function, operators: &Vec, - input_wasm: &'a [u8], + input_code_section: InMemData<'a>, ty: &wasmparser::BlockType, ) -> crate::Result<()> { if self.loop_to_mutate == nodeidx { - self.unroll_loop(ast, nodeidx, newfunc, operators, input_wasm)?; + self.unroll_loop(ast, nodeidx, newfunc, operators, input_code_section)?; } else { - self.write_loop_default(ast, nodeidx, body, newfunc, operators, input_wasm, ty)?; + self.write_loop_default( + ast, + nodeidx, + body, + newfunc, + operators, + input_code_section, + ty, + )?; } Ok(()) } @@ -210,7 +228,7 @@ impl AstMutator for LoopUnrollMutator { ast: &Ast, locals: &[(u32, ValType)], operators: &Vec, - input_wasm: &'a [u8], + input_code_section: InMemData<'a>, ) -> crate::Result { // Select the if index let mut newfunc = Function::new(locals.to_vec()); @@ -221,7 +239,13 @@ impl AstMutator for LoopUnrollMutator { let writer = LoopUnrollWriter { loop_to_mutate: *loop_index, }; - writer.write(ast, ast.get_root(), &mut newfunc, operators, input_wasm)?; + writer.write( + ast, + ast.get_root(), + &mut newfunc, + operators, + input_code_section, + )?; Ok(newfunc) } } diff --git a/crates/wasm-mutate/src/mutators/peephole.rs b/crates/wasm-mutate/src/mutators/peephole.rs index 97a24f10ac..6523850afa 100644 --- a/crates/wasm-mutate/src/mutators/peephole.rs +++ b/crates/wasm-mutate/src/mutators/peephole.rs @@ -42,7 +42,7 @@ use egg::{Rewrite, Runner}; use rand::RngExt; use wasm_encoder::reencode::{Reencode, RoundtripReencoder}; use wasm_encoder::{CodeSection, ConstExpr, Function, GlobalSection, Module, ValType}; -use wasmparser::{CodeSectionReader, FunctionBody, GlobalSectionReader, LocalsReader}; +use wasmparser::{CodeSectionReader, FunctionBody, GlobalSectionReader, InMemData, LocalsReader}; /// This mutator applies a random peephole transformation to the input Wasm module #[derive(Clone)] @@ -108,6 +108,7 @@ impl PeepholeMutator { ) -> Result> + 'a>> { let code_section = config.info().code.unwrap(); let reader = config.info().get_binary_reader(code_section); + let input_code_section = InMemData::new(config.info().get_code_section().data); let sectionreader = CodeSectionReader::new(reader)?; let function_count = sectionreader.count(); let mut function_to_mutate = config.rng().random_range(0..function_count); @@ -260,6 +261,7 @@ impl PeepholeMutator { &mut newfunc, &minidfg, &egraph, + input_code_section, )?; let mut codes = CodeSection::new(); diff --git a/crates/wasm-mutate/src/mutators/peephole/eggsy/encoder.rs b/crates/wasm-mutate/src/mutators/peephole/eggsy/encoder.rs index 590b23db42..8be1c0696f 100644 --- a/crates/wasm-mutate/src/mutators/peephole/eggsy/encoder.rs +++ b/crates/wasm-mutate/src/mutators/peephole/eggsy/encoder.rs @@ -8,6 +8,7 @@ use crate::mutators::peephole::{OperatorAndByteOffset, dfg::BBlock}; use egg::RecExpr; use wasm_encoder::Function; +use wasmparser::InMemData; use self::expr2wasm::ResourceRequest; @@ -34,11 +35,12 @@ impl Encoder { newfunc: &mut Function, dfg: &MiniDFG, egraph: &EG, + input_code_section: InMemData, ) -> crate::Result> { // Copy previous code let range = basicblock.range.clone(); let byterange = (&operators[0].1, &operators[range.start].1); - let bytes = &config.info().get_code_section().data[*byterange.0..*byterange.1]; + let bytes = &input_code_section[*byterange.0..*byterange.1]; newfunc.raw(bytes.iter().copied()); // Write all entries in the minidfg in reverse order @@ -65,7 +67,7 @@ impl Encoder { &operators[range.end].1, // In the worst case the next instruction will be and end &operators[operators.len() - 1].1, ); - let bytes = &config.info().get_code_section().data[*byterange.0..=*byterange.1]; + let bytes = &input_code_section[*byterange.0..=*byterange.1]; newfunc.raw(bytes.iter().copied()); Ok(resource_request) diff --git a/crates/wasm-mutate/src/mutators/remove_item.rs b/crates/wasm-mutate/src/mutators/remove_item.rs index 7fd9da4dbb..ef07952b4b 100644 --- a/crates/wasm-mutate/src/mutators/remove_item.rs +++ b/crates/wasm-mutate/src/mutators/remove_item.rs @@ -123,7 +123,7 @@ impl RemoveItem<'_> { self.parse_core_module( &mut module, wasmparser::Parser::new(0), - self.info.input_wasm, + self.info.input_wasm.data, )?; // If an index was used that was actually being removed then flag this diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index fb9a2b4504..555cd728ab 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -13,6 +13,7 @@ * limitations under the License. */ +use crate::offsets::*; use crate::prelude::*; use crate::{limits::*, *}; use core::marker; @@ -26,7 +27,7 @@ pub(crate) const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm"; pub struct BinaryReader<'a> { buffer: &'a [u8], position: usize, - original_offset: usize, + original_offset: u64, // When the `features` feature is disabled then the `WasmFeatures` type // still exists but this field is still omitted. When `features` is @@ -54,9 +55,10 @@ impl<'a> BinaryReader<'a> { /// The returned binary reader will have all features known to this crate /// enabled. To reject binaries that aren't valid unless a certain feature /// is enabled use the [`BinaryReader::new_features`] constructor instead. - pub fn new(data: &[u8], original_offset: usize) -> BinaryReader<'_> { + pub fn new(data: &[u8], original_offset: u64) -> BinaryReader<'_> { + let max_len = max_memory_offset(u64::MAX - original_offset, data.len()); BinaryReader { - buffer: data, + buffer: &data[..max_len], position: 0, original_offset, #[cfg(feature = "features")] @@ -97,11 +99,12 @@ impl<'a> BinaryReader<'a> { #[cfg(feature = "features")] pub fn new_features( data: &[u8], - original_offset: usize, + original_offset: u64, features: WasmFeatures, ) -> BinaryReader<'_> { + let max_len = max_memory_offset(u64::MAX - original_offset, data.len()); BinaryReader { - buffer: data, + buffer: &data[..max_len], position: 0, original_offset, features, @@ -119,10 +122,12 @@ impl<'a> BinaryReader<'a> { /// Otherwise parsing values from either `self` or the return value should /// return the same thing. pub(crate) fn shrink(&self) -> BinaryReader<'a> { + let buffer = &self.buffer[self.position..]; + let original_offset = self.original_position(); BinaryReader { - buffer: &self.buffer[self.position..], + buffer, position: 0, - original_offset: self.original_offset + self.position, + original_offset, #[cfg(feature = "features")] features: self.features, } @@ -130,8 +135,8 @@ impl<'a> BinaryReader<'a> { /// Gets the original position of the binary reader. #[inline] - pub fn original_position(&self) -> usize { - self.original_offset + self.position + pub fn original_position(&self) -> u64 { + self.original_offset + self.position as u64 } /// Returns the currently active set of wasm features that this reader is @@ -152,28 +157,39 @@ impl<'a> BinaryReader<'a> { } /// Returns a range from the starting offset to the end of the buffer. - pub fn range(&self) -> Range { - self.original_offset..self.original_offset + self.buffer.len() + pub fn range(&self) -> Range { + self.original_offset..(self.original_offset + self.max_offset() as u64) } pub(crate) fn remaining_buffer(&self) -> &'a [u8] { &self.buffer[self.position..] } + /// Returns a range from the current position to the end of the buffer. + pub fn remaining_range(&self) -> Range { + self.original_position()..(self.original_offset + self.max_offset() as u64) + } + + fn max_offset(&self) -> usize { + // constructor enforces: + // self.buffer.len() <= max_memory_offset(u64::MAX - self.original_offset, self.buffer.len()) + self.buffer.len() + } + fn ensure_has_byte(&self) -> Result<()> { - if self.position < self.buffer.len() { + if self.position < self.max_offset() { Ok(()) } else { - Err(Error::eof(self.original_position(), 1)) + Err(self.eof_err(1)) } } - pub(crate) fn ensure_has_bytes(&self, len: usize) -> Result<()> { - if self.position + len <= self.buffer.len() { - Ok(()) - } else { - let hint = self.position + len - self.buffer.len(); - Err(Error::eof(self.original_position(), hint)) + /// Returns the offset past `len` bytes on success + pub(crate) fn ensure_has_bytes(&self, len: usize) -> Result { + let remaining = self.bytes_remaining(); + match len <= remaining { + true => Ok(self.position + len), + false => Err(self.eof_err(len - remaining)), } } @@ -195,7 +211,7 @@ impl<'a> BinaryReader<'a> { Ok(b) } - pub(crate) fn external_kind_from_byte(byte: u8, offset: usize) -> Result { + pub(crate) fn external_kind_from_byte(byte: u8, offset: u64) -> Result { match byte { 0x00 => Ok(ExternalKind::Func), 0x01 => Ok(ExternalKind::Table), @@ -244,7 +260,7 @@ impl<'a> BinaryReader<'a> { /// Returns whether the `BinaryReader` has reached the end of the file. #[inline] pub fn eof(&self) -> bool { - self.position >= self.buffer.len() + self.position >= self.max_offset() } /// Returns the `BinaryReader`'s current position. @@ -256,7 +272,7 @@ impl<'a> BinaryReader<'a> { /// Returns the number of bytes remaining in the `BinaryReader`. #[inline] pub fn bytes_remaining(&self) -> usize { - self.buffer.len() - self.position + self.max_offset() - self.position } /// Advances the `BinaryReader` `size` bytes, and returns a slice from the @@ -265,10 +281,10 @@ impl<'a> BinaryReader<'a> { /// # Errors /// If `size` exceeds the remaining length in `BinaryReader`. pub fn read_bytes(&mut self, size: usize) -> Result<&'a [u8]> { - self.ensure_has_bytes(size)?; let start = self.position; - self.position += size; - Ok(&self.buffer[start..self.position]) + let end = self.ensure_has_bytes(size)?; + self.position = end; + Ok(&self.buffer[start..end]) } /// Reads a length-prefixed list of bytes from this reader and returns a @@ -285,13 +301,8 @@ impl<'a> BinaryReader<'a> { /// # Errors /// If `BinaryReader` has less than four bytes remaining. pub fn read_u32(&mut self) -> Result { - self.ensure_has_bytes(4)?; - let word = u32::from_le_bytes( - self.buffer[self.position..self.position + 4] - .try_into() - .unwrap(), - ); - self.position += 4; + let chunk = self.read_bytes(4)?; + let word = u32::from_le_bytes(chunk.try_into().unwrap()); Ok(word) } @@ -299,13 +310,8 @@ impl<'a> BinaryReader<'a> { /// # Errors /// If `BinaryReader` has less than eight bytes remaining. pub fn read_u64(&mut self) -> Result { - self.ensure_has_bytes(8)?; - let word = u64::from_le_bytes( - self.buffer[self.position..self.position + 8] - .try_into() - .unwrap(), - ); - self.position += 8; + let chunk = self.read_bytes(8)?; + let word = u64::from_le_bytes(chunk.try_into().unwrap()); Ok(word) } @@ -316,17 +322,13 @@ impl<'a> BinaryReader<'a> { /// If `BinaryReader` has no bytes remaining. #[inline] pub fn read_u8(&mut self) -> Result { - let b = match self.buffer.get(self.position) { - Some(b) => *b, - None => return Err(self.eof_err()), - }; - self.position += 1; + let [b] = self.read_bytes(1)?.try_into().unwrap(); Ok(b) } #[cold] - fn eof_err(&self) -> Error { - Error::eof(self.original_position(), 1) + fn eof_err(&self, hint: usize) -> Error { + Error::eof(self.original_position(), hint) } /// Advances the `BinaryReader` up to four bytes to parse a variable @@ -414,12 +416,13 @@ impl<'a> BinaryReader<'a> { /// Executes `f` to skip some data in this binary reader and then returns a /// reader which will read the skipped data. pub fn skip(&mut self, f: impl FnOnce(&mut Self) -> Result<()>) -> Result { + let start_offset = self.original_position(); let start = self.position; f(self)?; let mut ret = self.clone(); ret.buffer = &self.buffer[start..self.position]; + ret.original_offset = start_offset; ret.position = 0; - ret.original_offset = self.original_offset + start; Ok(ret) } @@ -618,7 +621,7 @@ impl<'a> BinaryReader<'a> { )) } - pub(crate) fn invalid_leading_byte_error(byte: u8, desc: &str, offset: usize) -> Error { + pub(crate) fn invalid_leading_byte_error(byte: u8, desc: &str, offset: u64) -> Error { format_err!(offset, "invalid leading byte (0x{byte:x}) for {desc}") } @@ -628,8 +631,9 @@ impl<'a> BinaryReader<'a> { } pub(crate) fn peek_bytes(&self, len: usize) -> Result<&[u8]> { - self.ensure_has_bytes(len)?; - Ok(&self.buffer[self.position..(self.position + len)]) + let start = self.position; + let end = self.ensure_has_bytes(len)?; + Ok(&self.buffer[start..end]) } pub(crate) fn read_block_type(&mut self) -> Result { @@ -1101,7 +1105,7 @@ impl<'a> BinaryReader<'a> { fn visit_0xfb_operator( &mut self, - pos: usize, + pos: u64, visitor: &mut T, ) -> Result<>::Output> where @@ -1318,7 +1322,7 @@ impl<'a> BinaryReader<'a> { fn visit_0xfc_operator( &mut self, - pos: usize, + pos: u64, visitor: &mut T, ) -> Result<>::Output> where @@ -1399,7 +1403,7 @@ impl<'a> BinaryReader<'a> { #[cfg(feature = "simd")] pub(super) fn visit_0xfd_operator( &mut self, - pos: usize, + pos: u64, visitor: &mut T, ) -> Result<>::Output> where @@ -1715,7 +1719,7 @@ impl<'a> BinaryReader<'a> { fn visit_0xfe_operator( &mut self, - pos: usize, + pos: u64, visitor: &mut T, ) -> Result<>::Output> where @@ -2002,3 +2006,33 @@ impl<'a> BinaryReader<'a> { } } } + +#[cfg(test)] +mod tests { + use super::*; + + macro_rules! assert_matches { + ($a:expr, $b:pat $(,)?) => { + match $a { + $b => {} + a => panic!("`{:?}` doesn't match `{}`", a, stringify!($b)), + } + }; + } + + #[test] + fn eof_on_large_offsets() { + let mut rdr = BinaryReader::new(&[10], u64::MAX); + assert_eq!(rdr.bytes_remaining(), 0); + assert_eq!( + rdr.read_u8().unwrap_err().message(), + "unexpected end-of-file" + ); + } + + #[test] + fn can_parse_on_large_offset() { + let mut rdr = BinaryReader::new(&[10], u64::from(u32::MAX) + 1); + assert_matches!(rdr.read_u8(), Ok(10)); + } +} diff --git a/crates/wasmparser/src/error.rs b/crates/wasmparser/src/error.rs index 1475f6a617..0e48f9646c 100644 --- a/crates/wasmparser/src/error.rs +++ b/crates/wasmparser/src/error.rs @@ -16,7 +16,7 @@ pub struct Error { pub(crate) struct ErrorInner { message: String, kind: ErrorKind, - offset: usize, + offset: u64, needed_hint: Option, } @@ -44,7 +44,7 @@ impl fmt::Display for Error { impl Error { #[cold] - pub(crate) fn _new(kind: ErrorKind, message: String, offset: usize) -> Self { + pub(crate) fn _new(kind: ErrorKind, message: String, offset: u64) -> Self { Error { inner: Box::new(ErrorInner { kind, @@ -56,12 +56,12 @@ impl Error { } #[cold] - pub(crate) fn new(message: impl Into, offset: usize) -> Self { + pub(crate) fn new(message: impl Into, offset: u64) -> Self { Self::_new(ErrorKind::Uncategorized, message.into(), offset) } #[cold] - pub(crate) fn invalid_heap_type(msg: &'static str, offset: usize) -> Self { + pub(crate) fn invalid_heap_type(msg: &'static str, offset: u64) -> Self { Self::_new(ErrorKind::InvalidHeapType, msg.into(), offset) } @@ -69,18 +69,18 @@ impl Error { pub(crate) fn wasm_feature( feature: crate::WasmFeatures, msg: impl fmt::Display, - offset: usize, + offset: u64, ) -> Self { Self::_new(ErrorKind::WasmFeature(feature), msg.to_string(), offset) } #[cold] - pub(crate) fn fmt(args: fmt::Arguments<'_>, offset: usize) -> Self { + pub(crate) fn fmt(args: fmt::Arguments<'_>, offset: u64) -> Self { Error::new(args.to_string(), offset) } #[cold] - pub(crate) fn eof(offset: usize, needed_hint: usize) -> Self { + pub(crate) fn eof(offset: u64, needed_hint: usize) -> Self { let mut err = Error::new("unexpected end-of-file", offset); err.inner.needed_hint = Some(needed_hint); err @@ -96,7 +96,7 @@ impl Error { } /// Get the offset within the Wasm binary where the error occurred. - pub fn offset(&self) -> usize { + pub fn offset(&self) -> u64 { self.inner.offset } diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs index d2abd4d33d..b26315c352 100644 --- a/crates/wasmparser/src/features.rs +++ b/crates/wasmparser/src/features.rs @@ -119,7 +119,7 @@ macro_rules! define_wasm_features { pub fn $field( features: WasmFeatures, msg: impl core::fmt::Display, - offset: usize, + offset: u64, ) -> Result<(), Error> { if features.$field() { Ok(()) diff --git a/crates/wasmparser/src/lib.rs b/crates/wasmparser/src/lib.rs index adb237211d..83fba6f9d9 100644 --- a/crates/wasmparser/src/lib.rs +++ b/crates/wasmparser/src/lib.rs @@ -1318,6 +1318,7 @@ pub use crate::arity::*; pub use crate::binary_reader::BinaryReader; pub use crate::error::{Error, Result}; pub use crate::features::*; +pub use crate::offsets::InMemData; pub use crate::parser::*; pub use crate::readers::*; @@ -1329,6 +1330,7 @@ mod binary_reader; mod error; mod features; mod limits; +mod offsets; mod parser; mod readers; diff --git a/crates/wasmparser/src/limits.rs b/crates/wasmparser/src/limits.rs index a82a244ff0..2d28a40290 100644 --- a/crates/wasmparser/src/limits.rs +++ b/crates/wasmparser/src/limits.rs @@ -65,7 +65,7 @@ pub fn max_wasm_memory64_pages(page_size: u64) -> u64 { pub use self::component_limits::*; #[cfg(feature = "component-model")] mod component_limits { - pub const MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB + pub const MAX_WASM_MODULE_SIZE: u32 = 1024 * 1024 * 1024; //= 1 GiB pub const MAX_WASM_MODULE_TYPE_DECLS: usize = 100_000; pub const MAX_WASM_COMPONENT_TYPE_DECLS: usize = 1_000_000; pub const MAX_WASM_INSTANCE_TYPE_DECLS: usize = 1_000_000; diff --git a/crates/wasmparser/src/offsets.rs b/crates/wasmparser/src/offsets.rs new file mode 100644 index 0000000000..649761f76f --- /dev/null +++ b/crates/wasmparser/src/offsets.rs @@ -0,0 +1,160 @@ +/* Copyright 2026 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! Logical offsets into the input wasm file are strictly limited to fit into +//! an integer of type [u64]. Data in each chunk is addressed through an offset +//! into an `[u8]` slice, which uses `usize`-addressing. +//! +//! The structures in this file bridge the gap. Given a logical offset, +//! we can compute a maximally allowed length of data at that offset. + +use core::{ + ops::{Bound, Deref, Index, Range, RangeBounds}, + u64, +}; + +// An (not necessarily exhaustive) list of properties we use of `u64` in relation +// to usize: +// - u64::MAX as an upper bound and sometimes invalid offset +// - 0u64 as the starting offset +// - we can add and subtract small offsets to recalculate the original position +// in some error paths, where saving the position directly would clutter registers. + +/// An offset into some chunk of memory occurs at some specified logical offset in +/// the file. We currently use `usize` to represent these offsets. +/// +/// This offset can always be added onto the logical offset without overflow. +/// Compute the maximum allowable memory offset under both contraints +// TODO: on platforms where usize::BITS > u64::BITS (currently almost no-where), +// we could use u64 directly instead of usize to represent offsets. +pub fn max_memory_offset(mut max_logical: u64, max: usize) -> usize { + if u64::BITS > usize::BITS { + max_logical = max_logical.min(usize::MAX as u64) + } + // we now know that max_logical fits into a usize + let max_logical = max_logical as usize; + + // the more "natural" `max_logical.min(max)` generates a cmov which this avoids + if max <= max_logical { + max + } else { + // unlikely + #[cold] + fn smaller(constrained: usize) -> usize { + constrained + } + smaller(max_logical) + } +} + +/// Useful datastructure when your input wasm is fully in memory. +/// +/// Use this to index into it with the offsets and ranges from the parser. +#[derive(Clone, Copy, Debug, Default)] +pub struct InMemData<'a> { + /// The contained data + pub data: &'a [u8], +} + +impl<'a> InMemData<'a> { + /// Convenience new creation + pub fn new(data: &'a [u8]) -> Self { + Self { data } + } + /// Translate a single offset from the parser into a memory offset into an input slice. + pub fn translate_offset(offset: u64) -> usize { + if u64::BITS > usize::BITS && offset > (usize::MAX as u64) { + // since data is fully in memory, such an offset should never be produced by the parser + panic!("unexpectedly large offset {offset}") + } + offset as usize + } + /// Get the length of a range + pub fn range_len(range: &Range) -> usize { + (Self::translate_offset(range.start)..Self::translate_offset(range.end)).len() + } + /// Get a slice of the data, or None if out of bounds. + pub fn get(&self, index: impl RangeBounds) -> Option<&'a [u8]> { + match (index.start_bound(), index.end_bound()) { + (Bound::Included(&start), Bound::Included(&end)) => self + .data + .get(Self::translate_offset(start)..=Self::translate_offset(end)), + (Bound::Included(&start), Bound::Excluded(&end)) => self + .data + .get(Self::translate_offset(start)..Self::translate_offset(end)), + (Bound::Included(&start), Bound::Unbounded) => { + self.data.get(Self::translate_offset(start)..) + } + (Bound::Unbounded, Bound::Included(&end)) => { + self.data.get(..=Self::translate_offset(end)) + } + (Bound::Unbounded, Bound::Excluded(&end)) => { + self.data.get(..Self::translate_offset(end)) + } + (Bound::Unbounded, Bound::Unbounded) => self.data.get(..), + (Bound::Excluded(_), _) => unreachable!("unsupported excluded start bound"), + } + } + /// Index into the data slice. + /// + /// These methods are also exposed as [Index] impls, but the lifetimes of the returned references differs. + pub fn index(&self, index: impl RangeBounds) -> &'a [u8] { + match (index.start_bound(), index.end_bound()) { + (Bound::Included(&start), Bound::Included(&end)) => { + &self.data[Self::translate_offset(start)..=Self::translate_offset(end)] + } + (Bound::Included(&start), Bound::Excluded(&end)) => { + &self.data[Self::translate_offset(start)..Self::translate_offset(end)] + } + (Bound::Included(&start), Bound::Unbounded) => { + &self.data[Self::translate_offset(start)..] + } + (Bound::Unbounded, Bound::Included(&end)) => &self.data[..=Self::translate_offset(end)], + (Bound::Unbounded, Bound::Excluded(&end)) => &self.data[..Self::translate_offset(end)], + (Bound::Unbounded, Bound::Unbounded) => &self.data[..], + (Bound::Excluded(_), _) => unreachable!("unsupported excluded start bound"), + } + } + /// Get a range representing the data range. + pub fn range(&self) -> Range { + 0..max_memory_offset(u64::MAX, self.data.len()) as u64 + } +} + +impl Deref for InMemData<'_> { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + self.data + } +} + +macro_rules! impl_index { + ($range:ty) => { + impl<'a> Index<$range> for InMemData<'a> { + type Output = [u8]; + + fn index(&self, index: $range) -> &Self::Output { + self.index(index) + } + } + }; +} + +impl_index!(core::ops::RangeInclusive); +impl_index!(core::ops::Range); +impl_index!(core::ops::RangeFrom); +impl_index!(core::ops::RangeTo); +impl_index!(core::ops::RangeToInclusive); +impl_index!(core::ops::RangeFull); diff --git a/crates/wasmparser/src/parser.rs b/crates/wasmparser/src/parser.rs index c3aa1072d4..fb82f8a324 100644 --- a/crates/wasmparser/src/parser.rs +++ b/crates/wasmparser/src/parser.rs @@ -1,6 +1,7 @@ #[cfg(feature = "features")] use crate::WasmFeatures; use crate::binary_reader::WASM_MAGIC_NUMBER; +use crate::offsets; use crate::prelude::*; use crate::{ BinaryReader, CustomSectionReader, DataSectionReader, ElementSectionReader, Error, @@ -88,7 +89,7 @@ pub(crate) enum Order { pub struct Parser { state: State, offset: u64, - max_size: u64, + max_offset: u64, encoding: Encoding, #[cfg(feature = "features")] features: WasmFeatures, @@ -112,9 +113,9 @@ enum State { pub enum Chunk<'a> { /// This can be returned at any time and indicates that more data is needed /// to proceed with parsing. Zero bytes were consumed from the input to - /// [`Parser::parse`]. The `u64` value here is a hint as to how many more + /// [`Parser::parse`]. The `usize` value here is a hint as to how many more /// bytes are needed to continue parsing. - NeedMoreData(u64), + NeedMoreData(usize), /// A chunk was successfully parsed. Parsed { @@ -156,7 +157,7 @@ pub enum Payload<'a> { /// The range of bytes that were parsed to consume the header of the /// module or component. Note that this range is relative to the start /// of the byte stream. - range: Range, + range: Range, }, /// A module type section was received and the provided reader can be @@ -189,7 +190,7 @@ pub enum Payload<'a> { func: u32, /// The range of bytes that specify the `func` field, specified in /// offsets relative to the start of the byte stream. - range: Range, + range: Range, }, /// A module element section was received and the provided reader can be /// used to parse the contents of the element section. @@ -200,7 +201,7 @@ pub enum Payload<'a> { count: u32, /// The range of bytes that specify the `count` field, specified in /// offsets relative to the start of the byte stream. - range: Range, + range: Range, }, /// A module data section was received and the provided reader can be /// used to parse the contents of the data section. @@ -221,7 +222,7 @@ pub enum Payload<'a> { count: u32, /// The range of bytes that represent this section, specified in /// offsets relative to the start of the byte stream. - range: Range, + range: Range, /// The size, in bytes, of the remaining contents of this section. /// /// This can be used in combination with [`Parser::skip_section`] @@ -260,7 +261,7 @@ pub enum Payload<'a> { /// /// Note that, to better support streaming parsing and validation, the /// validator does *not* check that this range is in bounds. - unchecked_range: Range, + unchecked_range: Range, }, /// A core instance section was received and the provided parser can be /// used to parse the contents of the core instance section. @@ -295,7 +296,7 @@ pub enum Payload<'a> { /// /// Note that, to better support streaming parsing and validation, the /// validator does *not* check that this range is in bounds. - unchecked_range: Range, + unchecked_range: Range, }, /// A component instance section was received and the provided reader can be /// used to parse the contents of the component instance section. @@ -319,7 +320,7 @@ pub enum Payload<'a> { /// The start function description. start: ComponentStartFunction, /// The range of bytes that specify the `start` field. - range: Range, + range: Range, }, /// A component import section was received and the provided reader can be /// used to parse the contents of the component import section. @@ -346,14 +347,14 @@ pub enum Payload<'a> { contents: &'a [u8], /// The range of bytes, relative to the start of the original data /// stream, that the contents of this section reside in. - range: Range, + range: Range, }, /// The end of the WebAssembly module or component was reached. /// /// The value is the offset in the input byte stream where the end /// was reached. - End(usize), + End(u64), } const CUSTOM_SECTION: u8 = 0; @@ -403,7 +404,7 @@ impl Parser { Parser { state: State::Header, offset, - max_size: u64::MAX, + max_offset: u64::MAX, // Assume the encoding is a module until we know otherwise encoding: Encoding::Module, #[cfg(feature = "features")] @@ -621,14 +622,14 @@ impl Parser { /// # parse(&b"\0asm\x01\0\0\0"[..]).unwrap(); /// ``` pub fn parse<'a>(&mut self, data: &'a [u8], eof: bool) -> Result> { - let (data, eof) = if usize_to_u64(data.len()) > self.max_size { - (&data[..(self.max_size as usize)], true) + debug_assert!(self.offset <= self.max_offset, "inverted offset range"); + let max_len = offsets::max_memory_offset(self.max_offset - self.offset, data.len()); + let (data, eof) = if max_len < data.len() { + (&data[..max_len], true) } else { (data, eof) }; - // TODO: thread through `offset: u64` to `BinaryReader`, remove - // the cast here. - let starting_offset = self.offset as usize; + let starting_offset = self.offset; let mut reader = BinaryReader::new(data, starting_offset); #[cfg(feature = "features")] { @@ -636,12 +637,12 @@ impl Parser { } match self.parse_reader(&mut reader, eof) { Ok(payload) => { - // Be sure to update our offset with how far we got in the - // reader - let consumed = reader.original_position() - starting_offset; - self.offset += usize_to_u64(consumed); - self.max_size -= usize_to_u64(consumed); + // Be sure to update our offset with how far we got in the reader + let consumed = reader.current_position(); + self.offset += consumed as u64; Ok(Chunk::Parsed { + // We can be sure that the difference fits into a usize, as both positions + // are inside the data chunk. consumed: consumed, payload, }) @@ -657,25 +658,24 @@ impl Parser { // data being pulled down, then propagate it, otherwise switch // the error to "feed me please" match e.needed_hint() { - Some(hint) => Ok(Chunk::NeedMoreData(usize_to_u64(hint))), + Some(hint) => Ok(Chunk::NeedMoreData(hint)), None => Err(e), } } } } - fn update_order(&mut self, order: Order, pos: usize) -> Result<()> { - let pos_u64 = usize_to_u64(pos); + fn update_order(&mut self, order: Order, pos: u64) -> Result<()> { if self.encoding == Encoding::Module { match self.order { - (last_order, last_pos) if last_order >= order && last_pos < pos_u64 => { + (last_order, last_pos) if last_order >= order && last_pos < pos => { bail!(pos, "section out of order") } _ => (), } } - self.order = (order, pos_u64); + self.order = (order, pos); Ok(()) } @@ -743,15 +743,19 @@ impl Parser { // but it is required for nested modules/components to correctly ensure // that all sections live entirely within their section of the // file. - let consumed = reader.original_position() - id_pos; - let section_overflow = self - .max_size - .checked_sub(usize_to_u64(consumed)) - .and_then(|s| s.checked_sub(len.into())) - .is_none(); - if section_overflow { - return Err(Error::new("section too large", len_pos)); - } + let section_start = reader.original_position(); + let Some(section_end) = + section_start + .checked_add(u64::from(len)) + .and_then(|section_end| { + (section_end <= self.max_offset).then_some(section_end) + }) + else { + return Err(Error::new( + &format!("section too large, {len} goes past 0x{:x}", self.max_offset), + len_pos, + )); + }; match (self.encoding, id) { // Custom sections for both modules and components. @@ -759,15 +763,15 @@ impl Parser { // Module sections (Encoding::Module, TYPE_SECTION) => { - self.update_order(Order::Type, reader.original_position())?; + self.update_order(Order::Type, section_start)?; section(reader, len, TypeSectionReader::new, TypeSection) } (Encoding::Module, IMPORT_SECTION) => { - self.update_order(Order::Import, reader.original_position())?; + self.update_order(Order::Import, section_start)?; section(reader, len, ImportSectionReader::new, ImportSection) } (Encoding::Module, FUNCTION_SECTION) => { - self.update_order(Order::Function, reader.original_position())?; + self.update_order(Order::Function, section_start)?; let s = section(reader, len, FunctionSectionReader::new, FunctionSection)?; match &s { FunctionSection(f) => self.counts.function_entries = Some(f.count()), @@ -776,37 +780,36 @@ impl Parser { Ok(s) } (Encoding::Module, TABLE_SECTION) => { - self.update_order(Order::Table, reader.original_position())?; + self.update_order(Order::Table, section_start)?; section(reader, len, TableSectionReader::new, TableSection) } (Encoding::Module, MEMORY_SECTION) => { - self.update_order(Order::Memory, reader.original_position())?; + self.update_order(Order::Memory, section_start)?; section(reader, len, MemorySectionReader::new, MemorySection) } (Encoding::Module, GLOBAL_SECTION) => { - self.update_order(Order::Global, reader.original_position())?; + self.update_order(Order::Global, section_start)?; section(reader, len, GlobalSectionReader::new, GlobalSection) } (Encoding::Module, EXPORT_SECTION) => { - self.update_order(Order::Export, reader.original_position())?; + self.update_order(Order::Export, section_start)?; section(reader, len, ExportSectionReader::new, ExportSection) } (Encoding::Module, START_SECTION) => { - self.update_order(Order::Start, reader.original_position())?; - let (func, range) = single_item(reader, len, "start")?; + self.update_order(Order::Start, section_start)?; + let (func, range) = single_item(reader, section_end, "start")?; Ok(StartSection { func, range }) } (Encoding::Module, ELEMENT_SECTION) => { - self.update_order(Order::Element, reader.original_position())?; + self.update_order(Order::Element, section_start)?; section(reader, len, ElementSectionReader::new, ElementSection) } (Encoding::Module, CODE_SECTION) => { - self.update_order(Order::Code, reader.original_position())?; - let start = reader.original_position(); + self.update_order(Order::Code, section_start)?; let count = delimited(reader, &mut len, |r| r.read_var_u32())?; self.counts.code_entries = Some(count); - self.check_function_code_counts(start)?; - let range = start..reader.original_position() + len as usize; + self.check_function_code_counts(section_start)?; + let range = section_start..section_end; self.state = State::FunctionBody { remaining: count, len, @@ -818,7 +821,7 @@ impl Parser { }) } (Encoding::Module, DATA_SECTION) => { - self.update_order(Order::Data, reader.original_position())?; + self.update_order(Order::Data, section_start)?; let s = section(reader, len, DataSectionReader::new, DataSection)?; match &s { DataSection(d) => self.counts.data_entries = Some(d.count()), @@ -828,13 +831,13 @@ impl Parser { Ok(s) } (Encoding::Module, DATA_COUNT_SECTION) => { - self.update_order(Order::DataCount, reader.original_position())?; - let (count, range) = single_item(reader, len, "data count")?; + self.update_order(Order::DataCount, section_start)?; + let (count, range) = single_item(reader, section_end, "data count")?; self.counts.data_count = Some(count); Ok(DataCountSection { count, range }) } (Encoding::Module, TAG_SECTION) => { - self.update_order(Order::Tag, reader.original_position())?; + self.update_order(Order::Tag, section_start)?; section(reader, len, TagSectionReader::new, TagSection) } @@ -842,31 +845,36 @@ impl Parser { #[cfg(feature = "component-model")] (Encoding::Component, COMPONENT_MODULE_SECTION) | (Encoding::Component, COMPONENT_SECTION) => { - if len as usize > MAX_WASM_MODULE_SIZE { + if len > MAX_WASM_MODULE_SIZE { bail!( len_pos, "{} section is too large", - if id == 1 { "module" } else { "component " } + if id == COMPONENT_MODULE_SECTION { + "module" + } else { + "component" + } ); } - let range = reader.original_position() - ..reader.original_position() + usize::try_from(len).unwrap(); - self.max_size -= u64::from(len); + let range = section_start..section_end; + // Do no consume these bytes from the reader. The parse function will + // additionally bump this by the consumed amount, which will land us + // at section_end. self.offset += u64::from(len); - let mut parser = Parser::new(usize_to_u64(reader.original_position())); + let mut parser = Parser::new(section_start); #[cfg(feature = "features")] { parser.features = self.features; } - parser.max_size = u64::from(len); + parser.max_offset = section_end; Ok(match id { - 1 => ModuleSection { + COMPONENT_MODULE_SECTION => ModuleSection { parser, unchecked_range: range, }, - 4 => ComponentSection { + COMPONENT_SECTION => ComponentSection { parser, unchecked_range: range, }, @@ -917,7 +925,7 @@ impl Parser { ) } } - let (start, range) = single_item(reader, len, "component start")?; + let (start, range) = single_item(reader, section_end, "component start")?; Ok(ComponentStartSection { start, range }) } #[cfg(feature = "component-model")] @@ -937,7 +945,7 @@ impl Parser { (_, id) => { let offset = reader.original_position(); let contents = reader.read_bytes(len as usize)?; - let range = offset..offset + len as usize; + let range = offset..section_end; Ok(UnknownSection { id, contents, @@ -1173,7 +1181,7 @@ impl Parser { /// Ok(()) /// } /// - /// fn print_range(section: &str, range: &Range) { + /// fn print_range(section: &str, range: &Range) { /// println!("{:>40}: {:#010x} - {:#010x}", section, range.start, range.end); /// } /// ``` @@ -1183,11 +1191,10 @@ impl Parser { _ => panic!("wrong state to call `skip_section`"), }; self.offset += u64::from(skip); - self.max_size -= u64::from(skip); self.state = State::SectionStart; } - fn check_function_code_counts(&self, pos: usize) -> Result<()> { + fn check_function_code_counts(&self, pos: u64) -> Result<()> { match (self.counts.function_entries, self.counts.code_entries) { (Some(n), Some(m)) if n != m => { bail!(pos, "function and code section have inconsistent lengths") @@ -1204,7 +1211,7 @@ impl Parser { } } - fn check_data_count(&self, pos: usize) -> Result<()> { + fn check_data_count(&self, pos: u64) -> Result<()> { match (self.counts.data_count, self.counts.data_entries) { (Some(n), Some(m)) if n != m => { bail!(pos, "data count and data section have inconsistent lengths") @@ -1217,10 +1224,6 @@ impl Parser { } } -fn usize_to_u64(a: usize) -> u64 { - a.try_into().unwrap() -} - /// Parses an entire section resident in memory into a `Payload`. /// /// Requires that `len` bytes are resident in `reader` and uses `ctor`/`variant` @@ -1245,15 +1248,16 @@ fn section<'a, T>( /// Reads a section that is represented by a single uleb-encoded `u32`. fn single_item<'a, T>( reader: &mut BinaryReader<'a>, - len: u32, + section_end: u64, desc: &str, -) -> Result<(T, Range)> +) -> Result<(T, Range)> where T: FromReader<'a>, { - let range = reader.original_position()..reader.original_position() + len as usize; + let range = reader.original_position()..section_end; let mut content = reader.skip(|r| { - r.read_bytes(len as usize)?; + // length is guaranteed to fit into a u32 + r.read_bytes((range.end - range.start) as usize)?; Ok(()) })?; // We can't recover from "unexpected eof" here because our entire section is @@ -1313,7 +1317,7 @@ impl Payload<'_> { /// The purpose of this method is to enable tools to easily iterate over /// entire sections if necessary and handle sections uniformly, for example /// dropping custom sections while preserving all other sections. - pub fn as_section(&self) -> Option<(u8, Range)> { + pub fn as_section(&self) -> Option<(u8, Range)> { use Payload::*; match self { @@ -1674,9 +1678,9 @@ mod tests { chunk: Chunk<'_>, expected_consumed: usize, expected_name: &str, - expected_data_offset: usize, + expected_data_offset: u64, expected_data: &[u8], - expected_range: Range, + expected_range: Range, ) { let (consumed, s) = match chunk { Chunk::Parsed { @@ -1909,9 +1913,11 @@ mod tests { // module. This is a custom section, one byte big, with one content byte. The // content byte, however, lives outside of the parent's module code // section. - assert_eq!( - sub.parse(&[0, 1, 0], false).unwrap_err().message(), - "section too large", + assert!( + sub.parse(&[0, 1, 0], false) + .unwrap_err() + .message() + .starts_with("section too large") ); } } diff --git a/crates/wasmparser/src/readers.rs b/crates/wasmparser/src/readers.rs index b818e65285..c2f9de4c1a 100644 --- a/crates/wasmparser/src/readers.rs +++ b/crates/wasmparser/src/readers.rs @@ -113,13 +113,13 @@ impl<'a, T> SectionLimited<'a, T> { } /// Returns whether the original byte offset of this section. - pub fn original_position(&self) -> usize { + pub fn original_position(&self) -> u64 { self.reader.original_position() } /// Returns the range, as byte offsets, of this section within the original /// wasm binary. - pub fn range(&self) -> Range { + pub fn range(&self) -> Range { self.reader.range() } @@ -182,7 +182,7 @@ pub struct SectionLimitedIntoIter<'a, T> { impl SectionLimitedIntoIter<'_, T> { /// Returns the current byte offset of the section within this iterator. - pub fn original_position(&self) -> usize { + pub fn original_position(&self) -> u64 { self.section.reader.original_position() } } @@ -230,7 +230,7 @@ impl<'a, T> Iterator for SectionLimitedIntoIterWithOffsets<'a, T> where T: FromReader<'a>, { - type Item = Result<(usize, T)>; + type Item = Result<(u64, T)>; fn next(&mut self) -> Option { let pos = self.iter.section.reader.original_position(); @@ -277,13 +277,13 @@ impl<'a, T> Subsections<'a, T> { } /// Returns whether the original byte offset of this section. - pub fn original_position(&self) -> usize { + pub fn original_position(&self) -> u64 { self.reader.original_position() } /// Returns the range, as byte offsets, of this section within the original /// wasm binary. - pub fn range(&self) -> Range { + pub fn range(&self) -> Range { self.reader.range() } diff --git a/crates/wasmparser/src/readers/component/aliases.rs b/crates/wasmparser/src/readers/component/aliases.rs index 92654f3d1f..8b7606e935 100644 --- a/crates/wasmparser/src/readers/component/aliases.rs +++ b/crates/wasmparser/src/readers/component/aliases.rs @@ -92,7 +92,7 @@ impl<'a> FromReader<'a> for ComponentAlias<'a> { fn component_outer_alias_kind_from_bytes( byte1: u8, byte2: Option, - offset: usize, + offset: u64, ) -> Result { Ok(match byte1 { 0x00 => match byte2.unwrap() { diff --git a/crates/wasmparser/src/readers/component/exports.rs b/crates/wasmparser/src/readers/component/exports.rs index 2b7a6be588..c3b0b8340b 100644 --- a/crates/wasmparser/src/readers/component/exports.rs +++ b/crates/wasmparser/src/readers/component/exports.rs @@ -23,7 +23,7 @@ impl ComponentExternalKind { pub(crate) fn from_bytes( byte1: u8, byte2: Option, - offset: usize, + offset: u64, ) -> Result { Ok(match byte1 { 0x00 => match byte2.unwrap() { diff --git a/crates/wasmparser/src/readers/component/names.rs b/crates/wasmparser/src/readers/component/names.rs index ddddc83186..ef42d9d4bc 100644 --- a/crates/wasmparser/src/readers/component/names.rs +++ b/crates/wasmparser/src/readers/component/names.rs @@ -11,7 +11,7 @@ pub type ComponentNameSectionReader<'a> = Subsections<'a, ComponentName<'a>>; pub enum ComponentName<'a> { Component { name: &'a str, - name_range: Range, + name_range: Range, }, CoreFuncs(NameMap<'a>), CoreGlobals(NameMap<'a>), @@ -35,16 +35,15 @@ pub enum ComponentName<'a> { data: &'a [u8], /// The range of bytes, relative to the start of the original data /// stream, that the contents of this subsection reside in. - range: Range, + range: Range, }, } impl<'a> Subsection<'a> for ComponentName<'a> { fn from_reader(id: u8, mut reader: BinaryReader<'a>) -> Result { - let data = reader.remaining_buffer(); - let offset = reader.original_position(); Ok(match id { 0 => { + let offset = reader.original_position(); let name = reader.read_unlimited_string()?; if !reader.eof() { return Err(Error::new( @@ -71,8 +70,8 @@ impl<'a> Subsection<'a> for ComponentName<'a> { _ => { return Ok(ComponentName::Unknown { ty: 1, - data, - range: offset..offset + data.len(), + data: reader.remaining_buffer(), + range: reader.remaining_range(), }); } }, @@ -84,8 +83,8 @@ impl<'a> Subsection<'a> for ComponentName<'a> { _ => { return Ok(ComponentName::Unknown { ty: 1, - data, - range: offset..offset + data.len(), + data: reader.remaining_buffer(), + range: reader.remaining_range(), }); } }; @@ -93,8 +92,8 @@ impl<'a> Subsection<'a> for ComponentName<'a> { } ty => ComponentName::Unknown { ty, - data, - range: offset..offset + data.len(), + data: reader.remaining_buffer(), + range: reader.remaining_range(), }, }) } diff --git a/crates/wasmparser/src/readers/core/code.rs b/crates/wasmparser/src/readers/core/code.rs index 95ce70b8d6..20f559f483 100644 --- a/crates/wasmparser/src/readers/core/code.rs +++ b/crates/wasmparser/src/readers/core/code.rs @@ -72,7 +72,7 @@ impl<'a> FunctionBody<'a> { } /// Gets the range of the function body. - pub fn range(&self) -> Range { + pub fn range(&self) -> Range { self.reader.range() } @@ -105,7 +105,7 @@ impl<'a> LocalsReader<'a> { } /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { + pub fn original_position(&self) -> u64 { self.reader.original_position() } diff --git a/crates/wasmparser/src/readers/core/custom.rs b/crates/wasmparser/src/readers/core/custom.rs index a8eac2f11e..491ebc7970 100644 --- a/crates/wasmparser/src/readers/core/custom.rs +++ b/crates/wasmparser/src/readers/core/custom.rs @@ -23,7 +23,7 @@ impl<'a> CustomSectionReader<'a> { /// The offset, relative to the start of the original module or component, /// that the `data` payload for this custom section starts at. - pub fn data_offset(&self) -> usize { + pub fn data_offset(&self) -> u64 { self.reader.original_position() } @@ -32,10 +32,15 @@ impl<'a> CustomSectionReader<'a> { self.reader.remaining_buffer() } + /// The range of bytes that specify the data contents of the custom section. + pub fn data_range(&self) -> Range { + self.reader.remaining_range() + } + /// The range of bytes that specify this whole custom section (including /// both the name of this custom section and its data) specified in /// offsets relative to the start of the byte stream. - pub fn range(&self) -> Range { + pub fn range(&self) -> Range { self.reader.range() } diff --git a/crates/wasmparser/src/readers/core/data.rs b/crates/wasmparser/src/readers/core/data.rs index 5709aa40c9..85c0b46c9d 100644 --- a/crates/wasmparser/src/readers/core/data.rs +++ b/crates/wasmparser/src/readers/core/data.rs @@ -24,7 +24,7 @@ pub struct Data<'a> { /// The data of the data segment. pub data: &'a [u8], /// The range of the data segment. - pub range: Range, + pub range: Range, } /// The kind of data segment. diff --git a/crates/wasmparser/src/readers/core/dylink0.rs b/crates/wasmparser/src/readers/core/dylink0.rs index 75295aac12..ae0087369d 100644 --- a/crates/wasmparser/src/readers/core/dylink0.rs +++ b/crates/wasmparser/src/readers/core/dylink0.rs @@ -61,14 +61,12 @@ pub enum Dylink0Subsection<'a> { Unknown { ty: u8, data: &'a [u8], - range: Range, + range: Range, }, } impl<'a> Subsection<'a> for Dylink0Subsection<'a> { fn from_reader(id: u8, mut reader: BinaryReader<'a>) -> Result { - let data = reader.remaining_buffer(); - let offset = reader.original_position(); Ok(match id { WASM_DYLINK_MEM_INFO => Self::MemInfo(MemInfo { memory_size: reader.read_var_u32()?, @@ -109,8 +107,8 @@ impl<'a> Subsection<'a> for Dylink0Subsection<'a> { ), ty => Self::Unknown { ty, - data, - range: offset..offset + data.len(), + data: reader.remaining_buffer(), + range: reader.remaining_range(), }, }) } diff --git a/crates/wasmparser/src/readers/core/elements.rs b/crates/wasmparser/src/readers/core/elements.rs index e50d7b81e8..4d6ac29d0a 100644 --- a/crates/wasmparser/src/readers/core/elements.rs +++ b/crates/wasmparser/src/readers/core/elements.rs @@ -27,7 +27,7 @@ pub struct Element<'a> { /// The initial elements of the element segment. pub items: ElementItems<'a>, /// The range of the the element segment. - pub range: Range, + pub range: Range, } /// The kind of element segment. diff --git a/crates/wasmparser/src/readers/core/imports.rs b/crates/wasmparser/src/readers/core/imports.rs index b25f6d7a9f..8c65e3db8e 100644 --- a/crates/wasmparser/src/readers/core/imports.rs +++ b/crates/wasmparser/src/readers/core/imports.rs @@ -45,7 +45,7 @@ pub enum TypeRef { #[derive(Debug, Clone)] pub enum Imports<'a> { /// The group contains a single import. - Single(usize, Import<'a>), + Single(u64, Import<'a>), /// The group contains many imports that share the same module name, but have different types. Compact1 { /// The module being imported from. @@ -200,7 +200,7 @@ impl<'a> SectionLimited<'a, Imports<'a>> { /// Converts the section into an iterator over individual [`Import`]s and their offsets, /// flattening any groups of compact imports. - pub fn into_imports_with_offsets(self) -> impl Iterator)>> { + pub fn into_imports_with_offsets(self) -> impl Iterator)>> { self.into_iter().flat_map(|res| match res { Ok(imports) => imports.into_iter(), Err(e) => ImportsIter { @@ -211,7 +211,7 @@ impl<'a> SectionLimited<'a, Imports<'a>> { } impl<'a> IntoIterator for Imports<'a> { - type Item = Result<(usize, Import<'a>)>; + type Item = Result<(u64, Import<'a>)>; type IntoIter = ImportsIter<'a>; fn into_iter(self) -> Self::IntoIter { @@ -244,7 +244,7 @@ pub struct ImportsIter<'a> { enum ImportsIterState<'a> { Done, Error(Error), - Single(usize, Import<'a>), + Single(u64, Import<'a>), Compact1 { module: &'a str, iter: SectionLimitedIntoIterWithOffsets<'a, ImportItemCompact<'a>>, @@ -257,7 +257,7 @@ enum ImportsIterState<'a> { } impl<'a> Iterator for ImportsIter<'a> { - type Item = Result<(usize, Import<'a>)>; + type Item = Result<(u64, Import<'a>)>; fn next(&mut self) -> Option { match &mut self.state { diff --git a/crates/wasmparser/src/readers/core/linking.rs b/crates/wasmparser/src/readers/core/linking.rs index 2e767b1a5e..2dbcb3b4e0 100644 --- a/crates/wasmparser/src/readers/core/linking.rs +++ b/crates/wasmparser/src/readers/core/linking.rs @@ -72,7 +72,7 @@ pub struct LinkingSectionReader<'a> { /// The subsections in this section. subsections: Subsections<'a, Linking<'a>>, /// The range of the entire section, including the version. - range: Range, + range: Range, } /// Represents a reader for segments from the linking custom section. @@ -376,14 +376,12 @@ pub enum Linking<'a> { data: &'a [u8], /// The range of bytes, relative to the start of the original data /// stream, that the contents of this subsection reside in. - range: Range, + range: Range, }, } impl<'a> Subsection<'a> for Linking<'a> { fn from_reader(id: u8, reader: BinaryReader<'a>) -> Result { - let data = reader.remaining_buffer(); - let offset = reader.original_position(); Ok(match id { 5 => Self::SegmentInfo(SegmentMap::new(reader)?), 6 => Self::InitFuncs(InitFuncMap::new(reader)?), @@ -391,8 +389,8 @@ impl<'a> Subsection<'a> for Linking<'a> { 8 => Self::SymbolTable(SymbolInfoMap::new(reader)?), ty => Self::Unknown { ty, - data, - range: offset..offset + data.len(), + data: reader.remaining_buffer(), + range: reader.remaining_range(), }, }) } @@ -427,13 +425,13 @@ impl<'a> LinkingSectionReader<'a> { } /// Returns the original byte offset of this section. - pub fn original_position(&self) -> usize { + pub fn original_position(&self) -> u64 { self.subsections.original_position() } /// Returns the range, as byte offsets, of this section within the original /// wasm binary. - pub fn range(&self) -> Range { + pub fn range(&self) -> Range { self.range.clone() } diff --git a/crates/wasmparser/src/readers/core/names.rs b/crates/wasmparser/src/readers/core/names.rs index 0e73334a18..348d33733d 100644 --- a/crates/wasmparser/src/readers/core/names.rs +++ b/crates/wasmparser/src/readers/core/names.rs @@ -82,7 +82,7 @@ pub enum Name<'a> { /// The specified name. name: &'a str, /// The byte range that `name` occupies in the original binary. - name_range: Range, + name_range: Range, }, /// The name is for the functions. Function(NameMap<'a>), @@ -114,7 +114,7 @@ pub enum Name<'a> { data: &'a [u8], /// The range of bytes, relative to the start of the original data /// stream, that the contents of this subsection reside in. - range: Range, + range: Range, }, } @@ -123,10 +123,9 @@ pub type NameSectionReader<'a> = Subsections<'a, Name<'a>>; impl<'a> Subsection<'a> for Name<'a> { fn from_reader(id: u8, mut reader: BinaryReader<'a>) -> Result { - let data = reader.remaining_buffer(); - let offset = reader.original_position(); Ok(match id { 0 => { + let offset = reader.original_position(); let name = reader.read_string()?; if !reader.eof() { return Err(Error::new( @@ -152,8 +151,8 @@ impl<'a> Subsection<'a> for Name<'a> { 11 => Name::Tag(NameMap::new(reader)?), ty => Name::Unknown { ty, - data, - range: offset..offset + data.len(), + data: reader.remaining_buffer(), + range: reader.remaining_range(), }, }) } diff --git a/crates/wasmparser/src/readers/core/operators.rs b/crates/wasmparser/src/readers/core/operators.rs index 66a217e040..478ba3c07f 100644 --- a/crates/wasmparser/src/readers/core/operators.rs +++ b/crates/wasmparser/src/readers/core/operators.rs @@ -475,7 +475,7 @@ impl<'a> OperatorsReader<'a> { } /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { + pub fn original_position(&self) -> u64 { self.reader.original_position() } @@ -532,7 +532,7 @@ impl<'a> OperatorsReader<'a> { /// } /// /// struct Dumper { - /// offset: usize + /// offset: u64 /// } /// /// macro_rules! define_visit_operator { @@ -562,7 +562,7 @@ impl<'a> OperatorsReader<'a> { } /// Reads an operator with its offset. - pub fn read_with_offset(&mut self) -> Result<(Operator<'a>, usize)> { + pub fn read_with_offset(&mut self) -> Result<(Operator<'a>, u64)> { let pos = self.reader.original_position(); Ok((self.read()?, pos)) } @@ -680,7 +680,7 @@ impl<'a> OperatorsIteratorWithOffsets<'a> { } impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> { - type Item = Result<(Operator<'a>, usize)>; + type Item = Result<(Operator<'a>, u64)>; /// Reads content of the code section with offsets. /// @@ -694,7 +694,7 @@ impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> { /// for body in code_reader { /// let body = body.expect("function body"); /// let mut op_reader = body.get_operators_reader().expect("op reader"); - /// let ops = op_reader.into_iter_with_offsets().collect::>>().expect("ops"); + /// let ops = op_reader.into_iter_with_offsets().collect::>>().expect("ops"); /// assert!( /// if let [(Operator::Nop, 23), (Operator::End, 24)] = ops.as_slice() { true } else { false }, /// "found {:?}", diff --git a/crates/wasmparser/src/readers/core/reloc.rs b/crates/wasmparser/src/readers/core/reloc.rs index 161983b07b..dfa2d6e37e 100644 --- a/crates/wasmparser/src/readers/core/reloc.rs +++ b/crates/wasmparser/src/readers/core/reloc.rs @@ -9,7 +9,7 @@ pub type RelocationEntryReader<'a> = SectionLimited<'a, RelocationEntry>; #[derive(Debug, Clone)] pub struct RelocSectionReader<'a> { section: u32, - range: Range, + range: Range, entries: SectionLimited<'a, RelocationEntry>, } @@ -32,7 +32,7 @@ impl<'a> RelocSectionReader<'a> { } /// The byte range of the entire section. - pub fn range(&self) -> Range { + pub fn range(&self) -> Range { self.range.clone() } @@ -246,7 +246,11 @@ impl RelocationEntry { let start = self.offset as usize; let end = start .checked_add(self.ty.extent()) - .ok_or_else(|| crate::Error::new("relocation range end overflow", start))?; + // TODO: this error reporting looks wrong! Note that it uses an offset relative + // to a section as total offset into the input file. + .ok_or_else(|| { + crate::Error::new("relocation range end overflow", self.offset as u64) + })?; Ok(start..end) } } diff --git a/crates/wasmparser/src/readers/core/types.rs b/crates/wasmparser/src/readers/core/types.rs index a935d4e54b..cd8b8b8c44 100644 --- a/crates/wasmparser/src/readers/core/types.rs +++ b/crates/wasmparser/src/readers/core/types.rs @@ -323,13 +323,13 @@ pub struct RecGroup { #[derive(Debug, Clone)] enum RecGroupInner { - Implicit((usize, SubType)), - Explicit(Vec<(usize, SubType)>), + Implicit((u64, SubType)), + Explicit(Vec<(u64, SubType)>), } impl RecGroup { /// Create an explicit `RecGroup` for the given types. - pub(crate) fn explicit(types: Vec<(usize, SubType)>) -> Self { + pub(crate) fn explicit(types: Vec<(u64, SubType)>) -> Self { RecGroup { inner: RecGroupInner::Explicit(types), } @@ -337,7 +337,7 @@ impl RecGroup { /// Create an implicit `RecGroup` for a type that was not contained /// in a `(rec ...)`. - pub(crate) fn implicit(offset: usize, ty: SubType) -> Self { + pub(crate) fn implicit(offset: u64, ty: SubType) -> Self { RecGroup { inner: RecGroupInner::Implicit((offset, ty)), } @@ -376,21 +376,21 @@ impl RecGroup { /// Returns an owning iterator of all subtypes in this recursion /// group, along with their offset. - pub fn into_types_and_offsets(self) -> impl ExactSizeIterator { + pub fn into_types_and_offsets(self) -> impl ExactSizeIterator { return match self.inner { RecGroupInner::Implicit(tup) => Iter::Implicit(Some(tup)), RecGroupInner::Explicit(types) => Iter::Explicit(types.into_iter()), }; enum Iter { - Implicit(Option<(usize, SubType)>), - Explicit(alloc::vec::IntoIter<(usize, SubType)>), + Implicit(Option<(u64, SubType)>), + Explicit(alloc::vec::IntoIter<(u64, SubType)>), } impl Iterator for Iter { - type Item = (usize, SubType); + type Item = (u64, SubType); - fn next(&mut self) -> Option<(usize, SubType)> { + fn next(&mut self) -> Option<(u64, SubType)> { match self { Self::Implicit(ty) => ty.take(), Self::Explicit(types) => types.next(), diff --git a/crates/wasmparser/src/resources.rs b/crates/wasmparser/src/resources.rs index cfbdf49523..010055142c 100644 --- a/crates/wasmparser/src/resources.rs +++ b/crates/wasmparser/src/resources.rs @@ -83,7 +83,7 @@ pub trait WasmModuleResources { &self, t: &mut ValType, features: &WasmFeatures, - offset: usize, + offset: u64, ) -> Result<(), Error> { features.check_value_type(*t, offset)?; match t { @@ -93,7 +93,7 @@ pub trait WasmModuleResources { } /// Check and canonicalize a reference type. - fn check_ref_type(&self, ref_type: &mut RefType, offset: usize) -> Result<(), Error> { + fn check_ref_type(&self, ref_type: &mut RefType, offset: u64) -> Result<(), Error> { let is_nullable = ref_type.is_nullable(); let mut heap_ty = ref_type.heap_type(); self.check_heap_type(&mut heap_ty, offset)?; @@ -105,7 +105,7 @@ pub trait WasmModuleResources { /// canonical form. /// /// Similar to `check_value_type` but for heap types. - fn check_heap_type(&self, heap_type: &mut HeapType, offset: usize) -> Result<(), Error>; + fn check_heap_type(&self, heap_type: &mut HeapType, offset: u64) -> Result<(), Error>; /// Get the top type for the given heap type. fn top_type(&self, heap_type: &HeapType) -> HeapType; @@ -152,7 +152,7 @@ where fn type_index_of_function(&self, func_idx: u32) -> Option { T::type_index_of_function(self, func_idx) } - fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<(), Error> { + fn check_heap_type(&self, t: &mut HeapType, offset: u64) -> Result<(), Error> { T::check_heap_type(self, t, offset) } fn top_type(&self, heap_type: &HeapType) -> HeapType { @@ -217,7 +217,7 @@ where T::type_index_of_function(self, func_idx) } - fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<(), Error> { + fn check_heap_type(&self, t: &mut HeapType, offset: u64) -> Result<(), Error> { T::check_heap_type(self, t, offset) } diff --git a/crates/wasmparser/src/validator.rs b/crates/wasmparser/src/validator.rs index 90e7a02f9a..758a303f3a 100644 --- a/crates/wasmparser/src/validator.rs +++ b/crates/wasmparser/src/validator.rs @@ -67,7 +67,7 @@ use self::types::{TypeAlloc, Types, TypesRef}; pub use func::{FuncToValidate, FuncValidator, FuncValidatorAllocations}; pub use operators::Frame; -fn check_max(cur_len: usize, amt_added: u32, max: usize, desc: &str, offset: usize) -> Result<()> { +fn check_max(cur_len: usize, amt_added: u32, max: usize, desc: &str, offset: u64) -> Result<()> { if max .checked_sub(cur_len) .and_then(|amt| amt.checked_sub(amt_added as usize)) @@ -83,7 +83,7 @@ fn check_max(cur_len: usize, amt_added: u32, max: usize, desc: &str, offset: usi Ok(()) } -fn combine_type_sizes(a: u32, b: u32, offset: usize) -> Result { +fn combine_type_sizes(a: u32, b: u32, offset: u64) -> Result { match a.checked_add(b) { Some(sum) if sum < MAX_WASM_TYPE_SIZE => Ok(sum), _ => Err(format_err!( @@ -179,7 +179,7 @@ enum State { } impl State { - fn ensure_parsable(&self, offset: usize) -> Result<()> { + fn ensure_parsable(&self, offset: u64) -> Result<()> { match self { Self::Module => Ok(()), #[cfg(feature = "component-model")] @@ -195,7 +195,7 @@ impl State { } } - fn ensure_module(&self, section: &str, offset: usize) -> Result<()> { + fn ensure_module(&self, section: &str, offset: u64) -> Result<()> { self.ensure_parsable(offset)?; let _ = section; @@ -211,7 +211,7 @@ impl State { } #[cfg(feature = "component-model")] - fn ensure_component(&self, section: &str, offset: usize) -> Result<()> { + fn ensure_component(&self, section: &str, offset: u64) -> Result<()> { self.ensure_parsable(offset)?; match self { @@ -236,7 +236,7 @@ impl WasmFeatures { /// /// To check that reference types are valid, we need access to the module /// types. Use module.check_value_type. - pub(crate) fn check_value_type(&self, ty: ValType, offset: usize) -> Result<()> { + pub(crate) fn check_value_type(&self, ty: ValType, offset: u64) -> Result<()> { match ty { ValType::I32 | ValType::I64 => Ok(()), ValType::F32 | ValType::F64 => { @@ -247,7 +247,7 @@ impl WasmFeatures { } } - pub(crate) fn check_ref_type(&self, r: RefType, offset: usize) -> Result<()> { + pub(crate) fn check_ref_type(&self, r: RefType, offset: u64) -> Result<()> { require_feature::reference_types(*self, "reference types support is not enabled", offset)?; match r.heap_type() { HeapType::Concrete(_) => { @@ -647,7 +647,7 @@ impl Validator { } /// Validates [`Payload::Version`](crate::Payload). - pub fn version(&mut self, num: u16, encoding: Encoding, range: &Range) -> Result<()> { + pub fn version(&mut self, num: u16, encoding: Encoding, range: &Range) -> Result<()> { match &self.state { State::Unparsed(expected) => { if let Some(expected) = expected { @@ -909,7 +909,7 @@ impl Validator { /// Validates [`Payload::StartSection`](crate::Payload). /// /// This method should only be called when parsing a module. - pub fn start_section(&mut self, func: u32, range: &Range) -> Result<()> { + pub fn start_section(&mut self, func: u32, range: &Range) -> Result<()> { let offset = range.start; self.state.ensure_module("start", offset)?; let state = self.module.as_mut().unwrap(); @@ -951,7 +951,7 @@ impl Validator { /// Validates [`Payload::DataCountSection`](crate::Payload). /// /// This method should only be called when parsing a module. - pub fn data_count_section(&mut self, count: u32, range: &Range) -> Result<()> { + pub fn data_count_section(&mut self, count: u32, range: &Range) -> Result<()> { let offset = range.start; self.state.ensure_module("data count", offset)?; @@ -971,7 +971,7 @@ impl Validator { /// Validates [`Payload::CodeSectionStart`](crate::Payload). /// /// This method should only be called when parsing a module. - pub fn code_section_start(&mut self, range: &Range) -> Result<()> { + pub fn code_section_start(&mut self, range: &Range) -> Result<()> { let offset = range.start; self.state.ensure_module("code", offset)?; @@ -1004,7 +1004,7 @@ impl Validator { self.state.ensure_module("code", offset)?; check_max( 0, - u32::try_from(body.range().len()) + u32::try_from(body.range().end - body.range().start) .expect("usize already validated to u32 during section-length decoding"), MAX_WASM_FUNCTION_SIZE, "function body size", @@ -1040,7 +1040,7 @@ impl Validator { /// /// This method should only be called when parsing a component. #[cfg(feature = "component-model")] - pub fn module_section(&mut self, range: &Range) -> Result<()> { + pub fn module_section(&mut self, range: &Range) -> Result<()> { self.state.ensure_component("module", range.start)?; let current = self.components.last_mut().unwrap(); @@ -1115,7 +1115,7 @@ impl Validator { /// /// This method should only be called when parsing a component. #[cfg(feature = "component-model")] - pub fn component_section(&mut self, range: &Range) -> Result<()> { + pub fn component_section(&mut self, range: &Range) -> Result<()> { self.state.ensure_component("component", range.start)?; let current = self.components.last_mut().unwrap(); @@ -1247,7 +1247,7 @@ impl Validator { pub fn component_start_section( &mut self, f: &crate::ComponentStartFunction, - range: &Range, + range: &Range, ) -> Result<()> { self.state.ensure_component("start", range.start)?; @@ -1321,14 +1321,14 @@ impl Validator { /// Validates [`Payload::UnknownSection`](crate::Payload). /// /// Currently always returns an error. - pub fn unknown_section(&mut self, id: u8, range: &Range) -> Result<()> { + pub fn unknown_section(&mut self, id: u8, range: &Range) -> Result<()> { Err(format_err!(range.start, "malformed section id: {id}")) } /// Validates [`Payload::End`](crate::Payload). /// /// Returns the types known to the validator for the module or component. - pub fn end(&mut self, offset: usize) -> Result { + pub fn end(&mut self, offset: u64) -> Result { match mem::replace(&mut self.state, State::End) { State::Unparsed(_) => Err(Error::new( "cannot call `end` before a header has been parsed", @@ -1389,8 +1389,8 @@ impl Validator { &mut self, section: &SectionLimited<'a, T>, name: &str, - validate_section: impl FnOnce(&mut ModuleState, &mut TypeAlloc, u32, usize) -> Result<()>, - mut validate_item: impl FnMut(&mut ModuleState, &mut TypeAlloc, T, usize) -> Result<()>, + validate_section: impl FnOnce(&mut ModuleState, &mut TypeAlloc, u32, u64) -> Result<()>, + mut validate_item: impl FnMut(&mut ModuleState, &mut TypeAlloc, T, u64) -> Result<()>, ) -> Result<()> where T: FromReader<'a>, @@ -1415,18 +1415,13 @@ impl Validator { &mut self, section: &SectionLimited<'a, T>, name: &str, - validate_section: impl FnOnce( - &mut Vec, - &mut TypeAlloc, - u32, - usize, - ) -> Result<()>, + validate_section: impl FnOnce(&mut Vec, &mut TypeAlloc, u32, u64) -> Result<()>, mut validate_item: impl FnMut( &mut Vec, &mut TypeAlloc, &WasmFeatures, T, - usize, + u64, ) -> Result<()>, ) -> Result<()> where diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 2bca41d77f..3a984b6859 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -25,7 +25,7 @@ use crate::{ }; use core::mem; -fn to_kebab_string<'a>(s: &'a str, desc: &str, offset: usize) -> Result { +fn to_kebab_string<'a>(s: &'a str, desc: &str, offset: u64) -> Result { match KebabString::new(s) { Some(s) => Ok(s), None => { @@ -282,21 +282,21 @@ pub(crate) struct CanonicalOptions { } impl CanonicalOptions { - pub(crate) fn require_sync(&self, offset: usize, where_: &str) -> Result<&Self> { + pub(crate) fn require_sync(&self, offset: u64, where_: &str) -> Result<&Self> { if !self.concurrency.is_sync() { bail!(offset, "cannot specify `async` option on `{where_}`") } Ok(self) } - pub(crate) fn require_memory(&self, offset: usize) -> Result<&Self> { + pub(crate) fn require_memory(&self, offset: u64) -> Result<&Self> { if self.memory.is_none() { bail!(offset, "canonical option `memory` is required"); } Ok(self) } - pub(crate) fn require_realloc(&self, offset: usize) -> Result<&Self> { + pub(crate) fn require_realloc(&self, offset: u64) -> Result<&Self> { // Memory is always required when `realloc` is required. self.require_memory(offset)?; @@ -307,29 +307,21 @@ impl CanonicalOptions { Ok(self) } - pub(crate) fn require_memory_if( - &self, - offset: usize, - when: impl Fn() -> bool, - ) -> Result<&Self> { + pub(crate) fn require_memory_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> { if self.memory.is_none() && when() { self.require_memory(offset)?; } Ok(self) } - pub(crate) fn require_realloc_if( - &self, - offset: usize, - when: impl Fn() -> bool, - ) -> Result<&Self> { + pub(crate) fn require_realloc_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> { if self.realloc.is_none() && when() { self.require_realloc(offset)?; } Ok(self) } - pub(crate) fn check_lower(&self, offset: usize) -> Result<&Self> { + pub(crate) fn check_lower(&self, offset: u64) -> Result<&Self> { if self.post_return.is_some() { bail!( offset, @@ -359,7 +351,7 @@ impl CanonicalOptions { types: &TypeList, state: &ComponentState, core_ty_id: CoreTypeId, - offset: usize, + offset: u64, ) -> Result<&Self> { debug_assert!(matches!( types[core_ty_id].composite_type.inner, @@ -414,7 +406,7 @@ impl CanonicalOptions { Ok(self) } - fn check_asyncness(&self, ty: &ComponentFuncType, offset: usize) -> Result<()> { + fn check_asyncness(&self, ty: &ComponentFuncType, offset: u64) -> Result<()> { // The `async` canonical ABI option is only allowed with `async`-typed // functions. if self.concurrency.is_async() && !ty.async_ { @@ -430,7 +422,7 @@ impl CanonicalOptions { &self, types: &mut TypeAlloc, actual: FuncType, - offset: usize, + offset: u64, ) -> Result { if let Some(declared_id) = self.core_type { let declared = types[declared_id].unwrap_func(); @@ -513,7 +505,7 @@ impl ComponentState { components: &mut [Self], ty: crate::CoreType, types: &mut TypeAlloc, - offset: usize, + offset: u64, check_limit: bool, ) -> Result<()> { let current = components.last_mut().unwrap(); @@ -538,7 +530,7 @@ impl ComponentState { &mut self, module: &Module, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { let imports = module.imports_for_module_type(offset)?; @@ -561,7 +553,7 @@ impl ComponentState { &mut self, instance: crate::Instance, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { let instance = match instance { crate::Instance::Instantiate { module_index, args } => { @@ -581,7 +573,7 @@ impl ComponentState { components: &mut Vec, ty: crate::ComponentType, types: &mut TypeAlloc, - offset: usize, + offset: u64, check_limit: bool, ) -> Result<()> { assert!(!components.is_empty()); @@ -675,7 +667,7 @@ impl ComponentState { &mut self, import: crate::ComponentImport<'_>, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { let mut entity = self.check_type_ref(&import.ty, types, offset)?; self.add_entity( @@ -703,7 +695,7 @@ impl ComponentState { ty: &mut ComponentEntityType, name_and_kind: Option<(&str, ExternKind)>, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { let kind = name_and_kind.map(|(_, k)| k); let (len, max, desc) = match ty { @@ -1170,7 +1162,7 @@ impl ComponentState { name: ComponentExternName<'_>, mut ty: ComponentEntityType, types: &mut TypeAlloc, - offset: usize, + offset: u64, check_limit: bool, ) -> Result<()> { if check_limit { @@ -1200,7 +1192,7 @@ impl ComponentState { &mut self, func: CanonicalFunction, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { match func { CanonicalFunction::Lift { @@ -1330,7 +1322,7 @@ impl ComponentState { type_index: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { let ty = self.function_type_at(type_index, types, offset)?; let core_ty_id = self.core_function_at(core_func_index, offset)?; @@ -1388,7 +1380,7 @@ impl ComponentState { func_index: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { let ty = &types[self.function_at(func_index, offset)?]; @@ -1405,28 +1397,28 @@ impl ComponentState { Ok(()) } - fn resource_new(&mut self, resource: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn resource_new(&mut self, resource: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> { let rep = self.check_local_resource(resource, types, offset)?; let id = types.intern_func_type(FuncType::new([rep], [ValType::I32]), offset); self.core_funcs.push(id); Ok(()) } - fn resource_drop(&mut self, resource: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn resource_drop(&mut self, resource: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> { self.resource_at(resource, types, offset)?; let id = types.intern_func_type(FuncType::new([ValType::I32], []), offset); self.core_funcs.push(id); Ok(()) } - fn resource_rep(&mut self, resource: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn resource_rep(&mut self, resource: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> { let rep = self.check_local_resource(resource, types, offset)?; let id = types.intern_func_type(FuncType::new([ValType::I32], [rep]), offset); self.core_funcs.push(id); Ok(()) } - fn backpressure_inc(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn backpressure_inc(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`backpressure.inc` requires the component model async feature", @@ -1438,7 +1430,7 @@ impl ComponentState { Ok(()) } - fn backpressure_dec(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn backpressure_dec(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`backpressure.dec` requires the component model async feature", @@ -1455,7 +1447,7 @@ impl ComponentState { result: &Option, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1505,7 +1497,7 @@ impl ComponentState { Ok(()) } - fn task_cancel(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn task_cancel(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`task.cancel` requires the component model async feature", @@ -1521,7 +1513,7 @@ impl ComponentState { &self, immediate: u32, operation: &str, - offset: usize, + offset: u64, ) -> Result<()> { if immediate > 0 { require_feature::cm_threading( @@ -1544,7 +1536,7 @@ impl ComponentState { ty: ValType, i: u32, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1564,7 +1556,7 @@ impl ComponentState { ty: ValType, i: u32, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1579,7 +1571,7 @@ impl ComponentState { Ok(()) } - fn validate_context_type(&mut self, ty: ValType, intrinsic: &str, offset: usize) -> Result<()> { + fn validate_context_type(&mut self, ty: ValType, intrinsic: &str, offset: u64) -> Result<()> { match ty { ValType::I32 => {} ValType::I64 => { @@ -1609,7 +1601,7 @@ impl ComponentState { Ok(()) } - fn subtask_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn subtask_drop(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`subtask.drop` requires the component model async feature", @@ -1621,7 +1613,7 @@ impl ComponentState { Ok(()) } - fn subtask_cancel(&mut self, async_: bool, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn subtask_cancel(&mut self, async_: bool, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`subtask.cancel` requires the component model async feature", @@ -1640,7 +1632,7 @@ impl ComponentState { Ok(()) } - fn stream_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn stream_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`stream.new` requires the component model async feature", @@ -1662,7 +1654,7 @@ impl ComponentState { ty: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1702,7 +1694,7 @@ impl ComponentState { ty: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1741,7 +1733,7 @@ impl ComponentState { ty: u32, cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1771,7 +1763,7 @@ impl ComponentState { ty: u32, cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1796,12 +1788,7 @@ impl ComponentState { Ok(()) } - fn stream_drop_readable( - &mut self, - ty: u32, - types: &mut TypeAlloc, - offset: usize, - ) -> Result<()> { + fn stream_drop_readable(&mut self, ty: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`stream.drop-readable` requires the component model async feature", @@ -1818,12 +1805,7 @@ impl ComponentState { Ok(()) } - fn stream_drop_writable( - &mut self, - ty: u32, - types: &mut TypeAlloc, - offset: usize, - ) -> Result<()> { + fn stream_drop_writable(&mut self, ty: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`stream.drop-writable` requires the component model async feature", @@ -1840,7 +1822,7 @@ impl ComponentState { Ok(()) } - fn future_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn future_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`future.new` requires the component model async feature", @@ -1862,7 +1844,7 @@ impl ComponentState { ty: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1902,7 +1884,7 @@ impl ComponentState { ty: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1940,7 +1922,7 @@ impl ComponentState { ty: u32, cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1970,7 +1952,7 @@ impl ComponentState { ty: u32, cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1995,12 +1977,7 @@ impl ComponentState { Ok(()) } - fn future_drop_readable( - &mut self, - ty: u32, - types: &mut TypeAlloc, - offset: usize, - ) -> Result<()> { + fn future_drop_readable(&mut self, ty: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`future.drop-readable` requires the component model async feature", @@ -2017,12 +1994,7 @@ impl ComponentState { Ok(()) } - fn future_drop_writable( - &mut self, - ty: u32, - types: &mut TypeAlloc, - offset: usize, - ) -> Result<()> { + fn future_drop_writable(&mut self, ty: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`future.drop-writable` requires the component model async feature", @@ -2043,7 +2015,7 @@ impl ComponentState { &mut self, options: Vec, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_error_context( self.features, @@ -2070,7 +2042,7 @@ impl ComponentState { &mut self, options: Vec, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_error_context( self.features, @@ -2090,7 +2062,7 @@ impl ComponentState { Ok(()) } - fn error_context_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn error_context_drop(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_error_context( self.features, "`error-context.drop` requires the component model error-context feature", @@ -2102,7 +2074,7 @@ impl ComponentState { Ok(()) } - fn waitable_set_new(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn waitable_set_new(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`waitable-set.new` requires the component model async feature", @@ -2114,12 +2086,7 @@ impl ComponentState { Ok(()) } - fn waitable_set_wait( - &mut self, - memory: u32, - types: &mut TypeAlloc, - offset: usize, - ) -> Result<()> { + fn waitable_set_wait(&mut self, memory: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`waitable-set.wait` requires the component model async feature", @@ -2135,12 +2102,7 @@ impl ComponentState { Ok(()) } - fn waitable_set_poll( - &mut self, - memory: u32, - types: &mut TypeAlloc, - offset: usize, - ) -> Result<()> { + fn waitable_set_poll(&mut self, memory: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`waitable-set.poll` requires the component model async feature", @@ -2156,7 +2118,7 @@ impl ComponentState { Ok(()) } - fn waitable_set_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn waitable_set_drop(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`waitable-set.drop` requires the component model async feature", @@ -2168,7 +2130,7 @@ impl ComponentState { Ok(()) } - fn waitable_join(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn waitable_join(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`waitable.join` requires the component model async feature", @@ -2180,7 +2142,7 @@ impl ComponentState { Ok(()) } - fn thread_index(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn thread_index(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_threading( self.features, "`thread.index` requires the component model threading feature", @@ -2197,7 +2159,7 @@ impl ComponentState { func_ty_index: u32, table_index: u32, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2250,7 +2212,7 @@ impl ComponentState { Ok(()) } - fn thread_resume_later(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn thread_resume_later(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_threading( self.features, "`thread.resume-later` requires the component model threading feature", @@ -2265,7 +2227,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2277,7 +2239,7 @@ impl ComponentState { Ok(()) } - fn thread_yield(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn thread_yield(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::cm_async( self.features, "`thread.yield` requires the component model async feature", @@ -2293,7 +2255,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2310,7 +2272,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2326,7 +2288,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2342,7 +2304,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2354,7 +2316,7 @@ impl ComponentState { Ok(()) } - fn check_local_resource(&self, idx: u32, types: &TypeList, offset: usize) -> Result { + fn check_local_resource(&self, idx: u32, types: &TypeList, offset: u64) -> Result { let resource = self.resource_at(idx, types, offset)?; match self .defined_resources @@ -2370,7 +2332,7 @@ impl ComponentState { &self, idx: u32, _types: &'a TypeList, - offset: usize, + offset: u64, ) -> Result { if let ComponentAnyTypeId::Resource(id) = self.component_type_at(idx, offset)? { return Ok(id); @@ -2382,7 +2344,7 @@ impl ComponentState { &mut self, func_ty_index: u32, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::shared_everything_threads( self.features, @@ -2409,7 +2371,7 @@ impl ComponentState { func_ty_index: u32, table_index: u32, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::shared_everything_threads( self.features, @@ -2462,7 +2424,7 @@ impl ComponentState { &self, func_ty_index: u32, types: &TypeAlloc, - offset: usize, + offset: u64, ) -> Result { let core_type_id = match self.core_type_at(func_ty_index, offset)? { ComponentCoreTypeId::Sub(c) => c, @@ -2489,7 +2451,7 @@ impl ComponentState { Ok(core_type_id) } - fn thread_available_parallelism(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn thread_available_parallelism(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> { require_feature::shared_everything_threads( self.features, "`thread.available_parallelism` requires the shared-everything-threads proposal", @@ -2514,7 +2476,7 @@ impl ComponentState { &mut self, instance: crate::ComponentInstance, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { let instance = match instance { crate::ComponentInstance::Instantiate { @@ -2535,7 +2497,7 @@ impl ComponentState { components: &mut [Self], alias: crate::ComponentAlias, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { let component = components.last_mut().unwrap(); @@ -2596,7 +2558,7 @@ impl ComponentState { args: &[u32], results: u32, types: &mut TypeList, - offset: usize, + offset: u64, ) -> Result<()> { require_feature::cm_values( self.features, @@ -2652,7 +2614,7 @@ impl ComponentState { &self, types: &TypeList, options: &[CanonicalOption], - offset: usize, + offset: u64, ) -> Result { fn display(option: CanonicalOption) -> &'static str { match option { @@ -2877,7 +2839,7 @@ impl ComponentState { &mut self, ty: &ComponentTypeRef, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result { Ok(match ty { ComponentTypeRef::Module(index) => { @@ -2942,7 +2904,7 @@ impl ComponentState { &mut self, export: &crate::ComponentExport, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result { let actual = match export.kind { ComponentExternalKind::Module => { @@ -2987,7 +2949,7 @@ impl ComponentState { components: &[Self], decls: Vec, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result { let mut state = Module::new(components[0].features); @@ -3046,7 +3008,7 @@ impl ComponentState { components: &mut Vec, decls: Vec, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result { let features = components[0].features; components.push(ComponentState::new(ComponentKind::ComponentType, features)); @@ -3083,7 +3045,7 @@ impl ComponentState { components: &mut Vec, decls: Vec, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result { let features = components[0].features; components.push(ComponentState::new(ComponentKind::InstanceType, features)); @@ -3143,7 +3105,7 @@ impl ComponentState { &self, ty: crate::ComponentFuncType, types: &TypeList, - offset: usize, + offset: u64, ) -> Result { let mut info = TypeInfo::new(); @@ -3208,13 +3170,13 @@ impl ComponentState { module_index: u32, module_args: Vec, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result { fn insert_arg<'a>( name: &'a str, arg: &'a InstanceType, args: &mut IndexMap<&'a str, &'a InstanceType>, - offset: usize, + offset: u64, ) -> Result<()> { if args.insert(name, arg).is_some() { bail!( @@ -3285,7 +3247,7 @@ impl ComponentState { component_index: u32, component_args: Vec, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result { let component_type_id = self.component_at(component_index, offset)?; let mut args = IndexMap::default(); @@ -3552,7 +3514,7 @@ impl ComponentState { &mut self, exports: Vec, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result { let mut info = TypeInfo::new(); let mut inst_exports = IndexMap::default(); @@ -3671,7 +3633,7 @@ impl ComponentState { &mut self, exports: Vec, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result { fn insert_export( types: &TypeList, @@ -3679,7 +3641,7 @@ impl ComponentState { export: EntityType, exports: &mut IndexMap, info: &mut TypeInfo, - offset: usize, + offset: u64, ) -> Result<()> { info.combine(export.info(types), offset)?; @@ -3763,7 +3725,7 @@ impl ComponentState { kind: ExternalKind, name: &str, types: &TypeList, - offset: usize, + offset: u64, ) -> Result<()> { macro_rules! push_module_export { ($expected:path, $collection:ident, $ty:literal) => {{ @@ -3849,7 +3811,7 @@ impl ComponentState { kind: ComponentExternalKind, name: &str, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { if let ComponentExternalKind::Value = kind { self.check_value_support(offset)?; @@ -3891,7 +3853,7 @@ impl ComponentState { Ok(()) } - fn alias_module(components: &mut [Self], count: u32, index: u32, offset: usize) -> Result<()> { + fn alias_module(components: &mut [Self], count: u32, index: u32, offset: u64) -> Result<()> { let component = Self::check_alias_count(components, count, offset)?; let ty = component.module_at(index, offset)?; @@ -3908,12 +3870,7 @@ impl ComponentState { Ok(()) } - fn alias_component( - components: &mut [Self], - count: u32, - index: u32, - offset: usize, - ) -> Result<()> { + fn alias_component(components: &mut [Self], count: u32, index: u32, offset: u64) -> Result<()> { let component = Self::check_alias_count(components, count, offset)?; let ty = component.component_at(index, offset)?; @@ -3930,12 +3887,7 @@ impl ComponentState { Ok(()) } - fn alias_core_type( - components: &mut [Self], - count: u32, - index: u32, - offset: usize, - ) -> Result<()> { + fn alias_core_type(components: &mut [Self], count: u32, index: u32, offset: u64) -> Result<()> { let component = Self::check_alias_count(components, count, offset)?; let ty = component.core_type_at(index, offset)?; @@ -3952,7 +3904,7 @@ impl ComponentState { count: u32, index: u32, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { let component = Self::check_alias_count(components, count, offset)?; let ty = component.component_type_at(index, offset)?; @@ -4002,7 +3954,7 @@ impl ComponentState { Ok(()) } - fn check_alias_count(components: &[Self], count: u32, offset: usize) -> Result<&Self> { + fn check_alias_count(components: &[Self], count: u32, offset: u64) -> Result<&Self> { let count = count as usize; if count >= components.len() { bail!(offset, "invalid outer alias count of {count}"); @@ -4015,7 +3967,7 @@ impl ComponentState { &self, ty: crate::ComponentDefinedType, types: &TypeList, - offset: usize, + offset: u64, ) -> Result { match ty { crate::ComponentDefinedType::Primitive(ty) => { @@ -4164,7 +4116,7 @@ impl ComponentState { &self, fields: &[(&str, crate::ComponentValType)], types: &TypeList, - offset: usize, + offset: u64, ) -> Result { let mut info = TypeInfo::new(); let mut field_map = IndexMap::default(); @@ -4201,7 +4153,7 @@ impl ComponentState { &self, cases: &[crate::VariantCase], types: &TypeList, - offset: usize, + offset: u64, ) -> Result { let mut info = TypeInfo::new(); let mut case_map: IndexMap = IndexMap::default(); @@ -4252,7 +4204,7 @@ impl ComponentState { &self, tys: &[crate::ComponentValType], types: &TypeList, - offset: usize, + offset: u64, ) -> Result { let mut info = TypeInfo::new(); if tys.is_empty() { @@ -4270,7 +4222,7 @@ impl ComponentState { Ok(ComponentDefinedType::Tuple(TupleType { info, types })) } - fn create_flags_type(&self, names: &[&str], offset: usize) -> Result { + fn create_flags_type(&self, names: &[&str], offset: u64) -> Result { let mut names_set = IndexSet::default(); names_set.reserve(names.len()); @@ -4295,7 +4247,7 @@ impl ComponentState { Ok(ComponentDefinedType::Flags(names_set)) } - fn create_enum_type(&self, cases: &[&str], offset: usize) -> Result { + fn create_enum_type(&self, cases: &[&str], offset: u64) -> Result { if cases.len() > u32::MAX as usize { return Err(Error::new( "enumeration type cannot be represented with a 32-bit discriminant value", @@ -4326,7 +4278,7 @@ impl ComponentState { fn create_component_val_type( &self, ty: crate::ComponentValType, - offset: usize, + offset: u64, ) -> Result { Ok(match ty { crate::ComponentValType::Primitive(pt) => { @@ -4339,14 +4291,14 @@ impl ComponentState { }) } - pub fn core_type_at(&self, idx: u32, offset: usize) -> Result { + pub fn core_type_at(&self, idx: u32, offset: u64) -> Result { self.core_types .get(idx as usize) .copied() .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds")) } - pub fn component_type_at(&self, idx: u32, offset: usize) -> Result { + pub fn component_type_at(&self, idx: u32, offset: u64) -> Result { self.types .get(idx as usize) .copied() @@ -4357,7 +4309,7 @@ impl ComponentState { &self, idx: u32, types: &'a TypeList, - offset: usize, + offset: u64, ) -> Result<&'a ComponentFuncType> { let id = self.component_type_at(idx, offset)?; match id { @@ -4366,7 +4318,7 @@ impl ComponentState { } } - fn function_at(&self, idx: u32, offset: usize) -> Result { + fn function_at(&self, idx: u32, offset: u64) -> Result { self.funcs.get(idx as usize).copied().ok_or_else(|| { format_err!( offset, @@ -4375,7 +4327,7 @@ impl ComponentState { }) } - fn component_at(&self, idx: u32, offset: usize) -> Result { + fn component_at(&self, idx: u32, offset: u64) -> Result { self.components.get(idx as usize).copied().ok_or_else(|| { format_err!( offset, @@ -4384,7 +4336,7 @@ impl ComponentState { }) } - fn instance_at(&self, idx: u32, offset: usize) -> Result { + fn instance_at(&self, idx: u32, offset: u64) -> Result { self.instances.get(idx as usize).copied().ok_or_else(|| { format_err!( offset, @@ -4393,7 +4345,7 @@ impl ComponentState { }) } - fn value_at(&mut self, idx: u32, offset: usize) -> Result<&ComponentValType> { + fn value_at(&mut self, idx: u32, offset: u64) -> Result<&ComponentValType> { match self.values.get_mut(idx as usize) { Some((ty, used)) if !*used => { *used = true; @@ -4404,14 +4356,14 @@ impl ComponentState { } } - fn defined_type_at(&self, idx: u32, offset: usize) -> Result { + fn defined_type_at(&self, idx: u32, offset: u64) -> Result { match self.component_type_at(idx, offset)? { ComponentAnyTypeId::Defined(id) => Ok(id), _ => bail!(offset, "type index {idx} is not a defined type"), } } - fn core_function_at(&self, idx: u32, offset: usize) -> Result { + fn core_function_at(&self, idx: u32, offset: u64) -> Result { match self.core_funcs.get(idx as usize) { Some(id) => Ok(*id), None => bail!( @@ -4421,14 +4373,14 @@ impl ComponentState { } } - fn module_at(&self, idx: u32, offset: usize) -> Result { + fn module_at(&self, idx: u32, offset: u64) -> Result { match self.core_modules.get(idx as usize) { Some(id) => Ok(*id), None => bail!(offset, "unknown module {idx}: module index out of bounds"), } } - fn core_instance_at(&self, idx: u32, offset: usize) -> Result { + fn core_instance_at(&self, idx: u32, offset: u64) -> Result { match self.core_instances.get(idx as usize) { Some(id) => Ok(*id), None => bail!( @@ -4443,7 +4395,7 @@ impl ComponentState { instance_index: u32, name: &str, types: &'a TypeList, - offset: usize, + offset: u64, ) -> Result<&'a EntityType> { match types[self.core_instance_at(instance_index, offset)?] .internal_exports(types) @@ -4457,28 +4409,28 @@ impl ComponentState { } } - fn global_at(&self, idx: u32, offset: usize) -> Result<&GlobalType> { + fn global_at(&self, idx: u32, offset: u64) -> Result<&GlobalType> { match self.core_globals.get(idx as usize) { Some(t) => Ok(t), None => bail!(offset, "unknown global {idx}: global index out of bounds"), } } - fn table_at(&self, idx: u32, offset: usize) -> Result<&TableType> { + fn table_at(&self, idx: u32, offset: u64) -> Result<&TableType> { match self.core_tables.get(idx as usize) { Some(t) => Ok(t), None => bail!(offset, "unknown table {idx}: table index out of bounds"), } } - fn memory_at(&self, idx: u32, offset: usize) -> Result<&MemoryType> { + fn memory_at(&self, idx: u32, offset: u64) -> Result<&MemoryType> { match self.core_memories.get(idx as usize) { Some(t) => Ok(t), None => bail!(offset, "unknown memory {idx}: memory index out of bounds"), } } - fn tag_at(&self, idx: u32, offset: usize) -> Result { + fn tag_at(&self, idx: u32, offset: u64) -> Result { match self.core_tags.get(idx as usize) { Some(t) => Ok(*t), None => bail!(offset, "unknown tag {idx}: tag index out of bounds"), @@ -4490,7 +4442,7 @@ impl ComponentState { /// /// At this time this requires that the memory is a plain 32-bit or 64-bit linear /// memory. Notably this disallows shared memory. - fn cabi_memory_at(&self, idx: u32, offset: usize) -> Result { + fn cabi_memory_at(&self, idx: u32, offset: u64) -> Result { let ty = self.memory_at(idx, offset)?; let valid_memory_type = MemoryType { initial: 0, @@ -4521,7 +4473,7 @@ impl ComponentState { /// Internally this will convert local data structures into a /// `ComponentType` which is suitable to use to describe the type of this /// component. - pub fn finish(&mut self, types: &TypeAlloc, offset: usize) -> Result { + pub fn finish(&mut self, types: &TypeAlloc, offset: u64) -> Result { let mut ty = ComponentType { // Inherit some fields based on translation of the component. info: self.type_info, @@ -4614,7 +4566,7 @@ impl ComponentState { Ok(ty) } - fn check_value_support(&self, offset: usize) -> Result<()> { + fn check_value_support(&self, offset: u64) -> Result<()> { require_feature::cm_values( self.features, "support for component model `value`s is not enabled", @@ -4623,7 +4575,7 @@ impl ComponentState { Ok(()) } - fn check_primitive_type(&self, ty: crate::PrimitiveValType, offset: usize) -> Result<()> { + fn check_primitive_type(&self, ty: crate::PrimitiveValType, offset: u64) -> Result<()> { if ty == crate::PrimitiveValType::ErrorContext { require_feature::cm_error_context( self.features, @@ -4644,7 +4596,7 @@ impl InternRecGroup for ComponentState { self.core_types.push(ComponentCoreTypeId::Sub(id)); } - fn type_id_at(&self, idx: u32, offset: usize) -> Result { + fn type_id_at(&self, idx: u32, offset: u64) -> Result { match self.core_type_at(idx, offset)? { ComponentCoreTypeId::Sub(id) => Ok(id), ComponentCoreTypeId::Module(_) => { @@ -4676,7 +4628,7 @@ impl ComponentNameContext { kind: ExternKind, ty: &ComponentEntityType, types: &TypeAlloc, - offset: usize, + offset: u64, kind_names: &mut IndexSet, items: &mut IndexMap, info: &mut TypeInfo, @@ -4803,7 +4755,7 @@ impl ComponentNameContext { version_suffix: Option<&str>, ty: &ComponentEntityType, types: &TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { let func = || { let id = match ty { @@ -4914,7 +4866,7 @@ impl ComponentNameContext { &self, id: AliasableResourceId, name: KebabStr<'_>, - offset: usize, + offset: u64, ) -> Result<()> { let expected_name_idx = match self.resource_name_map.get(&id) { Some(idx) => *idx, diff --git a/crates/wasmparser/src/validator/component_types.rs b/crates/wasmparser/src/validator/component_types.rs index 67f73e2369..c619cb7f2e 100644 --- a/crates/wasmparser/src/validator/component_types.rs +++ b/crates/wasmparser/src/validator/component_types.rs @@ -137,7 +137,7 @@ impl PrimitiveValType { types: &TypeList, _abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: u64, core: ArgOrField, ) -> Result<()> { match (self, core) { @@ -759,7 +759,7 @@ impl ComponentValType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: u64, core: ArgOrField, ) -> Result<()> { match self { @@ -1200,7 +1200,7 @@ pub(crate) enum LoweredFuncType { } impl LoweredFuncType { - pub(crate) fn intern(self, types: &mut TypeAlloc, offset: usize) -> CoreTypeId { + pub(crate) fn intern(self, types: &mut TypeAlloc, offset: u64) -> CoreTypeId { match self { LoweredFuncType::New(ty) => types.intern_func_type(ty, offset), LoweredFuncType::Existing(id) => id, @@ -1216,7 +1216,7 @@ impl ComponentFuncType { types: &TypeList, options: &CanonicalOptions, abi: Abi, - offset: usize, + offset: u64, ) -> Result { let mut sig = LoweredSignature::default(); @@ -1335,7 +1335,7 @@ impl ComponentFuncType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: u64, ) -> Result { let core_type_id = options.core_type.unwrap(); let core_func_ty = types[core_type_id].unwrap_func(); @@ -1394,7 +1394,7 @@ impl RecordType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: u64, core: ArgOrField, ) -> Result<()> { lower_gc_product_type( @@ -1424,7 +1424,7 @@ impl VariantType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: u64, core: ArgOrField, ) -> Result<()> { lower_gc_sum_type(types, abi, options, offset, core, "variant") @@ -1437,7 +1437,7 @@ fn lower_gc_sum_type( types: &TypeList, _abi: Abi, _options: &CanonicalOptions, - offset: usize, + offset: u64, core: ArgOrField, kind: &str, ) -> Result<()> { @@ -1471,7 +1471,7 @@ impl TupleType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: u64, core: ArgOrField, ) -> Result<()> { lower_gc_product_type( @@ -1732,7 +1732,7 @@ impl ComponentDefinedType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: u64, core: ArgOrField, ) -> Result<()> { match self { @@ -1834,7 +1834,7 @@ fn lower_gc_product_type<'a, I>( types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: u64, core: ArgOrField, kind: &str, ) -> core::result::Result<(), Error> @@ -3180,7 +3180,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: &ComponentEntityType, b: &ComponentEntityType, - offset: usize, + offset: u64, ) -> Result<()> { use ComponentEntityType::*; @@ -3214,7 +3214,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: ComponentTypeId, b: ComponentTypeId, - offset: usize, + offset: u64, ) -> Result<()> { // Components are ... tricky. They follow the same basic // structure as core wasm modules, but they also have extra @@ -3299,7 +3299,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a_id: ComponentInstanceTypeId, b_id: ComponentInstanceTypeId, - offset: usize, + offset: u64, ) -> Result<()> { // For instance type subtyping, all exports in the other // instance type must be present in this instance type's @@ -3335,7 +3335,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: ComponentFuncTypeId, b: ComponentFuncTypeId, - offset: usize, + offset: u64, ) -> Result<()> { let a = &self.a[a]; let b = &self.b[b]; @@ -3414,7 +3414,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: ComponentCoreModuleTypeId, b: ComponentCoreModuleTypeId, - offset: usize, + offset: u64, ) -> Result<()> { // For module type subtyping, all exports in the other module // type must be present in this module type's exports (i.e. it @@ -3453,7 +3453,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: ComponentAnyTypeId, b: ComponentAnyTypeId, - offset: usize, + offset: u64, ) -> Result<()> { match (a, b) { (ComponentAnyTypeId::Resource(a), ComponentAnyTypeId::Resource(b)) => { @@ -3529,7 +3529,7 @@ impl<'a> SubtypeCx<'a> { a: &IndexMap, b: ComponentTypeId, kind: ExternKind, - offset: usize, + offset: u64, ) -> Result { // First, determine the mapping from resources in `b` to those supplied // by arguments in `a`. @@ -3671,7 +3671,7 @@ impl<'a> SubtypeCx<'a> { Ok(mapping) } - pub(crate) fn entity_type(&self, a: &EntityType, b: &EntityType, offset: usize) -> Result<()> { + pub(crate) fn entity_type(&self, a: &EntityType, b: &EntityType, offset: u64) -> Result<()> { match (a, b) { (EntityType::Func(a), EntityType::Func(b)) | (EntityType::FuncExact(a), EntityType::Func(b)) => { @@ -3710,7 +3710,7 @@ impl<'a> SubtypeCx<'a> { } } - pub(crate) fn table_type(a: &TableType, b: &TableType, offset: usize) -> Result<()> { + pub(crate) fn table_type(a: &TableType, b: &TableType, offset: u64) -> Result<()> { if a.element_type != b.element_type { bail!( offset, @@ -3729,7 +3729,7 @@ impl<'a> SubtypeCx<'a> { } } - pub(crate) fn memory_type(a: &MemoryType, b: &MemoryType, offset: usize) -> Result<()> { + pub(crate) fn memory_type(a: &MemoryType, b: &MemoryType, offset: u64) -> Result<()> { if a.shared != b.shared { bail!(offset, "mismatch in the shared flag for memories") } @@ -3746,7 +3746,7 @@ impl<'a> SubtypeCx<'a> { } } - fn core_func_type(&self, a: CoreTypeId, b: CoreTypeId, offset: usize) -> Result<()> { + fn core_func_type(&self, a: CoreTypeId, b: CoreTypeId, offset: u64) -> Result<()> { debug_assert!(self.a.get(a).is_some()); debug_assert!(self.b.get(b).is_some()); if self.a.id_is_subtype(a, b) { @@ -3768,7 +3768,7 @@ impl<'a> SubtypeCx<'a> { &self, a: &ComponentValType, b: &ComponentValType, - offset: usize, + offset: u64, ) -> Result<()> { match (a, b) { (ComponentValType::Primitive(a), ComponentValType::Primitive(b)) => { @@ -3792,7 +3792,7 @@ impl<'a> SubtypeCx<'a> { &self, a: ComponentDefinedTypeId, b: ComponentDefinedTypeId, - offset: usize, + offset: u64, ) -> Result<()> { use ComponentDefinedType::*; @@ -3976,7 +3976,7 @@ impl<'a> SubtypeCx<'a> { &self, a: PrimitiveValType, b: PrimitiveValType, - offset: usize, + offset: u64, ) -> Result<()> { // Note that this intentionally diverges from the upstream specification // at this time and only considers exact equality for subtyping diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs index a6204d9550..cc111ca341 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -58,12 +58,7 @@ impl ModuleState { ((*index - 1) as u32, ty) } - pub fn add_global( - &mut self, - mut global: Global, - types: &TypeList, - offset: usize, - ) -> Result<()> { + pub fn add_global(&mut self, mut global: Global, types: &TypeList, offset: u64) -> Result<()> { self.module .check_global_type(&mut global.ty, types, offset)?; self.check_const_expr(&global.init_expr, global.ty.content_type, types)?; @@ -71,12 +66,7 @@ impl ModuleState { Ok(()) } - pub fn add_table( - &mut self, - mut table: Table<'_>, - types: &TypeList, - offset: usize, - ) -> Result<()> { + pub fn add_table(&mut self, mut table: Table<'_>, types: &TypeList, offset: u64) -> Result<()> { self.module.check_table_type(&mut table.ty, types, offset)?; match &table.init { @@ -99,7 +89,7 @@ impl ModuleState { Ok(()) } - pub fn add_data_segment(&mut self, data: Data, types: &TypeList, offset: usize) -> Result<()> { + pub fn add_data_segment(&mut self, data: Data, types: &TypeList, offset: u64) -> Result<()> { match data.kind { DataKind::Passive => { require_feature::bulk_memory( @@ -123,7 +113,7 @@ impl ModuleState { &mut self, mut e: Element, types: &TypeList, - offset: usize, + offset: u64, ) -> Result<()> { // the `funcref` value type is allowed all the way back to the MVP, so // don't check it here @@ -225,7 +215,7 @@ impl ModuleState { return Ok(()); struct VisitConstOperator<'a> { - offset: usize, + offset: u64, uninserted_funcref: bool, ops: OperatorValidator, resources: OperatorValidatorResources<'a>, @@ -522,7 +512,7 @@ impl Module { &mut self, rec_group: RecGroup, types: &mut TypeAlloc, - offset: usize, + offset: u64, check_limit: bool, ) -> Result<()> { if check_limit { @@ -541,7 +531,7 @@ impl Module { &mut self, mut import: crate::Import, types: &TypeList, - offset: usize, + offset: u64, ) -> Result<()> { let entity = self.check_type_ref(&mut import.ty, types, offset)?; @@ -600,7 +590,7 @@ impl Module { &mut self, name: &str, ty: EntityType, - offset: usize, + offset: u64, check_limit: bool, types: &TypeList, ) -> Result<()> { @@ -629,25 +619,25 @@ impl Module { } } - pub fn add_function(&mut self, type_index: u32, types: &TypeList, offset: usize) -> Result<()> { + pub fn add_function(&mut self, type_index: u32, types: &TypeList, offset: u64) -> Result<()> { self.func_type_at(type_index, types, offset)?; self.functions.push(type_index); Ok(()) } - pub fn add_memory(&mut self, ty: MemoryType, offset: usize) -> Result<()> { + pub fn add_memory(&mut self, ty: MemoryType, offset: u64) -> Result<()> { self.check_memory_type(&ty, offset)?; self.memories.push(ty); Ok(()) } - pub fn add_tag(&mut self, ty: TagType, types: &TypeList, offset: usize) -> Result<()> { + pub fn add_tag(&mut self, ty: TagType, types: &TypeList, offset: u64) -> Result<()> { self.check_tag_type(&ty, types, offset)?; self.tags.push(self.types[ty.func_type_idx as usize]); Ok(()) } - fn sub_type_at<'a>(&self, types: &'a TypeList, idx: u32, offset: usize) -> Result<&'a SubType> { + fn sub_type_at<'a>(&self, types: &'a TypeList, idx: u32, offset: u64) -> Result<&'a SubType> { let id = self.type_id_at(idx, offset)?; Ok(&types[id]) } @@ -656,7 +646,7 @@ impl Module { &self, type_index: u32, types: &'a TypeList, - offset: usize, + offset: u64, ) -> Result<&'a FuncType> { match &self .sub_type_at(types, type_index, offset)? @@ -672,7 +662,7 @@ impl Module { &self, type_ref: &mut TypeRef, types: &TypeList, - offset: usize, + offset: u64, ) -> Result { Ok(match type_ref { TypeRef::Func(type_index) => { @@ -702,7 +692,7 @@ impl Module { }) } - fn check_table_type(&self, ty: &mut TableType, types: &TypeList, offset: usize) -> Result<()> { + fn check_table_type(&self, ty: &mut TableType, types: &TypeList, offset: u64) -> Result<()> { // The `funcref` value type is allowed all the way back to the MVP, so // don't check it here. if ty.element_type != RefType::FUNCREF { @@ -748,7 +738,7 @@ impl Module { Ok(()) } - fn check_memory_type(&self, ty: &MemoryType, offset: usize) -> Result<()> { + fn check_memory_type(&self, ty: &MemoryType, offset: u64) -> Result<()> { self.check_limits(ty.initial, ty.maximum, offset)?; if ty.memory64 { @@ -809,7 +799,7 @@ impl Module { #[cfg(feature = "component-model")] pub(crate) fn imports_for_module_type( &self, - offset: usize, + offset: u64, ) -> Result> { // Ensure imports are unique, which is a requirement of the component model: // https://github.com/WebAssembly/component-model/blob/d09f907/design/mvp/Explainer.md#import-and-export-definitions @@ -828,7 +818,7 @@ impl Module { .collect::>() } - fn check_value_type(&self, ty: &mut ValType, offset: usize) -> Result<()> { + fn check_value_type(&self, ty: &mut ValType, offset: u64) -> Result<()> { // The above only checks the value type for features. // We must check it if it's a reference. match ty { @@ -837,7 +827,7 @@ impl Module { } } - fn check_ref_type(&self, ty: &mut RefType, offset: usize) -> Result<()> { + fn check_ref_type(&self, ty: &mut RefType, offset: u64) -> Result<()> { self.features.check_ref_type(*ty, offset)?; let mut hty = ty.heap_type(); self.check_heap_type(&mut hty, offset)?; @@ -845,7 +835,7 @@ impl Module { Ok(()) } - fn check_heap_type(&self, ty: &mut HeapType, offset: usize) -> Result<()> { + fn check_heap_type(&self, ty: &mut HeapType, offset: u64) -> Result<()> { // Check that the heap type is valid. let type_index = match ty { HeapType::Abstract { .. } => return Ok(()), @@ -864,7 +854,7 @@ impl Module { } } - fn check_tag_type(&self, ty: &TagType, types: &TypeList, offset: usize) -> Result<()> { + fn check_tag_type(&self, ty: &TagType, types: &TypeList, offset: u64) -> Result<()> { require_feature::exceptions(self.features, "exceptions proposal not enabled", offset)?; let ty = self.func_type_at(ty.func_type_idx, types, offset)?; if !ty.results().is_empty() { @@ -877,12 +867,7 @@ impl Module { Ok(()) } - fn check_global_type( - &self, - ty: &mut GlobalType, - types: &TypeList, - offset: usize, - ) -> Result<()> { + fn check_global_type(&self, ty: &mut GlobalType, types: &TypeList, offset: u64) -> Result<()> { self.check_value_type(&mut ty.content_type, offset)?; if ty.shared { require_feature::shared_everything_threads( @@ -900,7 +885,7 @@ impl Module { Ok(()) } - fn check_limits(&self, initial: T, maximum: Option, offset: usize) -> Result<()> + fn check_limits(&self, initial: T, maximum: Option, offset: u64) -> Result<()> where T: Into, { @@ -934,7 +919,7 @@ impl Module { pub fn export_to_entity_type( &mut self, export: &crate::Export, - offset: usize, + offset: u64, ) -> Result { let check = |ty: &str, index: u32, total: usize| { if index as usize >= total { @@ -976,7 +961,7 @@ impl Module { &self, func_idx: u32, types: &'a TypeList, - offset: usize, + offset: u64, ) -> Result<&'a FuncType> { match self.functions.get(func_idx as usize) { Some(idx) => self.func_type_at(*idx, types, offset), @@ -987,7 +972,7 @@ impl Module { } } - fn global_at(&self, idx: u32, offset: usize) -> Result<&GlobalType> { + fn global_at(&self, idx: u32, offset: u64) -> Result<&GlobalType> { match self.globals.get(idx as usize) { Some(t) => Ok(t), None => Err(format_err!( @@ -997,7 +982,7 @@ impl Module { } } - fn table_at(&self, idx: u32, offset: usize) -> Result<&TableType> { + fn table_at(&self, idx: u32, offset: u64) -> Result<&TableType> { match self.tables.get(idx as usize) { Some(t) => Ok(t), None => Err(format_err!( @@ -1007,7 +992,7 @@ impl Module { } } - fn memory_at(&self, idx: u32, offset: usize) -> Result<&MemoryType> { + fn memory_at(&self, idx: u32, offset: u64) -> Result<&MemoryType> { match self.memories.get(idx as usize) { Some(t) => Ok(t), None => Err(format_err!( @@ -1027,7 +1012,7 @@ impl InternRecGroup for Module { self.types.push(id); } - fn type_id_at(&self, idx: u32, offset: usize) -> Result { + fn type_id_at(&self, idx: u32, offset: u64) -> Result { self.types .get(idx as usize) .copied() @@ -1080,7 +1065,7 @@ impl WasmModuleResources for OperatorValidatorResources<'_> { self.module.functions.get(at as usize).copied() } - fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<()> { + fn check_heap_type(&self, t: &mut HeapType, offset: u64) -> Result<()> { self.module.check_heap_type(t, offset) } @@ -1168,7 +1153,7 @@ impl WasmModuleResources for ValidatorResources { self.0.functions.get(at as usize).copied() } - fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<()> { + fn check_heap_type(&self, t: &mut HeapType, offset: u64) -> Result<()> { self.0.check_heap_type(t, offset) } diff --git a/crates/wasmparser/src/validator/core/canonical.rs b/crates/wasmparser/src/validator/core/canonical.rs index 007f3e239f..4022e5cd02 100644 --- a/crates/wasmparser/src/validator/core/canonical.rs +++ b/crates/wasmparser/src/validator/core/canonical.rs @@ -76,7 +76,7 @@ use crate::{ pub(crate) trait InternRecGroup { fn add_type_id(&mut self, id: CoreTypeId); - fn type_id_at(&self, idx: u32, offset: usize) -> Result; + fn type_id_at(&self, idx: u32, offset: u64) -> Result; fn types_len(&self) -> u32; fn features(&self) -> &WasmFeatures; @@ -87,7 +87,7 @@ pub(crate) trait InternRecGroup { &mut self, types: &mut TypeAlloc, mut rec_group: RecGroup, - offset: usize, + offset: u64, ) -> Result<()> where Self: Sized, @@ -128,7 +128,7 @@ pub(crate) trait InternRecGroup { rec_group: RecGroupId, id: CoreTypeId, types: &mut TypeAlloc, - offset: usize, + offset: u64, ) -> Result<()> { let ty = &types[id]; if !ty.is_final || ty.supertype_idx.is_some() { @@ -173,7 +173,7 @@ pub(crate) trait InternRecGroup { rec_group: RecGroupId, id: CoreTypeId, types: &TypeList, - offset: usize, + offset: u64, ) -> Result<()> { let ty = &types[id].composite_type; if ty.descriptor_idx.is_some() || ty.describes_idx.is_some() { @@ -287,7 +287,7 @@ pub(crate) trait InternRecGroup { &mut self, ty: &CompositeType, types: &TypeList, - offset: usize, + offset: u64, ) -> Result<()> { let features = *self.features(); let check = |ty: &ValType, shared: bool| { @@ -390,7 +390,7 @@ pub(crate) trait InternRecGroup { types: &TypeList, rec_group: RecGroupId, index: PackedIndex, - offset: usize, + offset: u64, ) -> Result { match index.unpack() { UnpackedIndex::Id(id) => Ok(id), @@ -419,13 +419,13 @@ pub(crate) struct TypeCanonicalizer<'a> { module: &'a dyn InternRecGroup, rec_group_start: u32, rec_group_len: u32, - offset: usize, + offset: u64, mode: CanonicalizationMode, within_rec_group: Option>, } impl<'a> TypeCanonicalizer<'a> { - pub fn new(module: &'a dyn InternRecGroup, offset: usize) -> Self { + pub fn new(module: &'a dyn InternRecGroup, offset: u64) -> Self { // These defaults will work for when we are canonicalizing types from // outside of a rec group definition, forcing all `PackedIndex`es to be // canonicalized to `CoreTypeId`s. diff --git a/crates/wasmparser/src/validator/func.rs b/crates/wasmparser/src/validator/func.rs index d0b105f1fa..325cfc8735 100644 --- a/crates/wasmparser/src/validator/func.rs +++ b/crates/wasmparser/src/validator/func.rs @@ -201,7 +201,7 @@ arity mismatch in validation /// /// This should be used if the application is already reading local /// definitions and there's no need to re-parse the function again. - pub fn define_locals(&mut self, offset: usize, count: u32, ty: ValType) -> Result<()> { + pub fn define_locals(&mut self, offset: u64, count: u32, ty: ValType) -> Result<()> { self.validator .define_locals(offset, count, ty, &self.resources) } @@ -213,7 +213,7 @@ arity mismatch in validation /// the operator itself are passed to this function to provide more useful /// error messages. On error, the validator may be left in an undefined /// state and should not be reused. - pub fn op(&mut self, offset: usize, operator: &Operator<'_>) -> Result<()> { + pub fn op(&mut self, offset: u64, operator: &Operator<'_>) -> Result<()> { self.visitor(offset).visit_operator(operator) } @@ -221,7 +221,7 @@ arity mismatch in validation /// to its previous state if this is unsuccessful. The validator may be reused /// even after an error. #[cfg(feature = "try-op")] - pub fn try_op(&mut self, offset: usize, operator: &Operator<'_>) -> Result<()> { + pub fn try_op(&mut self, offset: u64, operator: &Operator<'_>) -> Result<()> { self.validator.begin_try_op(); let res = self.op(offset, operator); if res.is_ok() { @@ -253,7 +253,7 @@ arity mismatch in validation /// ``` pub fn visitor<'this, 'a: 'this>( &'this mut self, - offset: usize, + offset: u64, ) -> impl VisitOperator<'a, Output = Result<()>> + ModuleArity + FrameStack + 'this { self.validator.with_resources(&self.resources, offset) } @@ -264,7 +264,7 @@ arity mismatch in validation #[cfg(feature = "simd")] pub fn simd_visitor<'this, 'a: 'this>( &'this mut self, - offset: usize, + offset: u64, ) -> impl crate::VisitSimdOperator<'a, Output = Result<()>> + ModuleArity + 'this { self.validator.with_resources_simd(&self.resources, offset) } @@ -397,7 +397,7 @@ mod tests { fn type_index_of_function(&self, _at: u32) -> Option { todo!() } - fn check_heap_type(&self, _t: &mut HeapType, _offset: usize) -> Result<()> { + fn check_heap_type(&self, _t: &mut HeapType, _offset: u64) -> Result<()> { Ok(()) } fn top_type(&self, _heap_type: &HeapType) -> HeapType { @@ -485,7 +485,7 @@ mod tests { op.operator_arity(&func_validator) .expect("valid operators should have arity"), ); - func_validator.op(usize::MAX, &op).expect("should be valid"); + func_validator.op(u64::MAX, &op).expect("should be valid"); } actual.push(arity); } diff --git a/crates/wasmparser/src/validator/names.rs b/crates/wasmparser/src/validator/names.rs index 0148d566c4..688803acce 100644 --- a/crates/wasmparser/src/validator/names.rs +++ b/crates/wasmparser/src/validator/names.rs @@ -282,7 +282,7 @@ const STATIC: &str = "[static]"; impl ComponentName { /// Attempts to parse `name` as a valid component name, returning `Err` if /// it's not valid. - pub fn new(name: &str, offset: usize) -> Result { + pub fn new(name: &str, offset: u64) -> Result { Self::new_with_features(name, offset, WasmFeatures::default()) } @@ -291,7 +291,7 @@ impl ComponentName { /// /// `features` can be used to enable or disable validation of certain forms /// of supported import names. - pub fn new_with_features(name: &str, offset: usize, features: WasmFeatures) -> Result { + pub fn new_with_features(name: &str, offset: u64, features: WasmFeatures) -> Result { let mut parser = ComponentNameParser { next: name, offset, @@ -581,7 +581,7 @@ impl<'a> HashName<'a> { // for error messages. struct ComponentNameParser<'a> { next: &'a str, - offset: usize, + offset: u64, features: WasmFeatures, } diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index 3d7ad79e7b..dbf19c8aa4 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -233,7 +233,7 @@ pub struct Frame { } struct OperatorValidatorTemp<'validator, 'resources, T> { - offset: usize, + offset: u64, inner: &'validator mut OperatorValidator, resources: &'resources T, } @@ -385,7 +385,7 @@ impl OperatorValidator { /// `ty`. pub fn new_func( ty: u32, - offset: usize, + offset: u64, features: &WasmFeatures, resources: &T, allocs: OperatorValidatorAllocations, @@ -450,7 +450,7 @@ impl OperatorValidator { pub fn define_locals( &mut self, - offset: usize, + offset: u64, count: u32, mut ty: ValType, resources: &impl WasmModuleResources, @@ -512,7 +512,7 @@ impl OperatorValidator { pub fn with_resources<'a, 'validator, 'resources, T>( &'validator mut self, resources: &'resources T, - offset: usize, + offset: u64, ) -> impl VisitOperator<'a, Output = Result<()>> + ModuleArity + FrameStack + 'validator where T: WasmModuleResources, @@ -531,7 +531,7 @@ impl OperatorValidator { pub fn with_resources_simd<'a, 'validator, 'resources, T>( &'validator mut self, resources: &'resources T, - offset: usize, + offset: u64, ) -> impl VisitSimdOperator<'a, Output = Result<()>> + ModuleArity + 'validator where T: WasmModuleResources, diff --git a/crates/wasmparser/src/validator/types.rs b/crates/wasmparser/src/validator/types.rs index 22fd2501e9..e314dde621 100644 --- a/crates/wasmparser/src/validator/types.rs +++ b/crates/wasmparser/src/validator/types.rs @@ -261,7 +261,7 @@ impl TypeInfo { /// Returns an error if the type size would exceed this crate's static limit /// of a type size. #[cfg(feature = "component-model")] - pub(crate) fn combine(&mut self, other: TypeInfo, offset: usize) -> Result<()> { + pub(crate) fn combine(&mut self, other: TypeInfo, offset: u64) -> Result<()> { let depth = self.depth().max(other.depth().saturating_add(1)); let size = super::combine_type_sizes(self.size(), other.size(), offset)?; let contains_borrow = self.contains_borrow() || other.contains_borrow(); @@ -994,7 +994,7 @@ impl TypeList { /// Helper for interning a sub type as a rec group; see /// [`Self::intern_canonical_rec_group`]. - pub fn intern_sub_type(&mut self, sub_ty: SubType, offset: usize) -> CoreTypeId { + pub fn intern_sub_type(&mut self, sub_ty: SubType, offset: u64) -> CoreTypeId { let (_is_new, group_id) = self.intern_canonical_rec_group(true, RecGroup::implicit(offset, sub_ty)); self[group_id].start @@ -1002,7 +1002,7 @@ impl TypeList { /// Helper for interning a function type as a rec group; see /// [`Self::intern_sub_type`]. - pub fn intern_func_type(&mut self, ty: FuncType, offset: usize) -> CoreTypeId { + pub fn intern_func_type(&mut self, ty: FuncType, offset: u64) -> CoreTypeId { self.intern_sub_type(SubType::func(ty, false), offset) } @@ -1011,7 +1011,7 @@ impl TypeList { &self, rec_group: RecGroupId, index: u32, - offset: usize, + offset: u64, ) -> Result { let elems = &self[rec_group]; let len = elems.end.index() - elems.start.index(); @@ -1068,7 +1068,7 @@ impl TypeList { &self, rec_group: RecGroupId, index: PackedIndex, - offset: usize, + offset: u64, ) -> Result { self.at_canonicalized_unpacked_index(rec_group, index.unpack(), offset) } @@ -1080,7 +1080,7 @@ impl TypeList { &self, rec_group: RecGroupId, index: UnpackedIndex, - offset: usize, + offset: u64, ) -> Result { match index { UnpackedIndex::Module(_) => panic!("not canonicalized"), @@ -1151,7 +1151,7 @@ impl TypeList { if let Some(id) = index.as_core_type_id() { id } else { - self.at_canonicalized_unpacked_index(group.unwrap(), index, usize::MAX) + self.at_canonicalized_unpacked_index(group.unwrap(), index, u64::MAX) .expect("type references are checked during canonicalization") } }; diff --git a/crates/wasmprinter/src/component.rs b/crates/wasmprinter/src/component.rs index af5217e465..d40d26c6db 100644 --- a/crates/wasmprinter/src/component.rs +++ b/crates/wasmprinter/src/component.rs @@ -1340,10 +1340,10 @@ impl Printer<'_, '_> { pub(crate) fn print_component_start( &mut self, state: &mut State, - pos: usize, + offset: u64, start: ComponentStartFunction, ) -> Result<()> { - self.newline(pos)?; + self.newline(offset)?; self.start_group("start ")?; self.print_idx(&state.component.func_names, start.func_index)?; diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index 6fba475625..829dd54a88 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -87,7 +87,7 @@ struct Printer<'cfg, 'env> { nesting: u32, line: usize, group_lines: Vec, - code_section_hints: Vec<(u32, Vec<(usize, BranchHint)>)>, + code_section_hints: Vec<(u32, Vec<(u64, BranchHint)>)>, } #[derive(Default)] @@ -305,11 +305,11 @@ impl Config { &self, wasm: &[u8], storage: &'a mut String, - ) -> Result, &'a str)> + 'a> { + ) -> Result, &'a str)> + 'a> { struct TrackingPrint<'a> { dst: &'a mut String, lines: Vec, - line_offsets: Vec>, + line_offsets: Vec>, } impl Print for TrackingPrint<'_> { @@ -317,7 +317,7 @@ impl Config { self.dst.push_str(s); Ok(()) } - fn start_line(&mut self, offset: Option) { + fn start_line(&mut self, offset: Option) { self.lines.push(self.dst.len()); self.line_offsets.push(offset); } @@ -383,7 +383,7 @@ impl Printer<'_, '_> { unchecked_range: range, .. } => { - let offset = range.end - range.start; + let offset = InMemData::range_len(&range); if offset > bytes.len() { bail!("invalid module or component section range"); } @@ -811,7 +811,7 @@ impl Printer<'_, '_> { Ok(()) } - fn end_group_at_pos(&mut self, offset: usize) -> Result<()> { + fn end_group_at_pos(&mut self, offset: u64) -> Result<()> { self.nesting -= 1; let start_group_line = self.group_lines.pop(); if self.config.print_offsets { @@ -876,7 +876,7 @@ impl Printer<'_, '_> { fn print_rec( &mut self, state: &mut State, - offset: Option, + offset: Option, rec: RecGroup, is_component: bool, ) -> Result<()> { @@ -1505,9 +1505,9 @@ impl Printer<'_, '_> { func_idx: u32, params: u32, body: &FunctionBody<'_>, - branch_hints: &[(usize, BranchHint)], + branch_hints: &[(u64, BranchHint)], mut validator: Option, - ) -> Result { + ) -> Result { let mut first = true; let mut local_idx = 0; let mut locals = NamedLocalPrinter::new("local"); @@ -1586,11 +1586,11 @@ impl Printer<'_, '_> { fn print_operators<'a, O: OpPrinter>( body: &mut BinaryReader<'a>, - mut branch_hints: &[(usize, BranchHint)], - func_start: usize, + mut branch_hints: &[(u64, BranchHint)], + func_start: u64, op_printer: &mut O, mut validator: Option, - ) -> Result { + ) -> Result { let mut ops = OperatorsReader::new(body.clone()); while !ops.eof() { if ops.is_end_then_eof() { @@ -1640,7 +1640,7 @@ impl Printer<'_, '_> { bail!("unexpected end of operators"); } - fn newline(&mut self, offset: usize) -> Result<()> { + fn newline(&mut self, offset: u64) -> Result<()> { self.print_newline(Some(offset)) } @@ -1648,7 +1648,7 @@ impl Printer<'_, '_> { self.print_newline(None) } - fn print_newline(&mut self, offset: Option) -> Result<()> { + fn print_newline(&mut self, offset: Option) -> Result<()> { self.result.newline()?; self.result.start_line(offset); diff --git a/crates/wasmprinter/src/operator.rs b/crates/wasmprinter/src/operator.rs index 1b8b4d6a8d..45d84a3d53 100644 --- a/crates/wasmprinter/src/operator.rs +++ b/crates/wasmprinter/src/operator.rs @@ -9,7 +9,7 @@ use wasmparser::{ }; pub struct OperatorState { - op_offset: usize, + op_offset: u64, nesting_start: u32, label: u32, label_indices: Vec, @@ -38,7 +38,7 @@ struct FoldedInstruction { plain: String, folded: Vec, results: u32, - offset: usize, + offset: u64, } struct Block { @@ -47,8 +47,8 @@ struct Block { plain: String, folded: Vec, predicate: Option>, - consequent: Option<(Vec, usize)>, - offset: usize, + consequent: Option<(Vec, u64)>, + offset: u64, } pub struct PrintOperatorFolded<'printer, 'state, 'a, 'b> { @@ -1430,8 +1430,8 @@ impl<'a> VisitSimdOperator<'a> for PrintOperator<'_, '_, '_, '_> { } pub trait OpPrinter { - fn branch_hint(&mut self, offset: usize, taken: bool) -> Result<()>; - fn set_offset(&mut self, offset: usize); + fn branch_hint(&mut self, offset: u64, taken: bool) -> Result<()>; + fn set_offset(&mut self, offset: u64); fn visit_operator( &mut self, reader: &mut OperatorsReader<'_>, @@ -1442,7 +1442,7 @@ pub trait OpPrinter { } impl OpPrinter for PrintOperator<'_, '_, '_, '_> { - fn branch_hint(&mut self, offset: usize, taken: bool) -> Result<()> { + fn branch_hint(&mut self, offset: u64, taken: bool) -> Result<()> { self.printer.newline(offset)?; let desc = if taken { "\"\\01\"" } else { "\"\\00\"" }; self.printer.result.start_comment()?; @@ -1451,7 +1451,7 @@ impl OpPrinter for PrintOperator<'_, '_, '_, '_> { Ok(()) } - fn set_offset(&mut self, offset: usize) { + fn set_offset(&mut self, offset: u64) { self.operator_state.op_offset = offset; } @@ -1486,7 +1486,7 @@ impl OpPrinter for PrintOperator<'_, '_, '_, '_> { } impl OpPrinter for PrintOperatorFolded<'_, '_, '_, '_> { - fn branch_hint(&mut self, offset: usize, taken: bool) -> Result<()> { + fn branch_hint(&mut self, offset: u64, taken: bool) -> Result<()> { let mut hint = String::new(); hint.push_str("@metadata.code.branch_hint "); hint.push_str(if taken { "\"\\01\"" } else { "\"\\00\"" }); @@ -1499,7 +1499,7 @@ impl OpPrinter for PrintOperatorFolded<'_, '_, '_, '_> { Ok(()) } - fn set_offset(&mut self, offset: usize) { + fn set_offset(&mut self, offset: u64) { self.operator_state.op_offset = offset; } diff --git a/crates/wasmprinter/src/print.rs b/crates/wasmprinter/src/print.rs index 0d869ed498..b746bf39d4 100644 --- a/crates/wasmprinter/src/print.rs +++ b/crates/wasmprinter/src/print.rs @@ -32,7 +32,7 @@ pub trait Print { /// Not all new lines have a binary offset associated with them but this /// method should be called for new lines in the output. This enables /// correlating binary offsets to lines in the output. - fn start_line(&mut self, binary_offset: Option) { + fn start_line(&mut self, binary_offset: Option) { let _ = binary_offset; } @@ -74,7 +74,7 @@ pub trait Print { fn print_custom_section( &mut self, name: &str, - binary_offset: usize, + binary_offset: u64, data: &[u8], ) -> io::Result { let _ = (name, binary_offset, data); diff --git a/crates/wast/tests/annotations.rs b/crates/wast/tests/annotations.rs index 49bb34e5a0..4b87f6f168 100644 --- a/crates/wast/tests/annotations.rs +++ b/crates/wast/tests/annotations.rs @@ -192,7 +192,7 @@ fn custom_section_order() -> anyhow::Result<()> { ); match &wasm[17] { - Payload::End(x) if *x == bytes.len() => {} + Payload::End(x) if InMemData::translate_offset(*x) == bytes.len() => {} p => panic!("`{:?}` doesn't match expected length of {}", p, bytes.len()), } diff --git a/crates/wit-component/src/encoding/dedupe.rs b/crates/wit-component/src/encoding/dedupe.rs index 204575c617..384b609650 100644 --- a/crates/wit-component/src/encoding/dedupe.rs +++ b/crates/wit-component/src/encoding/dedupe.rs @@ -18,7 +18,7 @@ use std::collections::HashMap; use std::fmt::Write; use wasm_encoder::reencode::{Reencode, RoundtripReencoder}; use wasm_encoder::{ImportSection, RawSection}; -use wasmparser::{Parser, Payload::*}; +use wasmparser::{InMemData, Parser, Payload::*}; /// A map of current names (possibly new) to original names, if any. #[derive(Default)] @@ -55,7 +55,8 @@ impl ModuleImportMap { let mut ret = ModuleImportMap::default(); let mut found_duplicate_imports = false; - for payload in Parser::new(0).parse_all(&wasm) { + let data = InMemData::new(&wasm); + for payload in Parser::new(0).parse_all(&data) { let payload = payload?; match &payload { Version { encoding, .. } if *encoding == wasmparser::Encoding::Component => { @@ -86,7 +87,7 @@ impl ModuleImportMap { if let Some((id, range)) = payload.as_section() { module.section(&RawSection { id, - data: &wasm[range], + data: &data[range], }); } } diff --git a/crates/wit-component/src/metadata.rs b/crates/wit-component/src/metadata.rs index d6f52df07a..c662e8cb97 100644 --- a/crates/wit-component/src/metadata.rs +++ b/crates/wit-component/src/metadata.rs @@ -49,7 +49,7 @@ use wasm_encoder::{ ComponentBuilder, ComponentExportKind, ComponentType, ComponentTypeRef, CustomSection, }; use wasm_metadata::Producers; -use wasmparser::{BinaryReader, Encoding, Parser, Payload}; +use wasmparser::{BinaryReader, Encoding, InMemData, Parser, Payload}; use wit_parser::{CloneMaps, Package, PackageName, Resolve, World, WorldId, WorldItem, WorldKey}; const CURRENT_VERSION: u8 = 0x04; @@ -227,11 +227,12 @@ impl EncodingMap { /// optionally returned with the custom sections stripped out. If no /// `component-type` custom sections are found then `None` is returned. pub fn decode(wasm: &[u8]) -> Result<(Option>, Bindgen)> { + let wasm = InMemData::new(wasm); let mut ret = Bindgen::default(); let mut new_module = wasm_encoder::Module::new(); let mut found_custom = false; - for payload in wasmparser::Parser::new(0).parse_all(wasm) { + for payload in wasmparser::Parser::new(0).parse_all(&wasm) { let payload = payload.context("decoding item in module")?; match payload { wasmparser::Payload::CustomSection(cs) if cs.name().starts_with("component-type") => { @@ -350,7 +351,8 @@ impl Bindgen { let resolve; let encoding; - let mut reader = BinaryReader::new(data, 0); + let data = InMemData::new(data); + let mut reader = BinaryReader::new(&data, 0); match reader.read_u8()? { // Historical 0x03 format where the support here will be deleted in // the future @@ -369,7 +371,7 @@ impl Bindgen { // Current format where `data` is a wasm component itself. _ => { - wasm = data; + wasm = data.data; (resolve, world, encoding) = decode_custom_section(wasm)?; } } diff --git a/fuzz/src/validate.rs b/fuzz/src/validate.rs index 2b87023b1b..8d6c8b2a98 100644 --- a/fuzz/src/validate.rs +++ b/fuzz/src/validate.rs @@ -1,5 +1,5 @@ use arbitrary::{Result, Unstructured}; -use wasmparser::{Parser, Validator, WasmFeatures}; +use wasmparser::{InMemData, Parser, Validator, WasmFeatures}; pub fn run(u: &mut Unstructured<'_>) -> Result<()> { // Either use `wasm-smith` to generate a module with possibly invalid @@ -33,6 +33,7 @@ pub fn validate_raw_bytes(u: &mut Unstructured<'_>) -> Result<()> { } fn validate_all(u: &mut Unstructured<'_>, mut validator: Validator, wasm: &[u8]) -> Result<()> { + let wasm = InMemData::new(wasm); // First try printing this module. Generate a random configuration for // printing and then see what happens. Mostly making sure nothing panics // here. @@ -43,12 +44,12 @@ fn validate_all(u: &mut Unstructured<'_>, mut validator: Validator, wasm: &[u8]) cfg.name_unnamed(u.arbitrary()?); log::debug!("print config {cfg:?}"); let mut wat = String::new(); - let _ = cfg.print(wasm, &mut wasmprinter::PrintFmtWrite(&mut wat)); + let _ = cfg.print(&wasm, &mut wasmprinter::PrintFmtWrite(&mut wat)); // After printing then try to parse and validate the module. See how far we // get as invalid modules are explicitly allowed here. Generally looking for // panics and excessive resource usage here. - for payload in Parser::new(0).parse_all(wasm) { + for payload in Parser::new(0).parse_all(&wasm) { let payload = match payload { Ok(p) => p, Err(_) => return Ok(()), diff --git a/src/addr2line.rs b/src/addr2line.rs index 5df52a4313..402aba38f6 100644 --- a/src/addr2line.rs +++ b/src/addr2line.rs @@ -31,7 +31,7 @@ impl<'a> Addr2lineModules<'a> { } => { assert!(cur_module.is_none()); cur_module = Some(Module { - range: range.start as u64..0, + range: range.start..0, code_start: None, custom_sections: HashMap::new(), context: None, @@ -45,12 +45,12 @@ impl<'a> Addr2lineModules<'a> { } Payload::CodeSectionStart { range, .. } => { assert!(cur_module.is_some()); - cur_module.as_mut().unwrap().code_start = Some(range.start as u64); + cur_module.as_mut().unwrap().code_start = Some(range.start); } Payload::End(offset) => { if let Some(mut module) = cur_module.take() { - module.range.end = offset as u64; + module.range.end = offset; modules.push(module); } } diff --git a/src/bin/wasm-tools/component.rs b/src/bin/wasm-tools/component.rs index 310658184f..67e758ccaf 100644 --- a/src/bin/wasm-tools/component.rs +++ b/src/bin/wasm-tools/component.rs @@ -11,7 +11,7 @@ use wasm_encoder::reencode::{Error, Reencode, ReencodeComponent, RoundtripReenco use wasm_tools::Output; use wasm_tools::wit::WitResolve; use wasmparser::types::{CoreTypeId, EntityType, Types}; -use wasmparser::{Payload, ValidPayload, WasmFeatures}; +use wasmparser::{InMemData, Payload, ValidPayload, WasmFeatures}; use wat::Detect; use wit_component::{ ComponentEncoder, DecodedWasm, Linker, StringEncoding, WitPrinter, embed_component_metadata, @@ -1358,6 +1358,7 @@ impl UnbundleOpts { fn run(self) -> Result<()> { let input = self.io.get_input_wasm(Some(&self.generate_dwarf))?; + let input = InMemData::new(&input); if !wasmparser::Parser::is_component(&input) { return self.io.output_wasm(&input, self.wat); } @@ -1373,7 +1374,7 @@ impl UnbundleOpts { } => unchecked_range, _ => continue, }; - modules_to_extract.push(if range.len() > self.threshold { + modules_to_extract.push(if InMemData::range_len(&range) > self.threshold { Some(&input[range]) } else { None diff --git a/src/bin/wasm-tools/demangle.rs b/src/bin/wasm-tools/demangle.rs index 0896b53f16..f25cb3f3f1 100644 --- a/src/bin/wasm-tools/demangle.rs +++ b/src/bin/wasm-tools/demangle.rs @@ -1,6 +1,6 @@ use anyhow::{Result, bail}; use wasm_encoder::{IndirectNameMap, NameMap, NameSection, RawSection}; -use wasmparser::{KnownCustom, Name, NameSectionReader, Parser, Payload::*}; +use wasmparser::{InMemData, KnownCustom, Name, NameSectionReader, Parser, Payload::*}; /// Demangle Rust and C++ symbol names in the `name` section. /// @@ -56,6 +56,7 @@ impl Opts { pub fn run(&self) -> Result<()> { let input = self.io.get_input_wasm(None)?; + let input = InMemData::new(&input); let mut module = wasm_encoder::Module::new(); for payload in Parser::new(0).parse_all(&input) { diff --git a/src/bin/wasm-tools/dump.rs b/src/bin/wasm-tools/dump.rs index 1750806915..c22fbd332e 100644 --- a/src/bin/wasm-tools/dump.rs +++ b/src/bin/wasm-tools/dump.rs @@ -29,8 +29,8 @@ impl Opts { } struct Dump<'a> { - bytes: &'a [u8], - cur: usize, + bytes: InMemData<'a>, + cur: u64, state: String, dst: Box, nesting: u32, @@ -71,7 +71,7 @@ const NBYTES: usize = 4; impl<'a> Dump<'a> { fn new(bytes: &'a [u8], dst: impl WriteColor + 'a) -> Dump<'a> { Dump { - bytes, + bytes: InMemData::new(bytes), cur: 0, nesting: 0, state: String::new(), @@ -82,7 +82,7 @@ impl<'a> Dump<'a> { fn run(&mut self) -> Result<()> { self.print_module()?; - assert_eq!(self.cur, self.bytes.len()); + assert_eq!(InMemData::translate_offset(self.cur), self.bytes.len()); Ok(()) } @@ -92,7 +92,7 @@ impl<'a> Dump<'a> { let mut component_types = Vec::new(); self.nesting += 1; - for item in Parser::new(0).parse_all(self.bytes) { + for item in Parser::new(0).parse_all(self.bytes.index(..)) { match item? { Payload::Version { num, @@ -265,7 +265,7 @@ impl<'a> Dump<'a> { match i.kind { DataKind::Passive => { write!(me.state, "data passive")?; - me.print(end - i.data.len())?; + me.print(end - i.data.len() as u64)?; } DataKind::Active { memory_index, @@ -289,7 +289,7 @@ impl<'a> Dump<'a> { write!(self.state, "code section")?; self.color_print(range.start)?; write!(self.state, "{count} count")?; - self.print(range.end - size as usize)?; + self.print(range.end - size as u64)?; } Payload::CodeSectionEntry(body) => { @@ -610,7 +610,7 @@ impl<'a> Dump<'a> { write!(self.dst, "---")?; } writeln!(self.dst, "-| ... {} bytes of data", c.data().len())?; - self.cur += c.data().len(); + self.cur = c.range().end; } } } @@ -628,8 +628,9 @@ impl<'a> Dump<'a> { for _ in 0..NBYTES { write!(self.dst, "---")?; } - writeln!(self.dst, "-| ... {} bytes of data", range.len())?; - self.cur += range.len(); + let len = InMemData::range_len(&range); + writeln!(self.dst, "-| ... {len} bytes of data")?; + self.cur = range.end; } None => { bail!("unsupported payload {other:?}") @@ -663,7 +664,7 @@ impl<'a> Dump<'a> { fn print_subsections<'b, T>( &mut self, mut section: Subsections<'b, T>, - print_item: impl Fn(&mut Self, T, usize) -> Result<()>, + print_item: impl Fn(&mut Self, T, u64) -> Result<()>, ) -> Result<()> where T: wasmparser::Subsection<'b>, @@ -699,7 +700,7 @@ impl<'a> Dump<'a> { Ok(()) } - fn print_core_name(&mut self, name: Name<'_>, end: usize) -> Result<()> { + fn print_core_name(&mut self, name: Name<'_>, end: u64) -> Result<()> { match name { Name::Module { name, name_range } => { write!(self.state, "module name")?; @@ -727,7 +728,7 @@ impl<'a> Dump<'a> { Ok(()) } - fn print_component_name(&mut self, name: ComponentName<'_>, end: usize) -> Result<()> { + fn print_component_name(&mut self, name: ComponentName<'_>, end: u64) -> Result<()> { match name { ComponentName::Component { name, name_range } => { write!(self.state, "component name")?; @@ -757,7 +758,7 @@ impl<'a> Dump<'a> { Ok(()) } - fn print_linking_subsection(&mut self, s: Linking<'_>, end: usize) -> Result<()> { + fn print_linking_subsection(&mut self, s: Linking<'_>, end: u64) -> Result<()> { match s { Linking::SegmentInfo(map) => self.section(map, "segment info", |me, pos, item| { write!(me.state, "{item:?}")?; @@ -787,7 +788,7 @@ impl<'a> Dump<'a> { &mut self, iter: SectionLimited<'b, T>, name: &str, - print: impl FnMut(&mut Self, usize, T) -> Result<()>, + print: impl FnMut(&mut Self, u64, T) -> Result<()>, ) -> Result<()> where T: FromReader<'b>, @@ -800,7 +801,7 @@ impl<'a> Dump<'a> { fn print_iter<'b, T>( &mut self, iter: SectionLimited<'b, T>, - mut print: impl FnMut(&mut Self, usize, T) -> Result<()>, + mut print: impl FnMut(&mut Self, u64, T) -> Result<()>, ) -> Result<()> where T: FromReader<'b>, @@ -825,15 +826,15 @@ impl<'a> Dump<'a> { Ok(()) } - fn color_print(&mut self, end: usize) -> Result<()> { + fn color_print(&mut self, end: u64) -> Result<()> { self.print_(end, true) } - fn print(&mut self, end: usize) -> Result<()> { + fn print(&mut self, end: u64) -> Result<()> { self.print_(end, false) } - fn print_(&mut self, end: usize, color: bool) -> Result<()> { + fn print_(&mut self, end: u64, color: bool) -> Result<()> { assert!( self.cur < end, "{:#x} >= {:#x}\ntrying to print: {}", @@ -841,7 +842,7 @@ impl<'a> Dump<'a> { end, self.state, ); - let bytes = &self.bytes[self.cur..end]; + let bytes = self.bytes.index(self.cur..end); self.print_byte_header()?; for (i, chunk) in bytes.chunks(NBYTES).enumerate() { if i > 0 { diff --git a/src/bin/wasm-tools/metadata.rs b/src/bin/wasm-tools/metadata.rs index 91af93fc25..22043bdae7 100644 --- a/src/bin/wasm-tools/metadata.rs +++ b/src/bin/wasm-tools/metadata.rs @@ -297,7 +297,7 @@ fn write_summary_table(payload: &Payload, f: &mut Box) -> Result .set_cell_alignment(CellAlignment::Right); // Get the max value of the `range` field. This is the upper memory bound. - fn find_range_max(max: &mut usize, payload: &Payload) { + fn find_range_max(max: &mut u64, payload: &Payload) { let range = &payload.metadata().range; if range.end > *max { *max = range.end; @@ -327,7 +327,7 @@ fn write_summary_table_inner( payload: &Payload, parent: &str, unknown_id: &mut u16, - range_max: usize, + range_max: u64, f: &mut Box, table: &mut Table, ) -> Result<()> { @@ -346,7 +346,7 @@ fn write_summary_table_inner( name } }; - let size = ByteSize::b((range.end - range.start) as u64) + let size = ByteSize::b(range.end - range.start) .display() .si_short() .to_string(); diff --git a/src/bin/wasm-tools/objdump.rs b/src/bin/wasm-tools/objdump.rs index bedb23849b..7e433579ee 100644 --- a/src/bin/wasm-tools/objdump.rs +++ b/src/bin/wasm-tools/objdump.rs @@ -100,11 +100,9 @@ impl Opts { ComponentImportSection(s) => printer.section(s, "component imports")?, ComponentExportSection(s) => printer.section(s, "component exports")?, - CustomSection(c) => printer.section_raw( - c.data_offset()..c.data_offset() + c.data().len(), - 1, - &format!("custom {:?}", c.name()), - )?, + CustomSection(c) => { + printer.section_raw(c.data_range(), 1, &format!("custom {:?}", c.name()))? + } End(_) => printer.end()?, @@ -200,7 +198,7 @@ impl Printer { self.section_raw(section.range(), section.count(), name) } - fn section_raw(&mut self, range: Range, count: u32, name: &str) -> Result<()> { + fn section_raw(&mut self, range: Range, count: u32, name: &str) -> Result<()> { writeln!( self.output, "{:40} | {:#10x} - {:#10x} | {:9} bytes | {} count", diff --git a/src/bin/wasm-tools/strip.rs b/src/bin/wasm-tools/strip.rs index 9b8eeec23a..09bdba2865 100644 --- a/src/bin/wasm-tools/strip.rs +++ b/src/bin/wasm-tools/strip.rs @@ -1,7 +1,7 @@ use anyhow::Result; use std::mem; use wasm_encoder::{ComponentSectionId, Encode, RawSection, Section}; -use wasmparser::{Parser, Payload::*}; +use wasmparser::{InMemData, Parser, Payload::*}; /// Removes custom sections from an input WebAssembly file. /// @@ -80,6 +80,7 @@ impl Opts { pub fn run(&self) -> Result<()> { let input = self.io.get_input_wasm(None)?; + let input = InMemData::new(&input); let to_delete = regex::RegexSet::new(self.delete.iter())?; let strip_custom_section = |name: &str| { diff --git a/src/bin/wasm-tools/validate.rs b/src/bin/wasm-tools/validate.rs index 19fd762cd1..64fa68ee4a 100644 --- a/src/bin/wasm-tools/validate.rs +++ b/src/bin/wasm-tools/validate.rs @@ -175,11 +175,11 @@ impl Opts { fn annotate_error_with_file_and_line( &self, wasm: &[u8], - offset: usize, + offset: u64, ) -> Result> { let mut modules = Addr2lineModules::parse(wasm)?; let code_section_relative = false; - let (context, text_rel) = match modules.context(offset as u64, code_section_relative)? { + let (context, text_rel) = match modules.context(offset, code_section_relative)? { Some(pair) => pair, None => return Ok(None), };