/// A binary reader for WebAssembly modules. #[derive(Debug, Clone)] pubstruct BinaryReaderError { // Wrap the actual error data in a `Box` so that the error is just one // word. This means that we can continue returning small `Result`s in // registers. pub(crate) inner: Box<BinaryReaderErrorInner>,
}
/// A binary reader of the WebAssembly structures and types. #[derive(Clone, Debug, Hash)] pubstruct BinaryReader<'a> {
buffer: &'a [u8],
position: usize,
original_offset: usize,
// When the `features` feature is disabled then the `WasmFeatures` type // still exists but this field is still omitted. When `features` is // disabled then the only constructor of this type is `BinaryReader::new` // which documents all known features being active. All known features // being active isn't represented by `WasmFeatures` when the feature is // disabled so the field is omitted here to prevent accidentally using the // wrong listing of features. // // Feature accessors are defined by `foreach_wasm_feature!` below with a // method-per-feature on `BinaryReader` which when the `features` feature // is disabled returns `true` by default. #[cfg(feature = "features")]
features: WasmFeatures,
}
impl<'a> BinaryReader<'a> { /// Creates a new binary reader which will parse the `data` provided. /// /// The `original_offset` provided is used for byte offsets in errors that /// are generated. That offset is added to the current position in `data`. /// This can be helpful when `data` is just a window of a view into a larger /// wasm binary perhaps not even entirely stored locally. /// /// 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. pubfn new(data: &[u8], original_offset: usize) -> BinaryReader {
BinaryReader {
buffer: data,
position: 0,
original_offset, #[cfg(feature = "features")]
features: WasmFeatures::all(),
}
}
/// Creates a new binary reader which will parse the `data` provided. /// /// The `original_offset` provided is used for byte offsets in errors that /// are generated. That offset is added to the current position in `data`. /// This can be helpful when `data` is just a window of a view into a larger /// wasm binary perhaps not even entirely stored locally. /// /// The `features` argument provided controls which WebAssembly features are /// active when parsing this data. Wasm features typically don't affect /// parsing too too much and are generally more applicable during /// validation, but features and proposals will often reinterpret /// previously-invalid constructs as now-valid things meaning something /// slightly different. This means that invalid bytes before a feature may /// now be interpreted differently after a feature is implemented. This /// means that the set of activated features can affect what errors are /// generated and when they are generated. /// /// In general it's safe to pass `WasmFeatures::all()` here. There's no /// downside to enabling all features while parsing and only enabling a /// subset of features during validation. /// /// Note that the activated set of features does not guarantee that /// `BinaryReader` will return an error for disabled features. For example /// if SIMD is disabled then SIMD instructions will still be parsed via /// [`BinaryReader::visit_operator`]. Validation must still be performed to /// provide a strict guarantee that if a feature is disabled that a binary /// doesn't leverage the feature. The activated set of features here instead /// only affects locations where preexisting bytes are reinterpreted in /// different ways with future proposals, such as the `memarg` moving from a /// 32-bit offset to a 64-bit offset with the `memory64` proposal. #[cfg(feature = "features")] pubfn new_features(
data: &[u8],
original_offset: usize,
features: WasmFeatures,
) -> BinaryReader {
BinaryReader {
buffer: data,
position: 0,
original_offset,
features,
}
}
/// "Shrinks" this binary reader to retain only the buffer left-to-parse. /// /// The primary purpose of this method is to change the return value of the /// `range()` method. That method returns the range of the original buffer /// within the wasm binary so calling `range()` on the returned /// `BinaryReader` will return a smaller range than if `range()` is called /// on `self`. /// /// Otherwise parsing values from either `self` or the return value should /// return the same thing. pub(crate) fn shrink(&self) -> BinaryReader<'a> {
BinaryReader {
buffer: &self.buffer[self.position..],
position: 0,
original_offset: self.original_offset + self.position, #[cfg(feature = "features")]
features: self.features,
}
}
/// Gets the original position of the binary reader. #[inline] pubfn original_position(&self) -> usize { self.original_offset + self.position
}
/// Returns the currently active set of wasm features that this reader is /// using while parsing. /// /// For more information see [`BinaryReader::new`]. #[cfg(feature = "features")] pubfn features(&self) -> WasmFeatures { self.features
}
/// Sets the wasm features active while parsing to the `features` specified. /// /// For more information see [`BinaryReader::new`]. #[cfg(feature = "features")] pubfn set_features(&mutself, features: WasmFeatures) { self.features = features;
}
/// Returns a range from the starting offset to the end of the buffer. pubfn range(&self) -> Range<usize> { self.original_offset..self.original_offset + self.buffer.len()
}
pub(crate) fn ensure_has_bytes(&self, len: usize) -> Result<()> { ifself.position + len <= self.buffer.len() {
Ok(())
} else { let hint = self.position + len - self.buffer.len();
Err(BinaryReaderError::eof(self.original_position(), hint))
}
}
/// Reads a value of type `T` from this binary reader, advancing the /// internal position in this reader forward as data is read. #[inline] pubfn read<T>(&mutself) -> Result<T> where
T: FromReader<'a>,
{
T::from_reader(self)
}
pub(crate) fn read_u7(&mutself) -> Result<u8> { let b = self.read_u8()?; if (b & 0x80) != 0 { return Err(BinaryReaderError::new( "invalid u7", self.original_position() - 1,
));
}
Ok(b)
}
/// Reads a variable-length 32-bit size from the byte stream while checking /// against a limit. pubfn read_size(&mutself, limit: usize, desc: &str) -> Result<usize> { let pos = self.original_position(); let size = self.read_var_u32()? as usize; if size > limit {
bail!(pos, "{desc} size is out of bounds");
}
Ok(size)
}
/// Reads a variable-length 32-bit size from the byte stream while checking /// against a limit. /// /// Then reads that many values of type `T` and returns them as an iterator. /// /// Note that regardless of how many items are read from the returned /// iterator the items will still be parsed from this reader. pubfn read_iter<'me, T>(
&'me mut self,
limit: usize,
desc: &str,
) -> Result<BinaryReaderIter<'a, 'me, T>> where
T: FromReader<'a>,
{ let size = self.read_size(limit, desc)?;
Ok(BinaryReaderIter {
remaining: size,
reader: self,
_marker: marker::PhantomData,
})
}
fn read_br_table(&mutself) -> Result<BrTable<'a>> { let cnt = self.read_size(MAX_WASM_BR_TABLE_SIZE, "br_table")?; let reader = self.skip(|reader| { for _ in0..cnt {
reader.read_var_u32()?;
}
Ok(())
})?; let default = self.read_var_u32()?;
Ok(BrTable {
reader,
cnt: cnt as u32,
default,
})
}
/// Returns whether the `BinaryReader` has reached the end of the file. #[inline] pubfn eof(&self) -> bool { self.position >= self.buffer.len()
}
/// Returns the `BinaryReader`'s current position. #[inline] pubfn current_position(&self) -> usize { self.position
}
/// Returns the number of bytes remaining in the `BinaryReader`. #[inline] pubfn bytes_remaining(&self) -> usize { self.buffer.len() - self.position
}
/// Advances the `BinaryReader` `size` bytes, and returns a slice from the /// current position of `size` length. /// /// # Errors /// If `size` exceeds the remaining length in `BinaryReader`. pubfn read_bytes(&mutself, size: usize) -> Result<&'a [u8]> { self.ensure_has_bytes(size)?; let start = self.position; self.position += size;
Ok(&self.buffer[start..self.position])
}
/// Reads a length-prefixed list of bytes from this reader and returns a /// new `BinaryReader` to read that list of bytes. pubfn read_reader(&mutself) -> Result<BinaryReader<'a>> { let size = self.read_var_u32()? as usize; self.skip(|reader| {
reader.read_bytes(size)?;
Ok(())
})
}
/// Advances the `BinaryReader` four bytes and returns a `u32`. /// # Errors /// If `BinaryReader` has less than four bytes remaining. pubfn read_u32(&mutself) -> 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;
Ok(word)
}
/// Advances the `BinaryReader` eight bytes and returns a `u64`. /// # Errors /// If `BinaryReader` has less than eight bytes remaining. pubfn read_u64(&mutself) -> 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;
Ok(word)
}
/// Advances the `BinaryReader` a single byte. /// /// # Errors /// /// If `BinaryReader` has no bytes remaining. #[inline] pubfn read_u8(&mutself) -> Result<u8> { let b = matchself.buffer.get(self.position) {
Some(b) => *b,
None => return Err(self.eof_err()),
}; self.position += 1;
Ok(b)
}
/// Advances the `BinaryReader` up to four bytes to parse a variable /// length integer as a `u32`. /// /// # Errors /// /// If `BinaryReader` has less than one or up to four bytes remaining, or /// the integer is larger than 32 bits. #[inline] pubfn read_var_u32(&mutself) -> Result<u32> { // Optimization for single byte i32. let byte = self.read_u8()?; if (byte & 0x80) == 0 {
Ok(u32::from(byte))
} else { self.read_var_u32_big(byte)
}
}
fn read_var_u32_big(&mutself, byte: u8) -> Result<u32> { letmut result = (byte & 0x7F) as u32; letmut shift = 7; loop { let byte = self.read_u8()?;
result |= ((byte & 0x7F) as u32) << shift; if shift >= 25 && (byte >> (32 - shift)) != 0 { let msg = if byte & 0x80 != 0 { "invalid var_u32: integer representation too long"
} else { "invalid var_u32: integer too large"
}; // The continuation bit or unused bits are set. return Err(BinaryReaderError::new(msg, self.original_position() - 1));
}
shift += 7; if (byte & 0x80) == 0 { break;
}
}
Ok(result)
}
/// Advances the `BinaryReader` up to four bytes to parse a variable /// length integer as a `u64`. /// /// # Errors /// /// If `BinaryReader` has less than one or up to eight bytes remaining, or /// the integer is larger than 64 bits. #[inline] pubfn read_var_u64(&mutself) -> Result<u64> { // Optimization for single byte u64. let byte = u64::from(self.read_u8()?); if (byte & 0x80) == 0 {
Ok(byte)
} else { self.read_var_u64_big(byte)
}
}
fn read_var_u64_big(&mutself, byte: u64) -> Result<u64> { letmut result = byte & 0x7F; letmut shift = 7; loop { let byte = u64::from(self.read_u8()?);
result |= (byte & 0x7F) << shift; if shift >= 57 && (byte >> (64 - shift)) != 0 { let msg = if byte & 0x80 != 0 { "invalid var_u64: integer representation too long"
} else { "invalid var_u64: integer too large"
}; // The continuation bit or unused bits are set. return Err(BinaryReaderError::new(msg, self.original_position() - 1));
}
shift += 7; if (byte & 0x80) == 0 { break;
}
}
Ok(result)
}
/// Executes `f` to skip some data in this binary reader and then returns a /// reader which will read the skipped data. pubfn skip(&mutself, f: impl FnOnce(&mutSelf) -> Result<()>) -> Result<Self> { let start = self.position;
f(self)?; letmut ret = self.clone();
ret.buffer = &self.buffer[start..self.position];
ret.position = 0;
ret.original_offset = self.original_offset + start;
Ok(ret)
}
/// Advances the `BinaryReader` past a WebAssembly string. This method does /// not perform any utf-8 validation. /// # Errors /// If `BinaryReader` has less than four bytes, the string's length exceeds /// the remaining bytes, or the string length /// exceeds `limits::MAX_WASM_STRING_SIZE`. pubfn skip_string(&mutself) -> Result<()> { let len = self.read_var_u32()? as usize; if len > MAX_WASM_STRING_SIZE { return Err(BinaryReaderError::new( "string size out of bounds", self.original_position() - 1,
));
} self.ensure_has_bytes(len)?; self.position += len;
Ok(())
}
/// Advances the `BinaryReader` up to four bytes to parse a variable /// length integer as a `i32`. /// # Errors /// If `BinaryReader` has less than one or up to four bytes remaining, or /// the integer is larger than 32 bits. #[inline] pubfn read_var_i32(&mutself) -> Result<i32> { // Optimization for single byte i32. let byte = self.read_u8()?; if (byte & 0x80) == 0 {
Ok(((byte as i32) << 25) >> 25)
} else { self.read_var_i32_big(byte)
}
}
fn read_var_i32_big(&mutself, byte: u8) -> Result<i32> { letmut result = (byte & 0x7F) as i32; letmut shift = 7; loop { let byte = self.read_u8()?;
result |= ((byte & 0x7F) as i32) << shift; if shift >= 25 { let continuation_bit = (byte & 0x80) != 0; let sign_and_unused_bit = (byte << 1) as i8 >> (32 - shift); if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) { let msg = if continuation_bit { "invalid var_i32: integer representation too long"
} else { "invalid var_i32: integer too large"
}; return Err(BinaryReaderError::new(msg, self.original_position() - 1));
} return Ok(result);
}
shift += 7; if (byte & 0x80) == 0 { break;
}
} let ashift = 32 - shift;
Ok((result << ashift) >> ashift)
}
/// Advances the `BinaryReader` up to four bytes to parse a variable /// length integer as a signed 33 bit integer, returned as a `i64`. /// # Errors /// If `BinaryReader` has less than one or up to five bytes remaining, or /// the integer is larger than 33 bits. pubfn read_var_s33(&mutself) -> Result<i64> { // Optimization for single byte. let byte = self.read_u8()?; if (byte & 0x80) == 0 { return Ok(((byte as i8) << 1) as i64 >> 1);
}
letmut result = (byte & 0x7F) as i64; letmut shift = 7; loop { let byte = self.read_u8()?;
result |= ((byte & 0x7F) as i64) << shift; if shift >= 25 { let continuation_bit = (byte & 0x80) != 0; let sign_and_unused_bit = (byte << 1) as i8 >> (33 - shift); if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) { return Err(BinaryReaderError::new( "invalid var_s33: integer representation too long", self.original_position() - 1,
));
} return Ok(result);
}
shift += 7; if (byte & 0x80) == 0 { break;
}
} let ashift = 64 - shift;
Ok((result << ashift) >> ashift)
}
/// Advances the `BinaryReader` up to eight bytes to parse a variable /// length integer as a 64 bit integer, returned as a `i64`. /// # Errors /// If `BinaryReader` has less than one or up to eight bytes remaining, or /// the integer is larger than 64 bits. pubfn read_var_i64(&mutself) -> Result<i64> { letmut result: i64 = 0; letmut shift = 0; loop { let byte = self.read_u8()?;
result |= i64::from(byte & 0x7F) << shift; if shift >= 57 { let continuation_bit = (byte & 0x80) != 0; let sign_and_unused_bit = ((byte << 1) as i8) >> (64 - shift); if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) { let msg = if continuation_bit { "invalid var_i64: integer representation too long"
} else { "invalid var_i64: integer too large"
}; return Err(BinaryReaderError::new(msg, self.original_position() - 1));
} return Ok(result);
}
shift += 7; if (byte & 0x80) == 0 { break;
}
} let ashift = 64 - shift;
Ok((result << ashift) >> ashift)
}
/// Advances the `BinaryReader` four bytes to parse a 32 bit floating point /// number, returned as `Ieee32`. /// # Errors /// If `BinaryReader` has less than four bytes remaining. pubfn read_f32(&mutself) -> Result<Ieee32> { let value = self.read_u32()?;
Ok(Ieee32(value))
}
/// Advances the `BinaryReader` eight bytes to parse a 64 bit floating point /// number, returned as `Ieee64`. /// # Errors /// If `BinaryReader` has less than eight bytes remaining. pubfn read_f64(&mutself) -> Result<Ieee64> { let value = self.read_u64()?;
Ok(Ieee64(value))
}
/// (internal) Reads a fixed-size WebAssembly string from the module. fn internal_read_string(&mutself, len: usize) -> Result<&e='color:blue'>'a str> { let bytes = self.read_bytes(len)?;
str::from_utf8(bytes).map_err(|_| {
BinaryReaderError::new("malformed UTF-8 encoding", self.original_position() - 1)
})
}
/// Reads a WebAssembly string from the module. /// /// # Errors /// /// If `BinaryReader` has less than up to four bytes remaining, the string's /// length exceeds the remaining bytes, the string's length exceeds /// `limits::MAX_WASM_STRING_SIZE`, or the string contains invalid utf-8. pubfn read_string(&mutself) -> Result<&'a str> { let len = self.read_var_u32()? as usize; if len > MAX_WASM_STRING_SIZE { return Err(BinaryReaderError::new( "string size out of bounds", self.original_position() - 1,
));
} returnself.internal_read_string(len);
}
/// Reads a unlimited WebAssembly string from the module. /// /// Note that this is similar to [`BinaryReader::read_string`] except that /// it will not limit the size of the returned string by /// `limits::MAX_WASM_STRING_SIZE`. pubfn read_unlimited_string(&mutself) -> Result<&'a str> { let len = self.read_var_u32()? as usize; returnself.internal_read_string(len);
}
pub(crate) fn read_block_type(&mutself) -> Result<BlockType> { let b = self.peek()?;
// Block types are encoded as either 0x40, a `valtype`, or `s33`. All // current `valtype` encodings are negative numbers when encoded with // sleb128, but it's also required that valtype encodings are in their // canonical form. For example an overlong encoding of -1 as `0xff 0x7f` // is not valid and it is required to be `0x7f`. This means that we // can't simply match on the `s33` that pops out below since reading the // whole `s33` might read an overlong encoding. // // To test for this the first byte `b` is inspected. The highest bit, // the continuation bit in LEB128 encoding, must be clear. The next bit, // the sign bit, must be set to indicate that the number is negative. If // these two conditions hold then we're guaranteed that this is a // negative number. // // After this a value type is read directly instead of looking for an // indexed value type. if b & 0x80 == 0 && b & 0x40 != 0 { if b == 0x40 { self.position += 1; return Ok(BlockType::Empty);
} return Ok(BlockType::Type(self.read()?));
}
// Not empty or a singular type, so read the function type index let idx = self.read_var_s33()?; match u32::try_from(idx) {
Ok(idx) => Ok(BlockType::FuncType(idx)),
Err(_) => { return Err(BinaryReaderError::new( "invalid function type", self.original_position(),
));
}
}
}
/// Visit the next available operator with the specified [`VisitOperator`] instance. /// /// Note that this does not implicitly propagate any additional information such as instruction /// offsets. In order to do so, consider storing such data within the visitor before visiting. /// /// # Errors /// /// If `BinaryReader` has less bytes remaining than required to parse the `Operator`. /// /// # Examples /// /// Store an offset for use in diagnostics or any other purposes: /// /// ``` /// # use wasmparser::{BinaryReader, VisitOperator, Result, for_each_operator}; /// /// pub fn dump(mut reader: BinaryReader) -> Result<()> { /// let mut visitor = Dumper { offset: 0 }; /// while !reader.eof() { /// visitor.offset = reader.original_position(); /// reader.visit_operator(&mut visitor)?; /// } /// Ok(()) /// } /// /// struct Dumper { /// offset: usize /// } /// /// macro_rules! define_visit_operator { /// ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { /// $( /// fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output { /// println!("{}: {}", self.offset, stringify!($visit)); /// } /// )* /// } /// } /// /// impl<'a> VisitOperator<'a> for Dumper { /// type Output = (); /// for_each_operator!(define_visit_operator); /// } /// /// ``` pubfn visit_operator<T>(&mutself, visitor: &mut T) -> Result<<T as VisitOperator<'a>>::Output> where
T: VisitOperator<'a>,
{ let pos = self.original_position(); let code = self.read_u8()? as u8;
Ok(match code { 0x00 => visitor.visit_unreachable(), 0x01 => visitor.visit_nop(), 0x02 => visitor.visit_block(self.read_block_type()?), 0x03 => visitor.visit_loop(self.read_block_type()?), 0x04 => visitor.visit_if(self.read_block_type()?), 0x05 => visitor.visit_else(), 0x06 => visitor.visit_try(self.read_block_type()?), 0x07 => visitor.visit_catch(self.read_var_u32()?), 0x08 => visitor.visit_throw(self.read_var_u32()?), 0x09 => visitor.visit_rethrow(self.read_var_u32()?), 0x0a => visitor.visit_throw_ref(), 0x0b => visitor.visit_end(), 0x0c => visitor.visit_br(self.read_var_u32()?), 0x0d => visitor.visit_br_if(self.read_var_u32()?), 0x0e => visitor.visit_br_table(self.read_br_table()?), 0x0f => visitor.visit_return(), 0x10 => visitor.visit_call(self.read_var_u32()?), 0x11 => { let index = self.read_var_u32()?; let table = self.read_table_index_or_zero_if_not_reference_types()?;
visitor.visit_call_indirect(index, table)
} 0x12 => visitor.visit_return_call(self.read_var_u32()?), 0x13 => visitor.visit_return_call_indirect(self.read_var_u32()?, self.read_var_u32()?), 0x14 => visitor.visit_call_ref(self.read()?), 0x15 => visitor.visit_return_call_ref(self.read()?), 0x18 => visitor.visit_delegate(self.read_var_u32()?), 0x19 => visitor.visit_catch_all(), 0x1a => visitor.visit_drop(), 0x1b => visitor.visit_select(), 0x1c => { let results = self.read_var_u32()?; if results != 1 { return Err(BinaryReaderError::new( "invalid result arity", self.position,
));
}
visitor.visit_typed_select(self.read()?)
} 0x1f => visitor.visit_try_table(self.read()?),
0x54 => { let memarg = self.read_memarg(0)?; let lane = self.read_lane_index(16)?;
visitor.visit_v128_load8_lane(memarg, lane)
} 0x55 => { let memarg = self.read_memarg(1)?; let lane = self.read_lane_index(8)?;
visitor.visit_v128_load16_lane(memarg, lane)
} 0x56 => { let memarg = self.read_memarg(2)?; let lane = self.read_lane_index(4)?;
visitor.visit_v128_load32_lane(memarg, lane)
} 0x57 => { let memarg = self.read_memarg(3)?; let lane = self.read_lane_index(2)?;
visitor.visit_v128_load64_lane(memarg, lane)
} 0x58 => { let memarg = self.read_memarg(0)?; let lane = self.read_lane_index(16)?;
visitor.visit_v128_store8_lane(memarg, lane)
} 0x59 => { let memarg = self.read_memarg(1)?; let lane = self.read_lane_index(8)?;
visitor.visit_v128_store16_lane(memarg, lane)
} 0x5a => { let memarg = self.read_memarg(2)?; let lane = self.read_lane_index(4)?;
visitor.visit_v128_store32_lane(memarg, lane)
} 0x5b => { let memarg = self.read_memarg(3)?; let lane = self.read_lane_index(2)?;
visitor.visit_v128_store64_lane(memarg, lane)
}
/// Reads the next available `Operator`. /// /// # Errors /// /// If `BinaryReader` has less bytes remaining than required to parse /// the `Operator`. pubfn read_operator(&mutself) -> Result<Operator<'a>> { self.visit_operator(&mut OperatorFactory::new())
}
/// Returns whether there is an `end` opcode followed by eof remaining in /// this reader. pubfn is_end_then_eof(&self) -> bool { self.remaining_buffer() == &[0x0b]
}
fn read_lane_index(&mutself, max: u8) -> Result<u8> { let index = self.read_u8()?; if index >= max { return Err(BinaryReaderError::new( "invalid lane index", self.original_position() - 1,
));
}
Ok(index)
}
fn read_memory_index_or_zero_if_not_multi_memory(&mutself) -> Result<u32> { ifself.multi_memory() { self.read_var_u32()
} else { // Before bulk memory this byte was required to be a single zero // byte, not a LEB-encoded zero, so require a precise zero byte. matchself.read_u8()? { 0 => Ok(0),
_ => bail!(self.original_position() - 1, "zero byte expected"),
}
}
}
fn read_table_index_or_zero_if_not_reference_types(&mutself) -> Result<u32> { ifself.reference_types() { self.read_var_u32()
} else { // Before reference types this byte was required to be a single zero // byte, not a LEB-encoded zero, so require a precise zero byte. matchself.read_u8()? { 0 => Ok(0),
_ => bail!(self.original_position() - 1, "zero byte expected"),
}
}
}
}
// See documentation on `BinaryReader::features` for more on what's going on // here.
macro_rules! define_feature_accessor {
($feature:ident = $default:expr) => { impl BinaryReader<'_> { #[inline] #[allow(dead_code)] pub(crate) fn $feature(&self) -> bool { #[cfg(feature = "features")]
{ self.features.$feature()
} #[cfg(not(feature = "features"))]
{ true
}
}
}
};
}
impl<'a> BrTable<'a> { /// Returns the number of `br_table` entries, not including the default /// label pubfn len(&self) -> u32 { self.cnt
}
/// Returns whether `BrTable` doesn't have any labels apart from the default one. pubfn is_empty(&self) -> bool { self.len() == 0
}
/// Returns the default target of this `br_table` instruction. pubfn default(&self) -> u32 { self.default
}
/// Returns the list of targets that this `br_table` instruction will be /// jumping to. /// /// This method will return an iterator which parses each target of this /// `br_table` except the default target. The returned iterator will /// yield `self.len()` elements. /// /// # Examples /// /// ```rust /// use wasmparser::{BinaryReader, Operator}; /// /// let buf = [0x0e, 0x02, 0x01, 0x02, 0x00]; /// let mut reader = BinaryReader::new(&buf, 0); /// let op = reader.read_operator().unwrap(); /// if let Operator::BrTable { targets } = op { /// let targets = targets.targets().collect::<Result<Vec<_>, _>>().unwrap(); /// assert_eq!(targets, [1, 2]); /// } /// ``` pubfn targets(&self) -> BrTableTargets {
BrTableTargets {
reader: self.reader.clone(),
remaining: self.cnt,
}
}
}
/// An iterator over the targets of a [`BrTable`]. /// /// # Note /// /// This iterator parses each target of the underlying `br_table` /// except for the default target. /// The iterator will yield exactly as many targets as the `br_table` has. pubstruct BrTableTargets<'a> {
reader: crate::BinaryReader<'a>,
remaining: u32,
}
impl<'a> Iterator for BrTableTargets<'a> { type Item = Result<u32>;
fn size_hint(&self) -> (usize, Option<usize>) { let remaining = usize::try_from(self.remaining).unwrap_or_else(|error| {
panic!("could not convert remaining `u32` into `usize`: {}", error)
});
(remaining, Some(remaining))
}
fn next(&mutself) -> Option<Self::Item> { ifself.remaining == 0 { if !self.reader.eof() { return Some(Err(BinaryReaderError::new( "trailing data in br_table", self.reader.original_position(),
)));
} return None;
} self.remaining -= 1;
Some(self.reader.read_var_u32())
}
}
/// A factory to construct [`Operator`] instances via the [`VisitOperator`] trait. struct OperatorFactory<'a> {
marker: core::marker::PhantomData<fn() -> &'a ()>,
}
impl<'a> OperatorFactory<'a> { /// Creates a new [`OperatorFactory`]. fn new() -> Self { Self {
marker: core::marker::PhantomData,
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.