From 2a6f9dbcd9ad4397bad624c8dc2ba08b9a2350e6 Mon Sep 17 00:00:00 2001 From: WorldSEnder Date: Sat, 18 Jul 2026 15:57:06 +0200 Subject: [PATCH 01/10] use u64 internally to track file offsets This replaces usize in a lot of places. Besides being a technically breaking change, this should not impact functionality. Solves a TODO left long ago in the entry code of parse. --- crates/wasmparser/src/binary_reader.rs | 124 +++---- crates/wasmparser/src/error.rs | 17 +- crates/wasmparser/src/features.rs | 3 +- crates/wasmparser/src/lib.rs | 1 + crates/wasmparser/src/limits.rs | 2 +- crates/wasmparser/src/offsets.rs | 173 ++++++++++ crates/wasmparser/src/parser.rs | 119 ++++--- crates/wasmparser/src/readers.rs | 13 +- .../src/readers/component/aliases.rs | 6 +- .../src/readers/component/exports.rs | 3 +- .../wasmparser/src/readers/component/names.rs | 23 +- crates/wasmparser/src/readers/core/code.rs | 9 +- crates/wasmparser/src/readers/core/custom.rs | 5 +- crates/wasmparser/src/readers/core/data.rs | 6 +- crates/wasmparser/src/readers/core/dylink0.rs | 9 +- .../wasmparser/src/readers/core/elements.rs | 4 +- crates/wasmparser/src/readers/core/imports.rs | 14 +- crates/wasmparser/src/readers/core/linking.rs | 15 +- crates/wasmparser/src/readers/core/names.rs | 16 +- .../wasmparser/src/readers/core/operators.rs | 11 +- crates/wasmparser/src/readers/core/reloc.rs | 15 +- crates/wasmparser/src/readers/core/types.rs | 19 +- crates/wasmparser/src/resources.rs | 13 +- crates/wasmparser/src/validator.rs | 59 ++-- crates/wasmparser/src/validator/component.rs | 305 +++++++++++------- .../src/validator/component_types.rs | 56 ++-- crates/wasmparser/src/validator/core.rs | 84 +++-- .../src/validator/core/canonical.rs | 20 +- crates/wasmparser/src/validator/func.rs | 17 +- crates/wasmparser/src/validator/names.rs | 11 +- crates/wasmparser/src/validator/operators.rs | 11 +- crates/wasmparser/src/validator/types.rs | 15 +- 32 files changed, 750 insertions(+), 448 deletions(-) create mode 100644 crates/wasmparser/src/offsets.rs diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index fb9a2b4504..5429e43c50 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; @@ -25,8 +26,8 @@ pub(crate) const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm"; #[derive(Clone, Debug, Hash)] pub struct BinaryReader<'a> { buffer: &'a [u8], - position: usize, - original_offset: usize, + position: MemOffset, + original_offset: LogicalOffset, // When the `features` feature is disabled then the `WasmFeatures` type // still exists but this field is still omitted. When `features` is @@ -54,10 +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: LogicalOffset) -> BinaryReader<'_> { BinaryReader { buffer: data, - position: 0, + position: MemOffset::zero_at(original_offset, data.len()), original_offset, #[cfg(feature = "features")] features: WasmFeatures::all(), @@ -97,12 +98,12 @@ impl<'a> BinaryReader<'a> { #[cfg(feature = "features")] pub fn new_features( data: &[u8], - original_offset: usize, + original_offset: LogicalOffset, features: WasmFeatures, ) -> BinaryReader<'_> { BinaryReader { buffer: data, - position: 0, + position: MemOffset::zero_at(original_offset, data.len()), original_offset, features, } @@ -119,10 +120,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.into_usize()..]; + let original_offset = self.original_offset + self.position; BinaryReader { - buffer: &self.buffer[self.position..], - position: 0, - original_offset: self.original_offset + self.position, + buffer, + position: MemOffset::zero_at(original_offset, buffer.len()), + original_offset, #[cfg(feature = "features")] features: self.features, } @@ -130,7 +133,7 @@ impl<'a> BinaryReader<'a> { /// Gets the original position of the binary reader. #[inline] - pub fn original_position(&self) -> usize { + pub fn original_position(&self) -> LogicalOffset { self.original_offset + self.position } @@ -152,28 +155,34 @@ 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()) } pub(crate) fn remaining_buffer(&self) -> &'a [u8] { - &self.buffer[self.position..] + &self.buffer[self.position.into_usize()..] + } + + pub(crate) fn remaining_range(&self) -> Range { + self.original_position()..(self.original_offset + self.max_offset()) + } + + fn max_offset(&self) -> MemOffset { + MemOffset::max(LogicalOffset::MAX - self.original_offset, 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)) + pub(crate) fn ensure_has_bytes(&self, len: usize) -> Result { + match self.position.try_add(len, self.max_offset()) { + Ok(end) => Ok(end), + Err(hint) => Err(self.eof_err(hint)), } } @@ -195,7 +204,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: LogicalOffset) -> Result { match byte { 0x00 => Ok(ExternalKind::Func), 0x01 => Ok(ExternalKind::Table), @@ -244,19 +253,25 @@ 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 reader's position as an offset into its data chunk. + #[inline] + pub(crate) fn current_mem_offset(&self) -> MemOffset { + self.position } /// Returns the `BinaryReader`'s current position. #[inline] pub fn current_position(&self) -> usize { - self.position + self.current_mem_offset().into_usize() } /// Returns the number of bytes remaining in the `BinaryReader`. #[inline] pub fn bytes_remaining(&self) -> usize { - self.buffer.len() - self.position + self.max_offset().into_usize() - self.position.into_usize() } /// Advances the `BinaryReader` `size` bytes, and returns a slice from the @@ -265,10 +280,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.into_usize()..end.into_usize()]) } /// Reads a length-prefixed list of bytes from this reader and returns a @@ -285,13 +300,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 +309,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 +321,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 @@ -417,9 +418,11 @@ impl<'a> BinaryReader<'a> { let start = self.position; f(self)?; let mut ret = self.clone(); - ret.buffer = &self.buffer[start..self.position]; - ret.position = 0; - ret.original_offset = self.original_offset + start; + let buffer = &self.buffer[start.into_usize()..self.position.into_usize()]; + let original_offset = self.original_offset + start; + ret.buffer = buffer; + ret.original_offset = original_offset; + ret.position = MemOffset::zero_at(original_offset, buffer.len()); Ok(ret) } @@ -618,18 +621,19 @@ 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: LogicalOffset) -> Error { format_err!(offset, "invalid leading byte (0x{byte:x}) for {desc}") } pub(crate) fn peek(&self) -> Result { self.ensure_has_byte()?; - Ok(self.buffer[self.position]) + Ok(self.buffer[self.position.into_usize()]) } 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.into_usize()..end.into_usize()]) } 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: LogicalOffset, visitor: &mut T, ) -> Result<>::Output> where @@ -1318,7 +1322,7 @@ impl<'a> BinaryReader<'a> { fn visit_0xfc_operator( &mut self, - pos: usize, + pos: LogicalOffset, 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: LogicalOffset, visitor: &mut T, ) -> Result<>::Output> where @@ -1715,7 +1719,7 @@ impl<'a> BinaryReader<'a> { fn visit_0xfe_operator( &mut self, - pos: usize, + pos: LogicalOffset, visitor: &mut T, ) -> Result<>::Output> where diff --git a/crates/wasmparser/src/error.rs b/crates/wasmparser/src/error.rs index 1475f6a617..d7ebffa29c 100644 --- a/crates/wasmparser/src/error.rs +++ b/crates/wasmparser/src/error.rs @@ -1,6 +1,7 @@ use core::fmt; use crate::WasmFeatures; +use crate::offsets::LogicalOffset; use crate::prelude::*; /// A binary reader for WebAssembly modules. @@ -16,7 +17,7 @@ pub struct Error { pub(crate) struct ErrorInner { message: String, kind: ErrorKind, - offset: usize, + offset: LogicalOffset, needed_hint: Option, } @@ -44,7 +45,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: LogicalOffset) -> Self { Error { inner: Box::new(ErrorInner { kind, @@ -56,12 +57,12 @@ impl Error { } #[cold] - pub(crate) fn new(message: impl Into, offset: usize) -> Self { + pub(crate) fn new(message: impl Into, offset: LogicalOffset) -> 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: LogicalOffset) -> Self { Self::_new(ErrorKind::InvalidHeapType, msg.into(), offset) } @@ -69,18 +70,18 @@ impl Error { pub(crate) fn wasm_feature( feature: crate::WasmFeatures, msg: impl fmt::Display, - offset: usize, + offset: LogicalOffset, ) -> 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: LogicalOffset) -> Self { Error::new(args.to_string(), offset) } #[cold] - pub(crate) fn eof(offset: usize, needed_hint: usize) -> Self { + pub(crate) fn eof(offset: LogicalOffset, needed_hint: usize) -> Self { let mut err = Error::new("unexpected end-of-file", offset); err.inner.needed_hint = Some(needed_hint); err @@ -96,7 +97,7 @@ impl Error { } /// Get the offset within the Wasm binary where the error occurred. - pub fn offset(&self) -> usize { + pub fn offset(&self) -> LogicalOffset { self.inner.offset } diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs index d2abd4d33d..e8ed876a96 100644 --- a/crates/wasmparser/src/features.rs +++ b/crates/wasmparser/src/features.rs @@ -110,6 +110,7 @@ macro_rules! define_wasm_features { pub(crate) mod require_feature { use crate::Error; use super::WasmFeatures; + use crate::offsets::LogicalOffset; $( #[inline] @@ -119,7 +120,7 @@ macro_rules! define_wasm_features { pub fn $field( features: WasmFeatures, msg: impl core::fmt::Display, - offset: usize, + offset: LogicalOffset, ) -> Result<(), Error> { if features.$field() { Ok(()) diff --git a/crates/wasmparser/src/lib.rs b/crates/wasmparser/src/lib.rs index adb237211d..f90265ca2b 100644 --- a/crates/wasmparser/src/lib.rs +++ b/crates/wasmparser/src/lib.rs @@ -1329,6 +1329,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..da22db9aa3 --- /dev/null +++ b/crates/wasmparser/src/offsets.rs @@ -0,0 +1,173 @@ +/* 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 [LogicalOffset]. 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::{ + num::TryFromIntError, + ops::{Add, AddAssign}, +}; + +pub type LogicalOffset = u64; + +// TODO: on platforms where usize::BITS > u64::BITS (currently almost no-where), +// this could wrap a u64 instead of a usize to be a bit smaller. +#[derive(Clone, Copy, Debug, Hash)] +pub struct MemOffset { + rep: usize, + #[cfg(debug_assertions)] + max: usize, +} + +impl PartialEq for MemOffset { + fn eq(&self, other: &Self) -> bool { + self.rep == other.rep + } +} + +impl PartialOrd for MemOffset { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Eq for MemOffset {} +impl Ord for MemOffset { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.rep.cmp(&other.rep) + } +} + +impl MemOffset { + pub fn max(max_logical: LogicalOffset, max: usize) -> Self { + let max_len_logical = max_logical; + let max_len = if LogicalOffset::BITS > usize::BITS { + let max_len_usize = usize::MAX as LogicalOffset; + // this now fits into a usize + max_len_logical.max(max_len_usize) as usize + } else { + // since usize seems to have more or equal bits, this fits always. + max_len_logical as usize + }; + let max_len = max_len.min(max); + Self { + rep: max_len, + #[cfg(debug_assertions)] + max: max_len, + } + } + pub fn zero_at(logical: LogicalOffset, max: usize) -> Self { + Self::try_from(logical, 0, max).unwrap() + } + pub fn try_from( + logical: LogicalOffset, + mem: usize, + max: usize, + ) -> Result { + let max = Self::max(LogicalOffset::MAX - logical, max).into_usize(); + if mem <= max { + Ok(Self { + rep: mem, + #[cfg(debug_assertions)] + max, + }) + } else { + Err(u32::try_from(u64::MAX).unwrap_err()) + } + } + pub fn into_usize(self) -> usize { + self.into() + } + pub fn try_add(self, additional: usize, max: MemOffset) -> Result { + #[cfg(debug_assertions)] + { + assert!( + self.max == max.max, + "self and max should be form the same memory extent" + ); + } + let remaining = max.into_usize().strict_sub(self.into_usize()); + if remaining < additional { + Err(additional - remaining) + } else { + Ok(Self { + rep: self.rep + additional, + #[cfg(debug_assertions)] + max: self.max, + }) + } + } + // convinience method we should put on LogicalOffset, but can't since inherent impls are not allowed there + pub fn logical_try_add(logical: LogicalOffset, additional: u32) -> Option { + logical.checked_add(additional as LogicalOffset) + } +} + +impl From for usize { + fn from(value: MemOffset) -> Self { + value.rep + } +} + +impl Add for LogicalOffset { + type Output = LogicalOffset; + fn add(self, rhs: MemOffset) -> Self::Output { + debug_assert!( + rhs <= MemOffset::max(LogicalOffset::MAX - self, usize::MAX), + "offset too large" + ); + self.strict_add(rhs.rep as u64) + } +} + +impl AddAssign for LogicalOffset { + fn add_assign(&mut self, rhs: MemOffset) { + *self = *self + rhs + } +} + +impl Add for MemOffset { + type Output = MemOffset; + fn add(self, rhs: usize) -> Self::Output { + let sum = if cfg!(debug_assertions) { + self.rep.checked_add(rhs).expect("shouldn't overflow") + } else { + self.rep.strict_add(rhs) + }; + #[cfg(debug_assertions)] + { + if sum > self.max { + panic!("unexpectedly large offset"); + } + } + Self { + rep: sum, + #[cfg(debug_assertions)] + max: self.max, + } + } +} + +impl AddAssign for MemOffset { + fn add_assign(&mut self, rhs: usize) { + *self = *self + rhs + } +} diff --git a/crates/wasmparser/src/parser.rs b/crates/wasmparser/src/parser.rs index c3aa1072d4..18515a8ad1 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::{LogicalOffset, MemOffset}; use crate::prelude::*; use crate::{ BinaryReader, CustomSectionReader, DataSectionReader, ElementSectionReader, Error, @@ -87,13 +88,13 @@ pub(crate) enum Order { #[derive(Debug, Clone)] pub struct Parser { state: State, - offset: u64, - max_size: u64, + offset: LogicalOffset, + max_offset: LogicalOffset, encoding: Encoding, #[cfg(feature = "features")] features: WasmFeatures, counts: ParserCounts, - order: (Order, u64), + order: (Order, LogicalOffset), } #[derive(Debug, Clone)] @@ -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(LogicalOffset), } 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,13 @@ 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) + let max_len = MemOffset::max(self.max_offset - self.offset, data.len()).into_usize(); + 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")] { @@ -638,11 +638,12 @@ impl Parser { 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); + let consumed = reader.current_mem_offset(); + self.offset += consumed; Ok(Chunk::Parsed { - consumed: consumed, + // We can be sure that the difference fits into a usize, as both positions + // are inside the data chunk. + consumed: consumed.into_usize(), 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: LogicalOffset) -> 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,10 @@ 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_end = match MemOffset::logical_try_add(reader.original_position(), len) { + Some(section_end) if section_end <= self.max_offset => section_end, + _ => return Err(Error::new("section too large", len_pos)), + }; match (self.encoding, id) { // Custom sections for both modules and components. @@ -793,7 +788,7 @@ impl Parser { } (Encoding::Module, START_SECTION) => { self.update_order(Order::Start, reader.original_position())?; - let (func, range) = single_item(reader, len, "start")?; + let (func, range) = single_item(reader, section_end, "start")?; Ok(StartSection { func, range }) } (Encoding::Module, ELEMENT_SECTION) => { @@ -806,7 +801,7 @@ impl Parser { 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; + let range = start..section_end; self.state = State::FunctionBody { remaining: count, len, @@ -829,7 +824,7 @@ impl Parser { } (Encoding::Module, DATA_COUNT_SECTION) => { self.update_order(Order::DataCount, reader.original_position())?; - let (count, range) = single_item(reader, len, "data count")?; + let (count, range) = single_item(reader, section_end, "data count")?; self.counts.data_count = Some(count); Ok(DataCountSection { count, range }) } @@ -842,24 +837,22 @@ 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 == 1 { "module" } else { "component" } ); } - let range = reader.original_position() - ..reader.original_position() + usize::try_from(len).unwrap(); - self.max_size -= u64::from(len); + let range = reader.original_position()..section_end; self.offset += u64::from(len); - let mut parser = Parser::new(usize_to_u64(reader.original_position())); + let mut parser = Parser::new(reader.original_position()); #[cfg(feature = "features")] { parser.features = self.features; } - parser.max_size = u64::from(len); + parser.max_offset = section_end; Ok(match id { 1 => ModuleSection { @@ -917,7 +910,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 +930,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 +1166,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 +1176,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: LogicalOffset) -> 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 +1196,7 @@ impl Parser { } } - fn check_data_count(&self, pos: usize) -> Result<()> { + fn check_data_count(&self, pos: LogicalOffset) -> 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 +1209,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 +1233,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: LogicalOffset, 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 +1302,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 +1663,9 @@ mod tests { chunk: Chunk<'_>, expected_consumed: usize, expected_name: &str, - expected_data_offset: usize, + expected_data_offset: LogicalOffset, expected_data: &[u8], - expected_range: Range, + expected_range: Range, ) { let (consumed, s) = match chunk { Chunk::Parsed { diff --git a/crates/wasmparser/src/readers.rs b/crates/wasmparser/src/readers.rs index b818e65285..6172401336 100644 --- a/crates/wasmparser/src/readers.rs +++ b/crates/wasmparser/src/readers.rs @@ -13,6 +13,7 @@ * limitations under the License. */ +use crate::offsets::LogicalOffset; use crate::{BinaryReader, Error, Result}; use ::core::fmt; use ::core::marker; @@ -113,13 +114,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) -> LogicalOffset { 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 +183,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) -> LogicalOffset { self.section.reader.original_position() } } @@ -230,7 +231,7 @@ impl<'a, T> Iterator for SectionLimitedIntoIterWithOffsets<'a, T> where T: FromReader<'a>, { - type Item = Result<(usize, T)>; + type Item = Result<(LogicalOffset, T)>; fn next(&mut self) -> Option { let pos = self.iter.section.reader.original_position(); @@ -277,13 +278,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) -> LogicalOffset { 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..1ac74e3da7 100644 --- a/crates/wasmparser/src/readers/component/aliases.rs +++ b/crates/wasmparser/src/readers/component/aliases.rs @@ -1,4 +1,6 @@ -use crate::{BinaryReader, ComponentExternalKind, ExternalKind, FromReader, Result}; +use crate::{ + BinaryReader, ComponentExternalKind, ExternalKind, FromReader, Result, offsets::LogicalOffset, +}; /// Represents the kind of an outer alias in a WebAssembly component. #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -92,7 +94,7 @@ impl<'a> FromReader<'a> for ComponentAlias<'a> { fn component_outer_alias_kind_from_bytes( byte1: u8, byte2: Option, - offset: usize, + offset: LogicalOffset, ) -> 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..f9ec23b92e 100644 --- a/crates/wasmparser/src/readers/component/exports.rs +++ b/crates/wasmparser/src/readers/component/exports.rs @@ -1,5 +1,6 @@ use crate::{ BinaryReader, ComponentExternName, ComponentTypeRef, FromReader, Result, SectionLimited, + offsets::LogicalOffset, }; /// Represents the kind of an external items of a WebAssembly component. @@ -23,7 +24,7 @@ impl ComponentExternalKind { pub(crate) fn from_bytes( byte1: u8, byte2: Option, - offset: usize, + offset: LogicalOffset, ) -> 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..a9f82a53e7 100644 --- a/crates/wasmparser/src/readers/component/names.rs +++ b/crates/wasmparser/src/readers/component/names.rs @@ -1,4 +1,6 @@ -use crate::{BinaryReader, Error, NameMap, Result, Subsection, Subsections}; +use crate::{ + BinaryReader, Error, NameMap, Result, Subsection, Subsections, offsets::LogicalOffset, +}; use core::ops::Range; /// Type used to iterate and parse the contents of the `component-name` custom @@ -11,7 +13,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 +37,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 +72,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 +85,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 +94,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..81668c3cc2 100644 --- a/crates/wasmparser/src/readers/core/code.rs +++ b/crates/wasmparser/src/readers/core/code.rs @@ -13,7 +13,10 @@ * limitations under the License. */ -use crate::{BinaryReader, FromReader, OperatorsReader, Result, SectionLimited, ValType}; +use crate::{ + BinaryReader, FromReader, OperatorsReader, Result, SectionLimited, ValType, + offsets::LogicalOffset, +}; use core::ops::Range; /// A reader for the code section of a WebAssembly module. @@ -72,7 +75,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 +108,7 @@ impl<'a> LocalsReader<'a> { } /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { + pub fn original_position(&self) -> LogicalOffset { self.reader.original_position() } diff --git a/crates/wasmparser/src/readers/core/custom.rs b/crates/wasmparser/src/readers/core/custom.rs index a8eac2f11e..4a142dbdd5 100644 --- a/crates/wasmparser/src/readers/core/custom.rs +++ b/crates/wasmparser/src/readers/core/custom.rs @@ -1,3 +1,4 @@ +use crate::offsets::LogicalOffset; use crate::{BinaryReader, Result}; use core::fmt; use core::ops::Range; @@ -23,7 +24,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) -> LogicalOffset { self.reader.original_position() } @@ -35,7 +36,7 @@ impl<'a> CustomSectionReader<'a> { /// 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..3dad3f8413 100644 --- a/crates/wasmparser/src/readers/core/data.rs +++ b/crates/wasmparser/src/readers/core/data.rs @@ -13,7 +13,9 @@ * limitations under the License. */ -use crate::{BinaryReader, ConstExpr, Error, FromReader, Result, SectionLimited}; +use crate::{ + BinaryReader, ConstExpr, Error, FromReader, Result, SectionLimited, offsets::LogicalOffset, +}; use core::ops::Range; /// Represents a data segment in a core WebAssembly module. @@ -24,7 +26,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..c39a34b7e2 100644 --- a/crates/wasmparser/src/readers/core/dylink0.rs +++ b/crates/wasmparser/src/readers/core/dylink0.rs @@ -1,3 +1,4 @@ +use crate::offsets::LogicalOffset; use crate::prelude::*; use crate::{BinaryReader, Result, Subsection, Subsections, SymbolFlags}; use core::ops::Range; @@ -61,14 +62,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 +108,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..cf28fdcd44 100644 --- a/crates/wasmparser/src/readers/core/elements.rs +++ b/crates/wasmparser/src/readers/core/elements.rs @@ -15,7 +15,7 @@ use crate::{ BinaryReader, ConstExpr, Error, ExternalKind, FromReader, OperatorsReader, - OperatorsReaderAllocations, RefType, Result, SectionLimited, + OperatorsReaderAllocations, RefType, Result, SectionLimited, offsets::LogicalOffset, }; use core::ops::Range; @@ -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..9df334e102 100644 --- a/crates/wasmparser/src/readers/core/imports.rs +++ b/crates/wasmparser/src/readers/core/imports.rs @@ -17,7 +17,7 @@ use core::mem; use crate::{ BinaryReader, Error, ExternalKind, FromReader, GlobalType, MemoryType, Result, SectionLimited, - SectionLimitedIntoIterWithOffsets, TableType, TagType, + SectionLimitedIntoIterWithOffsets, TableType, TagType, offsets::LogicalOffset, }; /// Represents a reference to a type definition in a WebAssembly module. @@ -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(LogicalOffset, 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,9 @@ 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 +213,7 @@ impl<'a> SectionLimited<'a, Imports<'a>> { } impl<'a> IntoIterator for Imports<'a> { - type Item = Result<(usize, Import<'a>)>; + type Item = Result<(LogicalOffset, Import<'a>)>; type IntoIter = ImportsIter<'a>; fn into_iter(self) -> Self::IntoIter { @@ -244,7 +246,7 @@ pub struct ImportsIter<'a> { enum ImportsIterState<'a> { Done, Error(Error), - Single(usize, Import<'a>), + Single(LogicalOffset, Import<'a>), Compact1 { module: &'a str, iter: SectionLimitedIntoIterWithOffsets<'a, ImportItemCompact<'a>>, @@ -257,7 +259,7 @@ enum ImportsIterState<'a> { } impl<'a> Iterator for ImportsIter<'a> { - type Item = Result<(usize, Import<'a>)>; + type Item = Result<(LogicalOffset, 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..3ee8dbcbca 100644 --- a/crates/wasmparser/src/readers/core/linking.rs +++ b/crates/wasmparser/src/readers/core/linking.rs @@ -1,3 +1,4 @@ +use crate::offsets::LogicalOffset; use crate::prelude::*; use crate::{BinaryReader, Error, FromReader, Result, SectionLimited, Subsection, Subsections}; use core::ops::Range; @@ -72,7 +73,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 +377,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 +390,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 +426,13 @@ impl<'a> LinkingSectionReader<'a> { } /// Returns the original byte offset of this section. - pub fn original_position(&self) -> usize { + pub fn original_position(&self) -> LogicalOffset { 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..ac96f37f98 100644 --- a/crates/wasmparser/src/readers/core/names.rs +++ b/crates/wasmparser/src/readers/core/names.rs @@ -13,7 +13,10 @@ * limitations under the License. */ -use crate::{BinaryReader, Error, FromReader, Result, SectionLimited, Subsection, Subsections}; +use crate::{ + BinaryReader, Error, FromReader, Result, SectionLimited, Subsection, Subsections, + offsets::LogicalOffset, +}; use core::ops::Range; /// Represents a name map from the names custom section. @@ -82,7 +85,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 +117,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 +126,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 +154,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..36f4816aa4 100644 --- a/crates/wasmparser/src/readers/core/operators.rs +++ b/crates/wasmparser/src/readers/core/operators.rs @@ -14,6 +14,7 @@ */ use crate::limits::{MAX_WASM_CATCHES, MAX_WASM_HANDLERS}; +use crate::offsets::LogicalOffset; use crate::prelude::*; use crate::{BinaryReader, Error, FromReader, Result, ValType}; use core::{fmt, mem}; @@ -475,7 +476,7 @@ impl<'a> OperatorsReader<'a> { } /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { + pub fn original_position(&self) -> LogicalOffset { self.reader.original_position() } @@ -532,7 +533,7 @@ impl<'a> OperatorsReader<'a> { /// } /// /// struct Dumper { - /// offset: usize + /// offset: u64 /// } /// /// macro_rules! define_visit_operator { @@ -562,7 +563,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>, LogicalOffset)> { let pos = self.reader.original_position(); Ok((self.read()?, pos)) } @@ -680,7 +681,7 @@ impl<'a> OperatorsIteratorWithOffsets<'a> { } impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> { - type Item = Result<(Operator<'a>, usize)>; + type Item = Result<(Operator<'a>, LogicalOffset)>; /// Reads content of the code section with offsets. /// @@ -694,7 +695,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..309045b01c 100644 --- a/crates/wasmparser/src/readers/core/reloc.rs +++ b/crates/wasmparser/src/readers/core/reloc.rs @@ -1,4 +1,4 @@ -use crate::{BinaryReader, FromReader, Result, SectionLimited}; +use crate::{BinaryReader, FromReader, Result, SectionLimited, offsets::LogicalOffset}; use core::ops::Range; /// Reader for relocation entries within a `reloc.*` section. @@ -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,14 @@ 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 LogicalOffset, + ) + })?; Ok(start..end) } } diff --git a/crates/wasmparser/src/readers/core/types.rs b/crates/wasmparser/src/readers/core/types.rs index a935d4e54b..c6e8b039b0 100644 --- a/crates/wasmparser/src/readers/core/types.rs +++ b/crates/wasmparser/src/readers/core/types.rs @@ -18,6 +18,7 @@ use crate::limits::{ MAX_WASM_FUNCTION_PARAMS, MAX_WASM_FUNCTION_RETURNS, MAX_WASM_STRUCT_FIELDS, MAX_WASM_SUPERTYPES, MAX_WASM_TYPES, }; +use crate::offsets::LogicalOffset; use crate::prelude::*; #[cfg(feature = "validate")] use crate::types::CoreTypeId; @@ -323,13 +324,13 @@ pub struct RecGroup { #[derive(Debug, Clone)] enum RecGroupInner { - Implicit((usize, SubType)), - Explicit(Vec<(usize, SubType)>), + Implicit((LogicalOffset, SubType)), + Explicit(Vec<(LogicalOffset, 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<(LogicalOffset, SubType)>) -> Self { RecGroup { inner: RecGroupInner::Explicit(types), } @@ -337,7 +338,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: LogicalOffset, ty: SubType) -> Self { RecGroup { inner: RecGroupInner::Implicit((offset, ty)), } @@ -376,21 +377,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<(LogicalOffset, SubType)>), + Explicit(alloc::vec::IntoIter<(LogicalOffset, SubType)>), } impl Iterator for Iter { - type Item = (usize, SubType); + type Item = (LogicalOffset, SubType); - fn next(&mut self) -> Option<(usize, SubType)> { + fn next(&mut self) -> Option<(LogicalOffset, 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..ad3bb43a0c 100644 --- a/crates/wasmparser/src/resources.rs +++ b/crates/wasmparser/src/resources.rs @@ -15,7 +15,7 @@ use crate::{ Error, FuncType, GlobalType, HeapType, MemoryType, RefType, SubType, TableType, ValType, - WasmFeatures, types::CoreTypeId, + WasmFeatures, offsets::LogicalOffset, types::CoreTypeId, }; /// Types that qualify as Wasm validation database. @@ -83,7 +83,7 @@ pub trait WasmModuleResources { &self, t: &mut ValType, features: &WasmFeatures, - offset: usize, + offset: LogicalOffset, ) -> 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: LogicalOffset) -> 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,8 @@ 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: LogicalOffset) + -> Result<(), Error>; /// Get the top type for the given heap type. fn top_type(&self, heap_type: &HeapType) -> HeapType; @@ -152,7 +153,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: LogicalOffset) -> Result<(), Error> { T::check_heap_type(self, t, offset) } fn top_type(&self, heap_type: &HeapType) -> HeapType { @@ -217,7 +218,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: LogicalOffset) -> 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..281d0dc21d 100644 --- a/crates/wasmparser/src/validator.rs +++ b/crates/wasmparser/src/validator.rs @@ -13,6 +13,7 @@ * limitations under the License. */ +use crate::offsets::LogicalOffset; use crate::prelude::*; use crate::{ AbstractHeapType, Encoding, Error, FromReader, FunctionBody, HeapType, Parser, Payload, @@ -67,7 +68,13 @@ 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: LogicalOffset, +) -> Result<()> { if max .checked_sub(cur_len) .and_then(|amt| amt.checked_sub(amt_added as usize)) @@ -83,7 +90,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: LogicalOffset) -> Result { match a.checked_add(b) { Some(sum) if sum < MAX_WASM_TYPE_SIZE => Ok(sum), _ => Err(format_err!( @@ -179,7 +186,7 @@ enum State { } impl State { - fn ensure_parsable(&self, offset: usize) -> Result<()> { + fn ensure_parsable(&self, offset: LogicalOffset) -> Result<()> { match self { Self::Module => Ok(()), #[cfg(feature = "component-model")] @@ -195,7 +202,7 @@ impl State { } } - fn ensure_module(&self, section: &str, offset: usize) -> Result<()> { + fn ensure_module(&self, section: &str, offset: LogicalOffset) -> Result<()> { self.ensure_parsable(offset)?; let _ = section; @@ -211,7 +218,7 @@ impl State { } #[cfg(feature = "component-model")] - fn ensure_component(&self, section: &str, offset: usize) -> Result<()> { + fn ensure_component(&self, section: &str, offset: LogicalOffset) -> Result<()> { self.ensure_parsable(offset)?; match self { @@ -236,7 +243,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: LogicalOffset) -> Result<()> { match ty { ValType::I32 | ValType::I64 => Ok(()), ValType::F32 | ValType::F64 => { @@ -247,7 +254,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: LogicalOffset) -> Result<()> { require_feature::reference_types(*self, "reference types support is not enabled", offset)?; match r.heap_type() { HeapType::Concrete(_) => { @@ -647,7 +654,12 @@ 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 +921,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 +963,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 +983,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 +1016,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 +1052,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 +1127,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 +1259,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 +1333,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: LogicalOffset) -> 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 +1401,13 @@ 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, + LogicalOffset, + ) -> Result<()>, + mut validate_item: impl FnMut(&mut ModuleState, &mut TypeAlloc, T, LogicalOffset) -> Result<()>, ) -> Result<()> where T: FromReader<'a>, @@ -1419,14 +1436,14 @@ impl Validator { &mut Vec, &mut TypeAlloc, u32, - usize, + LogicalOffset, ) -> Result<()>, mut validate_item: impl FnMut( &mut Vec, &mut TypeAlloc, &WasmFeatures, T, - usize, + LogicalOffset, ) -> Result<()>, ) -> Result<()> where diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 2bca41d77f..32f7909943 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -13,7 +13,6 @@ use super::{ core::{InternRecGroup, Module}, types::{CoreTypeId, EntityType, TypeAlloc, TypeData, TypeInfo, TypeList}, }; -use crate::collections::index_map::Entry; use crate::limits::*; use crate::prelude::*; use crate::validator::names::{ComponentName, ComponentNameKind, KebabStr, KebabString}; @@ -23,9 +22,10 @@ use crate::{ GlobalType, InstantiationArgKind, MemoryType, PackedIndex, RefType, Result, SubType, TableType, TypeBounds, ValType, WasmFeatures, require_feature, }; +use crate::{collections::index_map::Entry, offsets::LogicalOffset}; 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: LogicalOffset) -> 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: LogicalOffset, 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: LogicalOffset) -> 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: LogicalOffset) -> Result<&Self> { // Memory is always required when `realloc` is required. self.require_memory(offset)?; @@ -309,7 +309,7 @@ impl CanonicalOptions { pub(crate) fn require_memory_if( &self, - offset: usize, + offset: LogicalOffset, when: impl Fn() -> bool, ) -> Result<&Self> { if self.memory.is_none() && when() { @@ -320,7 +320,7 @@ impl CanonicalOptions { pub(crate) fn require_realloc_if( &self, - offset: usize, + offset: LogicalOffset, when: impl Fn() -> bool, ) -> Result<&Self> { if self.realloc.is_none() && when() { @@ -329,7 +329,7 @@ impl CanonicalOptions { Ok(self) } - pub(crate) fn check_lower(&self, offset: usize) -> Result<&Self> { + pub(crate) fn check_lower(&self, offset: LogicalOffset) -> Result<&Self> { if self.post_return.is_some() { bail!( offset, @@ -359,7 +359,7 @@ impl CanonicalOptions { types: &TypeList, state: &ComponentState, core_ty_id: CoreTypeId, - offset: usize, + offset: LogicalOffset, ) -> Result<&Self> { debug_assert!(matches!( types[core_ty_id].composite_type.inner, @@ -414,7 +414,7 @@ impl CanonicalOptions { Ok(self) } - fn check_asyncness(&self, ty: &ComponentFuncType, offset: usize) -> Result<()> { + fn check_asyncness(&self, ty: &ComponentFuncType, offset: LogicalOffset) -> Result<()> { // The `async` canonical ABI option is only allowed with `async`-typed // functions. if self.concurrency.is_async() && !ty.async_ { @@ -430,7 +430,7 @@ impl CanonicalOptions { &self, types: &mut TypeAlloc, actual: FuncType, - offset: usize, + offset: LogicalOffset, ) -> Result { if let Some(declared_id) = self.core_type { let declared = types[declared_id].unwrap_func(); @@ -513,7 +513,7 @@ impl ComponentState { components: &mut [Self], ty: crate::CoreType, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, check_limit: bool, ) -> Result<()> { let current = components.last_mut().unwrap(); @@ -538,7 +538,7 @@ impl ComponentState { &mut self, module: &Module, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let imports = module.imports_for_module_type(offset)?; @@ -561,7 +561,7 @@ impl ComponentState { &mut self, instance: crate::Instance, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let instance = match instance { crate::Instance::Instantiate { module_index, args } => { @@ -581,7 +581,7 @@ impl ComponentState { components: &mut Vec, ty: crate::ComponentType, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, check_limit: bool, ) -> Result<()> { assert!(!components.is_empty()); @@ -675,7 +675,7 @@ impl ComponentState { &mut self, import: crate::ComponentImport<'_>, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let mut entity = self.check_type_ref(&import.ty, types, offset)?; self.add_entity( @@ -703,7 +703,7 @@ impl ComponentState { ty: &mut ComponentEntityType, name_and_kind: Option<(&str, ExternKind)>, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let kind = name_and_kind.map(|(_, k)| k); let (len, max, desc) = match ty { @@ -1170,7 +1170,7 @@ impl ComponentState { name: ComponentExternName<'_>, mut ty: ComponentEntityType, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, check_limit: bool, ) -> Result<()> { if check_limit { @@ -1200,7 +1200,7 @@ impl ComponentState { &mut self, func: CanonicalFunction, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { match func { CanonicalFunction::Lift { @@ -1330,7 +1330,7 @@ impl ComponentState { type_index: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> 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 +1388,7 @@ impl ComponentState { func_index: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let ty = &types[self.function_at(func_index, offset)?]; @@ -1405,28 +1405,43 @@ 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: LogicalOffset, + ) -> 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: LogicalOffset, + ) -> 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: LogicalOffset, + ) -> 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: LogicalOffset) -> Result<()> { require_feature::cm_async( self.features, "`backpressure.inc` requires the component model async feature", @@ -1438,7 +1453,7 @@ impl ComponentState { Ok(()) } - fn backpressure_dec(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn backpressure_dec(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> Result<()> { require_feature::cm_async( self.features, "`backpressure.dec` requires the component model async feature", @@ -1455,7 +1470,7 @@ impl ComponentState { result: &Option, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1505,7 +1520,7 @@ impl ComponentState { Ok(()) } - fn task_cancel(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn task_cancel(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> Result<()> { require_feature::cm_async( self.features, "`task.cancel` requires the component model async feature", @@ -1521,7 +1536,7 @@ impl ComponentState { &self, immediate: u32, operation: &str, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { if immediate > 0 { require_feature::cm_threading( @@ -1544,7 +1559,7 @@ impl ComponentState { ty: ValType, i: u32, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1564,7 +1579,7 @@ impl ComponentState { ty: ValType, i: u32, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1579,7 +1594,12 @@ 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: LogicalOffset, + ) -> Result<()> { match ty { ValType::I32 => {} ValType::I64 => { @@ -1609,7 +1629,7 @@ impl ComponentState { Ok(()) } - fn subtask_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn subtask_drop(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> Result<()> { require_feature::cm_async( self.features, "`subtask.drop` requires the component model async feature", @@ -1621,7 +1641,12 @@ 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: LogicalOffset, + ) -> Result<()> { require_feature::cm_async( self.features, "`subtask.cancel` requires the component model async feature", @@ -1640,7 +1665,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: LogicalOffset) -> Result<()> { require_feature::cm_async( self.features, "`stream.new` requires the component model async feature", @@ -1662,7 +1687,7 @@ impl ComponentState { ty: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1702,7 +1727,7 @@ impl ComponentState { ty: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1741,7 +1766,7 @@ impl ComponentState { ty: u32, cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1771,7 +1796,7 @@ impl ComponentState { ty: u32, cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1800,7 +1825,7 @@ impl ComponentState { &mut self, ty: u32, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1822,7 +1847,7 @@ impl ComponentState { &mut self, ty: u32, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1840,7 +1865,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: LogicalOffset) -> Result<()> { require_feature::cm_async( self.features, "`future.new` requires the component model async feature", @@ -1862,7 +1887,7 @@ impl ComponentState { ty: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1902,7 +1927,7 @@ impl ComponentState { ty: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1940,7 +1965,7 @@ impl ComponentState { ty: u32, cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1970,7 +1995,7 @@ impl ComponentState { ty: u32, cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1999,7 +2024,7 @@ impl ComponentState { &mut self, ty: u32, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -2021,7 +2046,7 @@ impl ComponentState { &mut self, ty: u32, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -2043,7 +2068,7 @@ impl ComponentState { &mut self, options: Vec, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_error_context( self.features, @@ -2070,7 +2095,7 @@ impl ComponentState { &mut self, options: Vec, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_error_context( self.features, @@ -2090,7 +2115,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: LogicalOffset) -> Result<()> { require_feature::cm_error_context( self.features, "`error-context.drop` requires the component model error-context feature", @@ -2102,7 +2127,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: LogicalOffset) -> Result<()> { require_feature::cm_async( self.features, "`waitable-set.new` requires the component model async feature", @@ -2118,7 +2143,7 @@ impl ComponentState { &mut self, memory: u32, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -2139,7 +2164,7 @@ impl ComponentState { &mut self, memory: u32, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_async( self.features, @@ -2156,7 +2181,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: LogicalOffset) -> Result<()> { require_feature::cm_async( self.features, "`waitable-set.drop` requires the component model async feature", @@ -2168,7 +2193,7 @@ impl ComponentState { Ok(()) } - fn waitable_join(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn waitable_join(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> Result<()> { require_feature::cm_async( self.features, "`waitable.join` requires the component model async feature", @@ -2180,7 +2205,7 @@ impl ComponentState { Ok(()) } - fn thread_index(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn thread_index(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> Result<()> { require_feature::cm_threading( self.features, "`thread.index` requires the component model threading feature", @@ -2197,7 +2222,7 @@ impl ComponentState { func_ty_index: u32, table_index: u32, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2250,7 +2275,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: LogicalOffset) -> Result<()> { require_feature::cm_threading( self.features, "`thread.resume-later` requires the component model threading feature", @@ -2265,7 +2290,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2277,7 +2302,7 @@ impl ComponentState { Ok(()) } - fn thread_yield(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn thread_yield(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> Result<()> { require_feature::cm_async( self.features, "`thread.yield` requires the component model async feature", @@ -2293,7 +2318,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2310,7 +2335,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2326,7 +2351,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2342,7 +2367,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2354,7 +2379,12 @@ 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: LogicalOffset, + ) -> Result { let resource = self.resource_at(idx, types, offset)?; match self .defined_resources @@ -2370,7 +2400,7 @@ impl ComponentState { &self, idx: u32, _types: &'a TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result { if let ComponentAnyTypeId::Resource(id) = self.component_type_at(idx, offset)? { return Ok(id); @@ -2382,7 +2412,7 @@ impl ComponentState { &mut self, func_ty_index: u32, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::shared_everything_threads( self.features, @@ -2409,7 +2439,7 @@ impl ComponentState { func_ty_index: u32, table_index: u32, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::shared_everything_threads( self.features, @@ -2462,7 +2492,7 @@ impl ComponentState { &self, func_ty_index: u32, types: &TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result { let core_type_id = match self.core_type_at(func_ty_index, offset)? { ComponentCoreTypeId::Sub(c) => c, @@ -2489,7 +2519,11 @@ 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: LogicalOffset, + ) -> Result<()> { require_feature::shared_everything_threads( self.features, "`thread.available_parallelism` requires the shared-everything-threads proposal", @@ -2514,7 +2548,7 @@ impl ComponentState { &mut self, instance: crate::ComponentInstance, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let instance = match instance { crate::ComponentInstance::Instantiate { @@ -2535,7 +2569,7 @@ impl ComponentState { components: &mut [Self], alias: crate::ComponentAlias, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let component = components.last_mut().unwrap(); @@ -2596,7 +2630,7 @@ impl ComponentState { args: &[u32], results: u32, types: &mut TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { require_feature::cm_values( self.features, @@ -2652,7 +2686,7 @@ impl ComponentState { &self, types: &TypeList, options: &[CanonicalOption], - offset: usize, + offset: LogicalOffset, ) -> Result { fn display(option: CanonicalOption) -> &'static str { match option { @@ -2877,7 +2911,7 @@ impl ComponentState { &mut self, ty: &ComponentTypeRef, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result { Ok(match ty { ComponentTypeRef::Module(index) => { @@ -2942,7 +2976,7 @@ impl ComponentState { &mut self, export: &crate::ComponentExport, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result { let actual = match export.kind { ComponentExternalKind::Module => { @@ -2987,7 +3021,7 @@ impl ComponentState { components: &[Self], decls: Vec, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result { let mut state = Module::new(components[0].features); @@ -3046,7 +3080,7 @@ impl ComponentState { components: &mut Vec, decls: Vec, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result { let features = components[0].features; components.push(ComponentState::new(ComponentKind::ComponentType, features)); @@ -3083,7 +3117,7 @@ impl ComponentState { components: &mut Vec, decls: Vec, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result { let features = components[0].features; components.push(ComponentState::new(ComponentKind::InstanceType, features)); @@ -3143,7 +3177,7 @@ impl ComponentState { &self, ty: crate::ComponentFuncType, types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result { let mut info = TypeInfo::new(); @@ -3208,13 +3242,13 @@ impl ComponentState { module_index: u32, module_args: Vec, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result { fn insert_arg<'a>( name: &'a str, arg: &'a InstanceType, args: &mut IndexMap<&'a str, &'a InstanceType>, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { if args.insert(name, arg).is_some() { bail!( @@ -3285,7 +3319,7 @@ impl ComponentState { component_index: u32, component_args: Vec, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result { let component_type_id = self.component_at(component_index, offset)?; let mut args = IndexMap::default(); @@ -3552,7 +3586,7 @@ impl ComponentState { &mut self, exports: Vec, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result { let mut info = TypeInfo::new(); let mut inst_exports = IndexMap::default(); @@ -3671,7 +3705,7 @@ impl ComponentState { &mut self, exports: Vec, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result { fn insert_export( types: &TypeList, @@ -3679,7 +3713,7 @@ impl ComponentState { export: EntityType, exports: &mut IndexMap, info: &mut TypeInfo, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { info.combine(export.info(types), offset)?; @@ -3763,7 +3797,7 @@ impl ComponentState { kind: ExternalKind, name: &str, types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { macro_rules! push_module_export { ($expected:path, $collection:ident, $ty:literal) => {{ @@ -3849,7 +3883,7 @@ impl ComponentState { kind: ComponentExternalKind, name: &str, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { if let ComponentExternalKind::Value = kind { self.check_value_support(offset)?; @@ -3891,7 +3925,12 @@ 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: LogicalOffset, + ) -> Result<()> { let component = Self::check_alias_count(components, count, offset)?; let ty = component.module_at(index, offset)?; @@ -3912,7 +3951,7 @@ impl ComponentState { components: &mut [Self], count: u32, index: u32, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let component = Self::check_alias_count(components, count, offset)?; let ty = component.component_at(index, offset)?; @@ -3934,7 +3973,7 @@ impl ComponentState { components: &mut [Self], count: u32, index: u32, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let component = Self::check_alias_count(components, count, offset)?; let ty = component.core_type_at(index, offset)?; @@ -3952,7 +3991,7 @@ impl ComponentState { count: u32, index: u32, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let component = Self::check_alias_count(components, count, offset)?; let ty = component.component_type_at(index, offset)?; @@ -4002,7 +4041,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: LogicalOffset) -> Result<&Self> { let count = count as usize; if count >= components.len() { bail!(offset, "invalid outer alias count of {count}"); @@ -4015,7 +4054,7 @@ impl ComponentState { &self, ty: crate::ComponentDefinedType, types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result { match ty { crate::ComponentDefinedType::Primitive(ty) => { @@ -4164,7 +4203,7 @@ impl ComponentState { &self, fields: &[(&str, crate::ComponentValType)], types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result { let mut info = TypeInfo::new(); let mut field_map = IndexMap::default(); @@ -4201,7 +4240,7 @@ impl ComponentState { &self, cases: &[crate::VariantCase], types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result { let mut info = TypeInfo::new(); let mut case_map: IndexMap = IndexMap::default(); @@ -4252,7 +4291,7 @@ impl ComponentState { &self, tys: &[crate::ComponentValType], types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result { let mut info = TypeInfo::new(); if tys.is_empty() { @@ -4270,7 +4309,11 @@ 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: LogicalOffset, + ) -> Result { let mut names_set = IndexSet::default(); names_set.reserve(names.len()); @@ -4295,7 +4338,11 @@ 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: LogicalOffset, + ) -> 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 +4373,7 @@ impl ComponentState { fn create_component_val_type( &self, ty: crate::ComponentValType, - offset: usize, + offset: LogicalOffset, ) -> Result { Ok(match ty { crate::ComponentValType::Primitive(pt) => { @@ -4339,14 +4386,14 @@ impl ComponentState { }) } - pub fn core_type_at(&self, idx: u32, offset: usize) -> Result { + pub fn core_type_at(&self, idx: u32, offset: LogicalOffset) -> 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: LogicalOffset) -> Result { self.types .get(idx as usize) .copied() @@ -4357,7 +4404,7 @@ impl ComponentState { &self, idx: u32, types: &'a TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<&'a ComponentFuncType> { let id = self.component_type_at(idx, offset)?; match id { @@ -4366,7 +4413,7 @@ impl ComponentState { } } - fn function_at(&self, idx: u32, offset: usize) -> Result { + fn function_at(&self, idx: u32, offset: LogicalOffset) -> Result { self.funcs.get(idx as usize).copied().ok_or_else(|| { format_err!( offset, @@ -4375,7 +4422,7 @@ impl ComponentState { }) } - fn component_at(&self, idx: u32, offset: usize) -> Result { + fn component_at(&self, idx: u32, offset: LogicalOffset) -> Result { self.components.get(idx as usize).copied().ok_or_else(|| { format_err!( offset, @@ -4384,7 +4431,7 @@ impl ComponentState { }) } - fn instance_at(&self, idx: u32, offset: usize) -> Result { + fn instance_at(&self, idx: u32, offset: LogicalOffset) -> Result { self.instances.get(idx as usize).copied().ok_or_else(|| { format_err!( offset, @@ -4393,7 +4440,7 @@ impl ComponentState { }) } - fn value_at(&mut self, idx: u32, offset: usize) -> Result<&ComponentValType> { + fn value_at(&mut self, idx: u32, offset: LogicalOffset) -> Result<&ComponentValType> { match self.values.get_mut(idx as usize) { Some((ty, used)) if !*used => { *used = true; @@ -4404,14 +4451,14 @@ impl ComponentState { } } - fn defined_type_at(&self, idx: u32, offset: usize) -> Result { + fn defined_type_at(&self, idx: u32, offset: LogicalOffset) -> 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: LogicalOffset) -> Result { match self.core_funcs.get(idx as usize) { Some(id) => Ok(*id), None => bail!( @@ -4421,14 +4468,18 @@ impl ComponentState { } } - fn module_at(&self, idx: u32, offset: usize) -> Result { + fn module_at(&self, idx: u32, offset: LogicalOffset) -> 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: LogicalOffset, + ) -> Result { match self.core_instances.get(idx as usize) { Some(id) => Ok(*id), None => bail!( @@ -4443,7 +4494,7 @@ impl ComponentState { instance_index: u32, name: &str, types: &'a TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<&'a EntityType> { match types[self.core_instance_at(instance_index, offset)?] .internal_exports(types) @@ -4457,28 +4508,28 @@ impl ComponentState { } } - fn global_at(&self, idx: u32, offset: usize) -> Result<&GlobalType> { + fn global_at(&self, idx: u32, offset: LogicalOffset) -> 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: LogicalOffset) -> 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: LogicalOffset) -> 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: LogicalOffset) -> 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 +4541,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: LogicalOffset) -> Result { let ty = self.memory_at(idx, offset)?; let valid_memory_type = MemoryType { initial: 0, @@ -4521,7 +4572,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: LogicalOffset) -> Result { let mut ty = ComponentType { // Inherit some fields based on translation of the component. info: self.type_info, @@ -4614,7 +4665,7 @@ impl ComponentState { Ok(ty) } - fn check_value_support(&self, offset: usize) -> Result<()> { + fn check_value_support(&self, offset: LogicalOffset) -> Result<()> { require_feature::cm_values( self.features, "support for component model `value`s is not enabled", @@ -4623,7 +4674,11 @@ impl ComponentState { Ok(()) } - fn check_primitive_type(&self, ty: crate::PrimitiveValType, offset: usize) -> Result<()> { + fn check_primitive_type( + &self, + ty: crate::PrimitiveValType, + offset: LogicalOffset, + ) -> Result<()> { if ty == crate::PrimitiveValType::ErrorContext { require_feature::cm_error_context( self.features, @@ -4644,7 +4699,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: LogicalOffset) -> Result { match self.core_type_at(idx, offset)? { ComponentCoreTypeId::Sub(id) => Ok(id), ComponentCoreTypeId::Module(_) => { @@ -4676,7 +4731,7 @@ impl ComponentNameContext { kind: ExternKind, ty: &ComponentEntityType, types: &TypeAlloc, - offset: usize, + offset: LogicalOffset, kind_names: &mut IndexSet, items: &mut IndexMap, info: &mut TypeInfo, @@ -4803,7 +4858,7 @@ impl ComponentNameContext { version_suffix: Option<&str>, ty: &ComponentEntityType, types: &TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let func = || { let id = match ty { @@ -4914,7 +4969,7 @@ impl ComponentNameContext { &self, id: AliasableResourceId, name: KebabStr<'_>, - offset: usize, + offset: LogicalOffset, ) -> 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..10d62d1d8d 100644 --- a/crates/wasmparser/src/validator/component_types.rs +++ b/crates/wasmparser/src/validator/component_types.rs @@ -2,6 +2,7 @@ use super::component::ExternKind; use super::{CanonicalOptions, Concurrency}; +use crate::offsets::LogicalOffset; use crate::validator::StringEncoding; use crate::validator::component::PtrSize; use crate::validator::names::KebabString; @@ -137,7 +138,7 @@ impl PrimitiveValType { types: &TypeList, _abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: LogicalOffset, core: ArgOrField, ) -> Result<()> { match (self, core) { @@ -759,7 +760,7 @@ impl ComponentValType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: LogicalOffset, core: ArgOrField, ) -> Result<()> { match self { @@ -1200,7 +1201,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: LogicalOffset) -> CoreTypeId { match self { LoweredFuncType::New(ty) => types.intern_func_type(ty, offset), LoweredFuncType::Existing(id) => id, @@ -1216,7 +1217,7 @@ impl ComponentFuncType { types: &TypeList, options: &CanonicalOptions, abi: Abi, - offset: usize, + offset: LogicalOffset, ) -> Result { let mut sig = LoweredSignature::default(); @@ -1335,7 +1336,7 @@ impl ComponentFuncType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: LogicalOffset, ) -> Result { let core_type_id = options.core_type.unwrap(); let core_func_ty = types[core_type_id].unwrap_func(); @@ -1394,7 +1395,7 @@ impl RecordType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: LogicalOffset, core: ArgOrField, ) -> Result<()> { lower_gc_product_type( @@ -1424,7 +1425,7 @@ impl VariantType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: LogicalOffset, core: ArgOrField, ) -> Result<()> { lower_gc_sum_type(types, abi, options, offset, core, "variant") @@ -1437,7 +1438,7 @@ fn lower_gc_sum_type( types: &TypeList, _abi: Abi, _options: &CanonicalOptions, - offset: usize, + offset: LogicalOffset, core: ArgOrField, kind: &str, ) -> Result<()> { @@ -1471,7 +1472,7 @@ impl TupleType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: LogicalOffset, core: ArgOrField, ) -> Result<()> { lower_gc_product_type( @@ -1732,7 +1733,7 @@ impl ComponentDefinedType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: LogicalOffset, core: ArgOrField, ) -> Result<()> { match self { @@ -1834,7 +1835,7 @@ fn lower_gc_product_type<'a, I>( types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: usize, + offset: LogicalOffset, core: ArgOrField, kind: &str, ) -> core::result::Result<(), Error> @@ -3180,7 +3181,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: &ComponentEntityType, b: &ComponentEntityType, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { use ComponentEntityType::*; @@ -3214,7 +3215,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: ComponentTypeId, b: ComponentTypeId, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { // Components are ... tricky. They follow the same basic // structure as core wasm modules, but they also have extra @@ -3299,7 +3300,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a_id: ComponentInstanceTypeId, b_id: ComponentInstanceTypeId, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { // For instance type subtyping, all exports in the other // instance type must be present in this instance type's @@ -3335,7 +3336,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: ComponentFuncTypeId, b: ComponentFuncTypeId, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let a = &self.a[a]; let b = &self.b[b]; @@ -3414,7 +3415,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: ComponentCoreModuleTypeId, b: ComponentCoreModuleTypeId, - offset: usize, + offset: LogicalOffset, ) -> 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 +3454,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: ComponentAnyTypeId, b: ComponentAnyTypeId, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { match (a, b) { (ComponentAnyTypeId::Resource(a), ComponentAnyTypeId::Resource(b)) => { @@ -3529,7 +3530,7 @@ impl<'a> SubtypeCx<'a> { a: &IndexMap, b: ComponentTypeId, kind: ExternKind, - offset: usize, + offset: LogicalOffset, ) -> Result { // First, determine the mapping from resources in `b` to those supplied // by arguments in `a`. @@ -3671,7 +3672,12 @@ 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: LogicalOffset, + ) -> Result<()> { match (a, b) { (EntityType::Func(a), EntityType::Func(b)) | (EntityType::FuncExact(a), EntityType::Func(b)) => { @@ -3710,7 +3716,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: LogicalOffset) -> Result<()> { if a.element_type != b.element_type { bail!( offset, @@ -3729,7 +3735,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: LogicalOffset) -> Result<()> { if a.shared != b.shared { bail!(offset, "mismatch in the shared flag for memories") } @@ -3746,7 +3752,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: LogicalOffset) -> 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 +3774,7 @@ impl<'a> SubtypeCx<'a> { &self, a: &ComponentValType, b: &ComponentValType, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { match (a, b) { (ComponentValType::Primitive(a), ComponentValType::Primitive(b)) => { @@ -3792,7 +3798,7 @@ impl<'a> SubtypeCx<'a> { &self, a: ComponentDefinedTypeId, b: ComponentDefinedTypeId, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { use ComponentDefinedType::*; @@ -3976,7 +3982,7 @@ impl<'a> SubtypeCx<'a> { &self, a: PrimitiveValType, b: PrimitiveValType, - offset: usize, + offset: LogicalOffset, ) -> 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..73c1502a56 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -12,7 +12,7 @@ use super::{ }; #[cfg(feature = "simd")] use crate::VisitSimdOperator; -use crate::{CompositeInnerType, prelude::*}; +use crate::{CompositeInnerType, offsets::LogicalOffset, prelude::*}; use crate::{ ConstExpr, Data, DataKind, Element, ElementKind, Error, ExternalKind, FrameKind, FrameStack, FuncType, Global, GlobalType, HeapType, MemoryType, RecGroup, RefType, Result, SubType, Table, @@ -62,7 +62,7 @@ impl ModuleState { &mut self, mut global: Global, types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { self.module .check_global_type(&mut global.ty, types, offset)?; @@ -75,7 +75,7 @@ impl ModuleState { &mut self, mut table: Table<'_>, types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { self.module.check_table_type(&mut table.ty, types, offset)?; @@ -99,7 +99,12 @@ 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: LogicalOffset, + ) -> Result<()> { match data.kind { DataKind::Passive => { require_feature::bulk_memory( @@ -123,7 +128,7 @@ impl ModuleState { &mut self, mut e: Element, types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { // the `funcref` value type is allowed all the way back to the MVP, so // don't check it here @@ -225,7 +230,7 @@ impl ModuleState { return Ok(()); struct VisitConstOperator<'a> { - offset: usize, + offset: LogicalOffset, uninserted_funcref: bool, ops: OperatorValidator, resources: OperatorValidatorResources<'a>, @@ -522,7 +527,7 @@ impl Module { &mut self, rec_group: RecGroup, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, check_limit: bool, ) -> Result<()> { if check_limit { @@ -541,7 +546,7 @@ impl Module { &mut self, mut import: crate::Import, types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let entity = self.check_type_ref(&mut import.ty, types, offset)?; @@ -600,7 +605,7 @@ impl Module { &mut self, name: &str, ty: EntityType, - offset: usize, + offset: LogicalOffset, check_limit: bool, types: &TypeList, ) -> Result<()> { @@ -629,25 +634,35 @@ 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: LogicalOffset, + ) -> 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: LogicalOffset) -> 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: LogicalOffset) -> 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: LogicalOffset, + ) -> Result<&'a SubType> { let id = self.type_id_at(idx, offset)?; Ok(&types[id]) } @@ -656,7 +671,7 @@ impl Module { &self, type_index: u32, types: &'a TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<&'a FuncType> { match &self .sub_type_at(types, type_index, offset)? @@ -672,7 +687,7 @@ impl Module { &self, type_ref: &mut TypeRef, types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result { Ok(match type_ref { TypeRef::Func(type_index) => { @@ -702,7 +717,12 @@ 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: LogicalOffset, + ) -> 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 +768,7 @@ impl Module { Ok(()) } - fn check_memory_type(&self, ty: &MemoryType, offset: usize) -> Result<()> { + fn check_memory_type(&self, ty: &MemoryType, offset: LogicalOffset) -> Result<()> { self.check_limits(ty.initial, ty.maximum, offset)?; if ty.memory64 { @@ -809,7 +829,7 @@ impl Module { #[cfg(feature = "component-model")] pub(crate) fn imports_for_module_type( &self, - offset: usize, + offset: LogicalOffset, ) -> 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 +848,7 @@ impl Module { .collect::>() } - fn check_value_type(&self, ty: &mut ValType, offset: usize) -> Result<()> { + fn check_value_type(&self, ty: &mut ValType, offset: LogicalOffset) -> Result<()> { // The above only checks the value type for features. // We must check it if it's a reference. match ty { @@ -837,7 +857,7 @@ impl Module { } } - fn check_ref_type(&self, ty: &mut RefType, offset: usize) -> Result<()> { + fn check_ref_type(&self, ty: &mut RefType, offset: LogicalOffset) -> Result<()> { self.features.check_ref_type(*ty, offset)?; let mut hty = ty.heap_type(); self.check_heap_type(&mut hty, offset)?; @@ -845,7 +865,7 @@ impl Module { Ok(()) } - fn check_heap_type(&self, ty: &mut HeapType, offset: usize) -> Result<()> { + fn check_heap_type(&self, ty: &mut HeapType, offset: LogicalOffset) -> Result<()> { // Check that the heap type is valid. let type_index = match ty { HeapType::Abstract { .. } => return Ok(()), @@ -864,7 +884,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: LogicalOffset) -> 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() { @@ -881,7 +901,7 @@ impl Module { &self, ty: &mut GlobalType, types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { self.check_value_type(&mut ty.content_type, offset)?; if ty.shared { @@ -900,7 +920,7 @@ impl Module { Ok(()) } - fn check_limits(&self, initial: T, maximum: Option, offset: usize) -> Result<()> + fn check_limits(&self, initial: T, maximum: Option, offset: LogicalOffset) -> Result<()> where T: Into, { @@ -934,7 +954,7 @@ impl Module { pub fn export_to_entity_type( &mut self, export: &crate::Export, - offset: usize, + offset: LogicalOffset, ) -> Result { let check = |ty: &str, index: u32, total: usize| { if index as usize >= total { @@ -976,7 +996,7 @@ impl Module { &self, func_idx: u32, types: &'a TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<&'a FuncType> { match self.functions.get(func_idx as usize) { Some(idx) => self.func_type_at(*idx, types, offset), @@ -987,7 +1007,7 @@ impl Module { } } - fn global_at(&self, idx: u32, offset: usize) -> Result<&GlobalType> { + fn global_at(&self, idx: u32, offset: LogicalOffset) -> Result<&GlobalType> { match self.globals.get(idx as usize) { Some(t) => Ok(t), None => Err(format_err!( @@ -997,7 +1017,7 @@ impl Module { } } - fn table_at(&self, idx: u32, offset: usize) -> Result<&TableType> { + fn table_at(&self, idx: u32, offset: LogicalOffset) -> Result<&TableType> { match self.tables.get(idx as usize) { Some(t) => Ok(t), None => Err(format_err!( @@ -1007,7 +1027,7 @@ impl Module { } } - fn memory_at(&self, idx: u32, offset: usize) -> Result<&MemoryType> { + fn memory_at(&self, idx: u32, offset: LogicalOffset) -> Result<&MemoryType> { match self.memories.get(idx as usize) { Some(t) => Ok(t), None => Err(format_err!( @@ -1027,7 +1047,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: LogicalOffset) -> Result { self.types .get(idx as usize) .copied() @@ -1080,7 +1100,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: LogicalOffset) -> Result<()> { self.module.check_heap_type(t, offset) } @@ -1168,7 +1188,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: LogicalOffset) -> 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..87dfd81d90 100644 --- a/crates/wasmparser/src/validator/core/canonical.rs +++ b/crates/wasmparser/src/validator/core/canonical.rs @@ -70,13 +70,15 @@ use super::{RecGroupId, TypeAlloc, TypeList}; use crate::{ CompositeInnerType, CompositeType, Error, PackedIndex, RecGroup, Result, StorageType, - UnpackedIndex, ValType, WasmFeatures, require_feature, + UnpackedIndex, ValType, WasmFeatures, + offsets::LogicalOffset, + require_feature, types::{CoreTypeId, TypeIdentifier}, }; 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: LogicalOffset) -> Result; fn types_len(&self) -> u32; fn features(&self) -> &WasmFeatures; @@ -87,7 +89,7 @@ pub(crate) trait InternRecGroup { &mut self, types: &mut TypeAlloc, mut rec_group: RecGroup, - offset: usize, + offset: LogicalOffset, ) -> Result<()> where Self: Sized, @@ -128,7 +130,7 @@ pub(crate) trait InternRecGroup { rec_group: RecGroupId, id: CoreTypeId, types: &mut TypeAlloc, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let ty = &types[id]; if !ty.is_final || ty.supertype_idx.is_some() { @@ -173,7 +175,7 @@ pub(crate) trait InternRecGroup { rec_group: RecGroupId, id: CoreTypeId, types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let ty = &types[id].composite_type; if ty.descriptor_idx.is_some() || ty.describes_idx.is_some() { @@ -287,7 +289,7 @@ pub(crate) trait InternRecGroup { &mut self, ty: &CompositeType, types: &TypeList, - offset: usize, + offset: LogicalOffset, ) -> Result<()> { let features = *self.features(); let check = |ty: &ValType, shared: bool| { @@ -390,7 +392,7 @@ pub(crate) trait InternRecGroup { types: &TypeList, rec_group: RecGroupId, index: PackedIndex, - offset: usize, + offset: LogicalOffset, ) -> Result { match index.unpack() { UnpackedIndex::Id(id) => Ok(id), @@ -419,13 +421,13 @@ pub(crate) struct TypeCanonicalizer<'a> { module: &'a dyn InternRecGroup, rec_group_start: u32, rec_group_len: u32, - offset: usize, + offset: LogicalOffset, 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: LogicalOffset) -> 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..abb26eb966 100644 --- a/crates/wasmparser/src/validator/func.rs +++ b/crates/wasmparser/src/validator/func.rs @@ -1,4 +1,5 @@ use super::operators::{Frame, OperatorValidator, OperatorValidatorAllocations}; +use crate::offsets::LogicalOffset; use crate::{BinaryReader, Result, ValType, VisitOperator}; use crate::{FrameStack, FunctionBody, ModuleArity, Operator, WasmFeatures, WasmModuleResources}; @@ -201,7 +202,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: LogicalOffset, count: u32, ty: ValType) -> Result<()> { self.validator .define_locals(offset, count, ty, &self.resources) } @@ -213,7 +214,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: LogicalOffset, operator: &Operator<'_>) -> Result<()> { self.visitor(offset).visit_operator(operator) } @@ -221,7 +222,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: LogicalOffset, operator: &Operator<'_>) -> Result<()> { self.validator.begin_try_op(); let res = self.op(offset, operator); if res.is_ok() { @@ -253,7 +254,7 @@ arity mismatch in validation /// ``` pub fn visitor<'this, 'a: 'this>( &'this mut self, - offset: usize, + offset: LogicalOffset, ) -> impl VisitOperator<'a, Output = Result<()>> + ModuleArity + FrameStack + 'this { self.validator.with_resources(&self.resources, offset) } @@ -264,7 +265,7 @@ arity mismatch in validation #[cfg(feature = "simd")] pub fn simd_visitor<'this, 'a: 'this>( &'this mut self, - offset: usize, + offset: LogicalOffset, ) -> impl crate::VisitSimdOperator<'a, Output = Result<()>> + ModuleArity + 'this { self.validator.with_resources_simd(&self.resources, offset) } @@ -397,7 +398,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: LogicalOffset) -> Result<()> { Ok(()) } fn top_type(&self, _heap_type: &HeapType) -> HeapType { @@ -485,7 +486,9 @@ 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(LogicalOffset::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..9ec07d2d25 100644 --- a/crates/wasmparser/src/validator/names.rs +++ b/crates/wasmparser/src/validator/names.rs @@ -1,6 +1,7 @@ //! Definitions of name-related helpers and newtypes, primarily for the //! component model. +use crate::offsets::LogicalOffset; use crate::prelude::*; use crate::{Result, WasmFeatures}; use core::cmp::Ordering; @@ -282,7 +283,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: LogicalOffset) -> Result { Self::new_with_features(name, offset, WasmFeatures::default()) } @@ -291,7 +292,11 @@ 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: LogicalOffset, + features: WasmFeatures, + ) -> Result { let mut parser = ComponentNameParser { next: name, offset, @@ -581,7 +586,7 @@ impl<'a> HashName<'a> { // for error messages. struct ComponentNameParser<'a> { next: &'a str, - offset: usize, + offset: LogicalOffset, features: WasmFeatures, } diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index 3d7ad79e7b..0416deb8d3 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -25,6 +25,7 @@ #[cfg(feature = "simd")] use crate::VisitSimdOperator; use crate::features::require_feature; +use crate::offsets::LogicalOffset; use crate::{ AbstractHeapType, BlockType, BrTable, Catch, ContType, Error, FieldType, FrameKind, FrameStack, FuncType, GlobalType, Handle, HeapType, Ieee32, Ieee64, MemArg, ModuleArity, RefType, Result, @@ -233,7 +234,7 @@ pub struct Frame { } struct OperatorValidatorTemp<'validator, 'resources, T> { - offset: usize, + offset: LogicalOffset, inner: &'validator mut OperatorValidator, resources: &'resources T, } @@ -385,7 +386,7 @@ impl OperatorValidator { /// `ty`. pub fn new_func( ty: u32, - offset: usize, + offset: LogicalOffset, features: &WasmFeatures, resources: &T, allocs: OperatorValidatorAllocations, @@ -450,7 +451,7 @@ impl OperatorValidator { pub fn define_locals( &mut self, - offset: usize, + offset: LogicalOffset, count: u32, mut ty: ValType, resources: &impl WasmModuleResources, @@ -512,7 +513,7 @@ impl OperatorValidator { pub fn with_resources<'a, 'validator, 'resources, T>( &'validator mut self, resources: &'resources T, - offset: usize, + offset: LogicalOffset, ) -> impl VisitOperator<'a, Output = Result<()>> + ModuleArity + FrameStack + 'validator where T: WasmModuleResources, @@ -531,7 +532,7 @@ impl OperatorValidator { pub fn with_resources_simd<'a, 'validator, 'resources, T>( &'validator mut self, resources: &'resources T, - offset: usize, + offset: LogicalOffset, ) -> 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..83e0f71434 100644 --- a/crates/wasmparser/src/validator/types.rs +++ b/crates/wasmparser/src/validator/types.rs @@ -1,6 +1,7 @@ //! Types relating to type information provided by validation. use super::core::Module; +use crate::offsets::LogicalOffset; #[cfg(feature = "component-model")] use crate::validator::component::ComponentState; #[cfg(feature = "component-model")] @@ -261,7 +262,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: LogicalOffset) -> 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 +995,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: LogicalOffset) -> CoreTypeId { let (_is_new, group_id) = self.intern_canonical_rec_group(true, RecGroup::implicit(offset, sub_ty)); self[group_id].start @@ -1002,7 +1003,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: LogicalOffset) -> CoreTypeId { self.intern_sub_type(SubType::func(ty, false), offset) } @@ -1011,7 +1012,7 @@ impl TypeList { &self, rec_group: RecGroupId, index: u32, - offset: usize, + offset: LogicalOffset, ) -> Result { let elems = &self[rec_group]; let len = elems.end.index() - elems.start.index(); @@ -1068,7 +1069,7 @@ impl TypeList { &self, rec_group: RecGroupId, index: PackedIndex, - offset: usize, + offset: LogicalOffset, ) -> Result { self.at_canonicalized_unpacked_index(rec_group, index.unpack(), offset) } @@ -1080,7 +1081,7 @@ impl TypeList { &self, rec_group: RecGroupId, index: UnpackedIndex, - offset: usize, + offset: LogicalOffset, ) -> Result { match index { UnpackedIndex::Module(_) => panic!("not canonicalized"), @@ -1151,7 +1152,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, LogicalOffset::MAX) .expect("type references are checked during canonicalization") } }; From 22c59c134b84e9a3bf71303ec7eda000ee3ba0d0 Mon Sep 17 00:00:00 2001 From: Martin Molzer Date: Tue, 21 Jul 2026 08:12:40 +0200 Subject: [PATCH 02/10] inline LogicalOffset as per review comment --- crates/wasmparser/src/binary_reader.rs | 26 +- crates/wasmparser/src/error.rs | 17 +- crates/wasmparser/src/features.rs | 3 +- crates/wasmparser/src/offsets.rs | 37 +- crates/wasmparser/src/parser.rs | 45 +-- crates/wasmparser/src/readers.rs | 13 +- .../src/readers/component/aliases.rs | 6 +- .../src/readers/component/exports.rs | 3 +- .../wasmparser/src/readers/component/names.rs | 8 +- crates/wasmparser/src/readers/core/code.rs | 9 +- crates/wasmparser/src/readers/core/custom.rs | 5 +- crates/wasmparser/src/readers/core/data.rs | 6 +- crates/wasmparser/src/readers/core/dylink0.rs | 3 +- .../wasmparser/src/readers/core/elements.rs | 4 +- crates/wasmparser/src/readers/core/imports.rs | 14 +- crates/wasmparser/src/readers/core/linking.rs | 9 +- crates/wasmparser/src/readers/core/names.rs | 9 +- .../wasmparser/src/readers/core/operators.rs | 7 +- crates/wasmparser/src/readers/core/reloc.rs | 11 +- crates/wasmparser/src/readers/core/types.rs | 19 +- crates/wasmparser/src/resources.rs | 13 +- crates/wasmparser/src/validator.rs | 62 +-- crates/wasmparser/src/validator/component.rs | 353 +++++++----------- .../src/validator/component_types.rs | 56 ++- crates/wasmparser/src/validator/core.rs | 99 ++--- .../src/validator/core/canonical.rs | 20 +- crates/wasmparser/src/validator/func.rs | 17 +- crates/wasmparser/src/validator/names.rs | 11 +- crates/wasmparser/src/validator/operators.rs | 11 +- crates/wasmparser/src/validator/types.rs | 15 +- 30 files changed, 350 insertions(+), 561 deletions(-) diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 5429e43c50..2476966725 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -27,7 +27,7 @@ pub(crate) const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm"; pub struct BinaryReader<'a> { buffer: &'a [u8], position: MemOffset, - original_offset: LogicalOffset, + original_offset: u64, // When the `features` feature is disabled then the `WasmFeatures` type // still exists but this field is still omitted. When `features` is @@ -55,7 +55,7 @@ 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: LogicalOffset) -> BinaryReader<'_> { + pub fn new(data: &[u8], original_offset: u64) -> BinaryReader<'_> { BinaryReader { buffer: data, position: MemOffset::zero_at(original_offset, data.len()), @@ -98,7 +98,7 @@ impl<'a> BinaryReader<'a> { #[cfg(feature = "features")] pub fn new_features( data: &[u8], - original_offset: LogicalOffset, + original_offset: u64, features: WasmFeatures, ) -> BinaryReader<'_> { BinaryReader { @@ -133,7 +133,7 @@ impl<'a> BinaryReader<'a> { /// Gets the original position of the binary reader. #[inline] - pub fn original_position(&self) -> LogicalOffset { + pub fn original_position(&self) -> u64 { self.original_offset + self.position } @@ -155,7 +155,7 @@ impl<'a> BinaryReader<'a> { } /// Returns a range from the starting offset to the end of the buffer. - pub fn range(&self) -> Range { + pub fn range(&self) -> Range { self.original_offset..(self.original_offset + self.max_offset()) } @@ -163,12 +163,12 @@ impl<'a> BinaryReader<'a> { &self.buffer[self.position.into_usize()..] } - pub(crate) fn remaining_range(&self) -> Range { + pub(crate) fn remaining_range(&self) -> Range { self.original_position()..(self.original_offset + self.max_offset()) } fn max_offset(&self) -> MemOffset { - MemOffset::max(LogicalOffset::MAX - self.original_offset, self.buffer.len()) + MemOffset::max(u64::MAX - self.original_offset, self.buffer.len()) } fn ensure_has_byte(&self) -> Result<()> { @@ -204,7 +204,7 @@ impl<'a> BinaryReader<'a> { Ok(b) } - pub(crate) fn external_kind_from_byte(byte: u8, offset: LogicalOffset) -> Result { + pub(crate) fn external_kind_from_byte(byte: u8, offset: u64) -> Result { match byte { 0x00 => Ok(ExternalKind::Func), 0x01 => Ok(ExternalKind::Table), @@ -621,7 +621,7 @@ impl<'a> BinaryReader<'a> { )) } - pub(crate) fn invalid_leading_byte_error(byte: u8, desc: &str, offset: LogicalOffset) -> 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}") } @@ -1105,7 +1105,7 @@ impl<'a> BinaryReader<'a> { fn visit_0xfb_operator( &mut self, - pos: LogicalOffset, + pos: u64, visitor: &mut T, ) -> Result<>::Output> where @@ -1322,7 +1322,7 @@ impl<'a> BinaryReader<'a> { fn visit_0xfc_operator( &mut self, - pos: LogicalOffset, + pos: u64, visitor: &mut T, ) -> Result<>::Output> where @@ -1403,7 +1403,7 @@ impl<'a> BinaryReader<'a> { #[cfg(feature = "simd")] pub(super) fn visit_0xfd_operator( &mut self, - pos: LogicalOffset, + pos: u64, visitor: &mut T, ) -> Result<>::Output> where @@ -1719,7 +1719,7 @@ impl<'a> BinaryReader<'a> { fn visit_0xfe_operator( &mut self, - pos: LogicalOffset, + pos: u64, visitor: &mut T, ) -> Result<>::Output> where diff --git a/crates/wasmparser/src/error.rs b/crates/wasmparser/src/error.rs index d7ebffa29c..0e48f9646c 100644 --- a/crates/wasmparser/src/error.rs +++ b/crates/wasmparser/src/error.rs @@ -1,7 +1,6 @@ use core::fmt; use crate::WasmFeatures; -use crate::offsets::LogicalOffset; use crate::prelude::*; /// A binary reader for WebAssembly modules. @@ -17,7 +16,7 @@ pub struct Error { pub(crate) struct ErrorInner { message: String, kind: ErrorKind, - offset: LogicalOffset, + offset: u64, needed_hint: Option, } @@ -45,7 +44,7 @@ impl fmt::Display for Error { impl Error { #[cold] - pub(crate) fn _new(kind: ErrorKind, message: String, offset: LogicalOffset) -> Self { + pub(crate) fn _new(kind: ErrorKind, message: String, offset: u64) -> Self { Error { inner: Box::new(ErrorInner { kind, @@ -57,12 +56,12 @@ impl Error { } #[cold] - pub(crate) fn new(message: impl Into, offset: LogicalOffset) -> 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: LogicalOffset) -> Self { + pub(crate) fn invalid_heap_type(msg: &'static str, offset: u64) -> Self { Self::_new(ErrorKind::InvalidHeapType, msg.into(), offset) } @@ -70,18 +69,18 @@ impl Error { pub(crate) fn wasm_feature( feature: crate::WasmFeatures, msg: impl fmt::Display, - offset: LogicalOffset, + offset: u64, ) -> Self { Self::_new(ErrorKind::WasmFeature(feature), msg.to_string(), offset) } #[cold] - pub(crate) fn fmt(args: fmt::Arguments<'_>, offset: LogicalOffset) -> Self { + pub(crate) fn fmt(args: fmt::Arguments<'_>, offset: u64) -> Self { Error::new(args.to_string(), offset) } #[cold] - pub(crate) fn eof(offset: LogicalOffset, 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 @@ -97,7 +96,7 @@ impl Error { } /// Get the offset within the Wasm binary where the error occurred. - pub fn offset(&self) -> LogicalOffset { + pub fn offset(&self) -> u64 { self.inner.offset } diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs index e8ed876a96..b26315c352 100644 --- a/crates/wasmparser/src/features.rs +++ b/crates/wasmparser/src/features.rs @@ -110,7 +110,6 @@ macro_rules! define_wasm_features { pub(crate) mod require_feature { use crate::Error; use super::WasmFeatures; - use crate::offsets::LogicalOffset; $( #[inline] @@ -120,7 +119,7 @@ macro_rules! define_wasm_features { pub fn $field( features: WasmFeatures, msg: impl core::fmt::Display, - offset: LogicalOffset, + offset: u64, ) -> Result<(), Error> { if features.$field() { Ok(()) diff --git a/crates/wasmparser/src/offsets.rs b/crates/wasmparser/src/offsets.rs index da22db9aa3..36fa6fa341 100644 --- a/crates/wasmparser/src/offsets.rs +++ b/crates/wasmparser/src/offsets.rs @@ -14,20 +14,17 @@ */ //! Logical offsets into the input wasm file are strictly limited to fit into -//! an integer of type [LogicalOffset]. Data in each chunk is addressed -//! through an offset into an `[u8]` slice, which uses `usize`-addressing. +//! 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::{ num::TryFromIntError, ops::{Add, AddAssign}, }; -pub type LogicalOffset = u64; - // TODO: on platforms where usize::BITS > u64::BITS (currently almost no-where), // this could wrap a u64 instead of a usize to be a bit smaller. #[derive(Clone, Copy, Debug, Hash)] @@ -57,10 +54,10 @@ impl Ord for MemOffset { } impl MemOffset { - pub fn max(max_logical: LogicalOffset, max: usize) -> Self { + pub fn max(max_logical: u64, max: usize) -> Self { let max_len_logical = max_logical; - let max_len = if LogicalOffset::BITS > usize::BITS { - let max_len_usize = usize::MAX as LogicalOffset; + let max_len = if u64::BITS > usize::BITS { + let max_len_usize = usize::MAX as u64; // this now fits into a usize max_len_logical.max(max_len_usize) as usize } else { @@ -74,15 +71,11 @@ impl MemOffset { max: max_len, } } - pub fn zero_at(logical: LogicalOffset, max: usize) -> Self { + pub fn zero_at(logical: u64, max: usize) -> Self { Self::try_from(logical, 0, max).unwrap() } - pub fn try_from( - logical: LogicalOffset, - mem: usize, - max: usize, - ) -> Result { - let max = Self::max(LogicalOffset::MAX - logical, max).into_usize(); + pub fn try_from(logical: u64, mem: usize, max: usize) -> Result { + let max = Self::max(u64::MAX - logical, max).into_usize(); if mem <= max { Ok(Self { rep: mem, @@ -115,9 +108,9 @@ impl MemOffset { }) } } - // convinience method we should put on LogicalOffset, but can't since inherent impls are not allowed there - pub fn logical_try_add(logical: LogicalOffset, additional: u32) -> Option { - logical.checked_add(additional as LogicalOffset) + // convinience method we should put on u64, but can't since inherent impls are not allowed there + pub fn logical_try_add(logical: u64, additional: u32) -> Option { + logical.checked_add(additional as u64) } } @@ -127,18 +120,18 @@ impl From for usize { } } -impl Add for LogicalOffset { - type Output = LogicalOffset; +impl Add for u64 { + type Output = u64; fn add(self, rhs: MemOffset) -> Self::Output { debug_assert!( - rhs <= MemOffset::max(LogicalOffset::MAX - self, usize::MAX), + rhs <= MemOffset::max(u64::MAX - self, usize::MAX), "offset too large" ); self.strict_add(rhs.rep as u64) } } -impl AddAssign for LogicalOffset { +impl AddAssign for u64 { fn add_assign(&mut self, rhs: MemOffset) { *self = *self + rhs } diff --git a/crates/wasmparser/src/parser.rs b/crates/wasmparser/src/parser.rs index 18515a8ad1..301f43de5f 100644 --- a/crates/wasmparser/src/parser.rs +++ b/crates/wasmparser/src/parser.rs @@ -1,7 +1,7 @@ #[cfg(feature = "features")] use crate::WasmFeatures; use crate::binary_reader::WASM_MAGIC_NUMBER; -use crate::offsets::{LogicalOffset, MemOffset}; +use crate::offsets::MemOffset; use crate::prelude::*; use crate::{ BinaryReader, CustomSectionReader, DataSectionReader, ElementSectionReader, Error, @@ -88,13 +88,13 @@ pub(crate) enum Order { #[derive(Debug, Clone)] pub struct Parser { state: State, - offset: LogicalOffset, - max_offset: LogicalOffset, + offset: u64, + max_offset: u64, encoding: Encoding, #[cfg(feature = "features")] features: WasmFeatures, counts: ParserCounts, - order: (Order, LogicalOffset), + order: (Order, u64), } #[derive(Debug, Clone)] @@ -157,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 @@ -190,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. @@ -201,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. @@ -222,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`] @@ -261,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. @@ -296,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. @@ -320,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. @@ -347,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(LogicalOffset), + End(u64), } const CUSTOM_SECTION: u8 = 0; @@ -665,7 +665,7 @@ impl Parser { } } - fn update_order(&mut self, order: Order, pos: LogicalOffset) -> Result<()> { + 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 => { @@ -743,7 +743,8 @@ 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 section_end = match MemOffset::logical_try_add(reader.original_position(), len) { + let section_end = match MemOffset::logical_try_add(reader.original_position(), len) + { Some(section_end) if section_end <= self.max_offset => section_end, _ => return Err(Error::new("section too large", len_pos)), }; @@ -1179,7 +1180,7 @@ impl Parser { self.state = State::SectionStart; } - fn check_function_code_counts(&self, pos: LogicalOffset) -> 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") @@ -1196,7 +1197,7 @@ impl Parser { } } - fn check_data_count(&self, pos: LogicalOffset) -> 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") @@ -1233,9 +1234,9 @@ 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>, - section_end: LogicalOffset, + section_end: u64, desc: &str, -) -> Result<(T, Range)> +) -> Result<(T, Range)> where T: FromReader<'a>, { @@ -1302,7 +1303,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 { @@ -1663,9 +1664,9 @@ mod tests { chunk: Chunk<'_>, expected_consumed: usize, expected_name: &str, - expected_data_offset: LogicalOffset, + expected_data_offset: u64, expected_data: &[u8], - expected_range: Range, + expected_range: Range, ) { let (consumed, s) = match chunk { Chunk::Parsed { diff --git a/crates/wasmparser/src/readers.rs b/crates/wasmparser/src/readers.rs index 6172401336..c2f9de4c1a 100644 --- a/crates/wasmparser/src/readers.rs +++ b/crates/wasmparser/src/readers.rs @@ -13,7 +13,6 @@ * limitations under the License. */ -use crate::offsets::LogicalOffset; use crate::{BinaryReader, Error, Result}; use ::core::fmt; use ::core::marker; @@ -114,13 +113,13 @@ impl<'a, T> SectionLimited<'a, T> { } /// Returns whether the original byte offset of this section. - pub fn original_position(&self) -> LogicalOffset { + 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() } @@ -183,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) -> LogicalOffset { + pub fn original_position(&self) -> u64 { self.section.reader.original_position() } } @@ -231,7 +230,7 @@ impl<'a, T> Iterator for SectionLimitedIntoIterWithOffsets<'a, T> where T: FromReader<'a>, { - type Item = Result<(LogicalOffset, T)>; + type Item = Result<(u64, T)>; fn next(&mut self) -> Option { let pos = self.iter.section.reader.original_position(); @@ -278,13 +277,13 @@ impl<'a, T> Subsections<'a, T> { } /// Returns whether the original byte offset of this section. - pub fn original_position(&self) -> LogicalOffset { + 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 1ac74e3da7..8b7606e935 100644 --- a/crates/wasmparser/src/readers/component/aliases.rs +++ b/crates/wasmparser/src/readers/component/aliases.rs @@ -1,6 +1,4 @@ -use crate::{ - BinaryReader, ComponentExternalKind, ExternalKind, FromReader, Result, offsets::LogicalOffset, -}; +use crate::{BinaryReader, ComponentExternalKind, ExternalKind, FromReader, Result}; /// Represents the kind of an outer alias in a WebAssembly component. #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -94,7 +92,7 @@ impl<'a> FromReader<'a> for ComponentAlias<'a> { fn component_outer_alias_kind_from_bytes( byte1: u8, byte2: Option, - offset: LogicalOffset, + 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 f9ec23b92e..c3b0b8340b 100644 --- a/crates/wasmparser/src/readers/component/exports.rs +++ b/crates/wasmparser/src/readers/component/exports.rs @@ -1,6 +1,5 @@ use crate::{ BinaryReader, ComponentExternName, ComponentTypeRef, FromReader, Result, SectionLimited, - offsets::LogicalOffset, }; /// Represents the kind of an external items of a WebAssembly component. @@ -24,7 +23,7 @@ impl ComponentExternalKind { pub(crate) fn from_bytes( byte1: u8, byte2: Option, - offset: LogicalOffset, + 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 a9f82a53e7..ef42d9d4bc 100644 --- a/crates/wasmparser/src/readers/component/names.rs +++ b/crates/wasmparser/src/readers/component/names.rs @@ -1,6 +1,4 @@ -use crate::{ - BinaryReader, Error, NameMap, Result, Subsection, Subsections, offsets::LogicalOffset, -}; +use crate::{BinaryReader, Error, NameMap, Result, Subsection, Subsections}; use core::ops::Range; /// Type used to iterate and parse the contents of the `component-name` custom @@ -13,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>), @@ -37,7 +35,7 @@ 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, }, } diff --git a/crates/wasmparser/src/readers/core/code.rs b/crates/wasmparser/src/readers/core/code.rs index 81668c3cc2..20f559f483 100644 --- a/crates/wasmparser/src/readers/core/code.rs +++ b/crates/wasmparser/src/readers/core/code.rs @@ -13,10 +13,7 @@ * limitations under the License. */ -use crate::{ - BinaryReader, FromReader, OperatorsReader, Result, SectionLimited, ValType, - offsets::LogicalOffset, -}; +use crate::{BinaryReader, FromReader, OperatorsReader, Result, SectionLimited, ValType}; use core::ops::Range; /// A reader for the code section of a WebAssembly module. @@ -75,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() } @@ -108,7 +105,7 @@ impl<'a> LocalsReader<'a> { } /// Gets the original position of the reader. - pub fn original_position(&self) -> LogicalOffset { + 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 4a142dbdd5..8fef4913ed 100644 --- a/crates/wasmparser/src/readers/core/custom.rs +++ b/crates/wasmparser/src/readers/core/custom.rs @@ -1,4 +1,3 @@ -use crate::offsets::LogicalOffset; use crate::{BinaryReader, Result}; use core::fmt; use core::ops::Range; @@ -24,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) -> LogicalOffset { + pub fn data_offset(&self) -> u64 { self.reader.original_position() } @@ -36,7 +35,7 @@ impl<'a> CustomSectionReader<'a> { /// 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 3dad3f8413..85c0b46c9d 100644 --- a/crates/wasmparser/src/readers/core/data.rs +++ b/crates/wasmparser/src/readers/core/data.rs @@ -13,9 +13,7 @@ * limitations under the License. */ -use crate::{ - BinaryReader, ConstExpr, Error, FromReader, Result, SectionLimited, offsets::LogicalOffset, -}; +use crate::{BinaryReader, ConstExpr, Error, FromReader, Result, SectionLimited}; use core::ops::Range; /// Represents a data segment in a core WebAssembly module. @@ -26,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 c39a34b7e2..ae0087369d 100644 --- a/crates/wasmparser/src/readers/core/dylink0.rs +++ b/crates/wasmparser/src/readers/core/dylink0.rs @@ -1,4 +1,3 @@ -use crate::offsets::LogicalOffset; use crate::prelude::*; use crate::{BinaryReader, Result, Subsection, Subsections, SymbolFlags}; use core::ops::Range; @@ -62,7 +61,7 @@ pub enum Dylink0Subsection<'a> { Unknown { ty: u8, data: &'a [u8], - range: Range, + range: Range, }, } diff --git a/crates/wasmparser/src/readers/core/elements.rs b/crates/wasmparser/src/readers/core/elements.rs index cf28fdcd44..4d6ac29d0a 100644 --- a/crates/wasmparser/src/readers/core/elements.rs +++ b/crates/wasmparser/src/readers/core/elements.rs @@ -15,7 +15,7 @@ use crate::{ BinaryReader, ConstExpr, Error, ExternalKind, FromReader, OperatorsReader, - OperatorsReaderAllocations, RefType, Result, SectionLimited, offsets::LogicalOffset, + OperatorsReaderAllocations, RefType, Result, SectionLimited, }; use core::ops::Range; @@ -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 9df334e102..8c65e3db8e 100644 --- a/crates/wasmparser/src/readers/core/imports.rs +++ b/crates/wasmparser/src/readers/core/imports.rs @@ -17,7 +17,7 @@ use core::mem; use crate::{ BinaryReader, Error, ExternalKind, FromReader, GlobalType, MemoryType, Result, SectionLimited, - SectionLimitedIntoIterWithOffsets, TableType, TagType, offsets::LogicalOffset, + SectionLimitedIntoIterWithOffsets, TableType, TagType, }; /// Represents a reference to a type definition in a WebAssembly module. @@ -45,7 +45,7 @@ pub enum TypeRef { #[derive(Debug, Clone)] pub enum Imports<'a> { /// The group contains a single import. - Single(LogicalOffset, 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,9 +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 { @@ -213,7 +211,7 @@ impl<'a> SectionLimited<'a, Imports<'a>> { } impl<'a> IntoIterator for Imports<'a> { - type Item = Result<(LogicalOffset, Import<'a>)>; + type Item = Result<(u64, Import<'a>)>; type IntoIter = ImportsIter<'a>; fn into_iter(self) -> Self::IntoIter { @@ -246,7 +244,7 @@ pub struct ImportsIter<'a> { enum ImportsIterState<'a> { Done, Error(Error), - Single(LogicalOffset, Import<'a>), + Single(u64, Import<'a>), Compact1 { module: &'a str, iter: SectionLimitedIntoIterWithOffsets<'a, ImportItemCompact<'a>>, @@ -259,7 +257,7 @@ enum ImportsIterState<'a> { } impl<'a> Iterator for ImportsIter<'a> { - type Item = Result<(LogicalOffset, 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 3ee8dbcbca..2dbcb3b4e0 100644 --- a/crates/wasmparser/src/readers/core/linking.rs +++ b/crates/wasmparser/src/readers/core/linking.rs @@ -1,4 +1,3 @@ -use crate::offsets::LogicalOffset; use crate::prelude::*; use crate::{BinaryReader, Error, FromReader, Result, SectionLimited, Subsection, Subsections}; use core::ops::Range; @@ -73,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. @@ -377,7 +376,7 @@ 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, }, } @@ -426,13 +425,13 @@ impl<'a> LinkingSectionReader<'a> { } /// Returns the original byte offset of this section. - pub fn original_position(&self) -> LogicalOffset { + 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 ac96f37f98..348d33733d 100644 --- a/crates/wasmparser/src/readers/core/names.rs +++ b/crates/wasmparser/src/readers/core/names.rs @@ -13,10 +13,7 @@ * limitations under the License. */ -use crate::{ - BinaryReader, Error, FromReader, Result, SectionLimited, Subsection, Subsections, - offsets::LogicalOffset, -}; +use crate::{BinaryReader, Error, FromReader, Result, SectionLimited, Subsection, Subsections}; use core::ops::Range; /// Represents a name map from the names custom section. @@ -85,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>), @@ -117,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, }, } diff --git a/crates/wasmparser/src/readers/core/operators.rs b/crates/wasmparser/src/readers/core/operators.rs index 36f4816aa4..478ba3c07f 100644 --- a/crates/wasmparser/src/readers/core/operators.rs +++ b/crates/wasmparser/src/readers/core/operators.rs @@ -14,7 +14,6 @@ */ use crate::limits::{MAX_WASM_CATCHES, MAX_WASM_HANDLERS}; -use crate::offsets::LogicalOffset; use crate::prelude::*; use crate::{BinaryReader, Error, FromReader, Result, ValType}; use core::{fmt, mem}; @@ -476,7 +475,7 @@ impl<'a> OperatorsReader<'a> { } /// Gets the original position of the reader. - pub fn original_position(&self) -> LogicalOffset { + pub fn original_position(&self) -> u64 { self.reader.original_position() } @@ -563,7 +562,7 @@ impl<'a> OperatorsReader<'a> { } /// Reads an operator with its offset. - pub fn read_with_offset(&mut self) -> Result<(Operator<'a>, LogicalOffset)> { + pub fn read_with_offset(&mut self) -> Result<(Operator<'a>, u64)> { let pos = self.reader.original_position(); Ok((self.read()?, pos)) } @@ -681,7 +680,7 @@ impl<'a> OperatorsIteratorWithOffsets<'a> { } impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> { - type Item = Result<(Operator<'a>, LogicalOffset)>; + type Item = Result<(Operator<'a>, u64)>; /// Reads content of the code section with offsets. /// diff --git a/crates/wasmparser/src/readers/core/reloc.rs b/crates/wasmparser/src/readers/core/reloc.rs index 309045b01c..dfa2d6e37e 100644 --- a/crates/wasmparser/src/readers/core/reloc.rs +++ b/crates/wasmparser/src/readers/core/reloc.rs @@ -1,4 +1,4 @@ -use crate::{BinaryReader, FromReader, Result, SectionLimited, offsets::LogicalOffset}; +use crate::{BinaryReader, FromReader, Result, SectionLimited}; use core::ops::Range; /// Reader for relocation entries within a `reloc.*` section. @@ -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() } @@ -249,10 +249,7 @@ impl RelocationEntry { // 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 LogicalOffset, - ) + 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 c6e8b039b0..cd8b8b8c44 100644 --- a/crates/wasmparser/src/readers/core/types.rs +++ b/crates/wasmparser/src/readers/core/types.rs @@ -18,7 +18,6 @@ use crate::limits::{ MAX_WASM_FUNCTION_PARAMS, MAX_WASM_FUNCTION_RETURNS, MAX_WASM_STRUCT_FIELDS, MAX_WASM_SUPERTYPES, MAX_WASM_TYPES, }; -use crate::offsets::LogicalOffset; use crate::prelude::*; #[cfg(feature = "validate")] use crate::types::CoreTypeId; @@ -324,13 +323,13 @@ pub struct RecGroup { #[derive(Debug, Clone)] enum RecGroupInner { - Implicit((LogicalOffset, SubType)), - Explicit(Vec<(LogicalOffset, SubType)>), + Implicit((u64, SubType)), + Explicit(Vec<(u64, SubType)>), } impl RecGroup { /// Create an explicit `RecGroup` for the given types. - pub(crate) fn explicit(types: Vec<(LogicalOffset, SubType)>) -> Self { + pub(crate) fn explicit(types: Vec<(u64, SubType)>) -> Self { RecGroup { inner: RecGroupInner::Explicit(types), } @@ -338,7 +337,7 @@ impl RecGroup { /// Create an implicit `RecGroup` for a type that was not contained /// in a `(rec ...)`. - pub(crate) fn implicit(offset: LogicalOffset, ty: SubType) -> Self { + pub(crate) fn implicit(offset: u64, ty: SubType) -> Self { RecGroup { inner: RecGroupInner::Implicit((offset, ty)), } @@ -377,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<(LogicalOffset, SubType)>), - Explicit(alloc::vec::IntoIter<(LogicalOffset, SubType)>), + Implicit(Option<(u64, SubType)>), + Explicit(alloc::vec::IntoIter<(u64, SubType)>), } impl Iterator for Iter { - type Item = (LogicalOffset, SubType); + type Item = (u64, SubType); - fn next(&mut self) -> Option<(LogicalOffset, 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 ad3bb43a0c..010055142c 100644 --- a/crates/wasmparser/src/resources.rs +++ b/crates/wasmparser/src/resources.rs @@ -15,7 +15,7 @@ use crate::{ Error, FuncType, GlobalType, HeapType, MemoryType, RefType, SubType, TableType, ValType, - WasmFeatures, offsets::LogicalOffset, types::CoreTypeId, + WasmFeatures, types::CoreTypeId, }; /// Types that qualify as Wasm validation database. @@ -83,7 +83,7 @@ pub trait WasmModuleResources { &self, t: &mut ValType, features: &WasmFeatures, - offset: LogicalOffset, + 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: LogicalOffset) -> 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,8 +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: LogicalOffset) - -> 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; @@ -153,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: LogicalOffset) -> 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 { @@ -218,7 +217,7 @@ where T::type_index_of_function(self, func_idx) } - fn check_heap_type(&self, t: &mut HeapType, offset: LogicalOffset) -> 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 281d0dc21d..758a303f3a 100644 --- a/crates/wasmparser/src/validator.rs +++ b/crates/wasmparser/src/validator.rs @@ -13,7 +13,6 @@ * limitations under the License. */ -use crate::offsets::LogicalOffset; use crate::prelude::*; use crate::{ AbstractHeapType, Encoding, Error, FromReader, FunctionBody, HeapType, Parser, Payload, @@ -68,13 +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: LogicalOffset, -) -> 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)) @@ -90,7 +83,7 @@ fn check_max( Ok(()) } -fn combine_type_sizes(a: u32, b: u32, offset: LogicalOffset) -> 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!( @@ -186,7 +179,7 @@ enum State { } impl State { - fn ensure_parsable(&self, offset: LogicalOffset) -> Result<()> { + fn ensure_parsable(&self, offset: u64) -> Result<()> { match self { Self::Module => Ok(()), #[cfg(feature = "component-model")] @@ -202,7 +195,7 @@ impl State { } } - fn ensure_module(&self, section: &str, offset: LogicalOffset) -> Result<()> { + fn ensure_module(&self, section: &str, offset: u64) -> Result<()> { self.ensure_parsable(offset)?; let _ = section; @@ -218,7 +211,7 @@ impl State { } #[cfg(feature = "component-model")] - fn ensure_component(&self, section: &str, offset: LogicalOffset) -> Result<()> { + fn ensure_component(&self, section: &str, offset: u64) -> Result<()> { self.ensure_parsable(offset)?; match self { @@ -243,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: LogicalOffset) -> Result<()> { + pub(crate) fn check_value_type(&self, ty: ValType, offset: u64) -> Result<()> { match ty { ValType::I32 | ValType::I64 => Ok(()), ValType::F32 | ValType::F64 => { @@ -254,7 +247,7 @@ impl WasmFeatures { } } - pub(crate) fn check_ref_type(&self, r: RefType, offset: LogicalOffset) -> 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(_) => { @@ -654,12 +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 { @@ -921,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(); @@ -963,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)?; @@ -983,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)?; @@ -1052,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(); @@ -1127,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(); @@ -1259,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)?; @@ -1333,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: LogicalOffset) -> 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", @@ -1401,13 +1389,8 @@ impl Validator { &mut self, section: &SectionLimited<'a, T>, name: &str, - validate_section: impl FnOnce( - &mut ModuleState, - &mut TypeAlloc, - u32, - LogicalOffset, - ) -> Result<()>, - mut validate_item: impl FnMut(&mut ModuleState, &mut TypeAlloc, T, LogicalOffset) -> 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>, @@ -1432,18 +1415,13 @@ impl Validator { &mut self, section: &SectionLimited<'a, T>, name: &str, - validate_section: impl FnOnce( - &mut Vec, - &mut TypeAlloc, - u32, - LogicalOffset, - ) -> Result<()>, + validate_section: impl FnOnce(&mut Vec, &mut TypeAlloc, u32, u64) -> Result<()>, mut validate_item: impl FnMut( &mut Vec, &mut TypeAlloc, &WasmFeatures, T, - LogicalOffset, + u64, ) -> Result<()>, ) -> Result<()> where diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 32f7909943..3a984b6859 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -13,6 +13,7 @@ use super::{ core::{InternRecGroup, Module}, types::{CoreTypeId, EntityType, TypeAlloc, TypeData, TypeInfo, TypeList}, }; +use crate::collections::index_map::Entry; use crate::limits::*; use crate::prelude::*; use crate::validator::names::{ComponentName, ComponentNameKind, KebabStr, KebabString}; @@ -22,10 +23,9 @@ use crate::{ GlobalType, InstantiationArgKind, MemoryType, PackedIndex, RefType, Result, SubType, TableType, TypeBounds, ValType, WasmFeatures, require_feature, }; -use crate::{collections::index_map::Entry, offsets::LogicalOffset}; use core::mem; -fn to_kebab_string<'a>(s: &'a str, desc: &str, offset: LogicalOffset) -> 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: LogicalOffset, 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: LogicalOffset) -> 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: LogicalOffset) -> 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: LogicalOffset, - 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: LogicalOffset, - 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: LogicalOffset) -> 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: LogicalOffset, + 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: LogicalOffset) -> 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: LogicalOffset, + 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: LogicalOffset, + 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: LogicalOffset, + 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: LogicalOffset, + 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: LogicalOffset, + 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: LogicalOffset, + 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: LogicalOffset, + 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: LogicalOffset, + offset: u64, check_limit: bool, ) -> Result<()> { if check_limit { @@ -1200,7 +1192,7 @@ impl ComponentState { &mut self, func: CanonicalFunction, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { match func { CanonicalFunction::Lift { @@ -1330,7 +1322,7 @@ impl ComponentState { type_index: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: LogicalOffset, + 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: LogicalOffset, + offset: u64, ) -> Result<()> { let ty = &types[self.function_at(func_index, offset)?]; @@ -1405,43 +1397,28 @@ impl ComponentState { Ok(()) } - fn resource_new( - &mut self, - resource: u32, - types: &mut TypeAlloc, - offset: LogicalOffset, - ) -> 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: LogicalOffset, - ) -> 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: LogicalOffset, - ) -> 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: LogicalOffset) -> 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", @@ -1453,7 +1430,7 @@ impl ComponentState { Ok(()) } - fn backpressure_dec(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> 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", @@ -1470,7 +1447,7 @@ impl ComponentState { result: &Option, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1520,7 +1497,7 @@ impl ComponentState { Ok(()) } - fn task_cancel(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> 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", @@ -1536,7 +1513,7 @@ impl ComponentState { &self, immediate: u32, operation: &str, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { if immediate > 0 { require_feature::cm_threading( @@ -1559,7 +1536,7 @@ impl ComponentState { ty: ValType, i: u32, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1579,7 +1556,7 @@ impl ComponentState { ty: ValType, i: u32, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1594,12 +1571,7 @@ impl ComponentState { Ok(()) } - fn validate_context_type( - &mut self, - ty: ValType, - intrinsic: &str, - offset: LogicalOffset, - ) -> Result<()> { + fn validate_context_type(&mut self, ty: ValType, intrinsic: &str, offset: u64) -> Result<()> { match ty { ValType::I32 => {} ValType::I64 => { @@ -1629,7 +1601,7 @@ impl ComponentState { Ok(()) } - fn subtask_drop(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> 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", @@ -1641,12 +1613,7 @@ impl ComponentState { Ok(()) } - fn subtask_cancel( - &mut self, - async_: bool, - types: &mut TypeAlloc, - offset: LogicalOffset, - ) -> 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", @@ -1665,7 +1632,7 @@ impl ComponentState { Ok(()) } - fn stream_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: LogicalOffset) -> 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", @@ -1687,7 +1654,7 @@ impl ComponentState { ty: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1727,7 +1694,7 @@ impl ComponentState { ty: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1766,7 +1733,7 @@ impl ComponentState { ty: u32, cancellable: bool, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1796,7 +1763,7 @@ impl ComponentState { ty: u32, cancellable: bool, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1821,12 +1788,7 @@ impl ComponentState { Ok(()) } - fn stream_drop_readable( - &mut self, - ty: u32, - types: &mut TypeAlloc, - offset: LogicalOffset, - ) -> 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", @@ -1843,12 +1805,7 @@ impl ComponentState { Ok(()) } - fn stream_drop_writable( - &mut self, - ty: u32, - types: &mut TypeAlloc, - offset: LogicalOffset, - ) -> 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", @@ -1865,7 +1822,7 @@ impl ComponentState { Ok(()) } - fn future_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: LogicalOffset) -> 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", @@ -1887,7 +1844,7 @@ impl ComponentState { ty: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1927,7 +1884,7 @@ impl ComponentState { ty: u32, options: &[CanonicalOption], types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1965,7 +1922,7 @@ impl ComponentState { ty: u32, cancellable: bool, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -1995,7 +1952,7 @@ impl ComponentState { ty: u32, cancellable: bool, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_async( self.features, @@ -2020,12 +1977,7 @@ impl ComponentState { Ok(()) } - fn future_drop_readable( - &mut self, - ty: u32, - types: &mut TypeAlloc, - offset: LogicalOffset, - ) -> 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", @@ -2042,12 +1994,7 @@ impl ComponentState { Ok(()) } - fn future_drop_writable( - &mut self, - ty: u32, - types: &mut TypeAlloc, - offset: LogicalOffset, - ) -> 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", @@ -2068,7 +2015,7 @@ impl ComponentState { &mut self, options: Vec, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_error_context( self.features, @@ -2095,7 +2042,7 @@ impl ComponentState { &mut self, options: Vec, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_error_context( self.features, @@ -2115,7 +2062,7 @@ impl ComponentState { Ok(()) } - fn error_context_drop(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> 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", @@ -2127,7 +2074,7 @@ impl ComponentState { Ok(()) } - fn waitable_set_new(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> 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", @@ -2139,12 +2086,7 @@ impl ComponentState { Ok(()) } - fn waitable_set_wait( - &mut self, - memory: u32, - types: &mut TypeAlloc, - offset: LogicalOffset, - ) -> 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", @@ -2160,12 +2102,7 @@ impl ComponentState { Ok(()) } - fn waitable_set_poll( - &mut self, - memory: u32, - types: &mut TypeAlloc, - offset: LogicalOffset, - ) -> 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", @@ -2181,7 +2118,7 @@ impl ComponentState { Ok(()) } - fn waitable_set_drop(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> 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", @@ -2193,7 +2130,7 @@ impl ComponentState { Ok(()) } - fn waitable_join(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> 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", @@ -2205,7 +2142,7 @@ impl ComponentState { Ok(()) } - fn thread_index(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> 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", @@ -2222,7 +2159,7 @@ impl ComponentState { func_ty_index: u32, table_index: u32, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2275,7 +2212,7 @@ impl ComponentState { Ok(()) } - fn thread_resume_later(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> 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", @@ -2290,7 +2227,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2302,7 +2239,7 @@ impl ComponentState { Ok(()) } - fn thread_yield(&mut self, types: &mut TypeAlloc, offset: LogicalOffset) -> 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", @@ -2318,7 +2255,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2335,7 +2272,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2351,7 +2288,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2367,7 +2304,7 @@ impl ComponentState { &mut self, _cancellable: bool, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_threading( self.features, @@ -2379,12 +2316,7 @@ impl ComponentState { Ok(()) } - fn check_local_resource( - &self, - idx: u32, - types: &TypeList, - offset: LogicalOffset, - ) -> 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 @@ -2400,7 +2332,7 @@ impl ComponentState { &self, idx: u32, _types: &'a TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result { if let ComponentAnyTypeId::Resource(id) = self.component_type_at(idx, offset)? { return Ok(id); @@ -2412,7 +2344,7 @@ impl ComponentState { &mut self, func_ty_index: u32, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::shared_everything_threads( self.features, @@ -2439,7 +2371,7 @@ impl ComponentState { func_ty_index: u32, table_index: u32, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::shared_everything_threads( self.features, @@ -2492,7 +2424,7 @@ impl ComponentState { &self, func_ty_index: u32, types: &TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result { let core_type_id = match self.core_type_at(func_ty_index, offset)? { ComponentCoreTypeId::Sub(c) => c, @@ -2519,11 +2451,7 @@ impl ComponentState { Ok(core_type_id) } - fn thread_available_parallelism( - &mut self, - types: &mut TypeAlloc, - offset: LogicalOffset, - ) -> 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", @@ -2548,7 +2476,7 @@ impl ComponentState { &mut self, instance: crate::ComponentInstance, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { let instance = match instance { crate::ComponentInstance::Instantiate { @@ -2569,7 +2497,7 @@ impl ComponentState { components: &mut [Self], alias: crate::ComponentAlias, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { let component = components.last_mut().unwrap(); @@ -2630,7 +2558,7 @@ impl ComponentState { args: &[u32], results: u32, types: &mut TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { require_feature::cm_values( self.features, @@ -2686,7 +2614,7 @@ impl ComponentState { &self, types: &TypeList, options: &[CanonicalOption], - offset: LogicalOffset, + offset: u64, ) -> Result { fn display(option: CanonicalOption) -> &'static str { match option { @@ -2911,7 +2839,7 @@ impl ComponentState { &mut self, ty: &ComponentTypeRef, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result { Ok(match ty { ComponentTypeRef::Module(index) => { @@ -2976,7 +2904,7 @@ impl ComponentState { &mut self, export: &crate::ComponentExport, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result { let actual = match export.kind { ComponentExternalKind::Module => { @@ -3021,7 +2949,7 @@ impl ComponentState { components: &[Self], decls: Vec, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result { let mut state = Module::new(components[0].features); @@ -3080,7 +3008,7 @@ impl ComponentState { components: &mut Vec, decls: Vec, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result { let features = components[0].features; components.push(ComponentState::new(ComponentKind::ComponentType, features)); @@ -3117,7 +3045,7 @@ impl ComponentState { components: &mut Vec, decls: Vec, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result { let features = components[0].features; components.push(ComponentState::new(ComponentKind::InstanceType, features)); @@ -3177,7 +3105,7 @@ impl ComponentState { &self, ty: crate::ComponentFuncType, types: &TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result { let mut info = TypeInfo::new(); @@ -3242,13 +3170,13 @@ impl ComponentState { module_index: u32, module_args: Vec, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result { fn insert_arg<'a>( name: &'a str, arg: &'a InstanceType, args: &mut IndexMap<&'a str, &'a InstanceType>, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { if args.insert(name, arg).is_some() { bail!( @@ -3319,7 +3247,7 @@ impl ComponentState { component_index: u32, component_args: Vec, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result { let component_type_id = self.component_at(component_index, offset)?; let mut args = IndexMap::default(); @@ -3586,7 +3514,7 @@ impl ComponentState { &mut self, exports: Vec, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result { let mut info = TypeInfo::new(); let mut inst_exports = IndexMap::default(); @@ -3705,7 +3633,7 @@ impl ComponentState { &mut self, exports: Vec, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result { fn insert_export( types: &TypeList, @@ -3713,7 +3641,7 @@ impl ComponentState { export: EntityType, exports: &mut IndexMap, info: &mut TypeInfo, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { info.combine(export.info(types), offset)?; @@ -3797,7 +3725,7 @@ impl ComponentState { kind: ExternalKind, name: &str, types: &TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { macro_rules! push_module_export { ($expected:path, $collection:ident, $ty:literal) => {{ @@ -3883,7 +3811,7 @@ impl ComponentState { kind: ComponentExternalKind, name: &str, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { if let ComponentExternalKind::Value = kind { self.check_value_support(offset)?; @@ -3925,12 +3853,7 @@ impl ComponentState { Ok(()) } - fn alias_module( - components: &mut [Self], - count: u32, - index: u32, - offset: LogicalOffset, - ) -> 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)?; @@ -3947,12 +3870,7 @@ impl ComponentState { Ok(()) } - fn alias_component( - components: &mut [Self], - count: u32, - index: u32, - offset: LogicalOffset, - ) -> 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)?; @@ -3969,12 +3887,7 @@ impl ComponentState { Ok(()) } - fn alias_core_type( - components: &mut [Self], - count: u32, - index: u32, - offset: LogicalOffset, - ) -> 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)?; @@ -3991,7 +3904,7 @@ impl ComponentState { count: u32, index: u32, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { let component = Self::check_alias_count(components, count, offset)?; let ty = component.component_type_at(index, offset)?; @@ -4041,7 +3954,7 @@ impl ComponentState { Ok(()) } - fn check_alias_count(components: &[Self], count: u32, offset: LogicalOffset) -> 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}"); @@ -4054,7 +3967,7 @@ impl ComponentState { &self, ty: crate::ComponentDefinedType, types: &TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result { match ty { crate::ComponentDefinedType::Primitive(ty) => { @@ -4203,7 +4116,7 @@ impl ComponentState { &self, fields: &[(&str, crate::ComponentValType)], types: &TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result { let mut info = TypeInfo::new(); let mut field_map = IndexMap::default(); @@ -4240,7 +4153,7 @@ impl ComponentState { &self, cases: &[crate::VariantCase], types: &TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result { let mut info = TypeInfo::new(); let mut case_map: IndexMap = IndexMap::default(); @@ -4291,7 +4204,7 @@ impl ComponentState { &self, tys: &[crate::ComponentValType], types: &TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result { let mut info = TypeInfo::new(); if tys.is_empty() { @@ -4309,11 +4222,7 @@ impl ComponentState { Ok(ComponentDefinedType::Tuple(TupleType { info, types })) } - fn create_flags_type( - &self, - names: &[&str], - offset: LogicalOffset, - ) -> Result { + fn create_flags_type(&self, names: &[&str], offset: u64) -> Result { let mut names_set = IndexSet::default(); names_set.reserve(names.len()); @@ -4338,11 +4247,7 @@ impl ComponentState { Ok(ComponentDefinedType::Flags(names_set)) } - fn create_enum_type( - &self, - cases: &[&str], - offset: LogicalOffset, - ) -> 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", @@ -4373,7 +4278,7 @@ impl ComponentState { fn create_component_val_type( &self, ty: crate::ComponentValType, - offset: LogicalOffset, + offset: u64, ) -> Result { Ok(match ty { crate::ComponentValType::Primitive(pt) => { @@ -4386,14 +4291,14 @@ impl ComponentState { }) } - pub fn core_type_at(&self, idx: u32, offset: LogicalOffset) -> 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: LogicalOffset) -> Result { + pub fn component_type_at(&self, idx: u32, offset: u64) -> Result { self.types .get(idx as usize) .copied() @@ -4404,7 +4309,7 @@ impl ComponentState { &self, idx: u32, types: &'a TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result<&'a ComponentFuncType> { let id = self.component_type_at(idx, offset)?; match id { @@ -4413,7 +4318,7 @@ impl ComponentState { } } - fn function_at(&self, idx: u32, offset: LogicalOffset) -> Result { + fn function_at(&self, idx: u32, offset: u64) -> Result { self.funcs.get(idx as usize).copied().ok_or_else(|| { format_err!( offset, @@ -4422,7 +4327,7 @@ impl ComponentState { }) } - fn component_at(&self, idx: u32, offset: LogicalOffset) -> Result { + fn component_at(&self, idx: u32, offset: u64) -> Result { self.components.get(idx as usize).copied().ok_or_else(|| { format_err!( offset, @@ -4431,7 +4336,7 @@ impl ComponentState { }) } - fn instance_at(&self, idx: u32, offset: LogicalOffset) -> Result { + fn instance_at(&self, idx: u32, offset: u64) -> Result { self.instances.get(idx as usize).copied().ok_or_else(|| { format_err!( offset, @@ -4440,7 +4345,7 @@ impl ComponentState { }) } - fn value_at(&mut self, idx: u32, offset: LogicalOffset) -> 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; @@ -4451,14 +4356,14 @@ impl ComponentState { } } - fn defined_type_at(&self, idx: u32, offset: LogicalOffset) -> 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: LogicalOffset) -> 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!( @@ -4468,18 +4373,14 @@ impl ComponentState { } } - fn module_at(&self, idx: u32, offset: LogicalOffset) -> 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: LogicalOffset, - ) -> 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!( @@ -4494,7 +4395,7 @@ impl ComponentState { instance_index: u32, name: &str, types: &'a TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result<&'a EntityType> { match types[self.core_instance_at(instance_index, offset)?] .internal_exports(types) @@ -4508,28 +4409,28 @@ impl ComponentState { } } - fn global_at(&self, idx: u32, offset: LogicalOffset) -> 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: LogicalOffset) -> 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: LogicalOffset) -> 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: LogicalOffset) -> 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"), @@ -4541,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: LogicalOffset) -> 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, @@ -4572,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: LogicalOffset) -> 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, @@ -4665,7 +4566,7 @@ impl ComponentState { Ok(ty) } - fn check_value_support(&self, offset: LogicalOffset) -> Result<()> { + fn check_value_support(&self, offset: u64) -> Result<()> { require_feature::cm_values( self.features, "support for component model `value`s is not enabled", @@ -4674,11 +4575,7 @@ impl ComponentState { Ok(()) } - fn check_primitive_type( - &self, - ty: crate::PrimitiveValType, - offset: LogicalOffset, - ) -> Result<()> { + fn check_primitive_type(&self, ty: crate::PrimitiveValType, offset: u64) -> Result<()> { if ty == crate::PrimitiveValType::ErrorContext { require_feature::cm_error_context( self.features, @@ -4699,7 +4596,7 @@ impl InternRecGroup for ComponentState { self.core_types.push(ComponentCoreTypeId::Sub(id)); } - fn type_id_at(&self, idx: u32, offset: LogicalOffset) -> 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(_) => { @@ -4731,7 +4628,7 @@ impl ComponentNameContext { kind: ExternKind, ty: &ComponentEntityType, types: &TypeAlloc, - offset: LogicalOffset, + offset: u64, kind_names: &mut IndexSet, items: &mut IndexMap, info: &mut TypeInfo, @@ -4858,7 +4755,7 @@ impl ComponentNameContext { version_suffix: Option<&str>, ty: &ComponentEntityType, types: &TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { let func = || { let id = match ty { @@ -4969,7 +4866,7 @@ impl ComponentNameContext { &self, id: AliasableResourceId, name: KebabStr<'_>, - offset: LogicalOffset, + 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 10d62d1d8d..c619cb7f2e 100644 --- a/crates/wasmparser/src/validator/component_types.rs +++ b/crates/wasmparser/src/validator/component_types.rs @@ -2,7 +2,6 @@ use super::component::ExternKind; use super::{CanonicalOptions, Concurrency}; -use crate::offsets::LogicalOffset; use crate::validator::StringEncoding; use crate::validator::component::PtrSize; use crate::validator::names::KebabString; @@ -138,7 +137,7 @@ impl PrimitiveValType { types: &TypeList, _abi: Abi, options: &CanonicalOptions, - offset: LogicalOffset, + offset: u64, core: ArgOrField, ) -> Result<()> { match (self, core) { @@ -760,7 +759,7 @@ impl ComponentValType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: LogicalOffset, + offset: u64, core: ArgOrField, ) -> Result<()> { match self { @@ -1201,7 +1200,7 @@ pub(crate) enum LoweredFuncType { } impl LoweredFuncType { - pub(crate) fn intern(self, types: &mut TypeAlloc, offset: LogicalOffset) -> 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, @@ -1217,7 +1216,7 @@ impl ComponentFuncType { types: &TypeList, options: &CanonicalOptions, abi: Abi, - offset: LogicalOffset, + offset: u64, ) -> Result { let mut sig = LoweredSignature::default(); @@ -1336,7 +1335,7 @@ impl ComponentFuncType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: LogicalOffset, + offset: u64, ) -> Result { let core_type_id = options.core_type.unwrap(); let core_func_ty = types[core_type_id].unwrap_func(); @@ -1395,7 +1394,7 @@ impl RecordType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: LogicalOffset, + offset: u64, core: ArgOrField, ) -> Result<()> { lower_gc_product_type( @@ -1425,7 +1424,7 @@ impl VariantType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: LogicalOffset, + offset: u64, core: ArgOrField, ) -> Result<()> { lower_gc_sum_type(types, abi, options, offset, core, "variant") @@ -1438,7 +1437,7 @@ fn lower_gc_sum_type( types: &TypeList, _abi: Abi, _options: &CanonicalOptions, - offset: LogicalOffset, + offset: u64, core: ArgOrField, kind: &str, ) -> Result<()> { @@ -1472,7 +1471,7 @@ impl TupleType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: LogicalOffset, + offset: u64, core: ArgOrField, ) -> Result<()> { lower_gc_product_type( @@ -1733,7 +1732,7 @@ impl ComponentDefinedType { types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: LogicalOffset, + offset: u64, core: ArgOrField, ) -> Result<()> { match self { @@ -1835,7 +1834,7 @@ fn lower_gc_product_type<'a, I>( types: &TypeList, abi: Abi, options: &CanonicalOptions, - offset: LogicalOffset, + offset: u64, core: ArgOrField, kind: &str, ) -> core::result::Result<(), Error> @@ -3181,7 +3180,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: &ComponentEntityType, b: &ComponentEntityType, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { use ComponentEntityType::*; @@ -3215,7 +3214,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: ComponentTypeId, b: ComponentTypeId, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { // Components are ... tricky. They follow the same basic // structure as core wasm modules, but they also have extra @@ -3300,7 +3299,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a_id: ComponentInstanceTypeId, b_id: ComponentInstanceTypeId, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { // For instance type subtyping, all exports in the other // instance type must be present in this instance type's @@ -3336,7 +3335,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: ComponentFuncTypeId, b: ComponentFuncTypeId, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { let a = &self.a[a]; let b = &self.b[b]; @@ -3415,7 +3414,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: ComponentCoreModuleTypeId, b: ComponentCoreModuleTypeId, - offset: LogicalOffset, + 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 @@ -3454,7 +3453,7 @@ impl<'a> SubtypeCx<'a> { &mut self, a: ComponentAnyTypeId, b: ComponentAnyTypeId, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { match (a, b) { (ComponentAnyTypeId::Resource(a), ComponentAnyTypeId::Resource(b)) => { @@ -3530,7 +3529,7 @@ impl<'a> SubtypeCx<'a> { a: &IndexMap, b: ComponentTypeId, kind: ExternKind, - offset: LogicalOffset, + offset: u64, ) -> Result { // First, determine the mapping from resources in `b` to those supplied // by arguments in `a`. @@ -3672,12 +3671,7 @@ impl<'a> SubtypeCx<'a> { Ok(mapping) } - pub(crate) fn entity_type( - &self, - a: &EntityType, - b: &EntityType, - offset: LogicalOffset, - ) -> 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)) => { @@ -3716,7 +3710,7 @@ impl<'a> SubtypeCx<'a> { } } - pub(crate) fn table_type(a: &TableType, b: &TableType, offset: LogicalOffset) -> Result<()> { + pub(crate) fn table_type(a: &TableType, b: &TableType, offset: u64) -> Result<()> { if a.element_type != b.element_type { bail!( offset, @@ -3735,7 +3729,7 @@ impl<'a> SubtypeCx<'a> { } } - pub(crate) fn memory_type(a: &MemoryType, b: &MemoryType, offset: LogicalOffset) -> 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") } @@ -3752,7 +3746,7 @@ impl<'a> SubtypeCx<'a> { } } - fn core_func_type(&self, a: CoreTypeId, b: CoreTypeId, offset: LogicalOffset) -> 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) { @@ -3774,7 +3768,7 @@ impl<'a> SubtypeCx<'a> { &self, a: &ComponentValType, b: &ComponentValType, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { match (a, b) { (ComponentValType::Primitive(a), ComponentValType::Primitive(b)) => { @@ -3798,7 +3792,7 @@ impl<'a> SubtypeCx<'a> { &self, a: ComponentDefinedTypeId, b: ComponentDefinedTypeId, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { use ComponentDefinedType::*; @@ -3982,7 +3976,7 @@ impl<'a> SubtypeCx<'a> { &self, a: PrimitiveValType, b: PrimitiveValType, - offset: LogicalOffset, + 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 73c1502a56..cc111ca341 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -12,7 +12,7 @@ use super::{ }; #[cfg(feature = "simd")] use crate::VisitSimdOperator; -use crate::{CompositeInnerType, offsets::LogicalOffset, prelude::*}; +use crate::{CompositeInnerType, prelude::*}; use crate::{ ConstExpr, Data, DataKind, Element, ElementKind, Error, ExternalKind, FrameKind, FrameStack, FuncType, Global, GlobalType, HeapType, MemoryType, RecGroup, RefType, Result, SubType, Table, @@ -58,12 +58,7 @@ impl ModuleState { ((*index - 1) as u32, ty) } - pub fn add_global( - &mut self, - mut global: Global, - types: &TypeList, - offset: LogicalOffset, - ) -> 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: LogicalOffset, - ) -> 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,12 +89,7 @@ impl ModuleState { Ok(()) } - pub fn add_data_segment( - &mut self, - data: Data, - types: &TypeList, - offset: LogicalOffset, - ) -> Result<()> { + pub fn add_data_segment(&mut self, data: Data, types: &TypeList, offset: u64) -> Result<()> { match data.kind { DataKind::Passive => { require_feature::bulk_memory( @@ -128,7 +113,7 @@ impl ModuleState { &mut self, mut e: Element, types: &TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { // the `funcref` value type is allowed all the way back to the MVP, so // don't check it here @@ -230,7 +215,7 @@ impl ModuleState { return Ok(()); struct VisitConstOperator<'a> { - offset: LogicalOffset, + offset: u64, uninserted_funcref: bool, ops: OperatorValidator, resources: OperatorValidatorResources<'a>, @@ -527,7 +512,7 @@ impl Module { &mut self, rec_group: RecGroup, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, check_limit: bool, ) -> Result<()> { if check_limit { @@ -546,7 +531,7 @@ impl Module { &mut self, mut import: crate::Import, types: &TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { let entity = self.check_type_ref(&mut import.ty, types, offset)?; @@ -605,7 +590,7 @@ impl Module { &mut self, name: &str, ty: EntityType, - offset: LogicalOffset, + offset: u64, check_limit: bool, types: &TypeList, ) -> Result<()> { @@ -634,35 +619,25 @@ impl Module { } } - pub fn add_function( - &mut self, - type_index: u32, - types: &TypeList, - offset: LogicalOffset, - ) -> 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: LogicalOffset) -> 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: LogicalOffset) -> 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: LogicalOffset, - ) -> 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]) } @@ -671,7 +646,7 @@ impl Module { &self, type_index: u32, types: &'a TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result<&'a FuncType> { match &self .sub_type_at(types, type_index, offset)? @@ -687,7 +662,7 @@ impl Module { &self, type_ref: &mut TypeRef, types: &TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result { Ok(match type_ref { TypeRef::Func(type_index) => { @@ -717,12 +692,7 @@ impl Module { }) } - fn check_table_type( - &self, - ty: &mut TableType, - types: &TypeList, - offset: LogicalOffset, - ) -> 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 { @@ -768,7 +738,7 @@ impl Module { Ok(()) } - fn check_memory_type(&self, ty: &MemoryType, offset: LogicalOffset) -> Result<()> { + fn check_memory_type(&self, ty: &MemoryType, offset: u64) -> Result<()> { self.check_limits(ty.initial, ty.maximum, offset)?; if ty.memory64 { @@ -829,7 +799,7 @@ impl Module { #[cfg(feature = "component-model")] pub(crate) fn imports_for_module_type( &self, - offset: LogicalOffset, + 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 @@ -848,7 +818,7 @@ impl Module { .collect::>() } - fn check_value_type(&self, ty: &mut ValType, offset: LogicalOffset) -> 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 { @@ -857,7 +827,7 @@ impl Module { } } - fn check_ref_type(&self, ty: &mut RefType, offset: LogicalOffset) -> 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)?; @@ -865,7 +835,7 @@ impl Module { Ok(()) } - fn check_heap_type(&self, ty: &mut HeapType, offset: LogicalOffset) -> 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(()), @@ -884,7 +854,7 @@ impl Module { } } - fn check_tag_type(&self, ty: &TagType, types: &TypeList, offset: LogicalOffset) -> 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() { @@ -897,12 +867,7 @@ impl Module { Ok(()) } - fn check_global_type( - &self, - ty: &mut GlobalType, - types: &TypeList, - offset: LogicalOffset, - ) -> 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( @@ -920,7 +885,7 @@ impl Module { Ok(()) } - fn check_limits(&self, initial: T, maximum: Option, offset: LogicalOffset) -> Result<()> + fn check_limits(&self, initial: T, maximum: Option, offset: u64) -> Result<()> where T: Into, { @@ -954,7 +919,7 @@ impl Module { pub fn export_to_entity_type( &mut self, export: &crate::Export, - offset: LogicalOffset, + offset: u64, ) -> Result { let check = |ty: &str, index: u32, total: usize| { if index as usize >= total { @@ -996,7 +961,7 @@ impl Module { &self, func_idx: u32, types: &'a TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result<&'a FuncType> { match self.functions.get(func_idx as usize) { Some(idx) => self.func_type_at(*idx, types, offset), @@ -1007,7 +972,7 @@ impl Module { } } - fn global_at(&self, idx: u32, offset: LogicalOffset) -> 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!( @@ -1017,7 +982,7 @@ impl Module { } } - fn table_at(&self, idx: u32, offset: LogicalOffset) -> 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!( @@ -1027,7 +992,7 @@ impl Module { } } - fn memory_at(&self, idx: u32, offset: LogicalOffset) -> 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!( @@ -1047,7 +1012,7 @@ impl InternRecGroup for Module { self.types.push(id); } - fn type_id_at(&self, idx: u32, offset: LogicalOffset) -> Result { + fn type_id_at(&self, idx: u32, offset: u64) -> Result { self.types .get(idx as usize) .copied() @@ -1100,7 +1065,7 @@ impl WasmModuleResources for OperatorValidatorResources<'_> { self.module.functions.get(at as usize).copied() } - fn check_heap_type(&self, t: &mut HeapType, offset: LogicalOffset) -> Result<()> { + fn check_heap_type(&self, t: &mut HeapType, offset: u64) -> Result<()> { self.module.check_heap_type(t, offset) } @@ -1188,7 +1153,7 @@ impl WasmModuleResources for ValidatorResources { self.0.functions.get(at as usize).copied() } - fn check_heap_type(&self, t: &mut HeapType, offset: LogicalOffset) -> 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 87dfd81d90..4022e5cd02 100644 --- a/crates/wasmparser/src/validator/core/canonical.rs +++ b/crates/wasmparser/src/validator/core/canonical.rs @@ -70,15 +70,13 @@ use super::{RecGroupId, TypeAlloc, TypeList}; use crate::{ CompositeInnerType, CompositeType, Error, PackedIndex, RecGroup, Result, StorageType, - UnpackedIndex, ValType, WasmFeatures, - offsets::LogicalOffset, - require_feature, + UnpackedIndex, ValType, WasmFeatures, require_feature, types::{CoreTypeId, TypeIdentifier}, }; pub(crate) trait InternRecGroup { fn add_type_id(&mut self, id: CoreTypeId); - fn type_id_at(&self, idx: u32, offset: LogicalOffset) -> Result; + fn type_id_at(&self, idx: u32, offset: u64) -> Result; fn types_len(&self) -> u32; fn features(&self) -> &WasmFeatures; @@ -89,7 +87,7 @@ pub(crate) trait InternRecGroup { &mut self, types: &mut TypeAlloc, mut rec_group: RecGroup, - offset: LogicalOffset, + offset: u64, ) -> Result<()> where Self: Sized, @@ -130,7 +128,7 @@ pub(crate) trait InternRecGroup { rec_group: RecGroupId, id: CoreTypeId, types: &mut TypeAlloc, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { let ty = &types[id]; if !ty.is_final || ty.supertype_idx.is_some() { @@ -175,7 +173,7 @@ pub(crate) trait InternRecGroup { rec_group: RecGroupId, id: CoreTypeId, types: &TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { let ty = &types[id].composite_type; if ty.descriptor_idx.is_some() || ty.describes_idx.is_some() { @@ -289,7 +287,7 @@ pub(crate) trait InternRecGroup { &mut self, ty: &CompositeType, types: &TypeList, - offset: LogicalOffset, + offset: u64, ) -> Result<()> { let features = *self.features(); let check = |ty: &ValType, shared: bool| { @@ -392,7 +390,7 @@ pub(crate) trait InternRecGroup { types: &TypeList, rec_group: RecGroupId, index: PackedIndex, - offset: LogicalOffset, + offset: u64, ) -> Result { match index.unpack() { UnpackedIndex::Id(id) => Ok(id), @@ -421,13 +419,13 @@ pub(crate) struct TypeCanonicalizer<'a> { module: &'a dyn InternRecGroup, rec_group_start: u32, rec_group_len: u32, - offset: LogicalOffset, + offset: u64, mode: CanonicalizationMode, within_rec_group: Option>, } impl<'a> TypeCanonicalizer<'a> { - pub fn new(module: &'a dyn InternRecGroup, offset: LogicalOffset) -> 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 abb26eb966..325cfc8735 100644 --- a/crates/wasmparser/src/validator/func.rs +++ b/crates/wasmparser/src/validator/func.rs @@ -1,5 +1,4 @@ use super::operators::{Frame, OperatorValidator, OperatorValidatorAllocations}; -use crate::offsets::LogicalOffset; use crate::{BinaryReader, Result, ValType, VisitOperator}; use crate::{FrameStack, FunctionBody, ModuleArity, Operator, WasmFeatures, WasmModuleResources}; @@ -202,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: LogicalOffset, 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) } @@ -214,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: LogicalOffset, operator: &Operator<'_>) -> Result<()> { + pub fn op(&mut self, offset: u64, operator: &Operator<'_>) -> Result<()> { self.visitor(offset).visit_operator(operator) } @@ -222,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: LogicalOffset, 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() { @@ -254,7 +253,7 @@ arity mismatch in validation /// ``` pub fn visitor<'this, 'a: 'this>( &'this mut self, - offset: LogicalOffset, + offset: u64, ) -> impl VisitOperator<'a, Output = Result<()>> + ModuleArity + FrameStack + 'this { self.validator.with_resources(&self.resources, offset) } @@ -265,7 +264,7 @@ arity mismatch in validation #[cfg(feature = "simd")] pub fn simd_visitor<'this, 'a: 'this>( &'this mut self, - offset: LogicalOffset, + offset: u64, ) -> impl crate::VisitSimdOperator<'a, Output = Result<()>> + ModuleArity + 'this { self.validator.with_resources_simd(&self.resources, offset) } @@ -398,7 +397,7 @@ mod tests { fn type_index_of_function(&self, _at: u32) -> Option { todo!() } - fn check_heap_type(&self, _t: &mut HeapType, _offset: LogicalOffset) -> Result<()> { + fn check_heap_type(&self, _t: &mut HeapType, _offset: u64) -> Result<()> { Ok(()) } fn top_type(&self, _heap_type: &HeapType) -> HeapType { @@ -486,9 +485,7 @@ mod tests { op.operator_arity(&func_validator) .expect("valid operators should have arity"), ); - func_validator - .op(LogicalOffset::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 9ec07d2d25..688803acce 100644 --- a/crates/wasmparser/src/validator/names.rs +++ b/crates/wasmparser/src/validator/names.rs @@ -1,7 +1,6 @@ //! Definitions of name-related helpers and newtypes, primarily for the //! component model. -use crate::offsets::LogicalOffset; use crate::prelude::*; use crate::{Result, WasmFeatures}; use core::cmp::Ordering; @@ -283,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: LogicalOffset) -> Result { + pub fn new(name: &str, offset: u64) -> Result { Self::new_with_features(name, offset, WasmFeatures::default()) } @@ -292,11 +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: LogicalOffset, - features: WasmFeatures, - ) -> Result { + pub fn new_with_features(name: &str, offset: u64, features: WasmFeatures) -> Result { let mut parser = ComponentNameParser { next: name, offset, @@ -586,7 +581,7 @@ impl<'a> HashName<'a> { // for error messages. struct ComponentNameParser<'a> { next: &'a str, - offset: LogicalOffset, + offset: u64, features: WasmFeatures, } diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index 0416deb8d3..dbf19c8aa4 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -25,7 +25,6 @@ #[cfg(feature = "simd")] use crate::VisitSimdOperator; use crate::features::require_feature; -use crate::offsets::LogicalOffset; use crate::{ AbstractHeapType, BlockType, BrTable, Catch, ContType, Error, FieldType, FrameKind, FrameStack, FuncType, GlobalType, Handle, HeapType, Ieee32, Ieee64, MemArg, ModuleArity, RefType, Result, @@ -234,7 +233,7 @@ pub struct Frame { } struct OperatorValidatorTemp<'validator, 'resources, T> { - offset: LogicalOffset, + offset: u64, inner: &'validator mut OperatorValidator, resources: &'resources T, } @@ -386,7 +385,7 @@ impl OperatorValidator { /// `ty`. pub fn new_func( ty: u32, - offset: LogicalOffset, + offset: u64, features: &WasmFeatures, resources: &T, allocs: OperatorValidatorAllocations, @@ -451,7 +450,7 @@ impl OperatorValidator { pub fn define_locals( &mut self, - offset: LogicalOffset, + offset: u64, count: u32, mut ty: ValType, resources: &impl WasmModuleResources, @@ -513,7 +512,7 @@ impl OperatorValidator { pub fn with_resources<'a, 'validator, 'resources, T>( &'validator mut self, resources: &'resources T, - offset: LogicalOffset, + offset: u64, ) -> impl VisitOperator<'a, Output = Result<()>> + ModuleArity + FrameStack + 'validator where T: WasmModuleResources, @@ -532,7 +531,7 @@ impl OperatorValidator { pub fn with_resources_simd<'a, 'validator, 'resources, T>( &'validator mut self, resources: &'resources T, - offset: LogicalOffset, + 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 83e0f71434..e314dde621 100644 --- a/crates/wasmparser/src/validator/types.rs +++ b/crates/wasmparser/src/validator/types.rs @@ -1,7 +1,6 @@ //! Types relating to type information provided by validation. use super::core::Module; -use crate::offsets::LogicalOffset; #[cfg(feature = "component-model")] use crate::validator::component::ComponentState; #[cfg(feature = "component-model")] @@ -262,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: LogicalOffset) -> 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(); @@ -995,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: LogicalOffset) -> 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 @@ -1003,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: LogicalOffset) -> CoreTypeId { + pub fn intern_func_type(&mut self, ty: FuncType, offset: u64) -> CoreTypeId { self.intern_sub_type(SubType::func(ty, false), offset) } @@ -1012,7 +1011,7 @@ impl TypeList { &self, rec_group: RecGroupId, index: u32, - offset: LogicalOffset, + offset: u64, ) -> Result { let elems = &self[rec_group]; let len = elems.end.index() - elems.start.index(); @@ -1069,7 +1068,7 @@ impl TypeList { &self, rec_group: RecGroupId, index: PackedIndex, - offset: LogicalOffset, + offset: u64, ) -> Result { self.at_canonicalized_unpacked_index(rec_group, index.unpack(), offset) } @@ -1081,7 +1080,7 @@ impl TypeList { &self, rec_group: RecGroupId, index: UnpackedIndex, - offset: LogicalOffset, + offset: u64, ) -> Result { match index { UnpackedIndex::Module(_) => panic!("not canonicalized"), @@ -1152,7 +1151,7 @@ impl TypeList { if let Some(id) = index.as_core_type_id() { id } else { - self.at_canonicalized_unpacked_index(group.unwrap(), index, LogicalOffset::MAX) + self.at_canonicalized_unpacked_index(group.unwrap(), index, u64::MAX) .expect("type references are checked during canonicalization") } }; From 5cf46076ff28b5f22ede76b868e2a7c91b53d741 Mon Sep 17 00:00:00 2001 From: Martin Molzer Date: Tue, 21 Jul 2026 09:00:41 +0200 Subject: [PATCH 03/10] self-review to simplify logic slightly --- crates/wasmparser/src/binary_reader.rs | 24 ++++- crates/wasmparser/src/offsets.rs | 127 ++++++++++--------------- crates/wasmparser/src/parser.rs | 10 +- 3 files changed, 76 insertions(+), 85 deletions(-) diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 2476966725..1b94c0a450 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -58,7 +58,7 @@ impl<'a> BinaryReader<'a> { pub fn new(data: &[u8], original_offset: u64) -> BinaryReader<'_> { BinaryReader { buffer: data, - position: MemOffset::zero_at(original_offset, data.len()), + position: MemOffset::zero(), original_offset, #[cfg(feature = "features")] features: WasmFeatures::all(), @@ -103,7 +103,7 @@ impl<'a> BinaryReader<'a> { ) -> BinaryReader<'_> { BinaryReader { buffer: data, - position: MemOffset::zero_at(original_offset, data.len()), + position: MemOffset::zero(), original_offset, features, } @@ -124,7 +124,7 @@ impl<'a> BinaryReader<'a> { let original_offset = self.original_offset + self.position; BinaryReader { buffer, - position: MemOffset::zero_at(original_offset, buffer.len()), + position: MemOffset::zero(), original_offset, #[cfg(feature = "features")] features: self.features, @@ -179,6 +179,7 @@ impl<'a> BinaryReader<'a> { } } + /// Returns the MemOffset past `len` bytes on success pub(crate) fn ensure_has_bytes(&self, len: usize) -> Result { match self.position.try_add(len, self.max_offset()) { Ok(end) => Ok(end), @@ -422,7 +423,7 @@ impl<'a> BinaryReader<'a> { let original_offset = self.original_offset + start; ret.buffer = buffer; ret.original_offset = original_offset; - ret.position = MemOffset::zero_at(original_offset, buffer.len()); + ret.position = MemOffset::zero(); Ok(ret) } @@ -2006,3 +2007,18 @@ impl<'a> BinaryReader<'a> { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[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" + ); + } +} diff --git a/crates/wasmparser/src/offsets.rs b/crates/wasmparser/src/offsets.rs index 36fa6fa341..849114e48d 100644 --- a/crates/wasmparser/src/offsets.rs +++ b/crates/wasmparser/src/offsets.rs @@ -20,97 +20,82 @@ //! 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::{ - num::TryFromIntError, - ops::{Add, AddAssign}, -}; +use core::ops::{Add, AddAssign}; -// TODO: on platforms where usize::BITS > u64::BITS (currently almost no-where), -// this could wrap a u64 instead of a usize to be a bit smaller. -#[derive(Clone, Copy, Debug, Hash)] -pub struct MemOffset { - rep: usize, - #[cfg(debug_assertions)] - max: usize, -} +// 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. -impl PartialEq for MemOffset { - fn eq(&self, other: &Self) -> bool { - self.rep == other.rep +/// Compute the maximum allowable memory offset under both contraints +fn max_memory_offset(mut max_logical: u64, max: usize) -> usize { + if u64::BITS > usize::BITS { + max_logical = max_logical.max(usize::MAX as u64) } -} + // we now know that max_logical fits into a usize + let max_logical = max_logical as usize; -impl PartialOrd for MemOffset { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) + // 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) } } -impl Eq for MemOffset {} -impl Ord for MemOffset { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.rep.cmp(&other.rep) - } +// TODO: on platforms where usize::BITS > u64::BITS (currently almost no-where), +// this could wrap a u64 instead of a usize to be a bit smaller. +/// An offset into some chunk of memory at some specified logical offset in +/// the file. +/// +/// The represented offset can always be converted into a `usize`, and can +/// always be added to the logical offset without overflow. +/// +/// The other function of this newtype is to allow `u64: Add` and +/// `MemOffset: Add` without confusing the two notions of offsets. +/// +/// We explicitly do not have `MemOffset: From` as not all offsets are +/// valid at all offsets. +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct MemOffset { + rep: usize, } impl MemOffset { pub fn max(max_logical: u64, max: usize) -> Self { - let max_len_logical = max_logical; - let max_len = if u64::BITS > usize::BITS { - let max_len_usize = usize::MAX as u64; - // this now fits into a usize - max_len_logical.max(max_len_usize) as usize - } else { - // since usize seems to have more or equal bits, this fits always. - max_len_logical as usize - }; - let max_len = max_len.min(max); Self { - rep: max_len, - #[cfg(debug_assertions)] - max: max_len, + rep: max_memory_offset(max_logical, max), } } - pub fn zero_at(logical: u64, max: usize) -> Self { - Self::try_from(logical, 0, max).unwrap() - } - pub fn try_from(logical: u64, mem: usize, max: usize) -> Result { - let max = Self::max(u64::MAX - logical, max).into_usize(); - if mem <= max { - Ok(Self { - rep: mem, - #[cfg(debug_assertions)] - max, - }) - } else { - Err(u32::try_from(u64::MAX).unwrap_err()) - } + pub fn zero() -> Self { + // 0 is always a valid offset + Self { rep: 0 } } pub fn into_usize(self) -> usize { self.into() } pub fn try_add(self, additional: usize, max: MemOffset) -> Result { - #[cfg(debug_assertions)] - { - assert!( - self.max == max.max, - "self and max should be form the same memory extent" - ); - } let remaining = max.into_usize().strict_sub(self.into_usize()); if remaining < additional { Err(additional - remaining) } else { Ok(Self { rep: self.rep + additional, - #[cfg(debug_assertions)] - max: self.max, }) } } // convinience method we should put on u64, but can't since inherent impls are not allowed there - pub fn logical_try_add(logical: u64, additional: u32) -> Option { - logical.checked_add(additional as u64) + pub fn logical_try_add_u32(logical: u64, additional: u32, max_logical: u64) -> Option { + let summed = logical.checked_add(additional as u64)?; + (summed <= max_logical).then_some(summed) } } @@ -125,7 +110,7 @@ impl Add for u64 { fn add(self, rhs: MemOffset) -> Self::Output { debug_assert!( rhs <= MemOffset::max(u64::MAX - self, usize::MAX), - "offset too large" + "offset too large", ); self.strict_add(rhs.rep as u64) } @@ -140,21 +125,9 @@ impl AddAssign for u64 { impl Add for MemOffset { type Output = MemOffset; fn add(self, rhs: usize) -> Self::Output { - let sum = if cfg!(debug_assertions) { - self.rep.checked_add(rhs).expect("shouldn't overflow") - } else { - self.rep.strict_add(rhs) - }; - #[cfg(debug_assertions)] - { - if sum > self.max { - panic!("unexpectedly large offset"); - } - } + debug_assert!(rhs <= (usize::MAX - self.rep), "offset too large",); Self { - rep: sum, - #[cfg(debug_assertions)] - max: self.max, + rep: self.rep.strict_add(rhs), } } } diff --git a/crates/wasmparser/src/parser.rs b/crates/wasmparser/src/parser.rs index 301f43de5f..7a4c14e666 100644 --- a/crates/wasmparser/src/parser.rs +++ b/crates/wasmparser/src/parser.rs @@ -743,10 +743,12 @@ 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 section_end = match MemOffset::logical_try_add(reader.original_position(), len) - { - Some(section_end) if section_end <= self.max_offset => section_end, - _ => return Err(Error::new("section too large", len_pos)), + let Some(section_end) = MemOffset::logical_try_add_u32( + reader.original_position(), + len, + self.max_offset, + ) else { + return Err(Error::new("section too large", len_pos)); }; match (self.encoding, id) { From e8fe38c630387adfc84dca55f085c5d1fc0d1549 Mon Sep 17 00:00:00 2001 From: Martin Molzer Date: Tue, 21 Jul 2026 09:44:51 +0200 Subject: [PATCH 04/10] convert wasmprinter and wasm-encoder --- crates/wasm-encoder/src/core/code.rs | 5 +- crates/wasm-encoder/src/reencode.rs | 8 +- crates/wasm-encoder/src/reencode/component.rs | 7 +- crates/wasmparser/src/binary_reader.rs | 6 ++ crates/wasmparser/src/lib.rs | 1 + crates/wasmparser/src/offsets.rs | 98 ++++++++++++++++++- crates/wasmprinter/src/component.rs | 4 +- crates/wasmprinter/src/lib.rs | 28 +++--- crates/wasmprinter/src/operator.rs | 20 ++-- crates/wasmprinter/src/print.rs | 4 +- 10 files changed, 145 insertions(+), 36 deletions(-) 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/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 1b94c0a450..45f1f2c83f 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -2021,4 +2021,10 @@ mod tests { "unexpected end-of-file" ); } + + #[test] + fn can_parse_on_large_offset() { + let mut rdr = BinaryReader::new(&[10], u32::MAX as u64 + 1); + assert_matches!(rdr.read_u8(), Ok(10)); + } } diff --git a/crates/wasmparser/src/lib.rs b/crates/wasmparser/src/lib.rs index f90265ca2b..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::*; diff --git a/crates/wasmparser/src/offsets.rs b/crates/wasmparser/src/offsets.rs index 849114e48d..f56161695b 100644 --- a/crates/wasmparser/src/offsets.rs +++ b/crates/wasmparser/src/offsets.rs @@ -20,7 +20,7 @@ //! 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::{Add, AddAssign}; +use core::ops::{Add, AddAssign, Bound, Deref, Index, Range, RangeBounds}; // An (not necessarily exhaustive) list of properties we use of `u64` in relation // to usize: @@ -137,3 +137,99 @@ impl AddAssign for MemOffset { *self = *self + rhs } } + +/// 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)] +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"), + } + } +} + +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!(std::ops::RangeInclusive); +impl_index!(std::ops::Range); +impl_index!(std::ops::RangeFrom); +impl_index!(std::ops::RangeTo); +impl_index!(std::ops::RangeToInclusive); +impl_index!(std::ops::RangeFull); 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); From 77ab11e8350057f14eb219132b9a3258cb9a0e94 Mon Sep 17 00:00:00 2001 From: Martin Molzer Date: Tue, 21 Jul 2026 10:16:11 +0200 Subject: [PATCH 05/10] convert wasm-metadata, wasm-mutate, wast (tests) --- crates/wasm-metadata/src/add_metadata.rs | 3 +- crates/wasm-metadata/src/metadata.rs | 2 +- crates/wasm-metadata/src/names/component.rs | 2 +- crates/wasm-metadata/src/names/module.rs | 2 +- crates/wasm-metadata/src/payload.rs | 10 ++-- crates/wasm-metadata/src/producers.rs | 6 +-- crates/wasm-metadata/src/rewrite.rs | 4 +- crates/wasm-mutate/src/info.rs | 40 ++++++++-------- crates/wasm-mutate/src/mutators.rs | 2 +- crates/wasm-mutate/src/mutators/codemotion.rs | 12 +++-- .../src/mutators/codemotion/if_complement.rs | 7 +-- .../wasm-mutate/src/mutators/codemotion/ir.rs | 18 ++++---- .../src/mutators/codemotion/loop_unrolling.rs | 46 ++++++++++++++----- crates/wasm-mutate/src/mutators/peephole.rs | 4 +- .../src/mutators/peephole/eggsy/encoder.rs | 6 ++- .../wasm-mutate/src/mutators/remove_item.rs | 2 +- crates/wasmparser/src/offsets.rs | 13 +++++- crates/wast/tests/annotations.rs | 2 +- 18 files changed, 111 insertions(+), 70 deletions(-) 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/offsets.rs b/crates/wasmparser/src/offsets.rs index f56161695b..47b2cffef0 100644 --- a/crates/wasmparser/src/offsets.rs +++ b/crates/wasmparser/src/offsets.rs @@ -20,7 +20,10 @@ //! 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::{Add, AddAssign, Bound, Deref, Index, Range, RangeBounds}; +use core::{ + ops::{Add, AddAssign, Bound, Deref, Index, Range, RangeBounds}, + u64, +}; // An (not necessarily exhaustive) list of properties we use of `u64` in relation // to usize: @@ -141,7 +144,7 @@ impl AddAssign for MemOffset { /// 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)] +#[derive(Clone, Copy, Debug, Default)] pub struct InMemData<'a> { /// The contained data pub data: &'a [u8], @@ -206,6 +209,12 @@ impl<'a> InMemData<'a> { (Bound::Excluded(_), _) => unreachable!("unsupported excluded start bound"), } } + /// Get a range representing the data range. + pub fn range(&self) -> Range { + let start = 0; + let end = start + MemOffset::max(u64::MAX, self.data.len()); + start..end + } } impl Deref for InMemData<'_> { 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()), } From af69edf16f31dd5c34bc3d55776aba82d0df7b1b Mon Sep 17 00:00:00 2001 From: Martin Molzer Date: Tue, 21 Jul 2026 10:37:39 +0200 Subject: [PATCH 06/10] fix msrv issue --- crates/wasmparser/src/offsets.rs | 9 ++++++--- crates/wit-component/src/encoding/dedupe.rs | 7 ++++--- crates/wit-component/src/metadata.rs | 10 ++++++---- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/crates/wasmparser/src/offsets.rs b/crates/wasmparser/src/offsets.rs index 47b2cffef0..1503b8be01 100644 --- a/crates/wasmparser/src/offsets.rs +++ b/crates/wasmparser/src/offsets.rs @@ -86,7 +86,8 @@ impl MemOffset { self.into() } pub fn try_add(self, additional: usize, max: MemOffset) -> Result { - let remaining = max.into_usize().strict_sub(self.into_usize()); + // MSRV: This could be a strict sub + let remaining = max.into_usize() - self.into_usize(); if remaining < additional { Err(additional - remaining) } else { @@ -115,7 +116,8 @@ impl Add for u64 { rhs <= MemOffset::max(u64::MAX - self, usize::MAX), "offset too large", ); - self.strict_add(rhs.rep as u64) + // MSRV: This could be a strict add + self + (rhs.rep as u64) } } @@ -130,7 +132,8 @@ impl Add for MemOffset { fn add(self, rhs: usize) -> Self::Output { debug_assert!(rhs <= (usize::MAX - self.rep), "offset too large",); Self { - rep: self.rep.strict_add(rhs), + // MSRV: This could be a strict add + rep: self.rep + rhs, } } } 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)?; } } From 018d1e95d3a32963d83698f44ee5a29cb8c4101a Mon Sep 17 00:00:00 2001 From: Martin Molzer Date: Tue, 21 Jul 2026 10:37:57 +0200 Subject: [PATCH 07/10] convert wasm-tools bins and fuzz --- crates/wasmparser/src/binary_reader.rs | 3 +- crates/wasmparser/src/readers/core/custom.rs | 5 +++ fuzz/src/validate.rs | 7 ++-- src/bin/wasm-tools/component.rs | 5 ++- src/bin/wasm-tools/demangle.rs | 3 +- src/bin/wasm-tools/dump.rs | 41 ++++++++++---------- src/bin/wasm-tools/metadata.rs | 4 +- src/bin/wasm-tools/objdump.rs | 10 ++--- src/bin/wasm-tools/strip.rs | 3 +- src/bin/wasm-tools/validate.rs | 2 +- 10 files changed, 46 insertions(+), 37 deletions(-) diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 45f1f2c83f..9ae6e15ad7 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -163,7 +163,8 @@ impl<'a> BinaryReader<'a> { &self.buffer[self.position.into_usize()..] } - pub(crate) fn remaining_range(&self) -> Range { + /// 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()) } diff --git a/crates/wasmparser/src/readers/core/custom.rs b/crates/wasmparser/src/readers/core/custom.rs index 8fef4913ed..491ebc7970 100644 --- a/crates/wasmparser/src/readers/core/custom.rs +++ b/crates/wasmparser/src/readers/core/custom.rs @@ -32,6 +32,11 @@ 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. 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/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..e919f1d179 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, "-| ... {} bytes of data", len)?; + 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..275fcc41cf 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<()> { 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..af3362e196 100644 --- a/src/bin/wasm-tools/validate.rs +++ b/src/bin/wasm-tools/validate.rs @@ -175,7 +175,7 @@ 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; From 23919076e7d759f7a81868911dc966d1c67d82e0 Mon Sep 17 00:00:00 2001 From: Martin Molzer Date: Tue, 21 Jul 2026 11:53:02 +0200 Subject: [PATCH 08/10] fix some lints and self-review --- crates/wasmparser/src/binary_reader.rs | 9 ++++ crates/wasmparser/src/offsets.rs | 14 +++--- crates/wasmparser/src/parser.rs | 63 +++++++++++++++----------- src/addr2line.rs | 6 +-- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 9ae6e15ad7..87ca18ff0d 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -2013,6 +2013,15 @@ impl<'a> BinaryReader<'a> { 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); diff --git a/crates/wasmparser/src/offsets.rs b/crates/wasmparser/src/offsets.rs index 1503b8be01..17efb79916 100644 --- a/crates/wasmparser/src/offsets.rs +++ b/crates/wasmparser/src/offsets.rs @@ -35,7 +35,7 @@ use core::{ /// Compute the maximum allowable memory offset under both contraints fn max_memory_offset(mut max_logical: u64, max: usize) -> usize { if u64::BITS > usize::BITS { - max_logical = max_logical.max(usize::MAX as u64) + 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; @@ -239,9 +239,9 @@ macro_rules! impl_index { }; } -impl_index!(std::ops::RangeInclusive); -impl_index!(std::ops::Range); -impl_index!(std::ops::RangeFrom); -impl_index!(std::ops::RangeTo); -impl_index!(std::ops::RangeToInclusive); -impl_index!(std::ops::RangeFull); +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 7a4c14e666..79a0a54c87 100644 --- a/crates/wasmparser/src/parser.rs +++ b/crates/wasmparser/src/parser.rs @@ -622,6 +622,7 @@ impl Parser { /// # parse(&b"\0asm\x01\0\0\0"[..]).unwrap(); /// ``` pub fn parse<'a>(&mut self, data: &'a [u8], eof: bool) -> Result> { + debug_assert!(self.offset <= self.max_offset, "inverted offset range"); let max_len = MemOffset::max(self.max_offset - self.offset, data.len()).into_usize(); let (data, eof) = if max_len < data.len() { (&data[..max_len], true) @@ -743,12 +744,14 @@ 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 Some(section_end) = MemOffset::logical_try_add_u32( - reader.original_position(), - len, - self.max_offset, - ) else { - return Err(Error::new("section too large", len_pos)); + let section_start = reader.original_position(); + let Some(section_end) = + MemOffset::logical_try_add_u32(section_start, len, self.max_offset) + else { + return Err(Error::new( + &format!("section too large, {len} goes past 0x{:x}", self.max_offset), + len_pos, + )); }; match (self.encoding, id) { @@ -757,15 +760,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()), @@ -774,37 +777,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())?; + 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..section_end; + self.check_function_code_counts(section_start)?; + let range = section_start..section_end; self.state = State::FunctionBody { remaining: count, len, @@ -816,7 +818,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()), @@ -826,13 +828,13 @@ impl Parser { Ok(s) } (Encoding::Module, DATA_COUNT_SECTION) => { - self.update_order(Order::DataCount, reader.original_position())?; + 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) } @@ -844,13 +846,20 @@ impl Parser { 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()..section_end; + 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(reader.original_position()); + let mut parser = Parser::new(section_start); #[cfg(feature = "features")] { parser.features = self.features; @@ -858,11 +867,11 @@ impl Parser { 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, }, 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); } } From 8c251e028d7246c96b22313de0e945c3def61155 Mon Sep 17 00:00:00 2001 From: Martin Molzer Date: Tue, 21 Jul 2026 12:04:41 +0200 Subject: [PATCH 09/10] fix clippy lints and adjust test on error message --- crates/wasmparser/src/parser.rs | 8 +++++--- src/bin/wasm-tools/dump.rs | 2 +- src/bin/wasm-tools/metadata.rs | 2 +- src/bin/wasm-tools/validate.rs | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/wasmparser/src/parser.rs b/crates/wasmparser/src/parser.rs index 79a0a54c87..c0fb7799bb 100644 --- a/crates/wasmparser/src/parser.rs +++ b/crates/wasmparser/src/parser.rs @@ -1910,9 +1910,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/src/bin/wasm-tools/dump.rs b/src/bin/wasm-tools/dump.rs index e919f1d179..c22fbd332e 100644 --- a/src/bin/wasm-tools/dump.rs +++ b/src/bin/wasm-tools/dump.rs @@ -629,7 +629,7 @@ impl<'a> Dump<'a> { write!(self.dst, "---")?; } let len = InMemData::range_len(&range); - writeln!(self.dst, "-| ... {} bytes of data", len)?; + writeln!(self.dst, "-| ... {len} bytes of data")?; self.cur = range.end; } None => { diff --git a/src/bin/wasm-tools/metadata.rs b/src/bin/wasm-tools/metadata.rs index 275fcc41cf..22043bdae7 100644 --- a/src/bin/wasm-tools/metadata.rs +++ b/src/bin/wasm-tools/metadata.rs @@ -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/validate.rs b/src/bin/wasm-tools/validate.rs index af3362e196..64fa68ee4a 100644 --- a/src/bin/wasm-tools/validate.rs +++ b/src/bin/wasm-tools/validate.rs @@ -179,7 +179,7 @@ impl Opts { ) -> 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), }; From e0533e04bbcc8857dc9747d13c7e4e01b1fccf13 Mon Sep 17 00:00:00 2001 From: Martin Molzer Date: Fri, 24 Jul 2026 19:59:15 +0200 Subject: [PATCH 10/10] remove and inline MemOffset structure by review --- crates/wasmparser/src/binary_reader.rs | 70 ++++++++--------- crates/wasmparser/src/offsets.rs | 105 +++---------------------- crates/wasmparser/src/parser.rs | 19 +++-- 3 files changed, 54 insertions(+), 140 deletions(-) diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 87ca18ff0d..555cd728ab 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -26,7 +26,7 @@ pub(crate) const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm"; #[derive(Clone, Debug, Hash)] pub struct BinaryReader<'a> { buffer: &'a [u8], - position: MemOffset, + position: usize, original_offset: u64, // When the `features` feature is disabled then the `WasmFeatures` type @@ -56,9 +56,10 @@ impl<'a> BinaryReader<'a> { /// 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: u64) -> BinaryReader<'_> { + let max_len = max_memory_offset(u64::MAX - original_offset, data.len()); BinaryReader { - buffer: data, - position: MemOffset::zero(), + buffer: &data[..max_len], + position: 0, original_offset, #[cfg(feature = "features")] features: WasmFeatures::all(), @@ -101,9 +102,10 @@ impl<'a> BinaryReader<'a> { original_offset: u64, features: WasmFeatures, ) -> BinaryReader<'_> { + let max_len = max_memory_offset(u64::MAX - original_offset, data.len()); BinaryReader { - buffer: data, - position: MemOffset::zero(), + buffer: &data[..max_len], + position: 0, original_offset, features, } @@ -120,11 +122,11 @@ 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.into_usize()..]; - let original_offset = self.original_offset + self.position; + let buffer = &self.buffer[self.position..]; + let original_offset = self.original_position(); BinaryReader { buffer, - position: MemOffset::zero(), + position: 0, original_offset, #[cfg(feature = "features")] features: self.features, @@ -134,7 +136,7 @@ impl<'a> BinaryReader<'a> { /// Gets the original position of the binary reader. #[inline] pub fn original_position(&self) -> u64 { - self.original_offset + self.position + self.original_offset + self.position as u64 } /// Returns the currently active set of wasm features that this reader is @@ -156,20 +158,22 @@ 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.max_offset()) + self.original_offset..(self.original_offset + self.max_offset() as u64) } pub(crate) fn remaining_buffer(&self) -> &'a [u8] { - &self.buffer[self.position.into_usize()..] + &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()) + self.original_position()..(self.original_offset + self.max_offset() as u64) } - fn max_offset(&self) -> MemOffset { - MemOffset::max(u64::MAX - self.original_offset, self.buffer.len()) + 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<()> { @@ -180,11 +184,12 @@ impl<'a> BinaryReader<'a> { } } - /// Returns the MemOffset past `len` bytes on success - pub(crate) fn ensure_has_bytes(&self, len: usize) -> Result { - match self.position.try_add(len, self.max_offset()) { - Ok(end) => Ok(end), - Err(hint) => Err(self.eof_err(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)), } } @@ -258,22 +263,16 @@ impl<'a> BinaryReader<'a> { self.position >= self.max_offset() } - /// Returns the reader's position as an offset into its data chunk. - #[inline] - pub(crate) fn current_mem_offset(&self) -> MemOffset { - self.position - } - /// Returns the `BinaryReader`'s current position. #[inline] pub fn current_position(&self) -> usize { - self.current_mem_offset().into_usize() + self.position } /// Returns the number of bytes remaining in the `BinaryReader`. #[inline] pub fn bytes_remaining(&self) -> usize { - self.max_offset().into_usize() - self.position.into_usize() + self.max_offset() - self.position } /// Advances the `BinaryReader` `size` bytes, and returns a slice from the @@ -285,7 +284,7 @@ impl<'a> BinaryReader<'a> { let start = self.position; let end = self.ensure_has_bytes(size)?; self.position = end; - Ok(&self.buffer[start.into_usize()..end.into_usize()]) + Ok(&self.buffer[start..end]) } /// Reads a length-prefixed list of bytes from this reader and returns a @@ -417,14 +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(); - let buffer = &self.buffer[start.into_usize()..self.position.into_usize()]; - let original_offset = self.original_offset + start; - ret.buffer = buffer; - ret.original_offset = original_offset; - ret.position = MemOffset::zero(); + ret.buffer = &self.buffer[start..self.position]; + ret.original_offset = start_offset; + ret.position = 0; Ok(ret) } @@ -629,13 +627,13 @@ impl<'a> BinaryReader<'a> { pub(crate) fn peek(&self) -> Result { self.ensure_has_byte()?; - Ok(self.buffer[self.position.into_usize()]) + Ok(self.buffer[self.position]) } pub(crate) fn peek_bytes(&self, len: usize) -> Result<&[u8]> { let start = self.position; let end = self.ensure_has_bytes(len)?; - Ok(&self.buffer[start.into_usize()..end.into_usize()]) + Ok(&self.buffer[start..end]) } pub(crate) fn read_block_type(&mut self) -> Result { @@ -2034,7 +2032,7 @@ mod tests { #[test] fn can_parse_on_large_offset() { - let mut rdr = BinaryReader::new(&[10], u32::MAX as u64 + 1); + let mut rdr = BinaryReader::new(&[10], u64::from(u32::MAX) + 1); assert_matches!(rdr.read_u8(), Ok(10)); } } diff --git a/crates/wasmparser/src/offsets.rs b/crates/wasmparser/src/offsets.rs index 17efb79916..649761f76f 100644 --- a/crates/wasmparser/src/offsets.rs +++ b/crates/wasmparser/src/offsets.rs @@ -21,7 +21,7 @@ //! we can compute a maximally allowed length of data at that offset. use core::{ - ops::{Add, AddAssign, Bound, Deref, Index, Range, RangeBounds}, + ops::{Bound, Deref, Index, Range, RangeBounds}, u64, }; @@ -32,8 +32,14 @@ use core::{ // - 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 -fn max_memory_offset(mut max_logical: u64, max: usize) -> usize { +// 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) } @@ -53,97 +59,6 @@ fn max_memory_offset(mut max_logical: u64, max: usize) -> usize { } } -// TODO: on platforms where usize::BITS > u64::BITS (currently almost no-where), -// this could wrap a u64 instead of a usize to be a bit smaller. -/// An offset into some chunk of memory at some specified logical offset in -/// the file. -/// -/// The represented offset can always be converted into a `usize`, and can -/// always be added to the logical offset without overflow. -/// -/// The other function of this newtype is to allow `u64: Add` and -/// `MemOffset: Add` without confusing the two notions of offsets. -/// -/// We explicitly do not have `MemOffset: From` as not all offsets are -/// valid at all offsets. -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[repr(transparent)] -pub struct MemOffset { - rep: usize, -} - -impl MemOffset { - pub fn max(max_logical: u64, max: usize) -> Self { - Self { - rep: max_memory_offset(max_logical, max), - } - } - pub fn zero() -> Self { - // 0 is always a valid offset - Self { rep: 0 } - } - pub fn into_usize(self) -> usize { - self.into() - } - pub fn try_add(self, additional: usize, max: MemOffset) -> Result { - // MSRV: This could be a strict sub - let remaining = max.into_usize() - self.into_usize(); - if remaining < additional { - Err(additional - remaining) - } else { - Ok(Self { - rep: self.rep + additional, - }) - } - } - // convinience method we should put on u64, but can't since inherent impls are not allowed there - pub fn logical_try_add_u32(logical: u64, additional: u32, max_logical: u64) -> Option { - let summed = logical.checked_add(additional as u64)?; - (summed <= max_logical).then_some(summed) - } -} - -impl From for usize { - fn from(value: MemOffset) -> Self { - value.rep - } -} - -impl Add for u64 { - type Output = u64; - fn add(self, rhs: MemOffset) -> Self::Output { - debug_assert!( - rhs <= MemOffset::max(u64::MAX - self, usize::MAX), - "offset too large", - ); - // MSRV: This could be a strict add - self + (rhs.rep as u64) - } -} - -impl AddAssign for u64 { - fn add_assign(&mut self, rhs: MemOffset) { - *self = *self + rhs - } -} - -impl Add for MemOffset { - type Output = MemOffset; - fn add(self, rhs: usize) -> Self::Output { - debug_assert!(rhs <= (usize::MAX - self.rep), "offset too large",); - Self { - // MSRV: This could be a strict add - rep: self.rep + rhs, - } - } -} - -impl AddAssign for MemOffset { - fn add_assign(&mut self, rhs: usize) { - *self = *self + rhs - } -} - /// Useful datastructure when your input wasm is fully in memory. /// /// Use this to index into it with the offsets and ranges from the parser. @@ -214,9 +129,7 @@ impl<'a> InMemData<'a> { } /// Get a range representing the data range. pub fn range(&self) -> Range { - let start = 0; - let end = start + MemOffset::max(u64::MAX, self.data.len()); - start..end + 0..max_memory_offset(u64::MAX, self.data.len()) as u64 } } diff --git a/crates/wasmparser/src/parser.rs b/crates/wasmparser/src/parser.rs index c0fb7799bb..fb82f8a324 100644 --- a/crates/wasmparser/src/parser.rs +++ b/crates/wasmparser/src/parser.rs @@ -1,7 +1,7 @@ #[cfg(feature = "features")] use crate::WasmFeatures; use crate::binary_reader::WASM_MAGIC_NUMBER; -use crate::offsets::MemOffset; +use crate::offsets; use crate::prelude::*; use crate::{ BinaryReader, CustomSectionReader, DataSectionReader, ElementSectionReader, Error, @@ -623,7 +623,7 @@ impl Parser { /// ``` pub fn parse<'a>(&mut self, data: &'a [u8], eof: bool) -> Result> { debug_assert!(self.offset <= self.max_offset, "inverted offset range"); - let max_len = MemOffset::max(self.max_offset - self.offset, data.len()).into_usize(); + 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 { @@ -637,14 +637,13 @@ 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.current_mem_offset(); - self.offset += 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.into_usize(), + consumed: consumed, payload, }) } @@ -746,7 +745,11 @@ impl Parser { // file. let section_start = reader.original_position(); let Some(section_end) = - MemOffset::logical_try_add_u32(section_start, len, self.max_offset) + 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),