Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 64 additions & 60 deletions crates/wasmparser/src/binary_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* limitations under the License.
*/

use crate::offsets::*;
use crate::prelude::*;
use crate::{limits::*, *};
use core::marker;
Expand All @@ -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
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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,
}
Expand All @@ -119,18 +120,20 @@ 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,
}
}

/// 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
}

Expand All @@ -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<usize> {
self.original_offset..self.original_offset + self.buffer.len()
pub fn range(&self) -> Range<LogicalOffset> {
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<LogicalOffset> {
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<MemOffset> {
match self.position.try_add(len, self.max_offset()) {
Ok(end) => Ok(end),
Err(hint) => Err(self.eof_err(hint)),
}
}

Expand All @@ -195,7 +204,7 @@ impl<'a> BinaryReader<'a> {
Ok(b)
}

pub(crate) fn external_kind_from_byte(byte: u8, offset: usize) -> Result<ExternalKind> {
pub(crate) fn external_kind_from_byte(byte: u8, offset: LogicalOffset) -> Result<ExternalKind> {
match byte {
0x00 => Ok(ExternalKind::Func),
0x01 => Ok(ExternalKind::Table),
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -285,27 +300,17 @@ impl<'a> BinaryReader<'a> {
/// # Errors
/// If `BinaryReader` has less than four bytes remaining.
pub fn read_u32(&mut self) -> Result<u32> {
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)
}

/// Advances the `BinaryReader` eight bytes and returns a `u64`.
/// # Errors
/// If `BinaryReader` has less than eight bytes remaining.
pub fn read_u64(&mut self) -> Result<u64> {
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)
}

Expand All @@ -316,17 +321,13 @@ impl<'a> BinaryReader<'a> {
/// If `BinaryReader` has no bytes remaining.
#[inline]
pub fn read_u8(&mut self) -> Result<u8> {
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
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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<u8> {
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<BlockType> {
Expand Down Expand Up @@ -1101,7 +1105,7 @@ impl<'a> BinaryReader<'a> {

fn visit_0xfb_operator<T>(
&mut self,
pos: usize,
pos: LogicalOffset,
visitor: &mut T,
) -> Result<<T as VisitOperator<'a>>::Output>
where
Expand Down Expand Up @@ -1318,7 +1322,7 @@ impl<'a> BinaryReader<'a> {

fn visit_0xfc_operator<T>(
&mut self,
pos: usize,
pos: LogicalOffset,
visitor: &mut T,
) -> Result<<T as VisitOperator<'a>>::Output>
where
Expand Down Expand Up @@ -1399,7 +1403,7 @@ impl<'a> BinaryReader<'a> {
#[cfg(feature = "simd")]
pub(super) fn visit_0xfd_operator<T>(
&mut self,
pos: usize,
pos: LogicalOffset,
visitor: &mut T,
) -> Result<<T as VisitOperator<'a>>::Output>
where
Expand Down Expand Up @@ -1715,7 +1719,7 @@ impl<'a> BinaryReader<'a> {

fn visit_0xfe_operator<T>(
&mut self,
pos: usize,
pos: LogicalOffset,
visitor: &mut T,
) -> Result<<T as VisitOperator<'a>>::Output>
where
Expand Down
17 changes: 9 additions & 8 deletions crates/wasmparser/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::fmt;

use crate::WasmFeatures;
use crate::offsets::LogicalOffset;
use crate::prelude::*;

/// A binary reader for WebAssembly modules.
Expand All @@ -16,7 +17,7 @@ pub struct Error {
pub(crate) struct ErrorInner {
message: String,
kind: ErrorKind,
offset: usize,
offset: LogicalOffset,
needed_hint: Option<usize>,
}

Expand Down Expand Up @@ -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,
Expand All @@ -56,31 +57,31 @@ impl Error {
}

#[cold]
pub(crate) fn new(message: impl Into<String>, offset: usize) -> Self {
pub(crate) fn new(message: impl Into<String>, 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)
}

#[cold]
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
Expand All @@ -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
}

Expand Down
3 changes: 2 additions & 1 deletion crates/wasmparser/src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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(())
Expand Down
1 change: 1 addition & 0 deletions crates/wasmparser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,7 @@ mod binary_reader;
mod error;
mod features;
mod limits;
mod offsets;
mod parser;
mod readers;

Expand Down
Loading
Loading