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") } };