diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/wasmparser-0.48.2/src | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/wasmparser-0.48.2/src')
31 files changed, 10600 insertions, 0 deletions
diff --git a/third_party/rust/wasmparser-0.48.2/src/binary_reader.rs b/third_party/rust/wasmparser-0.48.2/src/binary_reader.rs new file mode 100644 index 0000000000..3cb6bdc1f1 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/binary_reader.rs @@ -0,0 +1,1775 @@ +/* Copyright 2018 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. + */ + +use std::boxed::Box; +use std::convert::TryInto; +use std::str; +use std::vec::Vec; + +use crate::limits::{ + MAX_WASM_FUNCTION_LOCALS, MAX_WASM_FUNCTION_PARAMS, MAX_WASM_FUNCTION_RETURNS, + MAX_WASM_FUNCTION_SIZE, MAX_WASM_STRING_SIZE, +}; + +use crate::primitives::{ + BinaryReaderError, BrTable, CustomSectionKind, ExternalKind, FuncType, GlobalType, Ieee32, + Ieee64, LinkingType, MemoryImmediate, MemoryType, NameType, Operator, RelocType, + ResizableLimits, Result, SIMDLaneIndex, SectionCode, TableType, Type, TypeOrFuncType, V128, +}; + +const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE; + +fn is_name(name: &str, expected: &'static str) -> bool { + name == expected +} + +fn is_name_prefix(name: &str, prefix: &'static str) -> bool { + name.starts_with(prefix) +} + +const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm"; +const WASM_EXPERIMENTAL_VERSION: u32 = 0xd; +const WASM_SUPPORTED_VERSION: u32 = 0x1; + +pub(crate) struct SectionHeader<'a> { + pub code: SectionCode<'a>, + pub payload_start: usize, + pub payload_len: usize, +} + +/// Bytecode range in the WebAssembly module. +#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Range { + /// The start bound of the range. + pub start: usize, + /// The end bound of the range. + pub end: usize, +} + +impl Range { + /// Constructs a new instance of `Range`. + /// + /// # Panics + /// If `start` is greater than `end`. + pub fn new(start: usize, end: usize) -> Range { + assert!(start <= end); + Range { start, end } + } + + /// Returns a new slice between `start` and `end - 1` from `data`. + pub fn slice<'a>(&self, data: &'a [u8]) -> &'a [u8] { + &data[self.start..self.end] + } +} + +/// A binary reader of the WebAssembly structures and types. +#[derive(Clone, Debug)] +pub struct BinaryReader<'a> { + pub(crate) buffer: &'a [u8], + pub(crate) position: usize, + pub(crate) original_offset: usize, +} + +impl<'a> BinaryReader<'a> { + /// Constructs `BinaryReader` type. + /// + /// # Examples + /// ``` + /// let fn_body = &vec![0x41, 0x00, 0x10, 0x00, 0x0B]; + /// let mut reader = wasmparser::BinaryReader::new(fn_body); + /// while !reader.eof() { + /// let op = reader.read_operator(); + /// println!("{:?}", op) + /// } + /// ``` + pub fn new(data: &[u8]) -> BinaryReader { + BinaryReader { + buffer: data, + position: 0, + original_offset: 0, + } + } + + /// Constructs a `BinaryReader` with an explicit starting offset. + pub fn new_with_offset(data: &[u8], original_offset: usize) -> BinaryReader { + BinaryReader { + buffer: data, + position: 0, + original_offset, + } + } + + pub fn original_position(&self) -> usize { + self.original_offset + self.position + } + + /// Returns a range from the starting offset to the end of the buffer. + pub fn range(&self) -> Range { + Range { + start: self.original_offset, + end: self.original_offset + self.buffer.len(), + } + } + + fn ensure_has_byte(&self) -> Result<()> { + if self.position < self.buffer.len() { + Ok(()) + } else { + Err(BinaryReaderError { + message: "Unexpected EOF", + offset: self.original_position(), + }) + } + } + + fn ensure_has_bytes(&self, len: usize) -> Result<()> { + if self.position + len <= self.buffer.len() { + Ok(()) + } else { + Err(BinaryReaderError { + message: "Unexpected EOF", + offset: self.original_position(), + }) + } + } + + fn read_var_u1(&mut self) -> Result<u32> { + let b = self.read_u8()?; + if (b & 0xFE) != 0 { + return Err(BinaryReaderError { + message: "Invalid var_u1", + offset: self.original_position() - 1, + }); + } + Ok(b) + } + + fn read_var_i7(&mut self) -> Result<i32> { + let b = self.read_u8()?; + if (b & 0x80) != 0 { + return Err(BinaryReaderError { + message: "Invalid var_i7", + offset: self.original_position() - 1, + }); + } + Ok((b << 25) as i32 >> 25) + } + + pub(crate) fn read_var_u7(&mut self) -> Result<u32> { + let b = self.read_u8()?; + if (b & 0x80) != 0 { + return Err(BinaryReaderError { + message: "Invalid var_u7", + offset: self.original_position() - 1, + }); + } + Ok(b) + } + + pub fn read_type(&mut self) -> Result<Type> { + let code = self.read_var_i7()?; + match code { + -0x01 => Ok(Type::I32), + -0x02 => Ok(Type::I64), + -0x03 => Ok(Type::F32), + -0x04 => Ok(Type::F64), + -0x05 => Ok(Type::V128), + -0x10 => Ok(Type::AnyFunc), + -0x11 => Ok(Type::AnyRef), + -0x12 => Ok(Type::NullRef), + -0x20 => Ok(Type::Func), + -0x40 => Ok(Type::EmptyBlockType), + _ => Err(BinaryReaderError { + message: "Invalid type", + offset: self.original_position() - 1, + }), + } + } + + /// Read a `count` indicating the number of times to call `read_local_decl`. + pub fn read_local_count(&mut self) -> Result<usize> { + let local_count = self.read_var_u32()? as usize; + if local_count > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "local_count is out of bounds", + offset: self.original_position() - 1, + }); + } + Ok(local_count) + } + + /// Read a `(count, value_type)` declaration of local variables of the same type. + pub fn read_local_decl(&mut self, locals_total: &mut usize) -> Result<(u32, Type)> { + let count = self.read_var_u32()?; + let value_type = self.read_type()?; + *locals_total = + locals_total + .checked_add(count as usize) + .ok_or_else(|| BinaryReaderError { + message: "locals_total is out of bounds", + offset: self.original_position() - 1, + })?; + if *locals_total > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "locals_total is out of bounds", + offset: self.original_position() - 1, + }); + } + Ok((count, value_type)) + } + + pub(crate) fn read_external_kind(&mut self) -> Result<ExternalKind> { + let code = self.read_u8()?; + match code { + 0 => Ok(ExternalKind::Function), + 1 => Ok(ExternalKind::Table), + 2 => Ok(ExternalKind::Memory), + 3 => Ok(ExternalKind::Global), + _ => Err(BinaryReaderError { + message: "Invalid external kind", + offset: self.original_position() - 1, + }), + } + } + + pub(crate) fn read_func_type(&mut self) -> Result<FuncType> { + let form = self.read_type()?; + let params_len = self.read_var_u32()? as usize; + if params_len > MAX_WASM_FUNCTION_PARAMS { + return Err(BinaryReaderError { + message: "function params size is out of bound", + offset: self.original_position() - 1, + }); + } + let mut params: Vec<Type> = Vec::with_capacity(params_len); + for _ in 0..params_len { + params.push(self.read_type()?); + } + let returns_len = self.read_var_u32()? as usize; + if returns_len > MAX_WASM_FUNCTION_RETURNS { + return Err(BinaryReaderError { + message: "function returns size is out of bound", + offset: self.original_position() - 1, + }); + } + let mut returns: Vec<Type> = Vec::with_capacity(returns_len); + for _ in 0..returns_len { + returns.push(self.read_type()?); + } + Ok(FuncType { + form, + params: params.into_boxed_slice(), + returns: returns.into_boxed_slice(), + }) + } + + fn read_resizable_limits(&mut self, max_present: bool) -> Result<ResizableLimits> { + let initial = self.read_var_u32()?; + let maximum = if max_present { + Some(self.read_var_u32()?) + } else { + None + }; + Ok(ResizableLimits { initial, maximum }) + } + + pub(crate) fn read_table_type(&mut self) -> Result<TableType> { + let element_type = self.read_type()?; + let flags = self.read_var_u32()?; + if (flags & !0x1) != 0 { + return Err(BinaryReaderError { + message: "invalid table resizable limits flags", + offset: self.original_position() - 1, + }); + } + let limits = self.read_resizable_limits((flags & 0x1) != 0)?; + Ok(TableType { + element_type, + limits, + }) + } + + pub(crate) fn read_memory_type(&mut self) -> Result<MemoryType> { + let flags = self.read_var_u32()?; + if (flags & !0x3) != 0 { + return Err(BinaryReaderError { + message: "invalid table resizable limits flags", + offset: self.original_position() - 1, + }); + } + let limits = self.read_resizable_limits((flags & 0x1) != 0)?; + let shared = (flags & 0x2) != 0; + Ok(MemoryType { limits, shared }) + } + + pub(crate) fn read_global_type(&mut self) -> Result<GlobalType> { + Ok(GlobalType { + content_type: self.read_type()?, + mutable: self.read_var_u1()? != 0, + }) + } + + fn read_memarg(&mut self) -> Result<MemoryImmediate> { + Ok(MemoryImmediate { + flags: self.read_var_u32()?, + offset: self.read_var_u32()?, + }) + } + + pub(crate) fn read_section_code(&mut self, id: u32, offset: usize) -> Result<SectionCode<'a>> { + match id { + 0 => { + let name = self.read_string()?; + let kind = if is_name(name, "name") { + CustomSectionKind::Name + } else if is_name(name, "producers") { + CustomSectionKind::Producers + } else if is_name(name, "sourceMappingURL") { + CustomSectionKind::SourceMappingURL + } else if is_name_prefix(name, "reloc.") { + CustomSectionKind::Reloc + } else if is_name(name, "linking") { + CustomSectionKind::Linking + } else { + CustomSectionKind::Unknown + }; + Ok(SectionCode::Custom { name, kind }) + } + 1 => Ok(SectionCode::Type), + 2 => Ok(SectionCode::Import), + 3 => Ok(SectionCode::Function), + 4 => Ok(SectionCode::Table), + 5 => Ok(SectionCode::Memory), + 6 => Ok(SectionCode::Global), + 7 => Ok(SectionCode::Export), + 8 => Ok(SectionCode::Start), + 9 => Ok(SectionCode::Element), + 10 => Ok(SectionCode::Code), + 11 => Ok(SectionCode::Data), + 12 => Ok(SectionCode::DataCount), + _ => Err(BinaryReaderError { + message: "Invalid section code", + offset, + }), + } + } + + fn read_br_table(&mut self) -> Result<BrTable<'a>> { + let targets_len = self.read_var_u32()? as usize; + if targets_len > MAX_WASM_BR_TABLE_SIZE { + return Err(BinaryReaderError { + message: "br_table size is out of bound", + offset: self.original_position() - 1, + }); + } + let start = self.position; + for _ in 0..targets_len { + self.skip_var_32()?; + } + self.skip_var_32()?; + Ok(BrTable { + buffer: &self.buffer[start..self.position], + cnt: targets_len as usize, + }) + } + + /// Returns whether the `BinaryReader` has reached the end of the file. + pub fn eof(&self) -> bool { + self.position >= self.buffer.len() + } + + /// Returns the `BinaryReader`'s current position. + pub fn current_position(&self) -> usize { + self.position + } + + /// Returns the number of bytes remaining in the `BinaryReader`. + pub fn 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`. + 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]) + } + + /// Advances the `BinaryReader` four bytes and returns a `u32`. + /// # 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; + 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; + Ok(word) + } + + /// Advances the `BinaryReader` a single byte, and returns the data as + /// a `u32`. + /// # Errors + /// If `BinaryReader` has no bytes remaining. + pub fn read_u8(&mut self) -> Result<u32> { + self.ensure_has_byte()?; + let b = u32::from(self.buffer[self.position]); + self.position += 1; + Ok(b) + } + + /// Advances the `BinaryReader` up to two bytes to parse a variable + /// length integer as a `u8`. + /// # Errors + /// If `BinaryReader` has less than one or two bytes remaining, or the + /// integer is larger than eight bits. + pub fn read_var_u8(&mut self) -> Result<u32> { + // Optimization for single byte i32. + let byte = self.read_u8()?; + if (byte & 0x80) == 0 { + return Ok(byte); + } + + let result = (self.read_u8()? << 7) | (byte & 0x7F); + if result >= 0x100 { + return Err(BinaryReaderError { + message: "Invalid var_u8", + offset: self.original_position() - 1, + }); + } + Ok(result) + } + + /// 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. + pub fn read_var_u32(&mut self) -> Result<u32> { + // Optimization for single byte i32. + let byte = self.read_u8()?; + if (byte & 0x80) == 0 { + return Ok(byte); + } + + let mut result = byte & 0x7F; + let mut shift = 7; + loop { + let byte = self.read_u8()?; + result |= ((byte & 0x7F) as u32) << shift; + if shift >= 25 && (byte >> (32 - shift)) != 0 { + // The continuation bit or unused bits are set. + return Err(BinaryReaderError { + message: "Invalid var_u32", + offset: self.original_position() - 1, + }); + } + shift += 7; + if (byte & 0x80) == 0 { + break; + } + } + Ok(result) + } + + /// Advances the `BinaryReader` up to four bytes over a variable length 32 + /// bit integer, discarding the result. + /// # Errors + /// If `BinaryReader` has less than one or up to four bytes remaining, or + /// the integer is larger than 32 bits. + pub fn skip_var_32(&mut self) -> Result<()> { + for _ in 0..5 { + let byte = self.read_u8()?; + if (byte & 0x80) == 0 { + return Ok(()); + } + } + Err(BinaryReaderError { + message: "Invalid var_32", + offset: self.original_position() - 1, + }) + } + + /// Alias method for `BinaryReader::skip_var_u32`. + pub fn skip_type(&mut self) -> Result<()> { + self.skip_var_32() + } + + /// Advances the `BinaryReader` `len` bytes, skipping the result. + /// # Errors + /// If `BinaryReader` has less than `len` bytes remaining. + pub fn skip_bytes(&mut self, len: usize) -> Result<()> { + self.ensure_has_bytes(len)?; + self.position += len; + Ok(()) + } + + /// 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`. + pub fn skip_string(&mut self) -> Result<()> { + let len = self.read_var_u32()? as usize; + if len > MAX_WASM_STRING_SIZE { + return Err(BinaryReaderError { + message: "string size in out of bounds", + offset: self.original_position() - 1, + }); + } + self.skip_bytes(len) + } + + pub(crate) fn skip_to(&mut self, position: usize) { + assert!( + self.position <= position && position <= self.buffer.len(), + "skip_to allowed only into region past current position" + ); + self.position = position; + } + + /// 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. + pub fn read_var_i32(&mut self) -> Result<i32> { + // Optimization for single byte i32. + let byte = self.read_u8()?; + if (byte & 0x80) == 0 { + return Ok(((byte as i32) << 25) >> 25); + } + + let mut result = (byte & 0x7F) as i32; + let mut 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) { + return Err(BinaryReaderError { + message: "Invalid var_i32", + offset: 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. + pub fn read_var_s33(&mut self) -> Result<i64> { + // Optimization for single byte. + let byte = self.read_u8()?; + if (byte & 0x80) == 0 { + return Ok(((byte as i8) << 1) as i64 >> 1); + } + + let mut result = (byte & 0x7F) as i64; + let mut 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 { + message: "Invalid var_s33", + offset: 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. + pub fn read_var_i64(&mut self) -> Result<i64> { + let mut result: i64 = 0; + let mut 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) { + return Err(BinaryReaderError { + message: "Invalid var_i64", + offset: 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 four bytes to parse a variable + /// length integer as a 32 bit floating point integer, returned as `Ieee32`. + /// # Errors + /// If `BinaryReader` has less than one or up to four bytes remaining, or + /// the integer is larger than 32 bits. + pub fn read_f32(&mut self) -> Result<Ieee32> { + let value = self.read_u32()?; + Ok(Ieee32(value)) + } + + /// Advances the `BinaryReader` up to four bytes to parse a variable + /// length integer as a 32 bit floating point integer, returned as `Ieee32`. + /// # Errors + /// If `BinaryReader` has less than one or up to four bytes remaining, or + /// the integer is larger than 32 bits. + pub fn read_f64(&mut self) -> Result<Ieee64> { + let value = self.read_u64()?; + Ok(Ieee64(value)) + } + + /// 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. + pub fn read_string(&mut self) -> Result<&'a str> { + let len = self.read_var_u32()? as usize; + if len > MAX_WASM_STRING_SIZE { + return Err(BinaryReaderError { + message: "string size in out of bounds", + offset: self.original_position() - 1, + }); + } + let bytes = self.read_bytes(len)?; + str::from_utf8(bytes).map_err(|_| BinaryReaderError { + message: "non-utf8 string", + offset: self.original_position() - 1, + }) + } + + fn read_memarg_of_align(&mut self, max_align: u32) -> Result<MemoryImmediate> { + let imm = self.read_memarg()?; + if imm.flags > max_align { + return Err(BinaryReaderError { + message: "Unexpected memarg alignment", + offset: self.original_position() - 1, + }); + } + Ok(imm) + } + + fn read_0xfe_operator(&mut self) -> Result<Operator<'a>> { + let code = self.read_u8()? as u8; + Ok(match code { + 0x00 => Operator::AtomicNotify { + memarg: self.read_memarg_of_align(2)?, + }, + 0x01 => Operator::I32AtomicWait { + memarg: self.read_memarg_of_align(2)?, + }, + 0x02 => Operator::I64AtomicWait { + memarg: self.read_memarg_of_align(3)?, + }, + 0x03 => Operator::AtomicFence { + flags: self.read_u8()? as u8, + }, + 0x10 => Operator::I32AtomicLoad { + memarg: self.read_memarg_of_align(2)?, + }, + 0x11 => Operator::I64AtomicLoad { + memarg: self.read_memarg_of_align(3)?, + }, + 0x12 => Operator::I32AtomicLoad8U { + memarg: self.read_memarg_of_align(0)?, + }, + 0x13 => Operator::I32AtomicLoad16U { + memarg: self.read_memarg_of_align(1)?, + }, + 0x14 => Operator::I64AtomicLoad8U { + memarg: self.read_memarg_of_align(0)?, + }, + 0x15 => Operator::I64AtomicLoad16U { + memarg: self.read_memarg_of_align(1)?, + }, + 0x16 => Operator::I64AtomicLoad32U { + memarg: self.read_memarg_of_align(2)?, + }, + 0x17 => Operator::I32AtomicStore { + memarg: self.read_memarg_of_align(2)?, + }, + 0x18 => Operator::I64AtomicStore { + memarg: self.read_memarg_of_align(3)?, + }, + 0x19 => Operator::I32AtomicStore8 { + memarg: self.read_memarg_of_align(0)?, + }, + 0x1a => Operator::I32AtomicStore16 { + memarg: self.read_memarg_of_align(1)?, + }, + 0x1b => Operator::I64AtomicStore8 { + memarg: self.read_memarg_of_align(0)?, + }, + 0x1c => Operator::I64AtomicStore16 { + memarg: self.read_memarg_of_align(1)?, + }, + 0x1d => Operator::I64AtomicStore32 { + memarg: self.read_memarg_of_align(2)?, + }, + 0x1e => Operator::I32AtomicRmwAdd { + memarg: self.read_memarg_of_align(2)?, + }, + 0x1f => Operator::I64AtomicRmwAdd { + memarg: self.read_memarg_of_align(3)?, + }, + 0x20 => Operator::I32AtomicRmw8AddU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x21 => Operator::I32AtomicRmw16AddU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x22 => Operator::I64AtomicRmw8AddU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x23 => Operator::I64AtomicRmw16AddU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x24 => Operator::I64AtomicRmw32AddU { + memarg: self.read_memarg_of_align(2)?, + }, + 0x25 => Operator::I32AtomicRmwSub { + memarg: self.read_memarg_of_align(2)?, + }, + 0x26 => Operator::I64AtomicRmwSub { + memarg: self.read_memarg_of_align(3)?, + }, + 0x27 => Operator::I32AtomicRmw8SubU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x28 => Operator::I32AtomicRmw16SubU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x29 => Operator::I64AtomicRmw8SubU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x2a => Operator::I64AtomicRmw16SubU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x2b => Operator::I64AtomicRmw32SubU { + memarg: self.read_memarg_of_align(2)?, + }, + 0x2c => Operator::I32AtomicRmwAnd { + memarg: self.read_memarg_of_align(2)?, + }, + 0x2d => Operator::I64AtomicRmwAnd { + memarg: self.read_memarg_of_align(3)?, + }, + 0x2e => Operator::I32AtomicRmw8AndU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x2f => Operator::I32AtomicRmw16AndU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x30 => Operator::I64AtomicRmw8AndU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x31 => Operator::I64AtomicRmw16AndU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x32 => Operator::I64AtomicRmw32AndU { + memarg: self.read_memarg_of_align(2)?, + }, + 0x33 => Operator::I32AtomicRmwOr { + memarg: self.read_memarg_of_align(2)?, + }, + 0x34 => Operator::I64AtomicRmwOr { + memarg: self.read_memarg_of_align(3)?, + }, + 0x35 => Operator::I32AtomicRmw8OrU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x36 => Operator::I32AtomicRmw16OrU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x37 => Operator::I64AtomicRmw8OrU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x38 => Operator::I64AtomicRmw16OrU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x39 => Operator::I64AtomicRmw32OrU { + memarg: self.read_memarg_of_align(2)?, + }, + 0x3a => Operator::I32AtomicRmwXor { + memarg: self.read_memarg_of_align(2)?, + }, + 0x3b => Operator::I64AtomicRmwXor { + memarg: self.read_memarg_of_align(3)?, + }, + 0x3c => Operator::I32AtomicRmw8XorU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x3d => Operator::I32AtomicRmw16XorU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x3e => Operator::I64AtomicRmw8XorU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x3f => Operator::I64AtomicRmw16XorU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x40 => Operator::I64AtomicRmw32XorU { + memarg: self.read_memarg_of_align(2)?, + }, + 0x41 => Operator::I32AtomicRmwXchg { + memarg: self.read_memarg_of_align(2)?, + }, + 0x42 => Operator::I64AtomicRmwXchg { + memarg: self.read_memarg_of_align(3)?, + }, + 0x43 => Operator::I32AtomicRmw8XchgU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x44 => Operator::I32AtomicRmw16XchgU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x45 => Operator::I64AtomicRmw8XchgU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x46 => Operator::I64AtomicRmw16XchgU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x47 => Operator::I64AtomicRmw32XchgU { + memarg: self.read_memarg_of_align(2)?, + }, + 0x48 => Operator::I32AtomicRmwCmpxchg { + memarg: self.read_memarg_of_align(2)?, + }, + 0x49 => Operator::I64AtomicRmwCmpxchg { + memarg: self.read_memarg_of_align(3)?, + }, + 0x4a => Operator::I32AtomicRmw8CmpxchgU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x4b => Operator::I32AtomicRmw16CmpxchgU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x4c => Operator::I64AtomicRmw8CmpxchgU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x4d => Operator::I64AtomicRmw16CmpxchgU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x4e => Operator::I64AtomicRmw32CmpxchgU { + memarg: self.read_memarg_of_align(2)?, + }, + + _ => { + return Err(BinaryReaderError { + message: "Unknown 0xFE opcode", + offset: self.original_position() - 1, + }); + } + }) + } + + fn read_blocktype(&mut self) -> Result<TypeOrFuncType> { + let position = self.position; + if let Ok(ty) = self.read_type() { + Ok(TypeOrFuncType::Type(ty)) + } else { + self.position = position; + let idx = self.read_var_s33()?; + if idx < 0 || idx > (std::u32::MAX as i64) { + return Err(BinaryReaderError { + message: "invalid function type", + offset: position, + }); + } + Ok(TypeOrFuncType::FuncType(idx as u32)) + } + } + + /// Reads the next available `Operator`. + /// # Errors + /// If `BinaryReader` has less bytes remaining than required to parse + /// the `Operator`. + pub fn read_operator(&mut self) -> Result<Operator<'a>> { + let code = self.read_u8()? as u8; + Ok(match code { + 0x00 => Operator::Unreachable, + 0x01 => Operator::Nop, + 0x02 => Operator::Block { + ty: self.read_blocktype()?, + }, + 0x03 => Operator::Loop { + ty: self.read_blocktype()?, + }, + 0x04 => Operator::If { + ty: self.read_blocktype()?, + }, + 0x05 => Operator::Else, + 0x0b => Operator::End, + 0x0c => Operator::Br { + relative_depth: self.read_var_u32()?, + }, + 0x0d => Operator::BrIf { + relative_depth: self.read_var_u32()?, + }, + 0x0e => Operator::BrTable { + table: self.read_br_table()?, + }, + 0x0f => Operator::Return, + 0x10 => Operator::Call { + function_index: self.read_var_u32()?, + }, + 0x11 => Operator::CallIndirect { + index: self.read_var_u32()?, + table_index: self.read_var_u32()?, + }, + 0x1a => Operator::Drop, + 0x1b => Operator::Select, + 0x1c => { + let results = self.read_var_u32()?; + if results != 1 { + return Err(BinaryReaderError { + message: "bad number of results", + offset: self.position, + }); + } + Operator::TypedSelect { + ty: self.read_type()?, + } + } + 0x20 => Operator::LocalGet { + local_index: self.read_var_u32()?, + }, + 0x21 => Operator::LocalSet { + local_index: self.read_var_u32()?, + }, + 0x22 => Operator::LocalTee { + local_index: self.read_var_u32()?, + }, + 0x23 => Operator::GlobalGet { + global_index: self.read_var_u32()?, + }, + 0x24 => Operator::GlobalSet { + global_index: self.read_var_u32()?, + }, + 0x25 => Operator::TableGet { + table: self.read_var_u32()?, + }, + 0x26 => Operator::TableSet { + table: self.read_var_u32()?, + }, + 0x28 => Operator::I32Load { + memarg: self.read_memarg()?, + }, + 0x29 => Operator::I64Load { + memarg: self.read_memarg()?, + }, + 0x2a => Operator::F32Load { + memarg: self.read_memarg()?, + }, + 0x2b => Operator::F64Load { + memarg: self.read_memarg()?, + }, + 0x2c => Operator::I32Load8S { + memarg: self.read_memarg()?, + }, + 0x2d => Operator::I32Load8U { + memarg: self.read_memarg()?, + }, + 0x2e => Operator::I32Load16S { + memarg: self.read_memarg()?, + }, + 0x2f => Operator::I32Load16U { + memarg: self.read_memarg()?, + }, + 0x30 => Operator::I64Load8S { + memarg: self.read_memarg()?, + }, + 0x31 => Operator::I64Load8U { + memarg: self.read_memarg()?, + }, + 0x32 => Operator::I64Load16S { + memarg: self.read_memarg()?, + }, + 0x33 => Operator::I64Load16U { + memarg: self.read_memarg()?, + }, + 0x34 => Operator::I64Load32S { + memarg: self.read_memarg()?, + }, + 0x35 => Operator::I64Load32U { + memarg: self.read_memarg()?, + }, + 0x36 => Operator::I32Store { + memarg: self.read_memarg()?, + }, + 0x37 => Operator::I64Store { + memarg: self.read_memarg()?, + }, + 0x38 => Operator::F32Store { + memarg: self.read_memarg()?, + }, + 0x39 => Operator::F64Store { + memarg: self.read_memarg()?, + }, + 0x3a => Operator::I32Store8 { + memarg: self.read_memarg()?, + }, + 0x3b => Operator::I32Store16 { + memarg: self.read_memarg()?, + }, + 0x3c => Operator::I64Store8 { + memarg: self.read_memarg()?, + }, + 0x3d => Operator::I64Store16 { + memarg: self.read_memarg()?, + }, + 0x3e => Operator::I64Store32 { + memarg: self.read_memarg()?, + }, + 0x3f => Operator::MemorySize { + reserved: self.read_var_u1()?, + }, + 0x40 => Operator::MemoryGrow { + reserved: self.read_var_u1()?, + }, + 0x41 => Operator::I32Const { + value: self.read_var_i32()?, + }, + 0x42 => Operator::I64Const { + value: self.read_var_i64()?, + }, + 0x43 => Operator::F32Const { + value: self.read_f32()?, + }, + 0x44 => Operator::F64Const { + value: self.read_f64()?, + }, + 0x45 => Operator::I32Eqz, + 0x46 => Operator::I32Eq, + 0x47 => Operator::I32Ne, + 0x48 => Operator::I32LtS, + 0x49 => Operator::I32LtU, + 0x4a => Operator::I32GtS, + 0x4b => Operator::I32GtU, + 0x4c => Operator::I32LeS, + 0x4d => Operator::I32LeU, + 0x4e => Operator::I32GeS, + 0x4f => Operator::I32GeU, + 0x50 => Operator::I64Eqz, + 0x51 => Operator::I64Eq, + 0x52 => Operator::I64Ne, + 0x53 => Operator::I64LtS, + 0x54 => Operator::I64LtU, + 0x55 => Operator::I64GtS, + 0x56 => Operator::I64GtU, + 0x57 => Operator::I64LeS, + 0x58 => Operator::I64LeU, + 0x59 => Operator::I64GeS, + 0x5a => Operator::I64GeU, + 0x5b => Operator::F32Eq, + 0x5c => Operator::F32Ne, + 0x5d => Operator::F32Lt, + 0x5e => Operator::F32Gt, + 0x5f => Operator::F32Le, + 0x60 => Operator::F32Ge, + 0x61 => Operator::F64Eq, + 0x62 => Operator::F64Ne, + 0x63 => Operator::F64Lt, + 0x64 => Operator::F64Gt, + 0x65 => Operator::F64Le, + 0x66 => Operator::F64Ge, + 0x67 => Operator::I32Clz, + 0x68 => Operator::I32Ctz, + 0x69 => Operator::I32Popcnt, + 0x6a => Operator::I32Add, + 0x6b => Operator::I32Sub, + 0x6c => Operator::I32Mul, + 0x6d => Operator::I32DivS, + 0x6e => Operator::I32DivU, + 0x6f => Operator::I32RemS, + 0x70 => Operator::I32RemU, + 0x71 => Operator::I32And, + 0x72 => Operator::I32Or, + 0x73 => Operator::I32Xor, + 0x74 => Operator::I32Shl, + 0x75 => Operator::I32ShrS, + 0x76 => Operator::I32ShrU, + 0x77 => Operator::I32Rotl, + 0x78 => Operator::I32Rotr, + 0x79 => Operator::I64Clz, + 0x7a => Operator::I64Ctz, + 0x7b => Operator::I64Popcnt, + 0x7c => Operator::I64Add, + 0x7d => Operator::I64Sub, + 0x7e => Operator::I64Mul, + 0x7f => Operator::I64DivS, + 0x80 => Operator::I64DivU, + 0x81 => Operator::I64RemS, + 0x82 => Operator::I64RemU, + 0x83 => Operator::I64And, + 0x84 => Operator::I64Or, + 0x85 => Operator::I64Xor, + 0x86 => Operator::I64Shl, + 0x87 => Operator::I64ShrS, + 0x88 => Operator::I64ShrU, + 0x89 => Operator::I64Rotl, + 0x8a => Operator::I64Rotr, + 0x8b => Operator::F32Abs, + 0x8c => Operator::F32Neg, + 0x8d => Operator::F32Ceil, + 0x8e => Operator::F32Floor, + 0x8f => Operator::F32Trunc, + 0x90 => Operator::F32Nearest, + 0x91 => Operator::F32Sqrt, + 0x92 => Operator::F32Add, + 0x93 => Operator::F32Sub, + 0x94 => Operator::F32Mul, + 0x95 => Operator::F32Div, + 0x96 => Operator::F32Min, + 0x97 => Operator::F32Max, + 0x98 => Operator::F32Copysign, + 0x99 => Operator::F64Abs, + 0x9a => Operator::F64Neg, + 0x9b => Operator::F64Ceil, + 0x9c => Operator::F64Floor, + 0x9d => Operator::F64Trunc, + 0x9e => Operator::F64Nearest, + 0x9f => Operator::F64Sqrt, + 0xa0 => Operator::F64Add, + 0xa1 => Operator::F64Sub, + 0xa2 => Operator::F64Mul, + 0xa3 => Operator::F64Div, + 0xa4 => Operator::F64Min, + 0xa5 => Operator::F64Max, + 0xa6 => Operator::F64Copysign, + 0xa7 => Operator::I32WrapI64, + 0xa8 => Operator::I32TruncF32S, + 0xa9 => Operator::I32TruncF32U, + 0xaa => Operator::I32TruncF64S, + 0xab => Operator::I32TruncF64U, + 0xac => Operator::I64ExtendI32S, + 0xad => Operator::I64ExtendI32U, + 0xae => Operator::I64TruncF32S, + 0xaf => Operator::I64TruncF32U, + 0xb0 => Operator::I64TruncF64S, + 0xb1 => Operator::I64TruncF64U, + 0xb2 => Operator::F32ConvertI32S, + 0xb3 => Operator::F32ConvertI32U, + 0xb4 => Operator::F32ConvertI64S, + 0xb5 => Operator::F32ConvertI64U, + 0xb6 => Operator::F32DemoteF64, + 0xb7 => Operator::F64ConvertI32S, + 0xb8 => Operator::F64ConvertI32U, + 0xb9 => Operator::F64ConvertI64S, + 0xba => Operator::F64ConvertI64U, + 0xbb => Operator::F64PromoteF32, + 0xbc => Operator::I32ReinterpretF32, + 0xbd => Operator::I64ReinterpretF64, + 0xbe => Operator::F32ReinterpretI32, + 0xbf => Operator::F64ReinterpretI64, + + 0xc0 => Operator::I32Extend8S, + 0xc1 => Operator::I32Extend16S, + 0xc2 => Operator::I64Extend8S, + 0xc3 => Operator::I64Extend16S, + 0xc4 => Operator::I64Extend32S, + + 0xd0 => Operator::RefNull, + 0xd1 => Operator::RefIsNull, + 0xd2 => Operator::RefFunc { + function_index: self.read_var_u32()?, + }, + + 0xfc => self.read_0xfc_operator()?, + 0xfd => self.read_0xfd_operator()?, + 0xfe => self.read_0xfe_operator()?, + + _ => { + return Err(BinaryReaderError { + message: "Unknown opcode", + offset: self.original_position() - 1, + }); + } + }) + } + + fn read_0xfc_operator(&mut self) -> Result<Operator<'a>> { + let code = self.read_u8()? as u8; + Ok(match code { + 0x00 => Operator::I32TruncSatF32S, + 0x01 => Operator::I32TruncSatF32U, + 0x02 => Operator::I32TruncSatF64S, + 0x03 => Operator::I32TruncSatF64U, + 0x04 => Operator::I64TruncSatF32S, + 0x05 => Operator::I64TruncSatF32U, + 0x06 => Operator::I64TruncSatF64S, + 0x07 => Operator::I64TruncSatF64U, + + 0x08 => { + let segment = self.read_var_u32()?; + let mem = self.read_u8()?; + if mem != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + Operator::MemoryInit { segment } + } + 0x09 => { + let segment = self.read_var_u32()?; + Operator::DataDrop { segment } + } + 0x0a => { + let dst = self.read_u8()?; + if dst != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + let src = self.read_u8()?; + if src != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + Operator::MemoryCopy + } + 0x0b => { + let mem = self.read_u8()?; + if mem != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + Operator::MemoryFill + } + 0x0c => { + let segment = self.read_var_u32()?; + let table = self.read_var_u32()?; + Operator::TableInit { segment, table } + } + 0x0d => { + let segment = self.read_var_u32()?; + Operator::ElemDrop { segment } + } + 0x0e => { + let dst_table = self.read_var_u32()?; + let src_table = self.read_var_u32()?; + Operator::TableCopy { + src_table, + dst_table, + } + } + + 0x0f => { + let table = self.read_var_u32()?; + Operator::TableGrow { table } + } + 0x10 => { + let table = self.read_var_u32()?; + Operator::TableSize { table } + } + + 0x11 => { + let table = self.read_var_u32()?; + Operator::TableFill { table } + } + + _ => { + return Err(BinaryReaderError { + message: "Unknown 0xfc opcode", + offset: self.original_position() - 1, + }); + } + }) + } + + fn read_lane_index(&mut self, max: u32) -> Result<SIMDLaneIndex> { + let index = self.read_u8()?; + if index >= max { + return Err(BinaryReaderError { + message: "invalid lane index", + offset: self.original_position() - 1, + }); + } + Ok(index as SIMDLaneIndex) + } + + fn read_v128(&mut self) -> Result<V128> { + let mut bytes = [0; 16]; + bytes.clone_from_slice(self.read_bytes(16)?); + Ok(V128(bytes)) + } + + fn read_0xfd_operator(&mut self) -> Result<Operator<'a>> { + let code = self.read_var_u8()? as u8; + Ok(match code { + 0x00 => Operator::V128Load { + memarg: self.read_memarg()?, + }, + 0x01 => Operator::V128Store { + memarg: self.read_memarg()?, + }, + 0x02 => Operator::V128Const { + value: self.read_v128()?, + }, + 0x04 => Operator::I8x16Splat, + 0x05 => Operator::I8x16ExtractLaneS { + lane: self.read_lane_index(16)?, + }, + 0x06 => Operator::I8x16ExtractLaneU { + lane: self.read_lane_index(16)?, + }, + 0x07 => Operator::I8x16ReplaceLane { + lane: self.read_lane_index(16)?, + }, + 0x08 => Operator::I16x8Splat, + 0x09 => Operator::I16x8ExtractLaneS { + lane: self.read_lane_index(8)?, + }, + 0x0a => Operator::I16x8ExtractLaneU { + lane: self.read_lane_index(8)?, + }, + 0x0b => Operator::I16x8ReplaceLane { + lane: self.read_lane_index(8)?, + }, + 0x0c => Operator::I32x4Splat, + 0x0d => Operator::I32x4ExtractLane { + lane: self.read_lane_index(4)?, + }, + 0x0e => Operator::I32x4ReplaceLane { + lane: self.read_lane_index(4)?, + }, + 0x0f => Operator::I64x2Splat, + 0x10 => Operator::I64x2ExtractLane { + lane: self.read_lane_index(2)?, + }, + 0x11 => Operator::I64x2ReplaceLane { + lane: self.read_lane_index(2)?, + }, + 0x12 => Operator::F32x4Splat, + 0x13 => Operator::F32x4ExtractLane { + lane: self.read_lane_index(4)?, + }, + 0x14 => Operator::F32x4ReplaceLane { + lane: self.read_lane_index(4)?, + }, + 0x15 => Operator::F64x2Splat, + 0x16 => Operator::F64x2ExtractLane { + lane: self.read_lane_index(2)?, + }, + 0x17 => Operator::F64x2ReplaceLane { + lane: self.read_lane_index(2)?, + }, + 0x18 => Operator::I8x16Eq, + 0x19 => Operator::I8x16Ne, + 0x1a => Operator::I8x16LtS, + 0x1b => Operator::I8x16LtU, + 0x1c => Operator::I8x16GtS, + 0x1d => Operator::I8x16GtU, + 0x1e => Operator::I8x16LeS, + 0x1f => Operator::I8x16LeU, + 0x20 => Operator::I8x16GeS, + 0x21 => Operator::I8x16GeU, + 0x22 => Operator::I16x8Eq, + 0x23 => Operator::I16x8Ne, + 0x24 => Operator::I16x8LtS, + 0x25 => Operator::I16x8LtU, + 0x26 => Operator::I16x8GtS, + 0x27 => Operator::I16x8GtU, + 0x28 => Operator::I16x8LeS, + 0x29 => Operator::I16x8LeU, + 0x2a => Operator::I16x8GeS, + 0x2b => Operator::I16x8GeU, + 0x2c => Operator::I32x4Eq, + 0x2d => Operator::I32x4Ne, + 0x2e => Operator::I32x4LtS, + 0x2f => Operator::I32x4LtU, + 0x30 => Operator::I32x4GtS, + 0x31 => Operator::I32x4GtU, + 0x32 => Operator::I32x4LeS, + 0x33 => Operator::I32x4LeU, + 0x34 => Operator::I32x4GeS, + 0x35 => Operator::I32x4GeU, + 0x40 => Operator::F32x4Eq, + 0x41 => Operator::F32x4Ne, + 0x42 => Operator::F32x4Lt, + 0x43 => Operator::F32x4Gt, + 0x44 => Operator::F32x4Le, + 0x45 => Operator::F32x4Ge, + 0x46 => Operator::F64x2Eq, + 0x47 => Operator::F64x2Ne, + 0x48 => Operator::F64x2Lt, + 0x49 => Operator::F64x2Gt, + 0x4a => Operator::F64x2Le, + 0x4b => Operator::F64x2Ge, + 0x4c => Operator::V128Not, + 0x4d => Operator::V128And, + 0x4e => Operator::V128Or, + 0x4f => Operator::V128Xor, + 0x50 => Operator::V128Bitselect, + 0x51 => Operator::I8x16Neg, + 0x52 => Operator::I8x16AnyTrue, + 0x53 => Operator::I8x16AllTrue, + 0x54 => Operator::I8x16Shl, + 0x55 => Operator::I8x16ShrS, + 0x56 => Operator::I8x16ShrU, + 0x57 => Operator::I8x16Add, + 0x58 => Operator::I8x16AddSaturateS, + 0x59 => Operator::I8x16AddSaturateU, + 0x5a => Operator::I8x16Sub, + 0x5b => Operator::I8x16SubSaturateS, + 0x5c => Operator::I8x16SubSaturateU, + 0x5d => Operator::I8x16Mul, + 0x62 => Operator::I16x8Neg, + 0x63 => Operator::I16x8AnyTrue, + 0x64 => Operator::I16x8AllTrue, + 0x65 => Operator::I16x8Shl, + 0x66 => Operator::I16x8ShrS, + 0x67 => Operator::I16x8ShrU, + 0x68 => Operator::I16x8Add, + 0x69 => Operator::I16x8AddSaturateS, + 0x6a => Operator::I16x8AddSaturateU, + 0x6b => Operator::I16x8Sub, + 0x6c => Operator::I16x8SubSaturateS, + 0x6d => Operator::I16x8SubSaturateU, + 0x6e => Operator::I16x8Mul, + 0x73 => Operator::I32x4Neg, + 0x74 => Operator::I32x4AnyTrue, + 0x75 => Operator::I32x4AllTrue, + 0x76 => Operator::I32x4Shl, + 0x77 => Operator::I32x4ShrS, + 0x78 => Operator::I32x4ShrU, + 0x79 => Operator::I32x4Add, + 0x7c => Operator::I32x4Sub, + 0x7f => Operator::I32x4Mul, + 0x84 => Operator::I64x2Neg, + 0x85 => Operator::I64x2AnyTrue, + 0x86 => Operator::I64x2AllTrue, + 0x87 => Operator::I64x2Shl, + 0x88 => Operator::I64x2ShrS, + 0x89 => Operator::I64x2ShrU, + 0x8a => Operator::I64x2Add, + 0x8d => Operator::I64x2Sub, + 0x90 => Operator::I64x2Mul, + 0x95 => Operator::F32x4Abs, + 0x96 => Operator::F32x4Neg, + 0x97 => Operator::F32x4Sqrt, + 0x9a => Operator::F32x4Add, + 0x9b => Operator::F32x4Sub, + 0x9c => Operator::F32x4Mul, + 0x9d => Operator::F32x4Div, + 0x9e => Operator::F32x4Min, + 0x9f => Operator::F32x4Max, + 0xa0 => Operator::F64x2Abs, + 0xa1 => Operator::F64x2Neg, + 0xa2 => Operator::F64x2Sqrt, + 0xa5 => Operator::F64x2Add, + 0xa6 => Operator::F64x2Sub, + 0xa7 => Operator::F64x2Mul, + 0xa8 => Operator::F64x2Div, + 0xa9 => Operator::F64x2Min, + 0xaa => Operator::F64x2Max, + 0xab => Operator::I32x4TruncSatF32x4S, + 0xac => Operator::I32x4TruncSatF32x4U, + 0xad => Operator::I64x2TruncSatF64x2S, + 0xae => Operator::I64x2TruncSatF64x2U, + 0xaf => Operator::F32x4ConvertI32x4S, + 0xb0 => Operator::F32x4ConvertI32x4U, + 0xb1 => Operator::F64x2ConvertI64x2S, + 0xb2 => Operator::F64x2ConvertI64x2U, + 0xc0 => Operator::V8x16Swizzle, + 0x03 | 0xc1 => { + let mut lanes = [0 as SIMDLaneIndex; 16]; + for lane in &mut lanes { + *lane = self.read_lane_index(32)? + } + Operator::V8x16Shuffle { lanes } + } + 0xc2 => Operator::V8x16LoadSplat { + memarg: self.read_memarg_of_align(0)?, + }, + 0xc3 => Operator::V16x8LoadSplat { + memarg: self.read_memarg_of_align(1)?, + }, + 0xc4 => Operator::V32x4LoadSplat { + memarg: self.read_memarg_of_align(2)?, + }, + 0xc5 => Operator::V64x2LoadSplat { + memarg: self.read_memarg_of_align(3)?, + }, + 0xc6 => Operator::I8x16NarrowI16x8S, + 0xc7 => Operator::I8x16NarrowI16x8U, + 0xc8 => Operator::I16x8NarrowI32x4S, + 0xc9 => Operator::I16x8NarrowI32x4U, + 0xca => Operator::I16x8WidenLowI8x16S, + 0xcb => Operator::I16x8WidenHighI8x16S, + 0xcc => Operator::I16x8WidenLowI8x16U, + 0xcd => Operator::I16x8WidenHighI8x16U, + 0xce => Operator::I32x4WidenLowI16x8S, + 0xcf => Operator::I32x4WidenHighI16x8S, + 0xd0 => Operator::I32x4WidenLowI16x8U, + 0xd1 => Operator::I32x4WidenHighI16x8U, + 0xd2 => Operator::I16x8Load8x8S { + memarg: self.read_memarg_of_align(3)?, + }, + 0xd3 => Operator::I16x8Load8x8U { + memarg: self.read_memarg_of_align(3)?, + }, + 0xd4 => Operator::I32x4Load16x4S { + memarg: self.read_memarg_of_align(3)?, + }, + 0xd5 => Operator::I32x4Load16x4U { + memarg: self.read_memarg_of_align(3)?, + }, + 0xd6 => Operator::I64x2Load32x2S { + memarg: self.read_memarg_of_align(3)?, + }, + 0xd7 => Operator::I64x2Load32x2U { + memarg: self.read_memarg_of_align(3)?, + }, + 0xd8 => Operator::V128AndNot, + 0xd9 => Operator::I8x16RoundingAverageU, + 0xda => Operator::I16x8RoundingAverageU, + _ => { + return Err(BinaryReaderError { + message: "Unknown 0xfd opcode", + offset: self.original_position() - 1, + }); + } + }) + } + + pub(crate) fn read_file_header(&mut self) -> Result<u32> { + let magic_number = self.read_bytes(4)?; + if magic_number != WASM_MAGIC_NUMBER { + return Err(BinaryReaderError { + message: "Bad magic number", + offset: self.original_position() - 4, + }); + } + let version = self.read_u32()?; + if version != WASM_SUPPORTED_VERSION && version != WASM_EXPERIMENTAL_VERSION { + return Err(BinaryReaderError { + message: "Bad version number", + offset: self.original_position() - 4, + }); + } + Ok(version) + } + + pub(crate) fn read_section_header(&mut self) -> Result<SectionHeader<'a>> { + let id_position = self.position; + let id = self.read_var_u7()?; + let payload_len = self.read_var_u32()? as usize; + let payload_start = self.position; + let code = self.read_section_code(id, id_position)?; + Ok(SectionHeader { + code, + payload_start, + payload_len, + }) + } + + pub(crate) fn read_name_type(&mut self) -> Result<NameType> { + let code = self.read_var_u7()?; + match code { + 0 => Ok(NameType::Module), + 1 => Ok(NameType::Function), + 2 => Ok(NameType::Local), + _ => Err(BinaryReaderError { + message: "Invalid name type", + offset: self.original_position() - 1, + }), + } + } + + pub(crate) fn read_linking_type(&mut self) -> Result<LinkingType> { + let ty = self.read_var_u32()?; + Ok(match ty { + 1 => LinkingType::StackPointer(self.read_var_u32()?), + _ => { + return Err(BinaryReaderError { + message: "Invalid linking type", + offset: self.original_position() - 1, + }); + } + }) + } + + pub(crate) fn read_reloc_type(&mut self) -> Result<RelocType> { + let code = self.read_var_u7()?; + match code { + 0 => Ok(RelocType::FunctionIndexLEB), + 1 => Ok(RelocType::TableIndexSLEB), + 2 => Ok(RelocType::TableIndexI32), + 3 => Ok(RelocType::GlobalAddrLEB), + 4 => Ok(RelocType::GlobalAddrSLEB), + 5 => Ok(RelocType::GlobalAddrI32), + 6 => Ok(RelocType::TypeIndexLEB), + 7 => Ok(RelocType::GlobalIndexLEB), + _ => Err(BinaryReaderError { + message: "Invalid reloc type", + offset: self.original_position() - 1, + }), + } + } + + pub(crate) fn skip_init_expr(&mut self) -> Result<()> { + // TODO add skip_operator() method and/or validate init_expr operators. + loop { + if let Operator::End = self.read_operator()? { + return Ok(()); + } + } + } +} + +impl<'a> BrTable<'a> { + /// Returns the number of `br_table` entries, not including the default + /// label + pub fn len(&self) -> usize { + self.cnt + } + + /// Returns whether `BrTable` doesn't have any labels apart from the default one. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Reads br_table entries. + /// + /// # Examples + /// ```rust + /// let buf = vec![0x0e, 0x02, 0x01, 0x02, 0x00]; + /// let mut reader = wasmparser::BinaryReader::new(&buf); + /// let op = reader.read_operator().unwrap(); + /// if let wasmparser::Operator::BrTable { ref table } = op { + /// let br_table_depths = table.read_table().unwrap(); + /// assert!(br_table_depths.0 == vec![1,2].into_boxed_slice() && + /// br_table_depths.1 == 0); + /// } else { + /// unreachable!(); + /// } + /// ``` + pub fn read_table(&self) -> Result<(Box<[u32]>, u32)> { + let mut reader = BinaryReader::new(self.buffer); + let mut table = Vec::new(); + while !reader.eof() { + table.push(reader.read_var_u32()?); + } + let default_target = table.pop().ok_or_else(|| BinaryReaderError { + message: "br_table missing default target", + offset: reader.original_position(), + })?; + Ok((table.into_boxed_slice(), default_target)) + } +} + +/// Iterator for `BrTable`. +/// +/// #Examples +/// ```rust +/// let buf = vec![0x0e, 0x02, 0x01, 0x02, 0x00]; +/// let mut reader = wasmparser::BinaryReader::new(&buf); +/// let op = reader.read_operator().unwrap(); +/// if let wasmparser::Operator::BrTable { ref table } = op { +/// for depth in table { +/// println!("BrTable depth: {}", depth); +/// } +/// } +/// ``` +#[derive(Clone, Debug)] +pub struct BrTableIterator<'a> { + reader: BinaryReader<'a>, +} + +impl<'a> IntoIterator for &'a BrTable<'a> { + type Item = u32; + type IntoIter = BrTableIterator<'a>; + + fn into_iter(self) -> Self::IntoIter { + BrTableIterator { + reader: BinaryReader::new(self.buffer), + } + } +} + +impl<'a> Iterator for BrTableIterator<'a> { + type Item = u32; + + fn next(&mut self) -> Option<u32> { + if self.reader.eof() { + return None; + } + self.reader.read_var_u32().ok() + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/lib.rs b/third_party/rust/wasmparser-0.48.2/src/lib.rs new file mode 100644 index 0000000000..e581b932da --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/lib.rs @@ -0,0 +1,131 @@ +/* Copyright 2017 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. + */ + +//! A simple event-driven library for parsing WebAssembly binary files +//! (or streams). +//! +//! The parser library reports events as they happend and only stores +//! parsing information for a brief period of time, making it very fast +//! and memory-efficient. The event-driven model, however, has some drawbacks. +//! If you need random access to the entire WebAssembly data-structure, +//! this is not the right library for you. You could however, build such +//! a data-structure using this library. + +pub use crate::binary_reader::BinaryReader; +pub use crate::binary_reader::Range; +use crate::binary_reader::SectionHeader; + +pub use crate::parser::ElemSectionEntryTable; +pub use crate::parser::LocalName; +pub use crate::parser::NameEntry; +pub use crate::parser::Parser; +pub use crate::parser::ParserInput; +pub use crate::parser::ParserState; +pub use crate::parser::RelocEntry; +pub use crate::parser::WasmDecoder; + +pub use crate::primitives::BinaryReaderError; +pub use crate::primitives::BrTable; +pub use crate::primitives::CustomSectionKind; +pub use crate::primitives::ExternalKind; +pub use crate::primitives::FuncType; +pub use crate::primitives::GlobalType; +pub use crate::primitives::Ieee32; +pub use crate::primitives::Ieee64; +pub use crate::primitives::ImportSectionEntryType; +pub use crate::primitives::LinkingType; +pub use crate::primitives::MemoryImmediate; +pub use crate::primitives::MemoryType; +pub use crate::primitives::NameType; +pub use crate::primitives::Naming; +pub use crate::primitives::Operator; +pub use crate::primitives::RelocType; +pub use crate::primitives::ResizableLimits; +pub use crate::primitives::Result; +pub use crate::primitives::SectionCode; +pub use crate::primitives::TableType; +pub use crate::primitives::Type; +pub use crate::primitives::TypeOrFuncType; +pub use crate::primitives::V128; + +pub use crate::validator::validate; +pub use crate::validator::validate_function_body; +pub use crate::validator::ValidatingOperatorParser; +pub use crate::validator::ValidatingParser; +pub use crate::validator::ValidatingParserConfig; + +pub use crate::module_resources::WasmFuncType; +pub use crate::module_resources::WasmGlobalType; +pub use crate::module_resources::WasmMemoryType; +pub use crate::module_resources::WasmModuleResources; +pub use crate::module_resources::WasmTableType; +pub use crate::module_resources::WasmType; + +pub(crate) use crate::module_resources::{wasm_func_type_inputs, wasm_func_type_outputs}; + +pub use crate::operators_validator::OperatorValidatorConfig; + +pub use crate::readers::CodeSectionReader; +pub use crate::readers::CustomSectionContent; +pub use crate::readers::Data; +pub use crate::readers::DataKind; +pub use crate::readers::DataSectionReader; +pub use crate::readers::Element; +pub use crate::readers::ElementItem; +pub use crate::readers::ElementItems; +pub use crate::readers::ElementItemsReader; +pub use crate::readers::ElementKind; +pub use crate::readers::ElementSectionReader; +pub use crate::readers::Export; +pub use crate::readers::ExportSectionReader; +pub use crate::readers::FunctionBody; +pub use crate::readers::FunctionSectionReader; +pub use crate::readers::Global; +pub use crate::readers::GlobalSectionReader; +pub use crate::readers::Import; +pub use crate::readers::ImportSectionReader; +pub use crate::readers::InitExpr; +pub use crate::readers::LinkingSectionReader; +pub use crate::readers::LocalsReader; +pub use crate::readers::MemorySectionReader; +pub use crate::readers::ModuleReader; +pub use crate::readers::Name; +pub use crate::readers::NameSectionReader; +pub use crate::readers::NamingReader; +pub use crate::readers::OperatorsReader; +pub use crate::readers::ProducersField; +pub use crate::readers::ProducersFieldValue; +pub use crate::readers::ProducersFieldValuesReader; +pub use crate::readers::ProducersSectionReader; +pub use crate::readers::Reloc; +pub use crate::readers::RelocSectionReader; +pub use crate::readers::Section; +pub use crate::readers::SectionContent; +pub use crate::readers::SectionIterator; +pub use crate::readers::SectionIteratorLimited; +pub use crate::readers::SectionReader; +pub use crate::readers::SectionWithLimitedItems; +pub use crate::readers::TableSectionReader; +pub use crate::readers::TypeSectionReader; + +mod binary_reader; +mod limits; +mod module_resources; +mod operators_validator; +mod parser; +mod primitives; +mod readers; +mod tests; +mod validator; diff --git a/third_party/rust/wasmparser-0.48.2/src/limits.rs b/third_party/rust/wasmparser-0.48.2/src/limits.rs new file mode 100644 index 0000000000..38594a6362 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/limits.rs @@ -0,0 +1,34 @@ +/* Copyright 2017 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. + */ + +// The following limits are imposed by wasmparser on WebAssembly modules. +// The limits are agreed upon with other engines for consistency. +pub const MAX_WASM_TYPES: usize = 1_000_000; +pub const MAX_WASM_FUNCTIONS: usize = 1_000_000; +pub const _MAX_WASM_IMPORTS: usize = 100_000; +pub const _MAX_WASM_EXPORTS: usize = 100_000; +pub const MAX_WASM_GLOBALS: usize = 1_000_000; +pub const _MAX_WASM_DATA_SEGMENTS: usize = 100_000; +pub const MAX_WASM_MEMORY_PAGES: usize = 65536; +pub const MAX_WASM_STRING_SIZE: usize = 100_000; +pub const _MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB +pub const MAX_WASM_FUNCTION_SIZE: usize = 128 * 1024; +pub const MAX_WASM_FUNCTION_LOCALS: usize = 50000; +pub const MAX_WASM_FUNCTION_PARAMS: usize = 1000; +pub const MAX_WASM_FUNCTION_RETURNS: usize = 1000; +pub const _MAX_WASM_TABLE_SIZE: usize = 10_000_000; +pub const MAX_WASM_TABLE_ENTRIES: usize = 10_000_000; +pub const MAX_WASM_TABLES: usize = 1; +pub const MAX_WASM_MEMORIES: usize = 1; diff --git a/third_party/rust/wasmparser-0.48.2/src/module_resources.rs b/third_party/rust/wasmparser-0.48.2/src/module_resources.rs new file mode 100644 index 0000000000..09b193757d --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/module_resources.rs @@ -0,0 +1,370 @@ +/* Copyright 2019 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. + */ + +/// Types that qualify as Wasm types for validation purposes. +/// +/// Must be comparable with `wasmparser` given Wasm types and +/// must be comparable to themselves. +pub trait WasmType: PartialEq<crate::Type> + PartialEq + Eq { + /// Converts the custom type into a `wasmparser` known type. + /// + /// # Note + /// + /// This interface is required as bridge until transitioning is complete. + fn to_parser_type(&self) -> crate::Type; +} + +/// Types that qualify as Wasm function types for validation purposes. +pub trait WasmFuncType { + /// A type that is comparable with Wasm types. + type Type: WasmType; + + /// Returns the number of input types. + fn len_inputs(&self) -> usize; + /// Returns the number of output types. + fn len_outputs(&self) -> usize; + /// Returns the type at given index if any. + /// + /// # Note + /// + /// The returned type may be wrapped by the user crate and thus + /// the actually returned type only has to be comparable to a Wasm type. + fn input_at(&self, at: u32) -> Option<&Self::Type>; + /// Returns the type at given index if any. + /// + /// # Note + /// + /// The returned type may be wrapped by the user crate and thus + /// the actually returned type only has to be comparable to a Wasm type. + fn output_at(&self, at: u32) -> Option<&Self::Type>; +} + +/// Iterator over the inputs of a Wasm function type. +pub(crate) struct WasmFuncTypeInputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + /// The iterated-over function type. + func_type: &'a F, + /// The current starting index. + start: u32, + /// The current ending index. + end: u32, +} + +impl<'a, F, T> WasmFuncTypeInputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + fn new(func_type: &'a F) -> Self { + Self { + func_type, + start: 0, + end: func_type.len_inputs() as u32, + } + } +} + +impl<'a, F, T> Iterator for WasmFuncTypeInputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + type Item = &'a T; + + fn next(&mut self) -> Option<Self::Item> { + if self.start == self.end { + return None; + } + let ty = self + .func_type + .input_at(self.start) + // Expected since `self.start != self.end`. + .expect("we expect to receive an input type at this point"); + self.start += 1; + Some(ty) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len(), Some(self.len())) + } +} + +impl<'a, F, T> DoubleEndedIterator for WasmFuncTypeInputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + fn next_back(&mut self) -> Option<Self::Item> { + if self.start == self.end { + return None; + } + let ty = self + .func_type + .input_at(self.end) + // Expected since `self.start != self.end`. + .expect("we expect to receive an input type at this point"); + self.end -= 1; + Some(ty) + } +} + +impl<'a, F, T> ExactSizeIterator for WasmFuncTypeInputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + fn len(&self) -> usize { + (self.end as usize) - (self.start as usize) + } +} + +/// Iterator over the outputs of a Wasm function type. +pub(crate) struct WasmFuncTypeOutputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + /// The iterated-over function type. + func_type: &'a F, + /// The current starting index. + start: u32, + /// The current ending index. + end: u32, +} + +impl<'a, F, T> WasmFuncTypeOutputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + fn new(func_type: &'a F) -> Self { + Self { + func_type, + start: 0, + end: func_type.len_outputs() as u32, + } + } +} + +impl<'a, F, T> Iterator for WasmFuncTypeOutputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + type Item = &'a T; + + fn next(&mut self) -> Option<Self::Item> { + if self.start == self.end { + return None; + } + let ty = self + .func_type + .output_at(self.start) + // Expected since `self.start != self.end`. + .expect("we expect to receive an input type at this point"); + self.start += 1; + Some(ty) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len(), Some(self.len())) + } +} + +impl<'a, F, T> DoubleEndedIterator for WasmFuncTypeOutputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + fn next_back(&mut self) -> Option<Self::Item> { + if self.start == self.end { + return None; + } + let ty = self + .func_type + .output_at(self.end) + // Expected since `self.start != self.end`. + .expect("we expect to receive an input type at this point"); + self.end -= 1; + Some(ty) + } +} + +impl<'a, F, T> ExactSizeIterator for WasmFuncTypeOutputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + fn len(&self) -> usize { + (self.end as usize) - (self.start as usize) + } +} + +/// Returns an iterator over the input types of a Wasm function type. +pub(crate) fn wasm_func_type_inputs<'a, F, T>(func_type: &'a F) -> WasmFuncTypeInputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + WasmFuncTypeInputs::new(func_type) +} + +/// Returns an iterator over the output types of a Wasm function type. +pub(crate) fn wasm_func_type_outputs<'a, F, T>(func_type: &'a F) -> WasmFuncTypeOutputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + WasmFuncTypeOutputs::new(func_type) +} + +/// Types that qualify as Wasm table types for validation purposes. +pub trait WasmTableType { + /// A type that is comparable with Wasm types. + type Type: WasmType; + + /// Returns the element type of the table. + fn element_type(&self) -> &Self::Type; + /// Returns the initial limit of the table. + fn initial_limit(&self) -> u32; + /// Returns the maximum limit of the table if any. + fn maximum_limit(&self) -> Option<u32>; +} + +/// Types that qualify as Wasm memory types for validation purposes. +pub trait WasmMemoryType { + /// Returns `true` if the linear memory is shared. + fn is_shared(&self) -> bool; + /// Returns the initial limit of the linear memory. + fn initial_limit(&self) -> u32; + /// Returns the maximum limit of the linear memory if any. + fn maximum_limit(&self) -> Option<u32>; +} + +/// Types that qualify as Wasm global types for validation purposes. +pub trait WasmGlobalType { + /// A type that is comparable with Wasm types. + type Type: WasmType; + + /// Returns `true` if the global variable is mutable. + fn is_mutable(&self) -> bool; + /// Returns the content type of the global variable. + fn content_type(&self) -> &Self::Type; +} + +/// Types that qualify as Wasm valiation database. +/// +/// # Note +/// +/// The `wasmparser` crate provides a builtin validation framework but allows +/// users of this crate to also feed the parsed Wasm into their own data +/// structure while parsing and also validate at the same time without +/// the need of an additional parsing or validation step or copying data around. +pub trait WasmModuleResources { + /// The function type used for validation. + type FuncType: WasmFuncType; + /// The table type used for validation. + type TableType: WasmTableType; + /// The memory type used for validation. + type MemoryType: WasmMemoryType; + /// The global type used for validation. + type GlobalType: WasmGlobalType; + + /// Returns the type at given index. + fn type_at(&self, at: u32) -> Option<&Self::FuncType>; + /// Returns the table at given index if any. + fn table_at(&self, at: u32) -> Option<&Self::TableType>; + /// Returns the linear memory at given index. + fn memory_at(&self, at: u32) -> Option<&Self::MemoryType>; + /// Returns the global variable at given index. + fn global_at(&self, at: u32) -> Option<&Self::GlobalType>; + /// Returns the function signature ID at given index. + fn func_type_id_at(&self, at: u32) -> Option<u32>; + + /// Returns the number of elements. + fn element_count(&self) -> u32; + /// Returns the number of bytes in the Wasm data section. + fn data_count(&self) -> u32; +} + +impl WasmType for crate::Type { + fn to_parser_type(&self) -> crate::Type { + *self + } +} + +impl WasmFuncType for crate::FuncType { + type Type = crate::Type; + + fn len_inputs(&self) -> usize { + self.params.len() + } + + fn len_outputs(&self) -> usize { + self.returns.len() + } + + fn input_at(&self, at: u32) -> Option<&Self::Type> { + self.params.get(at as usize) + } + + fn output_at(&self, at: u32) -> Option<&Self::Type> { + self.returns.get(at as usize) + } +} + +impl WasmGlobalType for crate::GlobalType { + type Type = crate::Type; + + fn is_mutable(&self) -> bool { + self.mutable + } + + fn content_type(&self) -> &Self::Type { + &self.content_type + } +} + +impl WasmTableType for crate::TableType { + type Type = crate::Type; + + fn element_type(&self) -> &Self::Type { + &self.element_type + } + + fn initial_limit(&self) -> u32 { + self.limits.initial + } + + fn maximum_limit(&self) -> Option<u32> { + self.limits.maximum + } +} + +impl WasmMemoryType for crate::MemoryType { + fn is_shared(&self) -> bool { + self.shared + } + + fn initial_limit(&self) -> u32 { + self.limits.initial + } + fn maximum_limit(&self) -> Option<u32> { + self.limits.maximum + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/operators_validator.rs b/third_party/rust/wasmparser-0.48.2/src/operators_validator.rs new file mode 100644 index 0000000000..71f9bc319c --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/operators_validator.rs @@ -0,0 +1,1896 @@ +/* Copyright 2019 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. + */ + +use std::cmp::min; +use std::result; +use std::str; + +use crate::primitives::{MemoryImmediate, Operator, SIMDLaneIndex, Type, TypeOrFuncType}; +use crate::{ + wasm_func_type_inputs, wasm_func_type_outputs, WasmFuncType, WasmGlobalType, WasmMemoryType, + WasmModuleResources, WasmTableType, WasmType, +}; + +/// Test if `subtype` is a subtype of `supertype`. +pub(crate) fn is_subtype_supertype(subtype: Type, supertype: Type) -> bool { + match supertype { + Type::AnyRef => { + subtype == Type::AnyRef || subtype == Type::AnyFunc || subtype == Type::NullRef + } + Type::AnyFunc => subtype == Type::AnyFunc || subtype == Type::NullRef, + _ => subtype == supertype, + } +} + +#[derive(Debug)] +struct BlockState { + start_types: Vec<Type>, + return_types: Vec<Type>, + stack_starts_at: usize, + jump_to_top: bool, + is_else_allowed: bool, + is_dead_code: bool, + polymorphic_values: Option<usize>, +} + +impl BlockState { + fn is_stack_polymorphic(&self) -> bool { + self.polymorphic_values.is_some() + } +} + +#[derive(Debug)] +struct FuncState { + local_types: Vec<Type>, + blocks: Vec<BlockState>, + stack_types: Vec<Type>, + end_function: bool, +} + +impl FuncState { + fn block_at(&self, depth: usize) -> &BlockState { + assert!(depth < self.blocks.len()); + &self.blocks[self.blocks.len() - 1 - depth] + } + fn last_block(&self) -> &BlockState { + self.blocks.last().unwrap() + } + fn assert_stack_type_at(&self, index: usize, expected: Type) -> bool { + let stack_starts_at = self.last_block().stack_starts_at; + if self.last_block().is_stack_polymorphic() + && stack_starts_at + index >= self.stack_types.len() + { + return true; + } + assert!(stack_starts_at + index < self.stack_types.len()); + is_subtype_supertype( + self.stack_types[self.stack_types.len() - 1 - index], + expected, + ) + } + fn assert_block_stack_len(&self, depth: usize, minimal_len: usize) -> bool { + assert!(depth < self.blocks.len()); + let blocks_end = self.blocks.len(); + let block_offset = blocks_end - 1 - depth; + for i in block_offset..blocks_end { + if self.blocks[i].is_stack_polymorphic() { + return true; + } + } + let block_starts_at = self.blocks[block_offset].stack_starts_at; + self.stack_types.len() >= block_starts_at + minimal_len + } + fn assert_last_block_stack_len_exact(&self, len: usize) -> bool { + let block_starts_at = self.last_block().stack_starts_at; + if self.last_block().is_stack_polymorphic() { + let polymorphic_values = self.last_block().polymorphic_values.unwrap(); + self.stack_types.len() + polymorphic_values <= block_starts_at + len + } else { + self.stack_types.len() == block_starts_at + len + } + } + fn remove_frame_stack_types(&mut self, remove_count: usize) -> OperatorValidatorResult<()> { + if remove_count == 0 { + return Ok(()); + } + let last_block = self.blocks.last_mut().unwrap(); + if last_block.is_stack_polymorphic() { + let len = self.stack_types.len(); + let remove_non_polymorphic = len + .checked_sub(last_block.stack_starts_at) + .ok_or("invalid block signature")? + .min(remove_count); + self.stack_types.truncate(len - remove_non_polymorphic); + let polymorphic_values = last_block.polymorphic_values.unwrap(); + let remove_polymorphic = min(remove_count - remove_non_polymorphic, polymorphic_values); + last_block.polymorphic_values = Some(polymorphic_values - remove_polymorphic); + } else { + assert!(self.stack_types.len() >= last_block.stack_starts_at + remove_count); + let keep = self.stack_types.len() - remove_count; + self.stack_types.truncate(keep); + } + Ok(()) + } + fn push_block<F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>( + &mut self, + ty: TypeOrFuncType, + block_type: BlockType, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<()> { + let (start_types, return_types) = match ty { + TypeOrFuncType::Type(Type::EmptyBlockType) => (vec![], vec![]), + TypeOrFuncType::Type(ty) => (vec![], vec![ty]), + TypeOrFuncType::FuncType(idx) => { + let ty = resources + .type_at(idx) + // Note: This was an out-of-bounds memory access before + // the change to return `Option` at `type_at`. So + // I assumed that invalid indices at this point are + // bugs. + .expect("function type index is out of bounds"); + ( + wasm_func_type_inputs(ty) + .map(WasmType::to_parser_type) + .collect::<Vec<_>>(), + wasm_func_type_outputs(ty) + .map(WasmType::to_parser_type) + .collect::<Vec<_>>(), + ) + } + }; + if block_type == BlockType::If { + let last_block = self.blocks.last().unwrap(); + if !last_block.is_stack_polymorphic() + || self.stack_types.len() > last_block.stack_starts_at + { + self.stack_types.pop(); + } + assert!(self.stack_types.len() >= last_block.stack_starts_at); + } + for (i, ty) in start_types.iter().rev().enumerate() { + if !self.assert_stack_type_at(i, *ty) { + return Err("stack operand type mismatch"); + } + } + let stack_starts_at = self.stack_types.len() - start_types.len(); + self.blocks.push(BlockState { + start_types, + return_types, + stack_starts_at, + jump_to_top: block_type == BlockType::Loop, + is_else_allowed: block_type == BlockType::If, + is_dead_code: false, + polymorphic_values: None, + }); + Ok(()) + } + fn pop_block(&mut self) { + assert!(self.blocks.len() > 1); + let last_block = self.blocks.pop().unwrap(); + if last_block.is_stack_polymorphic() { + assert!( + self.stack_types.len() + <= last_block.return_types.len() + last_block.stack_starts_at + ); + } else { + assert!( + self.stack_types.len() + == last_block.return_types.len() + last_block.stack_starts_at + ); + } + let keep = last_block.stack_starts_at; + self.stack_types.truncate(keep); + self.stack_types.extend_from_slice(&last_block.return_types); + } + fn reset_block(&mut self) { + assert!(self.last_block().is_else_allowed); + let last_block = self.blocks.last_mut().unwrap(); + let keep = last_block.stack_starts_at; + self.stack_types.truncate(keep); + self.stack_types + .extend(last_block.start_types.iter().cloned()); + last_block.is_else_allowed = false; + last_block.polymorphic_values = None; + } + fn change_frame(&mut self, remove_count: usize) -> OperatorValidatorResult<()> { + self.remove_frame_stack_types(remove_count) + } + fn change_frame_with_type( + &mut self, + remove_count: usize, + ty: Type, + ) -> OperatorValidatorResult<()> { + self.remove_frame_stack_types(remove_count)?; + self.stack_types.push(ty); + Ok(()) + } + fn change_frame_with_types<I>( + &mut self, + remove_count: usize, + new_items: I, + ) -> OperatorValidatorResult<()> + where + I: Iterator<Item = Type>, + { + self.remove_frame_stack_types(remove_count)?; + self.stack_types.extend(new_items); + Ok(()) + } + fn change_frame_to_exact_types_from(&mut self, depth: usize) -> OperatorValidatorResult<()> { + let types = self.block_at(depth).return_types.clone(); + let last_block = self.blocks.last_mut().unwrap(); + let keep = last_block.stack_starts_at; + self.stack_types.truncate(keep); + self.stack_types.extend_from_slice(&types); + last_block.polymorphic_values = None; + Ok(()) + } + fn change_frame_after_select(&mut self, ty: Option<Type>) -> OperatorValidatorResult<()> { + self.remove_frame_stack_types(3)?; + if ty.is_none() { + let last_block = self.blocks.last_mut().unwrap(); + assert!(last_block.is_stack_polymorphic()); + last_block.polymorphic_values = Some(last_block.polymorphic_values.unwrap() + 1); + return Ok(()); + } + self.stack_types.push(ty.unwrap()); + Ok(()) + } + fn start_dead_code(&mut self) { + let last_block = self.blocks.last_mut().unwrap(); + let keep = last_block.stack_starts_at; + self.stack_types.truncate(keep); + last_block.is_dead_code = true; + last_block.polymorphic_values = Some(0); + } + fn end_function(&mut self) { + self.end_function = true; + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +enum BlockType { + Block, + Loop, + If, +} + +pub enum FunctionEnd { + No, + Yes, +} + +type OperatorValidatorResult<T> = result::Result<T, &'static str>; + +#[derive(Copy, Clone, Debug)] +pub struct OperatorValidatorConfig { + pub enable_threads: bool, + pub enable_reference_types: bool, + pub enable_simd: bool, + pub enable_bulk_memory: bool, + pub enable_multi_value: bool, + + #[cfg(feature = "deterministic")] + pub deterministic_only: bool, +} + +pub(crate) const DEFAULT_OPERATOR_VALIDATOR_CONFIG: OperatorValidatorConfig = + OperatorValidatorConfig { + enable_threads: false, + enable_reference_types: false, + enable_simd: false, + enable_bulk_memory: false, + enable_multi_value: false, + + #[cfg(feature = "deterministic")] + deterministic_only: true, + }; + +#[derive(Debug)] +pub(crate) struct OperatorValidator { + func_state: FuncState, + config: OperatorValidatorConfig, +} + +impl OperatorValidator { + pub fn new<F, T>( + func_type: &F, + locals: &[(u32, Type)], + config: OperatorValidatorConfig, + ) -> OperatorValidator + where + F: WasmFuncType<Type = T>, + T: WasmType, + { + let local_types = { + let mut local_types = wasm_func_type_inputs(func_type) + .map(WasmType::to_parser_type) + .collect::<Vec<_>>(); + for local in locals { + for _ in 0..local.0 { + local_types.push(local.1); + } + } + local_types + }; + let mut blocks = Vec::new(); + let last_returns = wasm_func_type_outputs(func_type) + .map(WasmType::to_parser_type) + .collect::<Vec<_>>(); + blocks.push(BlockState { + start_types: vec![], + return_types: last_returns, + stack_starts_at: 0, + jump_to_top: false, + is_else_allowed: false, + is_dead_code: false, + polymorphic_values: None, + }); + + OperatorValidator { + func_state: FuncState { + local_types, + blocks, + stack_types: Vec::new(), + end_function: false, + }, + config, + } + } + + pub fn is_dead_code(&self) -> bool { + self.func_state.last_block().is_dead_code + } + + fn check_frame_size(&self, require_count: usize) -> OperatorValidatorResult<()> { + if !self.func_state.assert_block_stack_len(0, require_count) { + Err("not enough operands") + } else { + Ok(()) + } + } + + fn check_operands_1(&self, operand: Type) -> OperatorValidatorResult<()> { + self.check_frame_size(1)?; + if !self.func_state.assert_stack_type_at(0, operand) { + return Err("stack operand type mismatch"); + } + Ok(()) + } + + fn check_operands_2(&self, operand1: Type, operand2: Type) -> OperatorValidatorResult<()> { + self.check_frame_size(2)?; + if !self.func_state.assert_stack_type_at(1, operand1) { + return Err("stack operand type mismatch"); + } + if !self.func_state.assert_stack_type_at(0, operand2) { + return Err("stack operand type mismatch"); + } + Ok(()) + } + + fn check_operands_3( + &self, + operand1: Type, + operand2: Type, + operand3: Type, + ) -> OperatorValidatorResult<()> { + self.check_frame_size(3)?; + if !self.func_state.assert_stack_type_at(2, operand1) { + return Err("stack operand type mismatch"); + } + if !self.func_state.assert_stack_type_at(1, operand2) { + return Err("stack operand type mismatch"); + } + if !self.func_state.assert_stack_type_at(0, operand3) { + return Err("stack operand type mismatch"); + } + Ok(()) + } + + fn check_operands<I>(&self, expected_types: I) -> OperatorValidatorResult<()> + where + I: ExactSizeIterator<Item = Type>, + { + let len = expected_types.len(); + self.check_frame_size(len)?; + for (i, expected_type) in expected_types.enumerate() { + if !self + .func_state + .assert_stack_type_at(len - 1 - i, expected_type) + { + return Err("stack operand type mismatch"); + } + } + Ok(()) + } + + fn check_block_return_types( + &self, + block: &BlockState, + reserve_items: usize, + ) -> OperatorValidatorResult<()> { + if !self.config.enable_multi_value && block.return_types.len() > 1 { + return Err("blocks, loops, and ifs may only return at most one \ + value when multi-value is not enabled"); + } + let len = block.return_types.len(); + for i in 0..len { + if !self + .func_state + .assert_stack_type_at(len - 1 - i + reserve_items, block.return_types[i]) + { + return Err("stack item type does not match block item type"); + } + } + Ok(()) + } + + fn check_block_return(&self) -> OperatorValidatorResult<()> { + let len = self.func_state.last_block().return_types.len(); + if !self.func_state.assert_last_block_stack_len_exact(len) { + return Err("stack size does not match block type"); + } + self.check_block_return_types(self.func_state.last_block(), 0) + } + + fn check_jump_from_block( + &self, + relative_depth: u32, + reserve_items: usize, + ) -> OperatorValidatorResult<()> { + if relative_depth as usize >= self.func_state.blocks.len() { + return Err("invalid block depth"); + } + let block = self.func_state.block_at(relative_depth as usize); + if block.jump_to_top { + if !self.func_state.assert_block_stack_len(0, reserve_items) { + return Err("stack size does not match target loop type"); + } + return Ok(()); + } + + let len = block.return_types.len(); + if !self + .func_state + .assert_block_stack_len(0, len + reserve_items) + { + return Err("stack size does not match target block type"); + } + self.check_block_return_types(block, reserve_items) + } + + fn match_block_return(&self, depth1: u32, depth2: u32) -> OperatorValidatorResult<()> { + if depth1 as usize >= self.func_state.blocks.len() { + return Err("invalid block depth"); + } + if depth2 as usize >= self.func_state.blocks.len() { + return Err("invalid block depth"); + } + let block1 = self.func_state.block_at(depth1 as usize); + let block2 = self.func_state.block_at(depth2 as usize); + let return_types1 = &block1.return_types; + let return_types2 = &block2.return_types; + if block1.jump_to_top || block2.jump_to_top { + if block1.jump_to_top { + if !block2.jump_to_top && !return_types2.is_empty() { + return Err("block types do not match"); + } + } else if !return_types1.is_empty() { + return Err("block types do not match"); + } + } else if *return_types1 != *return_types2 { + return Err("block types do not match"); + } + Ok(()) + } + + fn check_memory_index< + F: WasmFuncType, + T: WasmTableType, + M: WasmMemoryType, + G: WasmGlobalType, + >( + &self, + memory_index: u32, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<()> { + if resources.memory_at(memory_index).is_none() { + return Err("no linear memories are present"); + } + Ok(()) + } + + fn check_shared_memory_index< + F: WasmFuncType, + T: WasmTableType, + M: WasmMemoryType, + G: WasmGlobalType, + >( + &self, + memory_index: u32, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<()> { + match resources.memory_at(memory_index) { + Some(memory) if !memory.is_shared() => { + return Err("atomic accesses require shared memory") + } + None => return Err("no linear memories are present"), + _ => Ok(()), + } + } + + fn check_memarg<F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>( + &self, + memarg: MemoryImmediate, + max_align: u32, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<()> { + self.check_memory_index(0, resources)?; + let align = memarg.flags; + if align > max_align { + return Err("alignment must not be larger than natural"); + } + Ok(()) + } + + #[cfg(feature = "deterministic")] + fn check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()> { + if !self.config.deterministic_only { + return Err("deterministic_only support is not enabled"); + } + Ok(()) + } + + #[inline(always)] + #[cfg(not(feature = "deterministic"))] + fn check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()> { + Ok(()) + } + + fn check_threads_enabled(&self) -> OperatorValidatorResult<()> { + if !self.config.enable_threads { + return Err("threads support is not enabled"); + } + Ok(()) + } + + fn check_reference_types_enabled(&self) -> OperatorValidatorResult<()> { + if !self.config.enable_reference_types { + return Err("reference types support is not enabled"); + } + Ok(()) + } + + fn check_simd_enabled(&self) -> OperatorValidatorResult<()> { + if !self.config.enable_simd { + return Err("SIMD support is not enabled"); + } + Ok(()) + } + + fn check_bulk_memory_enabled(&self) -> OperatorValidatorResult<()> { + if !self.config.enable_bulk_memory { + return Err("bulk memory support is not enabled"); + } + Ok(()) + } + + fn check_shared_memarg_wo_align< + F: WasmFuncType, + T: WasmTableType, + M: WasmMemoryType, + G: WasmGlobalType, + >( + &self, + _: MemoryImmediate, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<()> { + self.check_shared_memory_index(0, resources)?; + Ok(()) + } + + fn check_simd_lane_index(&self, index: SIMDLaneIndex, max: u8) -> OperatorValidatorResult<()> { + if index >= max { + return Err("SIMD index out of bounds"); + } + Ok(()) + } + + fn check_block_type<F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>( + &self, + ty: TypeOrFuncType, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<()> { + match ty { + TypeOrFuncType::Type(Type::EmptyBlockType) + | TypeOrFuncType::Type(Type::I32) + | TypeOrFuncType::Type(Type::I64) + | TypeOrFuncType::Type(Type::F32) + | TypeOrFuncType::Type(Type::F64) => Ok(()), + TypeOrFuncType::Type(Type::AnyRef) | TypeOrFuncType::Type(Type::AnyFunc) => { + self.check_reference_types_enabled() + } + TypeOrFuncType::Type(Type::V128) => self.check_simd_enabled(), + TypeOrFuncType::FuncType(idx) => match resources.type_at(idx) { + None => Err("type index out of bounds"), + Some(ty) if !self.config.enable_multi_value => { + if ty.len_outputs() > 1 { + return Err("blocks, loops, and ifs may only return at most one \ + value when multi-value is not enabled"); + } + if ty.len_inputs() > 0 { + return Err("blocks, loops, and ifs accept no parameters \ + when multi-value is not enabled"); + } + Ok(()) + } + Some(_) => Ok(()), + }, + _ => Err("invalid block return type"), + } + } + + fn check_block_params< + F: WasmFuncType, + T: WasmTableType, + M: WasmMemoryType, + G: WasmGlobalType, + >( + &self, + ty: TypeOrFuncType, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + skip: usize, + ) -> OperatorValidatorResult<()> { + if let TypeOrFuncType::FuncType(idx) = ty { + let func_ty = resources + .type_at(idx) + // Note: This was an out-of-bounds memory access before + // the change to return `Option` at `type_at`. So + // I assumed that invalid indices at this point are + // bugs. + .expect("function type index is out of bounds"); + let len = func_ty.len_inputs(); + self.check_frame_size(len + skip)?; + for (i, ty) in wasm_func_type_inputs(func_ty).enumerate() { + if !self + .func_state + .assert_stack_type_at(len - 1 - i + skip, ty.to_parser_type()) + { + return Err("stack operand type mismatch for block"); + } + } + } + Ok(()) + } + + fn check_select(&self) -> OperatorValidatorResult<Option<Type>> { + self.check_frame_size(3)?; + let func_state = &self.func_state; + let last_block = func_state.last_block(); + + let ty = if last_block.is_stack_polymorphic() { + match func_state.stack_types.len() - last_block.stack_starts_at { + 0 => return Ok(None), + 1 => { + self.check_operands_1(Type::I32)?; + return Ok(None); + } + 2 => { + self.check_operands_1(Type::I32)?; + func_state.stack_types[func_state.stack_types.len() - 2] + } + _ => { + let ty = func_state.stack_types[func_state.stack_types.len() - 3]; + self.check_operands_2(ty, Type::I32)?; + ty + } + } + } else { + let ty = func_state.stack_types[func_state.stack_types.len() - 3]; + self.check_operands_2(ty, Type::I32)?; + ty + }; + + if !ty.is_valid_for_old_select() { + return Err("invalid type for select"); + } + + Ok(Some(ty)) + } + + pub(crate) fn process_operator< + F: WasmFuncType, + T: WasmTableType, + M: WasmMemoryType, + G: WasmGlobalType, + >( + &mut self, + operator: &Operator, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<FunctionEnd> { + if self.func_state.end_function { + return Err("unexpected operator"); + } + match *operator { + Operator::Unreachable => self.func_state.start_dead_code(), + Operator::Nop => (), + Operator::Block { ty } => { + self.check_block_type(ty, resources)?; + self.check_block_params(ty, resources, 0)?; + self.func_state + .push_block(ty, BlockType::Block, resources)?; + } + Operator::Loop { ty } => { + self.check_block_type(ty, resources)?; + self.check_block_params(ty, resources, 0)?; + self.func_state.push_block(ty, BlockType::Loop, resources)?; + } + Operator::If { ty } => { + self.check_block_type(ty, resources)?; + self.check_operands_1(Type::I32)?; + self.check_block_params(ty, resources, 1)?; + self.func_state.push_block(ty, BlockType::If, resources)?; + } + Operator::Else => { + if !self.func_state.last_block().is_else_allowed { + return Err("unexpected else: if block is not started"); + } + self.check_block_return()?; + self.func_state.reset_block() + } + Operator::End => { + self.check_block_return()?; + if self.func_state.blocks.len() == 1 { + self.func_state.end_function(); + return Ok(FunctionEnd::Yes); + } + + let last_block = &self.func_state.last_block(); + if last_block.is_else_allowed && last_block.start_types != last_block.return_types { + return Err("else is expected: if block has a type that can't be implemented with a no-op"); + } + self.func_state.pop_block() + } + Operator::Br { relative_depth } => { + self.check_jump_from_block(relative_depth, 0)?; + self.func_state.start_dead_code() + } + Operator::BrIf { relative_depth } => { + self.check_operands_1(Type::I32)?; + self.check_jump_from_block(relative_depth, 1)?; + if self.func_state.last_block().is_stack_polymorphic() { + self.func_state + .change_frame_to_exact_types_from(relative_depth as usize)?; + } else { + self.func_state.change_frame(1)?; + } + } + Operator::BrTable { ref table } => { + self.check_operands_1(Type::I32)?; + let mut depth0: Option<u32> = None; + for relative_depth in table { + if depth0.is_none() { + self.check_jump_from_block(relative_depth, 1)?; + depth0 = Some(relative_depth); + continue; + } + self.match_block_return(relative_depth, depth0.unwrap())?; + } + self.func_state.start_dead_code() + } + Operator::Return => { + let depth = (self.func_state.blocks.len() - 1) as u32; + self.check_jump_from_block(depth, 0)?; + self.func_state.start_dead_code() + } + Operator::Call { function_index } => match resources.func_type_id_at(function_index) { + Some(type_index) => { + let ty = resources + .type_at(type_index) + // Note: This was an out-of-bounds memory access before + // the change to return `Option` at `type_at`. So + // I assumed that invalid indices at this point are + // bugs. + .expect("function type index is out of bounds"); + self.check_operands(wasm_func_type_inputs(ty).map(WasmType::to_parser_type))?; + self.func_state.change_frame_with_types( + ty.len_inputs(), + wasm_func_type_outputs(ty).map(WasmType::to_parser_type), + )?; + } + None => return Err("function index out of bounds"), + }, + Operator::CallIndirect { index, table_index } => { + if resources.table_at(table_index).is_none() { + return Err("table index out of bounds"); + } + match resources.type_at(index) { + None => return Err("type index out of bounds"), + Some(ty) => { + let types = { + let mut types = Vec::with_capacity(ty.len_inputs() + 1); + types.extend(wasm_func_type_inputs(ty).map(WasmType::to_parser_type)); + types.push(Type::I32); + types + }; + self.check_operands(types.into_iter())?; + self.func_state.change_frame_with_types( + ty.len_inputs() + 1, + wasm_func_type_outputs(ty).map(WasmType::to_parser_type), + )?; + } + } + } + Operator::Drop => { + self.check_frame_size(1)?; + self.func_state.change_frame(1)?; + } + Operator::Select => { + let ty = self.check_select()?; + self.func_state.change_frame_after_select(ty)?; + } + Operator::TypedSelect { ty } => { + self.check_operands_3(Type::I32, ty, ty)?; + self.func_state.change_frame_after_select(Some(ty))?; + } + Operator::LocalGet { local_index } => { + if local_index as usize >= self.func_state.local_types.len() { + return Err("local index out of bounds"); + } + let local_type = self.func_state.local_types[local_index as usize]; + self.func_state.change_frame_with_type(0, local_type)?; + } + Operator::LocalSet { local_index } => { + if local_index as usize >= self.func_state.local_types.len() { + return Err("local index out of bounds"); + } + let local_type = self.func_state.local_types[local_index as usize]; + self.check_operands_1(local_type)?; + self.func_state.change_frame(1)?; + } + Operator::LocalTee { local_index } => { + if local_index as usize >= self.func_state.local_types.len() { + return Err("local index out of bounds"); + } + let local_type = self.func_state.local_types[local_index as usize]; + self.check_operands_1(local_type)?; + self.func_state.change_frame_with_type(1, local_type)?; + } + Operator::GlobalGet { global_index } => { + if let Some(ty) = resources.global_at(global_index) { + self.func_state + .change_frame_with_type(0, ty.content_type().to_parser_type())?; + } else { + return Err("global index out of bounds"); + }; + } + Operator::GlobalSet { global_index } => { + if let Some(ty) = resources.global_at(global_index) { + if !ty.is_mutable() { + return Err("global expected to be mutable"); + } + self.check_operands_1(ty.content_type().to_parser_type())?; + self.func_state.change_frame(1)?; + } else { + return Err("global index out of bounds"); + }; + } + Operator::I32Load { memarg } => { + self.check_memarg(memarg, 2, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64Load { memarg } => { + self.check_memarg(memarg, 3, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::F32Load { memarg } => { + self.check_non_deterministic_enabled()?; + self.check_memarg(memarg, 2, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F64Load { memarg } => { + self.check_non_deterministic_enabled()?; + self.check_memarg(memarg, 3, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::I32Load8S { memarg } => { + self.check_memarg(memarg, 0, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32Load8U { memarg } => { + self.check_memarg(memarg, 0, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32Load16S { memarg } => { + self.check_memarg(memarg, 1, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32Load16U { memarg } => { + self.check_memarg(memarg, 1, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64Load8S { memarg } => { + self.check_memarg(memarg, 0, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64Load8U { memarg } => { + self.check_memarg(memarg, 0, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64Load16S { memarg } => { + self.check_memarg(memarg, 1, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64Load16U { memarg } => { + self.check_memarg(memarg, 1, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64Load32S { memarg } => { + self.check_memarg(memarg, 2, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64Load32U { memarg } => { + self.check_memarg(memarg, 2, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I32Store { memarg } => { + self.check_memarg(memarg, 2, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame(2)?; + } + Operator::I64Store { memarg } => { + self.check_memarg(memarg, 3, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame(2)?; + } + Operator::F32Store { memarg } => { + self.check_non_deterministic_enabled()?; + self.check_memarg(memarg, 2, resources)?; + self.check_operands_2(Type::I32, Type::F32)?; + self.func_state.change_frame(2)?; + } + Operator::F64Store { memarg } => { + self.check_non_deterministic_enabled()?; + self.check_memarg(memarg, 3, resources)?; + self.check_operands_2(Type::I32, Type::F64)?; + self.func_state.change_frame(2)?; + } + Operator::I32Store8 { memarg } => { + self.check_memarg(memarg, 0, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame(2)?; + } + Operator::I32Store16 { memarg } => { + self.check_memarg(memarg, 1, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame(2)?; + } + Operator::I64Store8 { memarg } => { + self.check_memarg(memarg, 0, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame(2)?; + } + Operator::I64Store16 { memarg } => { + self.check_memarg(memarg, 1, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame(2)?; + } + Operator::I64Store32 { memarg } => { + self.check_memarg(memarg, 2, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame(2)?; + } + Operator::MemorySize { + reserved: memory_index, + } => { + self.check_memory_index(memory_index, resources)?; + self.func_state.change_frame_with_type(0, Type::I32)?; + } + Operator::MemoryGrow { + reserved: memory_index, + } => { + self.check_memory_index(memory_index, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32Const { .. } => self.func_state.change_frame_with_type(0, Type::I32)?, + Operator::I64Const { .. } => self.func_state.change_frame_with_type(0, Type::I64)?, + Operator::F32Const { .. } => { + self.check_non_deterministic_enabled()?; + self.func_state.change_frame_with_type(0, Type::F32)?; + } + Operator::F64Const { .. } => { + self.check_non_deterministic_enabled()?; + self.func_state.change_frame_with_type(0, Type::F64)?; + } + Operator::I32Eqz => { + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32Eq + | Operator::I32Ne + | Operator::I32LtS + | Operator::I32LtU + | Operator::I32GtS + | Operator::I32GtU + | Operator::I32LeS + | Operator::I32LeU + | Operator::I32GeS + | Operator::I32GeU => { + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::I64Eqz => { + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64Eq + | Operator::I64Ne + | Operator::I64LtS + | Operator::I64LtU + | Operator::I64GtS + | Operator::I64GtU + | Operator::I64LeS + | Operator::I64LeU + | Operator::I64GeS + | Operator::I64GeU => { + self.check_operands_2(Type::I64, Type::I64)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::F32Eq + | Operator::F32Ne + | Operator::F32Lt + | Operator::F32Gt + | Operator::F32Le + | Operator::F32Ge => { + self.check_non_deterministic_enabled()?; + self.check_operands_2(Type::F32, Type::F32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::F64Eq + | Operator::F64Ne + | Operator::F64Lt + | Operator::F64Gt + | Operator::F64Le + | Operator::F64Ge => { + self.check_non_deterministic_enabled()?; + self.check_operands_2(Type::F64, Type::F64)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::I32Clz | Operator::I32Ctz | Operator::I32Popcnt => { + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32Add + | Operator::I32Sub + | Operator::I32Mul + | Operator::I32DivS + | Operator::I32DivU + | Operator::I32RemS + | Operator::I32RemU + | Operator::I32And + | Operator::I32Or + | Operator::I32Xor + | Operator::I32Shl + | Operator::I32ShrS + | Operator::I32ShrU + | Operator::I32Rotl + | Operator::I32Rotr => { + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::I64Clz | Operator::I64Ctz | Operator::I64Popcnt => { + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64Add + | Operator::I64Sub + | Operator::I64Mul + | Operator::I64DivS + | Operator::I64DivU + | Operator::I64RemS + | Operator::I64RemU + | Operator::I64And + | Operator::I64Or + | Operator::I64Xor + | Operator::I64Shl + | Operator::I64ShrS + | Operator::I64ShrU + | Operator::I64Rotl + | Operator::I64Rotr => { + self.check_operands_2(Type::I64, Type::I64)?; + self.func_state.change_frame_with_type(2, Type::I64)?; + } + Operator::F32Abs + | Operator::F32Neg + | Operator::F32Ceil + | Operator::F32Floor + | Operator::F32Trunc + | Operator::F32Nearest + | Operator::F32Sqrt => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F32Add + | Operator::F32Sub + | Operator::F32Mul + | Operator::F32Div + | Operator::F32Min + | Operator::F32Max + | Operator::F32Copysign => { + self.check_non_deterministic_enabled()?; + self.check_operands_2(Type::F32, Type::F32)?; + self.func_state.change_frame_with_type(2, Type::F32)?; + } + Operator::F64Abs + | Operator::F64Neg + | Operator::F64Ceil + | Operator::F64Floor + | Operator::F64Trunc + | Operator::F64Nearest + | Operator::F64Sqrt => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::F64Add + | Operator::F64Sub + | Operator::F64Mul + | Operator::F64Div + | Operator::F64Min + | Operator::F64Max + | Operator::F64Copysign => { + self.check_non_deterministic_enabled()?; + self.check_operands_2(Type::F64, Type::F64)?; + self.func_state.change_frame_with_type(2, Type::F64)?; + } + Operator::I32WrapI64 => { + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32TruncF32S | Operator::I32TruncF32U => { + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32TruncF64S | Operator::I32TruncF64U => { + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64ExtendI32S | Operator::I64ExtendI32U => { + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64TruncF32S | Operator::I64TruncF32U => { + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64TruncF64S | Operator::I64TruncF64U => { + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::F32ConvertI32S | Operator::F32ConvertI32U => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F32ConvertI64S | Operator::F32ConvertI64U => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F32DemoteF64 => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F64ConvertI32S | Operator::F64ConvertI32U => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::F64ConvertI64S | Operator::F64ConvertI64U => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::F64PromoteF32 => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::I32ReinterpretF32 => { + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64ReinterpretF64 => { + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::F32ReinterpretI32 => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F64ReinterpretI64 => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::I32TruncSatF32S | Operator::I32TruncSatF32U => { + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32TruncSatF64S | Operator::I32TruncSatF64U => { + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64TruncSatF32S | Operator::I64TruncSatF32U => { + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64TruncSatF64S | Operator::I64TruncSatF64U => { + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I32Extend16S | Operator::I32Extend8S => { + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + + Operator::I64Extend32S | Operator::I64Extend16S | Operator::I64Extend8S => { + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + + Operator::I32AtomicLoad { memarg } + | Operator::I32AtomicLoad16U { memarg } + | Operator::I32AtomicLoad8U { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64AtomicLoad { memarg } + | Operator::I64AtomicLoad32U { memarg } + | Operator::I64AtomicLoad16U { memarg } + | Operator::I64AtomicLoad8U { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I32AtomicStore { memarg } + | Operator::I32AtomicStore16 { memarg } + | Operator::I32AtomicStore8 { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame(2)?; + } + Operator::I64AtomicStore { memarg } + | Operator::I64AtomicStore32 { memarg } + | Operator::I64AtomicStore16 { memarg } + | Operator::I64AtomicStore8 { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame(2)?; + } + Operator::I32AtomicRmwAdd { memarg } + | Operator::I32AtomicRmwSub { memarg } + | Operator::I32AtomicRmwAnd { memarg } + | Operator::I32AtomicRmwOr { memarg } + | Operator::I32AtomicRmwXor { memarg } + | Operator::I32AtomicRmw16AddU { memarg } + | Operator::I32AtomicRmw16SubU { memarg } + | Operator::I32AtomicRmw16AndU { memarg } + | Operator::I32AtomicRmw16OrU { memarg } + | Operator::I32AtomicRmw16XorU { memarg } + | Operator::I32AtomicRmw8AddU { memarg } + | Operator::I32AtomicRmw8SubU { memarg } + | Operator::I32AtomicRmw8AndU { memarg } + | Operator::I32AtomicRmw8OrU { memarg } + | Operator::I32AtomicRmw8XorU { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::I64AtomicRmwAdd { memarg } + | Operator::I64AtomicRmwSub { memarg } + | Operator::I64AtomicRmwAnd { memarg } + | Operator::I64AtomicRmwOr { memarg } + | Operator::I64AtomicRmwXor { memarg } + | Operator::I64AtomicRmw32AddU { memarg } + | Operator::I64AtomicRmw32SubU { memarg } + | Operator::I64AtomicRmw32AndU { memarg } + | Operator::I64AtomicRmw32OrU { memarg } + | Operator::I64AtomicRmw32XorU { memarg } + | Operator::I64AtomicRmw16AddU { memarg } + | Operator::I64AtomicRmw16SubU { memarg } + | Operator::I64AtomicRmw16AndU { memarg } + | Operator::I64AtomicRmw16OrU { memarg } + | Operator::I64AtomicRmw16XorU { memarg } + | Operator::I64AtomicRmw8AddU { memarg } + | Operator::I64AtomicRmw8SubU { memarg } + | Operator::I64AtomicRmw8AndU { memarg } + | Operator::I64AtomicRmw8OrU { memarg } + | Operator::I64AtomicRmw8XorU { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame_with_type(2, Type::I64)?; + } + Operator::I32AtomicRmwXchg { memarg } + | Operator::I32AtomicRmw16XchgU { memarg } + | Operator::I32AtomicRmw8XchgU { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::I32AtomicRmwCmpxchg { memarg } + | Operator::I32AtomicRmw16CmpxchgU { memarg } + | Operator::I32AtomicRmw8CmpxchgU { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_3(Type::I32, Type::I32, Type::I32)?; + self.func_state.change_frame_with_type(3, Type::I32)?; + } + Operator::I64AtomicRmwXchg { memarg } + | Operator::I64AtomicRmw32XchgU { memarg } + | Operator::I64AtomicRmw16XchgU { memarg } + | Operator::I64AtomicRmw8XchgU { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame_with_type(2, Type::I64)?; + } + Operator::I64AtomicRmwCmpxchg { memarg } + | Operator::I64AtomicRmw32CmpxchgU { memarg } + | Operator::I64AtomicRmw16CmpxchgU { memarg } + | Operator::I64AtomicRmw8CmpxchgU { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_3(Type::I32, Type::I64, Type::I64)?; + self.func_state.change_frame_with_type(3, Type::I64)?; + } + Operator::AtomicNotify { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::I32AtomicWait { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_3(Type::I32, Type::I32, Type::I64)?; + self.func_state.change_frame_with_type(3, Type::I32)?; + } + Operator::I64AtomicWait { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_3(Type::I32, Type::I64, Type::I64)?; + self.func_state.change_frame_with_type(3, Type::I32)?; + } + Operator::AtomicFence { ref flags } => { + self.check_threads_enabled()?; + if *flags != 0 { + return Err("non-zero flags for fence not supported yet"); + } + } + Operator::RefNull => { + self.check_reference_types_enabled()?; + self.func_state.change_frame_with_type(0, Type::NullRef)?; + } + Operator::RefIsNull => { + self.check_reference_types_enabled()?; + self.check_operands_1(Type::AnyRef)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::RefFunc { function_index } => { + self.check_reference_types_enabled()?; + if resources.func_type_id_at(function_index).is_none() { + return Err("function index out of bounds"); + } + self.func_state.change_frame_with_type(0, Type::AnyFunc)?; + } + Operator::V128Load { memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 4, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::V128Store { memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 4, resources)?; + self.check_operands_2(Type::I32, Type::V128)?; + self.func_state.change_frame(2)?; + } + Operator::V128Const { .. } => { + self.check_simd_enabled()?; + self.func_state.change_frame_with_type(0, Type::V128)?; + } + Operator::I8x16Splat | Operator::I16x8Splat | Operator::I32x4Splat => { + self.check_simd_enabled()?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::I64x2Splat => { + self.check_simd_enabled()?; + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::F32x4Splat => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::F64x2Splat => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::I8x16ExtractLaneS { lane } | Operator::I8x16ExtractLaneU { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 16)?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I16x8ExtractLaneS { lane } | Operator::I16x8ExtractLaneU { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 8)?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32x4ExtractLane { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 4)?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I8x16ReplaceLane { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 16)?; + self.check_operands_2(Type::V128, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::I16x8ReplaceLane { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 8)?; + self.check_operands_2(Type::V128, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::I32x4ReplaceLane { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 4)?; + self.check_operands_2(Type::V128, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::I64x2ExtractLane { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 2)?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64x2ReplaceLane { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 2)?; + self.check_operands_2(Type::V128, Type::I64)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::F32x4ExtractLane { lane } => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 4)?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F32x4ReplaceLane { lane } => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 4)?; + self.check_operands_2(Type::V128, Type::F32)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::F64x2ExtractLane { lane } => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 2)?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::F64x2ReplaceLane { lane } => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 2)?; + self.check_operands_2(Type::V128, Type::F64)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::F32x4Eq + | Operator::F32x4Ne + | Operator::F32x4Lt + | Operator::F32x4Gt + | Operator::F32x4Le + | Operator::F32x4Ge + | Operator::F64x2Eq + | Operator::F64x2Ne + | Operator::F64x2Lt + | Operator::F64x2Gt + | Operator::F64x2Le + | Operator::F64x2Ge + | Operator::F32x4Add + | Operator::F32x4Sub + | Operator::F32x4Mul + | Operator::F32x4Div + | Operator::F32x4Min + | Operator::F32x4Max + | Operator::F64x2Add + | Operator::F64x2Sub + | Operator::F64x2Mul + | Operator::F64x2Div + | Operator::F64x2Min + | Operator::F64x2Max => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_operands_2(Type::V128, Type::V128)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::I8x16Eq + | Operator::I8x16Ne + | Operator::I8x16LtS + | Operator::I8x16LtU + | Operator::I8x16GtS + | Operator::I8x16GtU + | Operator::I8x16LeS + | Operator::I8x16LeU + | Operator::I8x16GeS + | Operator::I8x16GeU + | Operator::I16x8Eq + | Operator::I16x8Ne + | Operator::I16x8LtS + | Operator::I16x8LtU + | Operator::I16x8GtS + | Operator::I16x8GtU + | Operator::I16x8LeS + | Operator::I16x8LeU + | Operator::I16x8GeS + | Operator::I16x8GeU + | Operator::I32x4Eq + | Operator::I32x4Ne + | Operator::I32x4LtS + | Operator::I32x4LtU + | Operator::I32x4GtS + | Operator::I32x4GtU + | Operator::I32x4LeS + | Operator::I32x4LeU + | Operator::I32x4GeS + | Operator::I32x4GeU + | Operator::V128And + | Operator::V128AndNot + | Operator::V128Or + | Operator::V128Xor + | Operator::I8x16Add + | Operator::I8x16AddSaturateS + | Operator::I8x16AddSaturateU + | Operator::I8x16Sub + | Operator::I8x16SubSaturateS + | Operator::I8x16SubSaturateU + | Operator::I8x16Mul + | Operator::I16x8Add + | Operator::I16x8AddSaturateS + | Operator::I16x8AddSaturateU + | Operator::I16x8Sub + | Operator::I16x8SubSaturateS + | Operator::I16x8SubSaturateU + | Operator::I16x8Mul + | Operator::I32x4Add + | Operator::I32x4Sub + | Operator::I32x4Mul + | Operator::I64x2Add + | Operator::I64x2Sub + | Operator::I64x2Mul + | Operator::I8x16RoundingAverageU + | Operator::I16x8RoundingAverageU + | Operator::I8x16NarrowI16x8S + | Operator::I8x16NarrowI16x8U + | Operator::I16x8NarrowI32x4S + | Operator::I16x8NarrowI32x4U => { + self.check_simd_enabled()?; + self.check_operands_2(Type::V128, Type::V128)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::F32x4Abs + | Operator::F32x4Neg + | Operator::F32x4Sqrt + | Operator::F64x2Abs + | Operator::F64x2Neg + | Operator::F64x2Sqrt + | Operator::F32x4ConvertI32x4S + | Operator::F32x4ConvertI32x4U + | Operator::F64x2ConvertI64x2S + | Operator::F64x2ConvertI64x2U => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::V128Not + | Operator::I8x16Neg + | Operator::I16x8Neg + | Operator::I32x4Neg + | Operator::I64x2Neg + | Operator::I32x4TruncSatF32x4S + | Operator::I32x4TruncSatF32x4U + | Operator::I64x2TruncSatF64x2S + | Operator::I64x2TruncSatF64x2U + | Operator::I16x8WidenLowI8x16S + | Operator::I16x8WidenHighI8x16S + | Operator::I16x8WidenLowI8x16U + | Operator::I16x8WidenHighI8x16U + | Operator::I32x4WidenLowI16x8S + | Operator::I32x4WidenHighI16x8S + | Operator::I32x4WidenLowI16x8U + | Operator::I32x4WidenHighI16x8U => { + self.check_simd_enabled()?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::V128Bitselect => { + self.check_simd_enabled()?; + self.check_operands_3(Type::V128, Type::V128, Type::V128)?; + self.func_state.change_frame_with_type(3, Type::V128)?; + } + Operator::I8x16AnyTrue + | Operator::I8x16AllTrue + | Operator::I16x8AnyTrue + | Operator::I16x8AllTrue + | Operator::I32x4AnyTrue + | Operator::I32x4AllTrue + | Operator::I64x2AnyTrue + | Operator::I64x2AllTrue => { + self.check_simd_enabled()?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I8x16Shl + | Operator::I8x16ShrS + | Operator::I8x16ShrU + | Operator::I16x8Shl + | Operator::I16x8ShrS + | Operator::I16x8ShrU + | Operator::I32x4Shl + | Operator::I32x4ShrS + | Operator::I32x4ShrU + | Operator::I64x2Shl + | Operator::I64x2ShrS + | Operator::I64x2ShrU => { + self.check_simd_enabled()?; + self.check_operands_2(Type::V128, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::V8x16Swizzle => { + self.check_simd_enabled()?; + self.check_operands_2(Type::V128, Type::V128)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::V8x16Shuffle { ref lanes } => { + self.check_simd_enabled()?; + self.check_operands_2(Type::V128, Type::V128)?; + for i in lanes { + self.check_simd_lane_index(*i, 32)?; + } + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::V8x16LoadSplat { memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 0, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::V16x8LoadSplat { memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 1, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::V32x4LoadSplat { memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 2, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::V64x2LoadSplat { memarg } + | Operator::I16x8Load8x8S { memarg } + | Operator::I16x8Load8x8U { memarg } + | Operator::I32x4Load16x4S { memarg } + | Operator::I32x4Load16x4U { memarg } + | Operator::I64x2Load32x2S { memarg } + | Operator::I64x2Load32x2U { memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 3, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + + Operator::MemoryInit { segment } => { + self.check_bulk_memory_enabled()?; + if segment >= resources.data_count() { + return Err("segment index out of bounds"); + } + self.check_memory_index(0, resources)?; + self.check_operands_3(Type::I32, Type::I32, Type::I32)?; + self.func_state.change_frame(3)?; + } + Operator::DataDrop { segment } => { + self.check_bulk_memory_enabled()?; + if segment >= resources.data_count() { + return Err("segment index out of bounds"); + } + } + Operator::MemoryCopy | Operator::MemoryFill => { + self.check_bulk_memory_enabled()?; + self.check_memory_index(0, resources)?; + self.check_operands_3(Type::I32, Type::I32, Type::I32)?; + self.func_state.change_frame(3)?; + } + Operator::TableInit { segment, table } => { + self.check_bulk_memory_enabled()?; + if segment >= resources.element_count() { + return Err("segment index out of bounds"); + } + if table > 0 { + self.check_reference_types_enabled()?; + } + if resources.table_at(table).is_none() { + return Err("table index out of bounds"); + } + self.check_operands_3(Type::I32, Type::I32, Type::I32)?; + self.func_state.change_frame(3)?; + } + Operator::ElemDrop { segment } => { + self.check_bulk_memory_enabled()?; + if segment >= resources.element_count() { + return Err("segment index out of bounds"); + } + } + Operator::TableCopy { + src_table, + dst_table, + } => { + self.check_bulk_memory_enabled()?; + if src_table > 0 || dst_table > 0 { + self.check_reference_types_enabled()?; + } + if resources.table_at(src_table).is_none() + || resources.table_at(dst_table).is_none() + { + return Err("table index out of bounds"); + } + self.check_operands_3(Type::I32, Type::I32, Type::I32)?; + self.func_state.change_frame(3)?; + } + Operator::TableGet { table } => { + self.check_reference_types_enabled()?; + let ty = match resources.table_at(table) { + Some(ty) => ty.element_type().to_parser_type(), + None => return Err("table index out of bounds"), + }; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, ty)?; + } + Operator::TableSet { table } => { + self.check_reference_types_enabled()?; + let ty = match resources.table_at(table) { + Some(ty) => ty.element_type().to_parser_type(), + None => return Err("table index out of bounds"), + }; + self.check_operands_2(Type::I32, ty)?; + self.func_state.change_frame(2)?; + } + Operator::TableGrow { table } => { + self.check_reference_types_enabled()?; + let ty = match resources.table_at(table) { + Some(ty) => ty.element_type().to_parser_type(), + None => return Err("table index out of bounds"), + }; + self.check_operands_2(ty, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::TableSize { table } => { + self.check_reference_types_enabled()?; + if resources.table_at(table).is_none() { + return Err("table index out of bounds"); + } + self.func_state.change_frame_with_type(0, Type::I32)?; + } + Operator::TableFill { table } => { + self.check_bulk_memory_enabled()?; + let ty = match resources.table_at(table) { + Some(ty) => ty.element_type().to_parser_type(), + None => return Err("table index out of bounds"), + }; + self.check_operands_3(Type::I32, ty, Type::I32)?; + self.func_state.change_frame(3)?; + } + } + Ok(FunctionEnd::No) + } + + pub(crate) fn process_end_function(&self) -> OperatorValidatorResult<()> { + if !self.func_state.end_function { + return Err("expected end of function"); + } + Ok(()) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/parser.rs b/third_party/rust/wasmparser-0.48.2/src/parser.rs new file mode 100644 index 0000000000..9906c6244c --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/parser.rs @@ -0,0 +1,1185 @@ +/* Copyright 2017 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. + */ +// See https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md + +use std::boxed::Box; +use std::vec::Vec; + +use crate::limits::{ + MAX_WASM_FUNCTIONS, MAX_WASM_FUNCTION_LOCALS, MAX_WASM_STRING_SIZE, MAX_WASM_TABLE_ENTRIES, +}; + +use crate::primitives::{ + BinaryReaderError, CustomSectionKind, ExternalKind, FuncType, GlobalType, + ImportSectionEntryType, LinkingType, MemoryType, Naming, Operator, RelocType, Result, + SectionCode, TableType, Type, +}; + +use crate::readers::{ + CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems, + ElementKind, ElementSectionReader, Export, ExportSectionReader, FunctionBody, + FunctionSectionReader, Global, GlobalSectionReader, Import, ImportSectionReader, + LinkingSectionReader, MemorySectionReader, ModuleReader, Name, NameSectionReader, NamingReader, + OperatorsReader, Reloc, RelocSectionReader, Section, SectionReader, TableSectionReader, + TypeSectionReader, +}; + +use crate::binary_reader::{BinaryReader, Range}; + +const MAX_DATA_CHUNK_SIZE: usize = MAX_WASM_STRING_SIZE; + +#[derive(Debug)] +pub struct LocalName<'a> { + pub index: u32, + pub locals: Box<[Naming<'a>]>, +} + +#[derive(Debug)] +pub enum NameEntry<'a> { + Module(&'a str), + Function(Box<[Naming<'a>]>), + Local(Box<[LocalName<'a>]>), +} + +#[derive(Debug)] +pub struct RelocEntry { + pub ty: RelocType, + pub offset: u32, + pub index: u32, + pub addend: Option<u32>, +} + +enum InitExpressionContinuationSection { + Global, + Element, + Data, +} + +#[derive(Debug)] +pub enum ParserState<'a> { + Error(BinaryReaderError), + Initial, + BeginWasm { + version: u32, + }, + EndWasm, + BeginSection { + code: SectionCode<'a>, + range: Range, + }, + EndSection, + SkippingSection, + ReadingCustomSection(CustomSectionKind), + ReadingSectionRawData, + SectionRawData(&'a [u8]), + + TypeSectionEntry(FuncType), + ImportSectionEntry { + module: &'a str, + field: &'a str, + ty: ImportSectionEntryType, + }, + FunctionSectionEntry(u32), + TableSectionEntry(TableType), + MemorySectionEntry(MemoryType), + ExportSectionEntry { + field: &'a str, + kind: ExternalKind, + index: u32, + }, + NameSectionEntry(NameEntry<'a>), + StartSectionEntry(u32), + DataCountSectionEntry(u32), + + BeginInitExpressionBody, + InitExpressionOperator(Operator<'a>), + EndInitExpressionBody, + + BeginFunctionBody { + range: Range, + }, + FunctionBodyLocals { + locals: Box<[(u32, Type)]>, + }, + CodeOperator(Operator<'a>), + EndFunctionBody, + SkippingFunctionBody, + + BeginElementSectionEntry { + /// `None` means this is a passive or defined entry + table: ElemSectionEntryTable, + ty: Type, + }, + ElementSectionEntryBody(Box<[ElementItem]>), + EndElementSectionEntry, + + BeginPassiveDataSectionEntry, + BeginActiveDataSectionEntry(u32), + EndDataSectionEntry, + BeginDataSectionEntryBody(u32), + DataSectionEntryBodyChunk(&'a [u8]), + EndDataSectionEntryBody, + + BeginGlobalSectionEntry(GlobalType), + EndGlobalSectionEntry, + + RelocSectionHeader(SectionCode<'a>), + RelocSectionEntry(RelocEntry), + LinkingSectionEntry(LinkingType), + + SourceMappingURL(&'a str), +} + +#[derive(Debug, Copy, Clone)] +pub enum ElemSectionEntryTable { + Passive, + Declared, + Active(u32), +} + +#[derive(Debug, Copy, Clone)] +pub enum ParserInput { + Default, + SkipSection, + SkipFunctionBody, + ReadCustomSection, + ReadSectionRawData, +} + +pub trait WasmDecoder<'a> { + fn read(&mut self) -> &ParserState<'a>; + fn push_input(&mut self, input: ParserInput); + fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a>; + fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b> + where + 'a: 'b; + fn last_state(&self) -> &ParserState<'a>; +} + +enum ParserSectionReader<'a> { + None, + CodeSectionReader(CodeSectionReader<'a>), + DataSectionReader(DataSectionReader<'a>), + ElementSectionReader(ElementSectionReader<'a>), + ExportSectionReader(ExportSectionReader<'a>), + FunctionSectionReader(FunctionSectionReader<'a>), + GlobalSectionReader(GlobalSectionReader<'a>), + ImportSectionReader(ImportSectionReader<'a>), + MemorySectionReader(MemorySectionReader<'a>), + TableSectionReader(TableSectionReader<'a>), + TypeSectionReader(TypeSectionReader<'a>), + NameSectionReader(NameSectionReader<'a>), + LinkingSectionReader(LinkingSectionReader<'a>), + RelocSectionReader(RelocSectionReader<'a>), +} + +macro_rules! section_reader { + ($self:ident, $ty_and_name:ident) => { + if let ParserSectionReader::$ty_and_name(ref mut reader) = $self.section_reader { + reader + } else { + panic!("expected {} reader", stringify!($ty_and_name)); + } + }; +} + +macro_rules! start_section_reader { + ($self:ident, $ty_and_name:ident, $factory:ident) => {{ + let reader = $self + .current_section + .as_ref() + .expect("section") + .$factory()?; + $self.section_entries_left = reader.get_count(); + $self.section_reader = ParserSectionReader::$ty_and_name(reader); + }}; +} + +/// The `Parser` type. A simple event-driven parser of WebAssembly binary +/// format. The `read(&mut self)` is used to iterate through WebAssembly records. +pub struct Parser<'a> { + data: &'a [u8], + state: ParserState<'a>, + module_reader: Option<ModuleReader<'a>>, + current_section: Option<Section<'a>>, + section_reader: ParserSectionReader<'a>, + element_items: Option<ElementItems<'a>>, + current_function_body: Option<FunctionBody<'a>>, + init_expr_continuation: Option<InitExpressionContinuationSection>, + current_data_segment: Option<&'a [u8]>, + binary_reader: Option<BinaryReader<'a>>, + operators_reader: Option<OperatorsReader<'a>>, + section_entries_left: u32, +} + +impl<'a> Parser<'a> { + /// Constructs `Parser` type. + /// + /// # Examples + /// ``` + /// let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// let mut parser = wasmparser::Parser::new(data); + /// ``` + pub fn new(data: &[u8]) -> Parser { + Parser { + data, + state: ParserState::Initial, + module_reader: None, + current_section: None, + section_reader: ParserSectionReader::None, + element_items: None, + current_function_body: None, + init_expr_continuation: None, + current_data_segment: None, + binary_reader: None, + operators_reader: None, + section_entries_left: 0, + } + } + + pub fn eof(&self) -> bool { + match self.state { + ParserState::EndWasm => true, + ParserState::BeginWasm { .. } | ParserState::EndSection => { + self.module_reader.as_ref().expect("module reader").eof() + } + _ => false, // in-process of reading + } + } + + pub fn current_position(&self) -> usize { + if let ParserState::Initial = self.state { + return 0; + } + if self.binary_reader.is_some() { + return self + .binary_reader + .as_ref() + .expect("binary reader") + .original_position(); + } + if self.operators_reader.is_some() { + return self + .operators_reader + .as_ref() + .expect("operators reader") + .original_position(); + } + match self.section_reader { + ParserSectionReader::CodeSectionReader(ref reader) => { + return reader.original_position() + } + ParserSectionReader::DataSectionReader(ref reader) => { + return reader.original_position() + } + ParserSectionReader::ElementSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::ExportSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::FunctionSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::GlobalSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::ImportSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::MemorySectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::TableSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::TypeSectionReader(ref reader) => { + return reader.original_position() + } + ParserSectionReader::NameSectionReader(ref reader) => { + return reader.original_position() + } + ParserSectionReader::LinkingSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::RelocSectionReader(ref reader) => { + return reader.original_position(); + } + _ => (), + }; + // TODO might not cover all cases + self.module_reader + .as_ref() + .expect("module reader") + .current_position() + } + + fn read_module(&mut self) -> Result<()> { + let module_reader = ModuleReader::new(self.data)?; + let version = module_reader.get_version(); + self.module_reader = Some(module_reader); + self.state = ParserState::BeginWasm { version }; + Ok(()) + } + + fn read_section_header(&mut self) -> Result<()> { + let section = self.module_reader.as_mut().expect("module reader").read()?; + let code = section.code; + let range = section.range(); + self.current_section = Some(section); + self.state = ParserState::BeginSection { code, range }; + Ok(()) + } + + fn read_type_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let type_entry = section_reader!(self, TypeSectionReader).read()?; + self.state = ParserState::TypeSectionEntry(type_entry); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_import_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Import { module, field, ty } = section_reader!(self, ImportSectionReader).read()?; + self.state = ParserState::ImportSectionEntry { module, field, ty }; + self.section_entries_left -= 1; + Ok(()) + } + + fn read_function_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let func_type = section_reader!(self, FunctionSectionReader).read()?; + self.state = ParserState::FunctionSectionEntry(func_type); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_memory_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let memory_type = section_reader!(self, MemorySectionReader).read()?; + self.state = ParserState::MemorySectionEntry(memory_type); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_global_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Global { ty, init_expr } = section_reader!(self, GlobalSectionReader).read()?; + self.state = ParserState::BeginGlobalSectionEntry(ty); + self.operators_reader = Some(init_expr.get_operators_reader()); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_init_expression_body(&mut self, cont: InitExpressionContinuationSection) { + self.state = ParserState::BeginInitExpressionBody; + self.init_expr_continuation = Some(cont); + } + + fn read_init_expression_operator(&mut self) -> Result<()> { + let op = self + .operators_reader + .as_mut() + .expect("operator reader") + .read()?; + if let Operator::End = op { + self.operators_reader = None; + self.state = ParserState::EndInitExpressionBody; + return Ok(()); + } + self.state = ParserState::InitExpressionOperator(op); + Ok(()) + } + + fn read_export_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Export { field, kind, index } = section_reader!(self, ExportSectionReader).read()?; + self.state = ParserState::ExportSectionEntry { field, kind, index }; + self.section_entries_left -= 1; + Ok(()) + } + + fn read_element_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Element { kind, items, ty } = section_reader!(self, ElementSectionReader).read()?; + let table = match kind { + ElementKind::Passive => ElemSectionEntryTable::Passive, + ElementKind::Declared => ElemSectionEntryTable::Declared, + ElementKind::Active { + table_index, + init_expr, + } => { + self.operators_reader = Some(init_expr.get_operators_reader()); + ElemSectionEntryTable::Active(table_index) + } + }; + self.state = ParserState::BeginElementSectionEntry { table, ty }; + self.element_items = Some(items); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_element_entry_body(&mut self) -> Result<()> { + let mut reader = self + .element_items + .take() + .expect("element items") + .get_items_reader()?; + let num_elements = reader.get_count() as usize; + if num_elements > MAX_WASM_TABLE_ENTRIES { + return Err(BinaryReaderError { + message: "num_elements is out of bounds", + offset: 0, // reader.position - 1, // TODO offset + }); + } + let mut elements = Vec::with_capacity(num_elements); + for _ in 0..num_elements { + elements.push(reader.read()?); + } + self.state = ParserState::ElementSectionEntryBody(elements.into_boxed_slice()); + Ok(()) + } + + fn read_function_body(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + self.current_function_body = None; + return self.check_section_end(); + } + let function_body = section_reader!(self, CodeSectionReader).read()?; + let range = function_body.range(); + self.state = ParserState::BeginFunctionBody { range }; + self.current_function_body = Some(function_body); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_function_body_locals(&mut self) -> Result<()> { + let function_body = self.current_function_body.as_mut().expect("function body"); + let mut reader = function_body.get_locals_reader()?; + let local_count = reader.get_count() as usize; + if local_count > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "local_count is out of bounds", + offset: reader.original_position() - 1, + }); + } + let mut locals: Vec<(u32, Type)> = Vec::with_capacity(local_count); + let mut locals_total: usize = 0; + for _ in 0..local_count { + let (count, ty) = reader.read()?; + locals_total = + locals_total + .checked_add(count as usize) + .ok_or_else(|| BinaryReaderError { + message: "locals_total is out of bounds", + offset: reader.original_position() - 1, + })?; + if locals_total > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "locals_total is out of bounds", + offset: reader.original_position() - 1, + }); + } + locals.push((count, ty)); + } + self.operators_reader = Some(function_body.get_operators_reader()?); + self.state = ParserState::FunctionBodyLocals { + locals: locals.into_boxed_slice(), + }; + Ok(()) + } + + fn read_code_operator(&mut self) -> Result<()> { + if self + .operators_reader + .as_ref() + .expect("operator reader") + .eof() + { + if let ParserState::CodeOperator(Operator::End) = self.state { + self.state = ParserState::EndFunctionBody; + self.operators_reader = None; + self.current_function_body = None; + return Ok(()); + } + let reader = self.operators_reader.as_ref().expect("operator reader"); + return Err(BinaryReaderError { + message: "Expected end of function marker", + offset: reader.original_position(), + }); + } + let reader = self.operators_reader.as_mut().expect("operator reader"); + let op = reader.read()?; + self.state = ParserState::CodeOperator(op); + Ok(()) + } + + fn read_table_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let table_entry = section_reader!(self, TableSectionReader).read()?; + self.state = ParserState::TableSectionEntry(table_entry); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_data_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Data { kind, data } = section_reader!(self, DataSectionReader).read()?; + match kind { + DataKind::Passive => { + self.state = ParserState::BeginPassiveDataSectionEntry; + } + DataKind::Active { + memory_index, + init_expr, + } => { + self.state = ParserState::BeginActiveDataSectionEntry(memory_index); + self.operators_reader = Some(init_expr.get_operators_reader()); + } + } + self.current_data_segment = Some(data); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_data_entry_body(&mut self) -> Result<()> { + let size = self.current_data_segment.expect("data entry").len(); + self.state = ParserState::BeginDataSectionEntryBody(size as u32); + Ok(()) + } + + fn read_naming<'b>( + mut naming_reader: NamingReader<'a>, + limit: usize, + ) -> Result<Box<[Naming<'b>]>> + where + 'a: 'b, + { + let count = naming_reader.get_count() as usize; + if count > limit { + return Err(BinaryReaderError { + message: "name map size is out of bound", + offset: naming_reader.original_position() - 1, + }); + } + let mut result = Vec::with_capacity(count); + for _ in 0..count { + result.push(naming_reader.read()?); + } + Ok(result.into_boxed_slice()) + } + + fn read_name_entry(&mut self) -> Result<()> { + if section_reader!(self, NameSectionReader).eof() { + return self.position_to_section_end(); + } + let entry = match section_reader!(self, NameSectionReader).read()? { + Name::Module(name) => NameEntry::Module(name.get_name()?), + Name::Function(func) => { + NameEntry::Function(Self::read_naming(func.get_map()?, MAX_WASM_FUNCTIONS)?) + } + Name::Local(locals) => { + let mut reader = locals.get_function_local_reader()?; + let funcs_len = reader.get_count() as usize; + if funcs_len > MAX_WASM_FUNCTIONS { + return Err(BinaryReaderError { + message: "function count is out of bounds", + offset: reader.original_position() - 1, + }); + } + let mut funcs: Vec<LocalName<'a>> = Vec::with_capacity(funcs_len); + for _ in 0..funcs_len { + let func = reader.read()?; + funcs.push(LocalName { + index: func.func_index, + locals: Self::read_naming(func.get_map()?, MAX_WASM_FUNCTION_LOCALS)?, + }); + } + NameEntry::Local(funcs.into_boxed_slice()) + } + }; + self.state = ParserState::NameSectionEntry(entry); + Ok(()) + } + + fn read_source_mapping(&mut self) -> Result<()> { + let url = self + .current_section + .as_ref() + .expect("section") + .get_sourcemappingurl_section_content()?; + self.state = ParserState::SourceMappingURL(url); + Ok(()) + } + + // See https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md + fn read_reloc_header(&mut self) -> Result<()> { + let section_code = section_reader!(self, RelocSectionReader).get_section_code(); + self.state = ParserState::RelocSectionHeader(section_code); + Ok(()) + } + + fn read_reloc_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Reloc { + ty, + offset, + index, + addend, + } = section_reader!(self, RelocSectionReader).read()?; + self.state = ParserState::RelocSectionEntry(RelocEntry { + ty, + offset, + index, + addend, + }); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_linking_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let entry = section_reader!(self, LinkingSectionReader).read()?; + self.state = ParserState::LinkingSectionEntry(entry); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_section_body(&mut self) -> Result<()> { + match self.state { + ParserState::BeginSection { + code: SectionCode::Type, + .. + } => { + start_section_reader!(self, TypeSectionReader, get_type_section_reader); + self.read_type_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Import, + .. + } => { + start_section_reader!(self, ImportSectionReader, get_import_section_reader); + self.read_import_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Function, + .. + } => { + start_section_reader!(self, FunctionSectionReader, get_function_section_reader); + self.read_function_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Memory, + .. + } => { + start_section_reader!(self, MemorySectionReader, get_memory_section_reader); + self.read_memory_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Global, + .. + } => { + start_section_reader!(self, GlobalSectionReader, get_global_section_reader); + self.read_global_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Export, + .. + } => { + start_section_reader!(self, ExportSectionReader, get_export_section_reader); + self.read_export_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Element, + .. + } => { + start_section_reader!(self, ElementSectionReader, get_element_section_reader); + self.read_element_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Code, + .. + } => { + start_section_reader!(self, CodeSectionReader, get_code_section_reader); + self.read_function_body()?; + } + ParserState::BeginSection { + code: SectionCode::Table, + .. + } => { + start_section_reader!(self, TableSectionReader, get_table_section_reader); + self.read_table_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Data, + .. + } => { + start_section_reader!(self, DataSectionReader, get_data_section_reader); + self.read_data_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Start, + .. + } => { + let func_index = self + .current_section + .as_ref() + .expect("section") + .get_start_section_content()?; + self.state = ParserState::StartSectionEntry(func_index); + } + ParserState::BeginSection { + code: SectionCode::DataCount, + .. + } => { + let func_index = self + .current_section + .as_ref() + .expect("section") + .get_data_count_section_content()?; + self.state = ParserState::DataCountSectionEntry(func_index); + } + ParserState::BeginSection { + code: SectionCode::Custom { .. }, + .. + } => { + self.create_custom_section_binary_reader(); + self.read_section_body_bytes()?; + } + _ => unreachable!(), + } + Ok(()) + } + + fn create_custom_section_binary_reader(&mut self) { + let reader = self + .current_section + .as_ref() + .expect("section") + .get_binary_reader(); + self.binary_reader = Some(reader); + } + + fn read_custom_section_body(&mut self) -> Result<()> { + match self.state { + ParserState::ReadingCustomSection(CustomSectionKind::Name) => { + let reader = self + .current_section + .as_ref() + .expect("section") + .get_name_section_reader()?; + self.section_reader = ParserSectionReader::NameSectionReader(reader); + self.read_name_entry()?; + } + ParserState::ReadingCustomSection(CustomSectionKind::SourceMappingURL) => { + self.read_source_mapping()?; + } + ParserState::ReadingCustomSection(CustomSectionKind::Reloc) => { + start_section_reader!(self, RelocSectionReader, get_reloc_section_reader); + self.read_reloc_header()?; + } + ParserState::ReadingCustomSection(CustomSectionKind::Linking) => { + start_section_reader!(self, LinkingSectionReader, get_linking_section_reader); + self.read_linking_entry()?; + } + ParserState::ReadingCustomSection(CustomSectionKind::Producers) + | ParserState::ReadingCustomSection(CustomSectionKind::Unknown) => { + self.create_custom_section_binary_reader(); + self.read_section_body_bytes()?; + } + _ => unreachable!(), + } + Ok(()) + } + + fn position_to_section_end(&mut self) -> Result<()> { + self.current_section = None; + self.binary_reader = None; + self.state = ParserState::EndSection; + Ok(()) + } + + fn check_section_end(&mut self) -> Result<()> { + match self.section_reader { + ParserSectionReader::CodeSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::DataSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::ElementSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::ExportSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::FunctionSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::GlobalSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::ImportSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::MemorySectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::TableSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::TypeSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::LinkingSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::RelocSectionReader(ref reader) => reader.ensure_end()?, + _ => unreachable!(), + } + self.position_to_section_end() + } + + fn read_section_body_bytes(&mut self) -> Result<()> { + if self.binary_reader.as_ref().expect("binary reader").eof() { + self.state = ParserState::EndSection; + self.binary_reader = None; + return Ok(()); + } + let binary_reader = self.binary_reader.as_mut().expect("binary reader"); + let to_read = if binary_reader.buffer.len() - binary_reader.position < MAX_DATA_CHUNK_SIZE { + binary_reader.buffer.len() - binary_reader.position + } else { + MAX_DATA_CHUNK_SIZE + }; + let bytes = binary_reader.read_bytes(to_read)?; + self.state = ParserState::SectionRawData(bytes); + Ok(()) + } + + fn read_data_chunk(&mut self) -> Result<()> { + let data = self.current_data_segment.expect("data"); + if data.is_empty() { + self.state = ParserState::EndDataSectionEntryBody; + self.current_data_segment = None; + return Ok(()); + } + let to_read = if data.len() > MAX_DATA_CHUNK_SIZE { + MAX_DATA_CHUNK_SIZE + } else { + data.len() + }; + let (head, tail) = data.split_at(to_read); + self.current_data_segment = Some(tail); + self.state = ParserState::DataSectionEntryBodyChunk(head); + Ok(()) + } + + fn read_next_section(&mut self) -> Result<()> { + if self.module_reader.as_ref().expect("module_reader").eof() { + self.current_section = None; + self.state = ParserState::EndWasm; + } else { + self.read_section_header()?; + } + Ok(()) + } + + fn read_wrapped(&mut self) -> Result<()> { + match self.state { + ParserState::EndWasm => panic!("Parser in end state"), + ParserState::Error(_) => panic!("Parser in error state"), + ParserState::Initial => self.read_module()?, + ParserState::BeginWasm { .. } | ParserState::EndSection => self.read_next_section()?, + ParserState::BeginSection { .. } => self.read_section_body()?, + ParserState::SkippingSection => { + self.position_to_section_end()?; + self.read_next_section()?; + } + ParserState::TypeSectionEntry(_) => self.read_type_entry()?, + ParserState::ImportSectionEntry { .. } => self.read_import_entry()?, + ParserState::FunctionSectionEntry(_) => self.read_function_entry()?, + ParserState::MemorySectionEntry(_) => self.read_memory_entry()?, + ParserState::TableSectionEntry(_) => self.read_table_entry()?, + ParserState::ExportSectionEntry { .. } => self.read_export_entry()?, + ParserState::BeginGlobalSectionEntry(_) => { + self.read_init_expression_body(InitExpressionContinuationSection::Global) + } + ParserState::EndGlobalSectionEntry => self.read_global_entry()?, + ParserState::BeginElementSectionEntry { + table: ElemSectionEntryTable::Active(_), + .. + } => self.read_init_expression_body(InitExpressionContinuationSection::Element), + ParserState::BeginElementSectionEntry { .. } => self.read_element_entry_body()?, + ParserState::BeginInitExpressionBody | ParserState::InitExpressionOperator(_) => { + self.read_init_expression_operator()? + } + ParserState::BeginPassiveDataSectionEntry => self.read_data_entry_body()?, + ParserState::BeginActiveDataSectionEntry(_) => { + self.read_init_expression_body(InitExpressionContinuationSection::Data) + } + ParserState::EndInitExpressionBody => { + match self.init_expr_continuation { + Some(InitExpressionContinuationSection::Global) => { + self.state = ParserState::EndGlobalSectionEntry + } + Some(InitExpressionContinuationSection::Element) => { + self.read_element_entry_body()? + } + Some(InitExpressionContinuationSection::Data) => self.read_data_entry_body()?, + None => unreachable!(), + } + self.init_expr_continuation = None; + } + ParserState::BeginFunctionBody { .. } => self.read_function_body_locals()?, + ParserState::FunctionBodyLocals { .. } | ParserState::CodeOperator(_) => { + self.read_code_operator()? + } + ParserState::EndFunctionBody => self.read_function_body()?, + ParserState::SkippingFunctionBody => { + self.current_function_body = None; + self.read_function_body()?; + } + ParserState::EndDataSectionEntry => self.read_data_entry()?, + ParserState::BeginDataSectionEntryBody(_) + | ParserState::DataSectionEntryBodyChunk(_) => self.read_data_chunk()?, + ParserState::EndDataSectionEntryBody => { + self.state = ParserState::EndDataSectionEntry; + } + ParserState::ElementSectionEntryBody(_) => { + self.state = ParserState::EndElementSectionEntry; + } + ParserState::EndElementSectionEntry => self.read_element_entry()?, + ParserState::StartSectionEntry(_) => self.position_to_section_end()?, + ParserState::DataCountSectionEntry(_) => self.position_to_section_end()?, + ParserState::NameSectionEntry(_) => self.read_name_entry()?, + ParserState::SourceMappingURL(_) => self.position_to_section_end()?, + ParserState::RelocSectionHeader(_) => { + let mut reader = self + .current_section + .as_ref() + .expect("section") + .get_binary_reader(); + self.section_entries_left = reader.read_var_u32()?; + self.binary_reader = Some(reader); + self.read_reloc_entry()?; + } + ParserState::RelocSectionEntry(_) => self.read_reloc_entry()?, + ParserState::LinkingSectionEntry(_) => self.read_linking_entry()?, + ParserState::ReadingCustomSection(_) => self.read_custom_section_body()?, + ParserState::ReadingSectionRawData | ParserState::SectionRawData(_) => { + self.read_section_body_bytes()? + } + } + Ok(()) + } + + fn skip_section(&mut self) { + match self.state { + ParserState::Initial + | ParserState::EndWasm + | ParserState::Error(_) + | ParserState::BeginWasm { .. } + | ParserState::EndSection => panic!("Invalid reader state during skip section"), + _ => self.state = ParserState::SkippingSection, + } + } + + fn skip_function_body(&mut self) { + match self.state { + ParserState::BeginFunctionBody { .. } + | ParserState::FunctionBodyLocals { .. } + | ParserState::CodeOperator(_) => self.state = ParserState::SkippingFunctionBody, + _ => panic!("Invalid reader state during skip function body"), + } + } + + fn read_custom_section(&mut self) { + match self.state { + ParserState::BeginSection { + code: SectionCode::Custom { kind, .. }, + .. + } => { + self.state = ParserState::ReadingCustomSection(kind); + } + _ => panic!("Invalid reader state during reading custom section"), + } + } + + fn read_raw_section_data(&mut self) { + match self.state { + ParserState::BeginSection { .. } => { + self.binary_reader = Some( + self.current_section + .as_ref() + .expect("section") + .get_binary_reader(), + ); + self.state = ParserState::ReadingSectionRawData; + } + _ => panic!("Invalid reader state during reading raw section data"), + } + } +} + +impl<'a> WasmDecoder<'a> for Parser<'a> { + /// Reads next record from the WebAssembly binary data. The methods returns + /// reference to current state of the parser. See `ParserState` num. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::WasmDecoder; + /// let mut parser = wasmparser::Parser::new(data); + /// { + /// let state = parser.read(); + /// println!("First state {:?}", state); + /// } + /// { + /// let state = parser.read(); + /// println!("Second state {:?}", state); + /// } + /// ``` + fn read(&mut self) -> &ParserState<'a> { + let result = self.read_wrapped(); + if result.is_err() { + self.state = ParserState::Error(result.err().unwrap()); + } + &self.state + } + + fn push_input(&mut self, input: ParserInput) { + match input { + ParserInput::Default => (), + ParserInput::SkipSection => self.skip_section(), + ParserInput::SkipFunctionBody => self.skip_function_body(), + ParserInput::ReadCustomSection => self.read_custom_section(), + ParserInput::ReadSectionRawData => self.read_raw_section_data(), + } + } + + /// Creates a BinaryReader when current state is ParserState::BeginSection + /// or ParserState::BeginFunctionBody. + /// + /// # Examples + /// ``` + /// # let data = &[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x84, + /// # 0x80, 0x80, 0x80, 0x0, 0x1, 0x60, 0x0, 0x0, 0x3, 0x83, + /// # 0x80, 0x80, 0x80, 0x0, 0x2, 0x0, 0x0, 0x6, 0x81, 0x80, + /// # 0x80, 0x80, 0x0, 0x0, 0xa, 0x91, 0x80, 0x80, 0x80, 0x0, + /// # 0x2, 0x83, 0x80, 0x80, 0x80, 0x0, 0x0, 0x1, 0xb, 0x83, + /// # 0x80, 0x80, 0x80, 0x0, 0x0, 0x0, 0xb]; + /// use wasmparser::{WasmDecoder, Parser, ParserState}; + /// let mut parser = Parser::new(data); + /// let mut types = Vec::new(); + /// let mut function_types = Vec::new(); + /// let mut function_readers = Vec::new(); + /// loop { + /// match parser.read() { + /// ParserState::Error(_) | + /// ParserState::EndWasm => break, + /// ParserState::TypeSectionEntry(ty) => { + /// types.push(ty.clone()); + /// } + /// ParserState::FunctionSectionEntry(id) => { + /// function_types.push(id.clone()); + /// } + /// ParserState::BeginFunctionBody {..} => { + /// let reader = parser.create_binary_reader(); + /// function_readers.push(reader); + /// } + /// _ => continue + /// } + /// } + /// for (i, reader) in function_readers.iter_mut().enumerate() { + /// // Access the function type through the types table. + /// let ty = &types[function_types[i] as usize]; + /// println!("\nFunction {} of type {:?}", i, ty); + /// // Read the local declarations required by the function body. + /// let local_decls_len = reader.read_local_count().unwrap(); + /// let mut local_decls = Vec::with_capacity(local_decls_len); + /// let mut local_count = ty.params.len(); + /// for _ in 0..local_decls_len { + /// let local_decl = reader.read_local_decl(&mut local_count).unwrap(); + /// local_decls.push(local_decl); + /// } + /// println!("Function locals: vars {:?}; total {} ", local_decls, local_count); + /// // Read the operations of the function body. + /// while let Ok(ref op) = reader.read_operator() { + /// println!(" {:?}", op); + /// } + /// } + /// ``` + fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b> + where + 'a: 'b, + { + match self.state { + ParserState::BeginSection { .. } => self + .current_section + .as_ref() + .expect("section") + .get_binary_reader(), + ParserState::BeginFunctionBody { .. } | ParserState::FunctionBodyLocals { .. } => self + .current_function_body + .as_ref() + .expect("function body") + .get_binary_reader(), + _ => panic!("Invalid reader state during get binary reader operation"), + } + } + + /// Reads next record from the WebAssembly binary data. It also allows to + /// control how parser will treat the next record(s). The method accepts the + /// `ParserInput` parameter that allows e.g. to skip section or function + /// operators. The methods returns reference to current state of the parser. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::WasmDecoder; + /// let mut parser = wasmparser::Parser::new(data); + /// let mut next_input = wasmparser::ParserInput::Default; + /// loop { + /// let state = parser.read_with_input(next_input); + /// match *state { + /// wasmparser::ParserState::EndWasm => break, + /// wasmparser::ParserState::BeginWasm { .. } | + /// wasmparser::ParserState::EndSection => + /// next_input = wasmparser::ParserInput::Default, + /// wasmparser::ParserState::BeginSection { ref code, .. } => { + /// println!("Found section: {:?}", code); + /// next_input = wasmparser::ParserInput::SkipSection; + /// }, + /// _ => unreachable!() + /// } + /// } + /// ``` + fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a> { + self.push_input(input); + self.read() + } + + fn last_state(&self) -> &ParserState<'a> { + &self.state + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/primitives.rs b/third_party/rust/wasmparser-0.48.2/src/primitives.rs new file mode 100644 index 0000000000..d7d2218aa4 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/primitives.rs @@ -0,0 +1,690 @@ +/* Copyright 2018 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. + */ + +use std::error::Error; +use std::fmt; +use std::result; + +#[derive(Debug, Copy, Clone)] +pub struct BinaryReaderError { + pub message: &'static str, + pub offset: usize, +} + +pub type Result<T> = result::Result<T, BinaryReaderError>; + +impl Error for BinaryReaderError {} + +impl fmt::Display for BinaryReaderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} (at offset {})", self.message, self.offset) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum CustomSectionKind { + Unknown, + Name, + Producers, + SourceMappingURL, + Reloc, + Linking, +} + +/// Section code as defined [here]. +/// +/// [here]: https://webassembly.github.io/spec/core/binary/modules.html#sections +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum SectionCode<'a> { + Custom { + name: &'a str, + kind: CustomSectionKind, + }, + Type, // Function signature declarations + Import, // Import declarations + Function, // Function declarations + Table, // Indirect function table and other tables + Memory, // Memory attributes + Global, // Global declarations + Export, // Exports + Start, // Start function declaration + Element, // Elements section + Code, // Function bodies (code) + Data, // Data segments + DataCount, // Count of passive data segments +} + +/// Types as defined [here]. +/// +/// [here]: https://webassembly.github.io/spec/core/syntax/types.html#types +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Type { + I32, + I64, + F32, + F64, + V128, + AnyFunc, + AnyRef, + NullRef, + Func, + EmptyBlockType, +} + +impl Type { + pub(crate) fn is_valid_for_old_select(self) -> bool { + match self { + Type::I32 | Type::I64 | Type::F32 | Type::F64 => true, + _ => false, + } + } +} + +/// Either a value type or a function type. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum TypeOrFuncType { + /// A value type. + /// + /// When used as the type for a block, this type is the optional result + /// type: `[] -> [t?]`. + Type(Type), + + /// A function type (referenced as an index into the types section). + FuncType(u32), +} + +/// External types as defined [here]. +/// +/// [here]: https://webassembly.github.io/spec/core/syntax/types.html#external-types +#[derive(Debug, Copy, Clone)] +pub enum ExternalKind { + Function, + Table, + Memory, + Global, +} + +#[derive(Debug, Clone)] +pub struct FuncType { + pub form: Type, + pub params: Box<[Type]>, + pub returns: Box<[Type]>, +} + +#[derive(Debug, Copy, Clone)] +pub struct ResizableLimits { + pub initial: u32, + pub maximum: Option<u32>, +} + +#[derive(Debug, Copy, Clone)] +pub struct TableType { + pub element_type: Type, + pub limits: ResizableLimits, +} + +#[derive(Debug, Copy, Clone)] +pub struct MemoryType { + pub limits: ResizableLimits, + pub shared: bool, +} + +#[derive(Debug, Copy, Clone)] +pub struct GlobalType { + pub content_type: Type, + pub mutable: bool, +} + +#[derive(Debug, Copy, Clone)] +pub enum ImportSectionEntryType { + Function(u32), + Table(TableType), + Memory(MemoryType), + Global(GlobalType), +} + +#[derive(Debug, Copy, Clone)] +pub struct MemoryImmediate { + pub flags: u32, + pub offset: u32, +} + +#[derive(Debug, Copy, Clone)] +pub struct Naming<'a> { + pub index: u32, + pub name: &'a str, +} + +#[derive(Debug, Copy, Clone)] +pub enum NameType { + Module, + Function, + Local, +} + +#[derive(Debug, Copy, Clone)] +pub enum LinkingType { + StackPointer(u32), +} + +#[derive(Debug, Copy, Clone)] +pub enum RelocType { + FunctionIndexLEB, + TableIndexSLEB, + TableIndexI32, + GlobalAddrLEB, + GlobalAddrSLEB, + GlobalAddrI32, + TypeIndexLEB, + GlobalIndexLEB, +} + +/// A br_table entries representation. +#[derive(Debug, Clone)] +pub struct BrTable<'a> { + pub(crate) buffer: &'a [u8], + pub(crate) cnt: usize, +} + +/// An IEEE binary32 immediate floating point value, represented as a u32 +/// containing the bitpattern. +/// +/// All bit patterns are allowed. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct Ieee32(pub(crate) u32); + +impl Ieee32 { + pub fn bits(self) -> u32 { + self.0 + } +} + +/// An IEEE binary64 immediate floating point value, represented as a u64 +/// containing the bitpattern. +/// +/// All bit patterns are allowed. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct Ieee64(pub(crate) u64); + +impl Ieee64 { + pub fn bits(self) -> u64 { + self.0 + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct V128(pub(crate) [u8; 16]); + +impl V128 { + pub fn bytes(&self) -> &[u8; 16] { + &self.0 + } +} + +pub type SIMDLaneIndex = u8; + +/// Instructions as defined [here]. +/// +/// [here]: https://webassembly.github.io/spec/core/binary/instructions.html +#[derive(Debug, Clone)] +pub enum Operator<'a> { + Unreachable, + Nop, + Block { ty: TypeOrFuncType }, + Loop { ty: TypeOrFuncType }, + If { ty: TypeOrFuncType }, + Else, + End, + Br { relative_depth: u32 }, + BrIf { relative_depth: u32 }, + BrTable { table: BrTable<'a> }, + Return, + Call { function_index: u32 }, + CallIndirect { index: u32, table_index: u32 }, + Drop, + Select, + TypedSelect { ty: Type }, + LocalGet { local_index: u32 }, + LocalSet { local_index: u32 }, + LocalTee { local_index: u32 }, + GlobalGet { global_index: u32 }, + GlobalSet { global_index: u32 }, + I32Load { memarg: MemoryImmediate }, + I64Load { memarg: MemoryImmediate }, + F32Load { memarg: MemoryImmediate }, + F64Load { memarg: MemoryImmediate }, + I32Load8S { memarg: MemoryImmediate }, + I32Load8U { memarg: MemoryImmediate }, + I32Load16S { memarg: MemoryImmediate }, + I32Load16U { memarg: MemoryImmediate }, + I64Load8S { memarg: MemoryImmediate }, + I64Load8U { memarg: MemoryImmediate }, + I64Load16S { memarg: MemoryImmediate }, + I64Load16U { memarg: MemoryImmediate }, + I64Load32S { memarg: MemoryImmediate }, + I64Load32U { memarg: MemoryImmediate }, + I32Store { memarg: MemoryImmediate }, + I64Store { memarg: MemoryImmediate }, + F32Store { memarg: MemoryImmediate }, + F64Store { memarg: MemoryImmediate }, + I32Store8 { memarg: MemoryImmediate }, + I32Store16 { memarg: MemoryImmediate }, + I64Store8 { memarg: MemoryImmediate }, + I64Store16 { memarg: MemoryImmediate }, + I64Store32 { memarg: MemoryImmediate }, + MemorySize { reserved: u32 }, + MemoryGrow { reserved: u32 }, + I32Const { value: i32 }, + I64Const { value: i64 }, + F32Const { value: Ieee32 }, + F64Const { value: Ieee64 }, + RefNull, + RefIsNull, + RefFunc { function_index: u32 }, + I32Eqz, + I32Eq, + I32Ne, + I32LtS, + I32LtU, + I32GtS, + I32GtU, + I32LeS, + I32LeU, + I32GeS, + I32GeU, + I64Eqz, + I64Eq, + I64Ne, + I64LtS, + I64LtU, + I64GtS, + I64GtU, + I64LeS, + I64LeU, + I64GeS, + I64GeU, + F32Eq, + F32Ne, + F32Lt, + F32Gt, + F32Le, + F32Ge, + F64Eq, + F64Ne, + F64Lt, + F64Gt, + F64Le, + F64Ge, + I32Clz, + I32Ctz, + I32Popcnt, + I32Add, + I32Sub, + I32Mul, + I32DivS, + I32DivU, + I32RemS, + I32RemU, + I32And, + I32Or, + I32Xor, + I32Shl, + I32ShrS, + I32ShrU, + I32Rotl, + I32Rotr, + I64Clz, + I64Ctz, + I64Popcnt, + I64Add, + I64Sub, + I64Mul, + I64DivS, + I64DivU, + I64RemS, + I64RemU, + I64And, + I64Or, + I64Xor, + I64Shl, + I64ShrS, + I64ShrU, + I64Rotl, + I64Rotr, + F32Abs, + F32Neg, + F32Ceil, + F32Floor, + F32Trunc, + F32Nearest, + F32Sqrt, + F32Add, + F32Sub, + F32Mul, + F32Div, + F32Min, + F32Max, + F32Copysign, + F64Abs, + F64Neg, + F64Ceil, + F64Floor, + F64Trunc, + F64Nearest, + F64Sqrt, + F64Add, + F64Sub, + F64Mul, + F64Div, + F64Min, + F64Max, + F64Copysign, + I32WrapI64, + I32TruncF32S, + I32TruncF32U, + I32TruncF64S, + I32TruncF64U, + I64ExtendI32S, + I64ExtendI32U, + I64TruncF32S, + I64TruncF32U, + I64TruncF64S, + I64TruncF64U, + F32ConvertI32S, + F32ConvertI32U, + F32ConvertI64S, + F32ConvertI64U, + F32DemoteF64, + F64ConvertI32S, + F64ConvertI32U, + F64ConvertI64S, + F64ConvertI64U, + F64PromoteF32, + I32ReinterpretF32, + I64ReinterpretF64, + F32ReinterpretI32, + F64ReinterpretI64, + I32Extend8S, + I32Extend16S, + I64Extend8S, + I64Extend16S, + I64Extend32S, + + // 0xFC operators + // Non-trapping Float-to-int Conversions + I32TruncSatF32S, + I32TruncSatF32U, + I32TruncSatF64S, + I32TruncSatF64U, + I64TruncSatF32S, + I64TruncSatF32U, + I64TruncSatF64S, + I64TruncSatF64U, + + // 0xFC operators + // bulk memory https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md + MemoryInit { segment: u32 }, + DataDrop { segment: u32 }, + MemoryCopy, + MemoryFill, + TableInit { segment: u32, table: u32 }, + ElemDrop { segment: u32 }, + TableCopy { dst_table: u32, src_table: u32 }, + TableFill { table: u32 }, + TableGet { table: u32 }, + TableSet { table: u32 }, + TableGrow { table: u32 }, + TableSize { table: u32 }, + + // 0xFE operators + // https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md + AtomicNotify { memarg: MemoryImmediate }, + I32AtomicWait { memarg: MemoryImmediate }, + I64AtomicWait { memarg: MemoryImmediate }, + AtomicFence { flags: u8 }, + I32AtomicLoad { memarg: MemoryImmediate }, + I64AtomicLoad { memarg: MemoryImmediate }, + I32AtomicLoad8U { memarg: MemoryImmediate }, + I32AtomicLoad16U { memarg: MemoryImmediate }, + I64AtomicLoad8U { memarg: MemoryImmediate }, + I64AtomicLoad16U { memarg: MemoryImmediate }, + I64AtomicLoad32U { memarg: MemoryImmediate }, + I32AtomicStore { memarg: MemoryImmediate }, + I64AtomicStore { memarg: MemoryImmediate }, + I32AtomicStore8 { memarg: MemoryImmediate }, + I32AtomicStore16 { memarg: MemoryImmediate }, + I64AtomicStore8 { memarg: MemoryImmediate }, + I64AtomicStore16 { memarg: MemoryImmediate }, + I64AtomicStore32 { memarg: MemoryImmediate }, + I32AtomicRmwAdd { memarg: MemoryImmediate }, + I64AtomicRmwAdd { memarg: MemoryImmediate }, + I32AtomicRmw8AddU { memarg: MemoryImmediate }, + I32AtomicRmw16AddU { memarg: MemoryImmediate }, + I64AtomicRmw8AddU { memarg: MemoryImmediate }, + I64AtomicRmw16AddU { memarg: MemoryImmediate }, + I64AtomicRmw32AddU { memarg: MemoryImmediate }, + I32AtomicRmwSub { memarg: MemoryImmediate }, + I64AtomicRmwSub { memarg: MemoryImmediate }, + I32AtomicRmw8SubU { memarg: MemoryImmediate }, + I32AtomicRmw16SubU { memarg: MemoryImmediate }, + I64AtomicRmw8SubU { memarg: MemoryImmediate }, + I64AtomicRmw16SubU { memarg: MemoryImmediate }, + I64AtomicRmw32SubU { memarg: MemoryImmediate }, + I32AtomicRmwAnd { memarg: MemoryImmediate }, + I64AtomicRmwAnd { memarg: MemoryImmediate }, + I32AtomicRmw8AndU { memarg: MemoryImmediate }, + I32AtomicRmw16AndU { memarg: MemoryImmediate }, + I64AtomicRmw8AndU { memarg: MemoryImmediate }, + I64AtomicRmw16AndU { memarg: MemoryImmediate }, + I64AtomicRmw32AndU { memarg: MemoryImmediate }, + I32AtomicRmwOr { memarg: MemoryImmediate }, + I64AtomicRmwOr { memarg: MemoryImmediate }, + I32AtomicRmw8OrU { memarg: MemoryImmediate }, + I32AtomicRmw16OrU { memarg: MemoryImmediate }, + I64AtomicRmw8OrU { memarg: MemoryImmediate }, + I64AtomicRmw16OrU { memarg: MemoryImmediate }, + I64AtomicRmw32OrU { memarg: MemoryImmediate }, + I32AtomicRmwXor { memarg: MemoryImmediate }, + I64AtomicRmwXor { memarg: MemoryImmediate }, + I32AtomicRmw8XorU { memarg: MemoryImmediate }, + I32AtomicRmw16XorU { memarg: MemoryImmediate }, + I64AtomicRmw8XorU { memarg: MemoryImmediate }, + I64AtomicRmw16XorU { memarg: MemoryImmediate }, + I64AtomicRmw32XorU { memarg: MemoryImmediate }, + I32AtomicRmwXchg { memarg: MemoryImmediate }, + I64AtomicRmwXchg { memarg: MemoryImmediate }, + I32AtomicRmw8XchgU { memarg: MemoryImmediate }, + I32AtomicRmw16XchgU { memarg: MemoryImmediate }, + I64AtomicRmw8XchgU { memarg: MemoryImmediate }, + I64AtomicRmw16XchgU { memarg: MemoryImmediate }, + I64AtomicRmw32XchgU { memarg: MemoryImmediate }, + I32AtomicRmwCmpxchg { memarg: MemoryImmediate }, + I64AtomicRmwCmpxchg { memarg: MemoryImmediate }, + I32AtomicRmw8CmpxchgU { memarg: MemoryImmediate }, + I32AtomicRmw16CmpxchgU { memarg: MemoryImmediate }, + I64AtomicRmw8CmpxchgU { memarg: MemoryImmediate }, + I64AtomicRmw16CmpxchgU { memarg: MemoryImmediate }, + I64AtomicRmw32CmpxchgU { memarg: MemoryImmediate }, + + // 0xFD operators + // SIMD https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md + V128Load { memarg: MemoryImmediate }, + V128Store { memarg: MemoryImmediate }, + V128Const { value: V128 }, + I8x16Splat, + I8x16ExtractLaneS { lane: SIMDLaneIndex }, + I8x16ExtractLaneU { lane: SIMDLaneIndex }, + I8x16ReplaceLane { lane: SIMDLaneIndex }, + I16x8Splat, + I16x8ExtractLaneS { lane: SIMDLaneIndex }, + I16x8ExtractLaneU { lane: SIMDLaneIndex }, + I16x8ReplaceLane { lane: SIMDLaneIndex }, + I32x4Splat, + I32x4ExtractLane { lane: SIMDLaneIndex }, + I32x4ReplaceLane { lane: SIMDLaneIndex }, + I64x2Splat, + I64x2ExtractLane { lane: SIMDLaneIndex }, + I64x2ReplaceLane { lane: SIMDLaneIndex }, + F32x4Splat, + F32x4ExtractLane { lane: SIMDLaneIndex }, + F32x4ReplaceLane { lane: SIMDLaneIndex }, + F64x2Splat, + F64x2ExtractLane { lane: SIMDLaneIndex }, + F64x2ReplaceLane { lane: SIMDLaneIndex }, + I8x16Eq, + I8x16Ne, + I8x16LtS, + I8x16LtU, + I8x16GtS, + I8x16GtU, + I8x16LeS, + I8x16LeU, + I8x16GeS, + I8x16GeU, + I16x8Eq, + I16x8Ne, + I16x8LtS, + I16x8LtU, + I16x8GtS, + I16x8GtU, + I16x8LeS, + I16x8LeU, + I16x8GeS, + I16x8GeU, + I32x4Eq, + I32x4Ne, + I32x4LtS, + I32x4LtU, + I32x4GtS, + I32x4GtU, + I32x4LeS, + I32x4LeU, + I32x4GeS, + I32x4GeU, + F32x4Eq, + F32x4Ne, + F32x4Lt, + F32x4Gt, + F32x4Le, + F32x4Ge, + F64x2Eq, + F64x2Ne, + F64x2Lt, + F64x2Gt, + F64x2Le, + F64x2Ge, + V128Not, + V128And, + V128AndNot, + V128Or, + V128Xor, + V128Bitselect, + I8x16Neg, + I8x16AnyTrue, + I8x16AllTrue, + I8x16Shl, + I8x16ShrS, + I8x16ShrU, + I8x16Add, + I8x16AddSaturateS, + I8x16AddSaturateU, + I8x16Sub, + I8x16SubSaturateS, + I8x16SubSaturateU, + I8x16Mul, + I16x8Neg, + I16x8AnyTrue, + I16x8AllTrue, + I16x8Shl, + I16x8ShrS, + I16x8ShrU, + I16x8Add, + I16x8AddSaturateS, + I16x8AddSaturateU, + I16x8Sub, + I16x8SubSaturateS, + I16x8SubSaturateU, + I16x8Mul, + I32x4Neg, + I32x4AnyTrue, + I32x4AllTrue, + I32x4Shl, + I32x4ShrS, + I32x4ShrU, + I32x4Add, + I32x4Sub, + I32x4Mul, + I64x2Neg, + I64x2AnyTrue, + I64x2AllTrue, + I64x2Shl, + I64x2ShrS, + I64x2ShrU, + I64x2Add, + I64x2Sub, + I64x2Mul, + F32x4Abs, + F32x4Neg, + F32x4Sqrt, + F32x4Add, + F32x4Sub, + F32x4Mul, + F32x4Div, + F32x4Min, + F32x4Max, + F64x2Abs, + F64x2Neg, + F64x2Sqrt, + F64x2Add, + F64x2Sub, + F64x2Mul, + F64x2Div, + F64x2Min, + F64x2Max, + I32x4TruncSatF32x4S, + I32x4TruncSatF32x4U, + I64x2TruncSatF64x2S, + I64x2TruncSatF64x2U, + F32x4ConvertI32x4S, + F32x4ConvertI32x4U, + F64x2ConvertI64x2S, + F64x2ConvertI64x2U, + V8x16Swizzle, + V8x16Shuffle { lanes: [SIMDLaneIndex; 16] }, + V8x16LoadSplat { memarg: MemoryImmediate }, + V16x8LoadSplat { memarg: MemoryImmediate }, + V32x4LoadSplat { memarg: MemoryImmediate }, + V64x2LoadSplat { memarg: MemoryImmediate }, + I8x16NarrowI16x8S, + I8x16NarrowI16x8U, + I16x8NarrowI32x4S, + I16x8NarrowI32x4U, + I16x8WidenLowI8x16S, + I16x8WidenHighI8x16S, + I16x8WidenLowI8x16U, + I16x8WidenHighI8x16U, + I32x4WidenLowI16x8S, + I32x4WidenHighI16x8S, + I32x4WidenLowI16x8U, + I32x4WidenHighI16x8U, + I16x8Load8x8S { memarg: MemoryImmediate }, + I16x8Load8x8U { memarg: MemoryImmediate }, + I32x4Load16x4S { memarg: MemoryImmediate }, + I32x4Load16x4U { memarg: MemoryImmediate }, + I64x2Load32x2S { memarg: MemoryImmediate }, + I64x2Load32x2U { memarg: MemoryImmediate }, + I8x16RoundingAverageU, + I16x8RoundingAverageU, +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/code_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/code_section.rs new file mode 100644 index 0000000000..fac9c6e229 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/code_section.rs @@ -0,0 +1,245 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, BinaryReaderError, OperatorsReader, Range, Result, SectionIteratorLimited, + SectionReader, SectionWithLimitedItems, Type, +}; + +#[derive(Debug)] +pub struct FunctionBody<'a> { + offset: usize, + data: &'a [u8], +} + +impl<'a> FunctionBody<'a> { + pub fn new(offset: usize, data: &'a [u8]) -> Self { + Self { offset, data } + } + + pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b> + where + 'a: 'b, + { + BinaryReader::new_with_offset(self.data, self.offset) + } + + fn skip_locals(reader: &mut BinaryReader) -> Result<()> { + let count = reader.read_var_u32()?; + for _ in 0..count { + reader.skip_var_32()?; + reader.skip_type()?; + } + Ok(()) + } + + pub fn get_locals_reader<'b>(&self) -> Result<LocalsReader<'b>> + where + 'a: 'b, + { + let mut reader = BinaryReader::new_with_offset(self.data, self.offset); + let count = reader.read_var_u32()?; + Ok(LocalsReader { reader, count }) + } + + pub fn get_operators_reader<'b>(&self) -> Result<OperatorsReader<'b>> + where + 'a: 'b, + { + let mut reader = BinaryReader::new_with_offset(self.data, self.offset); + Self::skip_locals(&mut reader)?; + let pos = reader.position; + Ok(OperatorsReader::new(&self.data[pos..], self.offset + pos)) + } + + pub fn range(&self) -> Range { + Range { + start: self.offset, + end: self.offset + self.data.len(), + } + } +} + +pub struct LocalsReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> LocalsReader<'a> { + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn read(&mut self) -> Result<(u32, Type)> { + let count = self.reader.read_var_u32()?; + let value_type = self.reader.read_type()?; + Ok((count, value_type)) + } +} + +pub struct CodeSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> IntoIterator for LocalsReader<'a> { + type Item = Result<(u32, Type)>; + type IntoIter = LocalsIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + let count = self.count; + LocalsIterator { + reader: self, + left: count, + err: false, + } + } +} + +pub struct LocalsIterator<'a> { + reader: LocalsReader<'a>, + left: u32, + err: bool, +} + +impl<'a> Iterator for LocalsIterator<'a> { + type Item = Result<(u32, Type)>; + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.left == 0 { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + self.left -= 1; + Some(result) + } + fn size_hint(&self) -> (usize, Option<usize>) { + let count = self.reader.get_count() as usize; + (count, Some(count)) + } +} + +impl<'a> CodeSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<CodeSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(CodeSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + fn verify_body_end(&self, end: usize) -> Result<()> { + if self.reader.buffer.len() < end { + return Err(BinaryReaderError { + message: "Function body extends past end of the code section", + offset: self.reader.original_offset + self.reader.buffer.len(), + }); + } + Ok(()) + } + + /// Reads content of the code section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("code section"); + /// let mut code_reader = section.get_code_section_reader().expect("code section reader"); + /// for _ in 0..code_reader.get_count() { + /// let body = code_reader.read().expect("function body"); + /// let mut binary_reader = body.get_binary_reader(); + /// assert!(binary_reader.read_local_count().expect("local count") == 0); + /// let op = binary_reader.read_operator().expect("first operator"); + /// println!("First operator: {:?}", op); + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<FunctionBody<'b>> + where + 'a: 'b, + { + let size = self.reader.read_var_u32()? as usize; + let body_start = self.reader.position; + let body_end = body_start + size; + self.verify_body_end(body_end)?; + self.reader.skip_to(body_end); + Ok(FunctionBody { + offset: self.reader.original_offset + body_start, + data: &self.reader.buffer[body_start..body_end], + }) + } +} + +impl<'a> SectionReader for CodeSectionReader<'a> { + type Item = FunctionBody<'a>; + fn read(&mut self) -> Result<Self::Item> { + CodeSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + CodeSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for CodeSectionReader<'a> { + fn get_count(&self) -> u32 { + CodeSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for CodeSectionReader<'a> { + type Item = Result<FunctionBody<'a>>; + type IntoIter = SectionIteratorLimited<CodeSectionReader<'a>>; + + /// Implements iterator over the code section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("code section"); + /// let mut code_reader = section.get_code_section_reader().expect("code section reader"); + /// for body in code_reader { + /// let mut binary_reader = body.expect("b").get_binary_reader(); + /// assert!(binary_reader.read_local_count().expect("local count") == 0); + /// let op = binary_reader.read_operator().expect("first operator"); + /// println!("First operator: {:?}", op); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/data_count_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/data_count_section.rs new file mode 100644 index 0000000000..ac0f9db0f7 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/data_count_section.rs @@ -0,0 +1,28 @@ +/* Copyright 2018 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. + */ + +use super::{BinaryReader, BinaryReaderError, Result}; + +pub(crate) fn read_data_count_section_content(data: &[u8], offset: usize) -> Result<u32> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + if !reader.eof() { + return Err(BinaryReaderError { + message: "Unexpected content in the data count section", + offset: offset + reader.position, + }); + } + Ok(count) +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/data_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/data_section.rs new file mode 100644 index 0000000000..29b7d8284e --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/data_section.rs @@ -0,0 +1,157 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, BinaryReaderError, InitExpr, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Data<'a> { + pub kind: DataKind<'a>, + pub data: &'a [u8], +} + +#[derive(Debug, Copy, Clone)] +pub enum DataKind<'a> { + Passive, + Active { + memory_index: u32, + init_expr: InitExpr<'a>, + }, +} + +pub struct DataSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> DataSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<DataSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(DataSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + fn verify_data_end(&self, end: usize) -> Result<()> { + if self.reader.buffer.len() < end { + return Err(BinaryReaderError { + message: "Data segment extends past end of the data section", + offset: self.reader.original_offset + self.reader.buffer.len(), + }); + } + Ok(()) + } + + /// Reads content of the data section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x05, 0x03, 0x01, 0x00, 0x02, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b, + /// # 0x0b, 0x0b, 0x01, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00]; + /// use wasmparser::{ModuleReader, DataKind}; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("memory section"); + /// let section = reader.read().expect("code section"); + /// let section = reader.read().expect("data section"); + /// let mut data_reader = section.get_data_section_reader().expect("data section reader"); + /// for _ in 0..data_reader.get_count() { + /// let data = data_reader.read().expect("data"); + /// println!("Data: {:?}", data); + /// if let DataKind::Active { init_expr, .. } = data.kind { + /// let mut init_expr_reader = init_expr.get_binary_reader(); + /// let op = init_expr_reader.read_operator().expect("op"); + /// println!("Init const: {:?}", op); + /// } + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Data<'b>> + where + 'a: 'b, + { + let flags = self.reader.read_var_u32()?; + let kind = if flags == 1 { + DataKind::Passive + } else { + let memory_index = match flags { + 0 => 0, + 2 => self.reader.read_var_u32()?, + _ => { + return Err(BinaryReaderError { + message: "invalid flags byte in data segment", + offset: self.reader.original_position() - 1, + }); + } + }; + let init_expr = { + let expr_offset = self.reader.position; + self.reader.skip_init_expr()?; + let data = &self.reader.buffer[expr_offset..self.reader.position]; + InitExpr::new(data, self.reader.original_offset + expr_offset) + }; + DataKind::Active { + memory_index, + init_expr, + } + }; + let data_len = self.reader.read_var_u32()? as usize; + let data_end = self.reader.position + data_len; + self.verify_data_end(data_end)?; + let data = &self.reader.buffer[self.reader.position..data_end]; + self.reader.skip_to(data_end); + Ok(Data { kind, data }) + } +} + +impl<'a> SectionReader for DataSectionReader<'a> { + type Item = Data<'a>; + fn read(&mut self) -> Result<Self::Item> { + DataSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + DataSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for DataSectionReader<'a> { + fn get_count(&self) -> u32 { + DataSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for DataSectionReader<'a> { + type Item = Result<Data<'a>>; + type IntoIter = SectionIteratorLimited<DataSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/element_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/element_section.rs new file mode 100644 index 0000000000..ef45113a3f --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/element_section.rs @@ -0,0 +1,301 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, BinaryReaderError, InitExpr, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, Type, +}; +use crate::{ExternalKind, Operator}; + +#[derive(Clone)] +pub struct Element<'a> { + pub kind: ElementKind<'a>, + pub items: ElementItems<'a>, + pub ty: Type, +} + +#[derive(Clone)] +pub enum ElementKind<'a> { + Passive, + Active { + table_index: u32, + init_expr: InitExpr<'a>, + }, + Declared, +} + +#[derive(Debug, Copy, Clone)] +pub struct ElementItems<'a> { + exprs: bool, + offset: usize, + data: &'a [u8], +} + +#[derive(Debug)] +pub enum ElementItem { + Null, + Func(u32), +} + +impl<'a> ElementItems<'a> { + pub fn get_items_reader<'b>(&self) -> Result<ElementItemsReader<'b>> + where + 'a: 'b, + { + ElementItemsReader::new(self.data, self.offset, self.exprs) + } +} + +pub struct ElementItemsReader<'a> { + reader: BinaryReader<'a>, + count: u32, + exprs: bool, +} + +impl<'a> ElementItemsReader<'a> { + pub fn new(data: &[u8], offset: usize, exprs: bool) -> Result<ElementItemsReader> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ElementItemsReader { + reader, + count, + exprs, + }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn uses_exprs(&self) -> bool { + self.exprs + } + + pub fn read(&mut self) -> Result<ElementItem> { + if self.exprs { + let offset = self.reader.original_position(); + let ret = match self.reader.read_operator()? { + Operator::RefNull => ElementItem::Null, + Operator::RefFunc { function_index } => ElementItem::Func(function_index), + _ => { + return Err(BinaryReaderError { + message: "invalid passive segment", + offset, + }) + } + }; + match self.reader.read_operator()? { + Operator::End => {} + _ => { + return Err(BinaryReaderError { + message: "invalid passive segment", + offset, + }) + } + } + Ok(ret) + } else { + self.reader.read_var_u32().map(ElementItem::Func) + } + } +} + +impl<'a> IntoIterator for ElementItemsReader<'a> { + type Item = Result<ElementItem>; + type IntoIter = ElementItemsIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + let count = self.count; + ElementItemsIterator { + reader: self, + left: count, + err: false, + } + } +} + +pub struct ElementItemsIterator<'a> { + reader: ElementItemsReader<'a>, + left: u32, + err: bool, +} + +impl<'a> Iterator for ElementItemsIterator<'a> { + type Item = Result<ElementItem>; + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.left == 0 { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + self.left -= 1; + Some(result) + } + fn size_hint(&self) -> (usize, Option<usize>) { + let count = self.reader.get_count() as usize; + (count, Some(count)) + } +} + +pub struct ElementSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ElementSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<ElementSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ElementSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the element section. + /// + /// # Examples + /// ```no-run + /// # let data: &[u8] = &[]; + /// use wasmparser::{ModuleReader, ElementKind}; + ///use wasmparser::Result; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("table section"); + /// let section = reader.read().expect("element section"); + /// let mut element_reader = section.get_element_section_reader().expect("element section reader"); + /// for _ in 0..element_reader.get_count() { + /// let element = element_reader.read().expect("element"); + /// if let ElementKind::Active { init_expr, .. } = element.kind { + /// let mut init_expr_reader = init_expr.get_binary_reader(); + /// let op = init_expr_reader.read_operator().expect("op"); + /// println!("Init const: {:?}", op); + /// } + /// let mut items_reader = element.items.get_items_reader().expect("items reader"); + /// for _ in 0..items_reader.get_count() { + /// let item = items_reader.read().expect("item"); + /// println!(" Item: {:?}", item); + /// } + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Element<'b>> + where + 'a: 'b, + { + let flags = self.reader.read_var_u32()?; + if (flags & !0b111) != 0 { + return Err(BinaryReaderError { + message: "invalid flags byte in element segment", + offset: self.reader.original_position() - 1, + }); + } + let kind = if flags & 0b001 != 0 { + if flags & 0b010 != 0 { + ElementKind::Declared + } else { + ElementKind::Passive + } + } else { + let table_index = if flags & 0b010 == 0 { + 0 + } else { + self.reader.read_var_u32()? + }; + let init_expr = { + let expr_offset = self.reader.position; + self.reader.skip_init_expr()?; + let data = &self.reader.buffer[expr_offset..self.reader.position]; + InitExpr::new(data, self.reader.original_offset + expr_offset) + }; + ElementKind::Active { + table_index, + init_expr, + } + }; + let exprs = flags & 0b100 != 0; + let ty = if flags & 0b011 != 0 { + if exprs { + self.reader.read_type()? + } else { + match self.reader.read_external_kind()? { + ExternalKind::Function => Type::AnyFunc, + _ => { + return Err(BinaryReaderError { + message: "only the function external type is supported in elem segment", + offset: self.reader.original_position() - 1, + }); + } + } + } + } else { + Type::AnyFunc + }; + let data_start = self.reader.position; + let items_count = self.reader.read_var_u32()?; + if exprs { + for _ in 0..items_count { + self.reader.skip_init_expr()?; + } + } else { + for _ in 0..items_count { + self.reader.skip_var_32()?; + } + } + let data_end = self.reader.position; + let items = ElementItems { + offset: self.reader.original_offset + data_start, + data: &self.reader.buffer[data_start..data_end], + exprs, + }; + Ok(Element { kind, items, ty }) + } +} + +impl<'a> SectionReader for ElementSectionReader<'a> { + type Item = Element<'a>; + fn read(&mut self) -> Result<Self::Item> { + ElementSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + ElementSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for ElementSectionReader<'a> { + fn get_count(&self) -> u32 { + ElementSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for ElementSectionReader<'a> { + type Item = Result<Element<'a>>; + type IntoIter = SectionIteratorLimited<ElementSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/export_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/export_section.rs new file mode 100644 index 0000000000..636ac2bcf3 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/export_section.rs @@ -0,0 +1,104 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, ExternalKind, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Export<'a> { + pub field: &'a str, + pub kind: ExternalKind, + pub index: u32, +} + +pub struct ExportSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ExportSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<ExportSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ExportSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the export section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x07, 0x5, 0x01, 0x01, 0x65, 0x00, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("export section"); + /// let mut export_reader = section.get_export_section_reader().expect("export section reader"); + /// for _ in 0..export_reader.get_count() { + /// let export = export_reader.read().expect("export"); + /// println!("Export: {:?}", export); + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Export<'b>> + where + 'a: 'b, + { + let field = self.reader.read_string()?; + let kind = self.reader.read_external_kind()?; + let index = self.reader.read_var_u32()?; + Ok(Export { field, kind, index }) + } +} + +impl<'a> SectionReader for ExportSectionReader<'a> { + type Item = Export<'a>; + fn read(&mut self) -> Result<Self::Item> { + ExportSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + ExportSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for ExportSectionReader<'a> { + fn get_count(&self) -> u32 { + ExportSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for ExportSectionReader<'a> { + type Item = Result<Export<'a>>; + type IntoIter = SectionIteratorLimited<ExportSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/function_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/function_section.rs new file mode 100644 index 0000000000..c81bb4d9ed --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/function_section.rs @@ -0,0 +1,86 @@ +/* Copyright 2018 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. + */ + +use super::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; + +pub struct FunctionSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> FunctionSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<FunctionSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(FunctionSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads function type index from the function section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let mut function_reader = section.get_function_section_reader().expect("function section reader"); + /// for _ in 0..function_reader.get_count() { + /// let ty = function_reader.read().expect("function type index"); + /// println!("Function type index: {}", ty); + /// } + /// ``` + pub fn read(&mut self) -> Result<u32> { + self.reader.read_var_u32() + } +} + +impl<'a> SectionReader for FunctionSectionReader<'a> { + type Item = u32; + fn read(&mut self) -> Result<Self::Item> { + FunctionSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + FunctionSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for FunctionSectionReader<'a> { + fn get_count(&self) -> u32 { + FunctionSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for FunctionSectionReader<'a> { + type Item = Result<u32>; + type IntoIter = SectionIteratorLimited<FunctionSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/global_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/global_section.rs new file mode 100644 index 0000000000..15a85a7c36 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/global_section.rs @@ -0,0 +1,108 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, GlobalType, InitExpr, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Global<'a> { + pub ty: GlobalType, + pub init_expr: InitExpr<'a>, +} + +pub struct GlobalSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> GlobalSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<GlobalSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(GlobalSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the global section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x06, 0x8, 0x01, 0x7F, 0x01, 0x41, 0x90, 0x88, 0x04, 0x0B, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("global section"); + /// let mut global_reader = section.get_global_section_reader().expect("global section reader"); + /// for _ in 0..global_reader.get_count() { + /// let global = global_reader.read().expect("global"); + /// println!("Global: {:?}", global); + /// let mut init_expr_reader = global.init_expr.get_binary_reader(); + /// let op = init_expr_reader.read_operator().expect("op"); + /// println!("Init const: {:?}", op); + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Global<'b>> + where + 'a: 'b, + { + let ty = self.reader.read_global_type()?; + let expr_offset = self.reader.position; + self.reader.skip_init_expr()?; + let data = &self.reader.buffer[expr_offset..self.reader.position]; + let init_expr = InitExpr::new(data, self.reader.original_offset + expr_offset); + Ok(Global { ty, init_expr }) + } +} + +impl<'a> SectionReader for GlobalSectionReader<'a> { + type Item = Global<'a>; + fn read(&mut self) -> Result<Self::Item> { + GlobalSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + GlobalSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for GlobalSectionReader<'a> { + fn get_count(&self) -> u32 { + GlobalSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for GlobalSectionReader<'a> { + type Item = Result<Global<'a>>; + type IntoIter = SectionIteratorLimited<GlobalSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/import_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/import_section.rs new file mode 100644 index 0000000000..92fd5f5e99 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/import_section.rs @@ -0,0 +1,109 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, ExternalKind, ImportSectionEntryType, Result, SectionIteratorLimited, + SectionReader, SectionWithLimitedItems, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Import<'a> { + pub module: &'a str, + pub field: &'a str, + pub ty: ImportSectionEntryType, +} + +pub struct ImportSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ImportSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<ImportSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ImportSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the import section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, + /// # 0x02, 0x07, 0x01, 0x01, 0x41, 0x01, 0x66, 0x00, 0x00, + /// # 0x03, 0x02, 0x01, 0x00, 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("import section"); + /// let mut import_reader = section.get_import_section_reader().expect("import section reader"); + /// for _ in 0..import_reader.get_count() { + /// let import = import_reader.read().expect("import"); + /// println!("Import: {:?}", import); + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Import<'b>> + where + 'a: 'b, + { + let module = self.reader.read_string()?; + let field = self.reader.read_string()?; + let kind = self.reader.read_external_kind()?; + let ty = match kind { + ExternalKind::Function => ImportSectionEntryType::Function(self.reader.read_var_u32()?), + ExternalKind::Table => ImportSectionEntryType::Table(self.reader.read_table_type()?), + ExternalKind::Memory => ImportSectionEntryType::Memory(self.reader.read_memory_type()?), + ExternalKind::Global => ImportSectionEntryType::Global(self.reader.read_global_type()?), + }; + Ok(Import { module, field, ty }) + } +} + +impl<'a> SectionReader for ImportSectionReader<'a> { + type Item = Import<'a>; + fn read(&mut self) -> Result<Self::Item> { + ImportSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + ImportSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for ImportSectionReader<'a> { + fn get_count(&self) -> u32 { + ImportSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for ImportSectionReader<'a> { + type Item = Result<Import<'a>>; + type IntoIter = SectionIteratorLimited<ImportSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/init_expr.rs b/third_party/rust/wasmparser-0.48.2/src/readers/init_expr.rs new file mode 100644 index 0000000000..98c301d350 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/init_expr.rs @@ -0,0 +1,42 @@ +/* Copyright 2018 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. + */ + +use super::{BinaryReader, OperatorsReader}; + +#[derive(Debug, Copy, Clone)] +pub struct InitExpr<'a> { + offset: usize, + data: &'a [u8], +} + +impl<'a> InitExpr<'a> { + pub fn new(data: &[u8], offset: usize) -> InitExpr { + InitExpr { offset, data } + } + + pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b> + where + 'a: 'b, + { + BinaryReader::new_with_offset(self.data, self.offset) + } + + pub fn get_operators_reader<'b>(&self) -> OperatorsReader<'b> + where + 'a: 'b, + { + OperatorsReader::new(self.data, self.offset) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/linking_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/linking_section.rs new file mode 100644 index 0000000000..4181cde2dd --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/linking_section.rs @@ -0,0 +1,75 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, LinkingType, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; + +pub struct LinkingSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> LinkingSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<LinkingSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(LinkingSectionReader { reader, count }) + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn read<'b>(&mut self) -> Result<LinkingType> + where + 'a: 'b, + { + Ok(self.reader.read_linking_type()?) + } +} + +impl<'a> SectionReader for LinkingSectionReader<'a> { + type Item = LinkingType; + fn read(&mut self) -> Result<Self::Item> { + LinkingSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + LinkingSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for LinkingSectionReader<'a> { + fn get_count(&self) -> u32 { + LinkingSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for LinkingSectionReader<'a> { + type Item = Result<LinkingType>; + type IntoIter = SectionIteratorLimited<LinkingSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/memory_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/memory_section.rs new file mode 100644 index 0000000000..6e9dcb9dd0 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/memory_section.rs @@ -0,0 +1,91 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, MemoryType, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; + +pub struct MemorySectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> MemorySectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<MemorySectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(MemorySectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the memory section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x05, 0x03, 0x01, 0x00, 0x02, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("memory section"); + /// let mut memory_reader = section.get_memory_section_reader().expect("memory section reader"); + /// for _ in 0..memory_reader.get_count() { + /// let memory = memory_reader.read().expect("memory"); + /// println!("Memory: {:?}", memory); + /// } + /// ``` + pub fn read(&mut self) -> Result<MemoryType> { + self.reader.read_memory_type() + } +} + +impl<'a> SectionReader for MemorySectionReader<'a> { + type Item = MemoryType; + fn read(&mut self) -> Result<Self::Item> { + MemorySectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + MemorySectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for MemorySectionReader<'a> { + fn get_count(&self) -> u32 { + MemorySectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for MemorySectionReader<'a> { + type Item = Result<MemoryType>; + type IntoIter = SectionIteratorLimited<MemorySectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/mod.rs b/third_party/rust/wasmparser-0.48.2/src/readers/mod.rs new file mode 100644 index 0000000000..6eca50d9ff --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/mod.rs @@ -0,0 +1,100 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, BinaryReaderError, CustomSectionKind, ExternalKind, FuncType, GlobalType, + ImportSectionEntryType, LinkingType, MemoryType, NameType, Naming, Operator, Range, RelocType, + Result, SectionCode, TableType, Type, +}; + +use super::SectionHeader; + +pub use self::code_section::CodeSectionReader; +pub use self::code_section::FunctionBody; +pub use self::code_section::LocalsReader; +use self::data_count_section::read_data_count_section_content; +pub use self::data_section::Data; +pub use self::data_section::DataKind; +pub use self::data_section::DataSectionReader; +pub use self::element_section::Element; +pub use self::element_section::ElementItem; +pub use self::element_section::ElementItems; +pub use self::element_section::ElementItemsReader; +pub use self::element_section::ElementKind; +pub use self::element_section::ElementSectionReader; +pub use self::export_section::Export; +pub use self::export_section::ExportSectionReader; +pub use self::function_section::FunctionSectionReader; +pub use self::global_section::Global; +pub use self::global_section::GlobalSectionReader; +pub use self::import_section::Import; +pub use self::import_section::ImportSectionReader; +pub use self::init_expr::InitExpr; +pub use self::memory_section::MemorySectionReader; +pub use self::module::CustomSectionContent; +pub use self::module::ModuleReader; +pub use self::module::Section; +pub use self::module::SectionContent; +use self::start_section::read_start_section_content; +pub use self::table_section::TableSectionReader; +pub use self::type_section::TypeSectionReader; + +pub use self::section_reader::SectionIterator; +pub use self::section_reader::SectionIteratorLimited; +pub use self::section_reader::SectionReader; +pub use self::section_reader::SectionWithLimitedItems; + +pub use self::name_section::FunctionName; +pub use self::name_section::LocalName; +pub use self::name_section::ModuleName; +pub use self::name_section::Name; +pub use self::name_section::NameSectionReader; +pub use self::name_section::NamingReader; + +pub use self::producers_section::ProducersField; +pub use self::producers_section::ProducersFieldValue; +pub use self::producers_section::ProducersFieldValuesReader; +pub use self::producers_section::ProducersSectionReader; + +pub use self::linking_section::LinkingSectionReader; + +pub use self::reloc_section::Reloc; +pub use self::reloc_section::RelocSectionReader; + +use self::sourcemappingurl_section::read_sourcemappingurl_section_content; + +pub use self::operators::OperatorsReader; + +mod code_section; +mod data_count_section; +mod data_section; +mod element_section; +mod export_section; +mod function_section; +mod global_section; +mod import_section; +mod init_expr; +mod linking_section; +mod memory_section; +mod module; +mod name_section; +mod operators; +mod producers_section; +mod reloc_section; +mod section_reader; +mod sourcemappingurl_section; +mod start_section; +mod table_section; +mod type_section; diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/module.rs b/third_party/rust/wasmparser-0.48.2/src/readers/module.rs new file mode 100644 index 0000000000..2eb63d61e5 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/module.rs @@ -0,0 +1,512 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, BinaryReaderError, CustomSectionKind, Range, Result, SectionCode, SectionHeader, +}; + +use super::{ + read_data_count_section_content, read_sourcemappingurl_section_content, + read_start_section_content, CodeSectionReader, DataSectionReader, ElementSectionReader, + ExportSectionReader, FunctionSectionReader, GlobalSectionReader, ImportSectionReader, + LinkingSectionReader, MemorySectionReader, NameSectionReader, ProducersSectionReader, + RelocSectionReader, TableSectionReader, TypeSectionReader, +}; + +#[derive(Debug)] +pub struct Section<'a> { + pub code: SectionCode<'a>, + offset: usize, + data: &'a [u8], +} + +impl<'a> Section<'a> { + /// Creates reader for the type section. Available when the reader just read + /// the type section. + pub fn get_type_section_reader<'b>(&self) -> Result<TypeSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Type => TypeSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_type_section_reader"), + } + } + + /// Creates reader for the function section. Available when the reader just read + /// the function section. + pub fn get_function_section_reader<'b>(&self) -> Result<FunctionSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Function => FunctionSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_function_section_reader"), + } + } + + /// Creates reader for the code section. Available when the reader just read + /// the code section. + pub fn get_code_section_reader<'b>(&self) -> Result<CodeSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Code => CodeSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_function_section_reader"), + } + } + + /// Creates reader for the export section. Available when the reader just read + /// the export section. + pub fn get_export_section_reader<'b>(&self) -> Result<ExportSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Export => ExportSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_export_section_reader"), + } + } + + /// Creates reader for the import section. Available when the reader just read + /// the import section. + pub fn get_import_section_reader<'b>(&self) -> Result<ImportSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Import => ImportSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_import_section_reader"), + } + } + + /// Creates reader for the global section. Available when the reader just read + /// the global section. + pub fn get_global_section_reader<'b>(&self) -> Result<GlobalSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Global => GlobalSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_global_section_reader"), + } + } + + /// Creates reader for the memory section. Available when the reader just read + /// the memory section. + pub fn get_memory_section_reader<'b>(&self) -> Result<MemorySectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Memory => MemorySectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_memory_section_reader"), + } + } + + /// Creates reader for the data section. Available when the reader just read + /// the data section. + pub fn get_data_section_reader<'b>(&self) -> Result<DataSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Data => DataSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_data_section_reader"), + } + } + + /// Creates reader for the table section. Available when the reader just read + /// the table section. + pub fn get_table_section_reader<'b>(&self) -> Result<TableSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Table => TableSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_table_section_reader"), + } + } + + /// Creates reader for the element section. Available when the reader just read + /// the element section. + pub fn get_element_section_reader<'b>(&self) -> Result<ElementSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Element => ElementSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_element_section_reader"), + } + } + + pub fn get_name_section_reader<'b>(&self) -> Result<NameSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Custom { + kind: CustomSectionKind::Name, + .. + } => NameSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_name_section_reader"), + } + } + + pub fn get_producers_section_reader<'b>(&self) -> Result<ProducersSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Custom { + kind: CustomSectionKind::Producers, + .. + } => ProducersSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_producers_section_reader"), + } + } + + pub fn get_linking_section_reader<'b>(&self) -> Result<LinkingSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Custom { + kind: CustomSectionKind::Linking, + .. + } => LinkingSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_linking_section_reader"), + } + } + + pub fn get_reloc_section_reader<'b>(&self) -> Result<RelocSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Custom { + kind: CustomSectionKind::Reloc, + .. + } => RelocSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_reloc_section_reader"), + } + } + + pub fn get_start_section_content(&self) -> Result<u32> { + match self.code { + SectionCode::Start => read_start_section_content(self.data, self.offset), + _ => panic!("Invalid state for get_start_section_content"), + } + } + + pub fn get_data_count_section_content(&self) -> Result<u32> { + match self.code { + SectionCode::DataCount => read_data_count_section_content(self.data, self.offset), + _ => panic!("Invalid state for get_data_count_section_content"), + } + } + + pub fn get_sourcemappingurl_section_content<'b>(&self) -> Result<&'b str> + where + 'a: 'b, + { + match self.code { + SectionCode::Custom { + kind: CustomSectionKind::SourceMappingURL, + .. + } => read_sourcemappingurl_section_content(self.data, self.offset), + _ => panic!("Invalid state for get_start_section_content"), + } + } + + pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b> + where + 'a: 'b, + { + BinaryReader::new_with_offset(self.data, self.offset) + } + + pub fn range(&self) -> Range { + Range { + start: self.offset, + end: self.offset + self.data.len(), + } + } + + pub fn content<'b>(&self) -> Result<SectionContent<'b>> + where + 'a: 'b, + { + let c = match self.code { + SectionCode::Type => SectionContent::Type(self.get_type_section_reader()?), + SectionCode::Function => SectionContent::Function(self.get_function_section_reader()?), + SectionCode::Code => SectionContent::Code(self.get_code_section_reader()?), + SectionCode::Export => SectionContent::Export(self.get_export_section_reader()?), + SectionCode::Import => SectionContent::Import(self.get_import_section_reader()?), + SectionCode::Global => SectionContent::Global(self.get_global_section_reader()?), + SectionCode::Memory => SectionContent::Memory(self.get_memory_section_reader()?), + SectionCode::Data => SectionContent::Data(self.get_data_section_reader()?), + SectionCode::Table => SectionContent::Table(self.get_table_section_reader()?), + SectionCode::Element => SectionContent::Element(self.get_element_section_reader()?), + SectionCode::Start => SectionContent::Start(self.get_start_section_content()?), + SectionCode::DataCount => { + SectionContent::DataCount(self.get_data_count_section_content()?) + } + SectionCode::Custom { kind, name } => { + // The invalid custom section may cause trouble during + // content() call. The spec recommends to ignore erroneous + // content in custom section. + // Return None in the content field if invalid. + let binary = self.get_binary_reader(); + let content = match kind { + CustomSectionKind::Name => self + .get_name_section_reader() + .ok() + .map(CustomSectionContent::Name), + CustomSectionKind::Producers => self + .get_producers_section_reader() + .ok() + .map(CustomSectionContent::Producers), + CustomSectionKind::Linking => self + .get_linking_section_reader() + .ok() + .map(CustomSectionContent::Linking), + CustomSectionKind::Reloc => self + .get_reloc_section_reader() + .ok() + .map(CustomSectionContent::Reloc), + CustomSectionKind::SourceMappingURL => self + .get_sourcemappingurl_section_content() + .ok() + .map(CustomSectionContent::SourceMappingURL), + _ => None, + }; + SectionContent::Custom { + name, + binary, + content, + } + } + }; + Ok(c) + } +} + +pub enum SectionContent<'a> { + Type(TypeSectionReader<'a>), + Function(FunctionSectionReader<'a>), + Code(CodeSectionReader<'a>), + Export(ExportSectionReader<'a>), + Import(ImportSectionReader<'a>), + Global(GlobalSectionReader<'a>), + Memory(MemorySectionReader<'a>), + Data(DataSectionReader<'a>), + Table(TableSectionReader<'a>), + Element(ElementSectionReader<'a>), + Start(u32), + DataCount(u32), + Custom { + name: &'a str, + binary: BinaryReader<'a>, + content: Option<CustomSectionContent<'a>>, + }, +} + +pub enum CustomSectionContent<'a> { + Name(NameSectionReader<'a>), + Producers(ProducersSectionReader<'a>), + Linking(LinkingSectionReader<'a>), + Reloc(RelocSectionReader<'a>), + SourceMappingURL(&'a str), +} + +/// Reads top-level WebAssembly file structure: header and sections. +pub struct ModuleReader<'a> { + reader: BinaryReader<'a>, + version: u32, + read_ahead: Option<(usize, SectionHeader<'a>)>, +} + +impl<'a> ModuleReader<'a> { + pub fn new(data: &[u8]) -> Result<ModuleReader> { + let mut reader = BinaryReader::new(data); + let version = reader.read_file_header()?; + Ok(ModuleReader { + reader, + version, + read_ahead: None, + }) + } + + pub fn get_version(&self) -> u32 { + self.version + } + + pub fn current_position(&self) -> usize { + match self.read_ahead { + Some((position, _)) => position, + _ => self.reader.current_position(), + } + } + + pub fn eof(&self) -> bool { + self.read_ahead.is_none() && self.reader.eof() + } + + fn verify_section_end(&self, end: usize) -> Result<()> { + if self.reader.buffer.len() < end { + return Err(BinaryReaderError { + message: "Section body extends past end of file", + offset: self.reader.buffer.len(), + }); + } + if self.reader.position > end { + return Err(BinaryReaderError { + message: "Section header is too big to fit into section body", + offset: end, + }); + } + Ok(()) + } + + /// Reads next top-level record from the WebAssembly binary data. + /// The methods returns reference to current state of the reader. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("reader"); + /// let section = reader.read().expect("section #1"); + /// println!("First section {:?}", section); + /// let section = reader.read().expect("section #2"); + /// println!("Second section {:?}", section); + /// assert!(!reader.eof(), "there are more sections"); + /// ``` + pub fn read<'b>(&mut self) -> Result<Section<'b>> + where + 'a: 'b, + { + let SectionHeader { + code, + payload_start, + payload_len, + } = match self.read_ahead.take() { + Some((_, section_header)) => section_header, + None => self.reader.read_section_header()?, + }; + let payload_end = payload_start + payload_len; + self.verify_section_end(payload_end)?; + let body_start = self.reader.position; + self.reader.skip_to(payload_end); + Ok(Section { + code, + offset: body_start, + data: &self.reader.buffer[body_start..payload_end], + }) + } + + fn ensure_read_ahead(&mut self) -> Result<()> { + if self.read_ahead.is_none() && !self.eof() { + let position = self.reader.current_position(); + self.read_ahead = Some((position, self.reader.read_section_header()?)); + } + Ok(()) + } + + /// Skips custom sections. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x00, 0x8, 0x03, 0x63, 0x61, 0x74, 0x01, 0x02, 0x03, 0x04, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// use wasmparser::SectionCode; + /// let mut reader = ModuleReader::new(data).expect("reader"); + /// while { reader.skip_custom_sections(); !reader.eof() } { + /// let section = reader.read().expect("section"); + /// if let SectionCode::Custom {..} = section.code { panic!("no custom"); } + /// println!("Section {:?}", section); + /// } + /// ``` + pub fn skip_custom_sections(&mut self) -> Result<()> { + loop { + self.ensure_read_ahead()?; + match self.read_ahead { + Some(( + _, + SectionHeader { + code: SectionCode::Custom { .. }, + payload_start, + payload_len, + }, + )) => { + self.verify_section_end(payload_start + payload_len)?; + // Skip section + self.read_ahead = None; + self.reader.skip_to(payload_start + payload_len); + } + _ => break, + }; + } + Ok(()) + } +} + +impl<'a> IntoIterator for ModuleReader<'a> { + type Item = Result<Section<'a>>; + type IntoIter = ModuleIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + ModuleIterator { + reader: self, + err: false, + } + } +} + +pub struct ModuleIterator<'a> { + reader: ModuleReader<'a>, + err: bool, +} + +impl<'a> Iterator for ModuleIterator<'a> { + type Item = Result<Section<'a>>; + + /// Iterates sections from the WebAssembly binary data. Stops at first error. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// for section in ModuleReader::new(data).expect("reader") { + /// println!("Section {:?}", section); + /// } + /// ``` + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.reader.eof() { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + Some(result) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/name_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/name_section.rs new file mode 100644 index 0000000000..f657c69fc7 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/name_section.rs @@ -0,0 +1,233 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, BinaryReaderError, NameType, Naming, Result, SectionIterator, SectionReader, +}; + +#[derive(Debug, Copy, Clone)] +pub struct ModuleName<'a> { + data: &'a [u8], + offset: usize, +} + +impl<'a> ModuleName<'a> { + pub fn get_name<'b>(&self) -> Result<&'b str> + where + 'a: 'b, + { + let mut reader = BinaryReader::new_with_offset(self.data, self.offset); + reader.read_string() + } +} + +pub struct NamingReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> NamingReader<'a> { + fn new(data: &'a [u8], offset: usize) -> Result<NamingReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(NamingReader { reader, count }) + } + + fn skip(reader: &mut BinaryReader) -> Result<()> { + let count = reader.read_var_u32()?; + for _ in 0..count { + reader.skip_var_32()?; + reader.skip_string()?; + } + Ok(()) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn read<'b>(&mut self) -> Result<Naming<'b>> + where + 'a: 'b, + { + let index = self.reader.read_var_u32()?; + let name = self.reader.read_string()?; + Ok(Naming { index, name }) + } +} + +#[derive(Debug, Copy, Clone)] +pub struct FunctionName<'a> { + data: &'a [u8], + offset: usize, +} + +impl<'a> FunctionName<'a> { + pub fn get_map<'b>(&self) -> Result<NamingReader<'b>> + where + 'a: 'b, + { + NamingReader::new(self.data, self.offset) + } +} + +#[derive(Debug, Copy, Clone)] +pub struct FunctionLocalName<'a> { + pub func_index: u32, + data: &'a [u8], + offset: usize, +} + +impl<'a> FunctionLocalName<'a> { + pub fn get_map<'b>(&self) -> Result<NamingReader<'b>> + where + 'a: 'b, + { + NamingReader::new(self.data, self.offset) + } +} + +pub struct FunctionLocalReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> FunctionLocalReader<'a> { + fn new(data: &'a [u8], offset: usize) -> Result<FunctionLocalReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(FunctionLocalReader { reader, count }) + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn read<'b>(&mut self) -> Result<FunctionLocalName<'b>> + where + 'a: 'b, + { + let func_index = self.reader.read_var_u32()?; + let start = self.reader.position; + NamingReader::skip(&mut self.reader)?; + let end = self.reader.position; + Ok(FunctionLocalName { + func_index, + data: &self.reader.buffer[start..end], + offset: self.reader.original_offset + start, + }) + } +} + +#[derive(Debug, Copy, Clone)] +pub struct LocalName<'a> { + data: &'a [u8], + offset: usize, +} + +impl<'a> LocalName<'a> { + pub fn get_function_local_reader<'b>(&self) -> Result<FunctionLocalReader<'b>> + where + 'a: 'b, + { + FunctionLocalReader::new(self.data, self.offset) + } +} + +#[derive(Debug, Copy, Clone)] +pub enum Name<'a> { + Module(ModuleName<'a>), + Function(FunctionName<'a>), + Local(LocalName<'a>), +} + +pub struct NameSectionReader<'a> { + reader: BinaryReader<'a>, +} + +impl<'a> NameSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<NameSectionReader<'a>> { + Ok(NameSectionReader { + reader: BinaryReader::new_with_offset(data, offset), + }) + } + + fn verify_section_end(&self, end: usize) -> Result<()> { + if self.reader.buffer.len() < end { + return Err(BinaryReaderError { + message: "Name entry extends past end of the code section", + offset: self.reader.original_offset + self.reader.buffer.len(), + }); + } + Ok(()) + } + + pub fn eof(&self) -> bool { + self.reader.eof() + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn read<'b>(&mut self) -> Result<Name<'b>> + where + 'a: 'b, + { + let ty = self.reader.read_name_type()?; + let payload_len = self.reader.read_var_u32()? as usize; + let payload_start = self.reader.position; + let payload_end = payload_start + payload_len; + self.verify_section_end(payload_end)?; + let offset = self.reader.original_offset + payload_start; + let data = &self.reader.buffer[payload_start..payload_end]; + self.reader.skip_to(payload_end); + Ok(match ty { + NameType::Module => Name::Module(ModuleName { data, offset }), + NameType::Function => Name::Function(FunctionName { data, offset }), + NameType::Local => Name::Local(LocalName { data, offset }), + }) + } +} + +impl<'a> SectionReader for NameSectionReader<'a> { + type Item = Name<'a>; + fn read(&mut self) -> Result<Self::Item> { + NameSectionReader::read(self) + } + fn eof(&self) -> bool { + NameSectionReader::eof(self) + } + fn original_position(&self) -> usize { + NameSectionReader::original_position(self) + } +} + +impl<'a> IntoIterator for NameSectionReader<'a> { + type Item = Result<Name<'a>>; + type IntoIter = SectionIterator<NameSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIterator::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/operators.rs b/third_party/rust/wasmparser-0.48.2/src/readers/operators.rs new file mode 100644 index 0000000000..0ecac8d5fb --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/operators.rs @@ -0,0 +1,171 @@ +/* Copyright 2018 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. + */ + +use super::{BinaryReader, BinaryReaderError, Operator, Result}; + +#[derive(Clone)] +pub struct OperatorsReader<'a> { + pub(crate) reader: BinaryReader<'a>, +} + +impl<'a> OperatorsReader<'a> { + pub(crate) fn new<'b>(data: &'a [u8], offset: usize) -> OperatorsReader<'b> + where + 'a: 'b, + { + OperatorsReader { + reader: BinaryReader::new_with_offset(data, offset), + } + } + + pub fn eof(&self) -> bool { + self.reader.eof() + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn ensure_end(&self) -> Result<()> { + if self.eof() { + return Ok(()); + } + Err(BinaryReaderError { + message: "Unexpected data at the end of operators", + offset: self.reader.original_position(), + }) + } + + pub fn read<'b>(&mut self) -> Result<Operator<'b>> + where + 'a: 'b, + { + self.reader.read_operator() + } + + pub fn into_iter_with_offsets<'b>(self) -> OperatorsIteratorWithOffsets<'b> + where + 'a: 'b, + { + OperatorsIteratorWithOffsets { + reader: self, + err: false, + } + } + + pub fn read_with_offset<'b>(&mut self) -> Result<(Operator<'b>, usize)> + where + 'a: 'b, + { + let pos = self.reader.original_position(); + Ok((self.read()?, pos)) + } +} + +impl<'a> IntoIterator for OperatorsReader<'a> { + type Item = Result<Operator<'a>>; + type IntoIter = OperatorsIterator<'a>; + + /// Reads content of the code section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::{ModuleReader, Result, Operator}; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("code section"); + /// let mut code_reader = section.get_code_section_reader().expect("code section reader"); + /// for _ in 0..code_reader.get_count() { + /// let body = code_reader.read().expect("function body"); + /// let mut op_reader = body.get_operators_reader().expect("op reader"); + /// let ops = op_reader.into_iter().collect::<Result<Vec<Operator>>>().expect("ops"); + /// assert!( + /// if let [Operator::Nop, Operator::End] = ops.as_slice() { true } else { false }, + /// "found {:?}", + /// ops + /// ); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + OperatorsIterator { + reader: self, + err: false, + } + } +} + +pub struct OperatorsIterator<'a> { + reader: OperatorsReader<'a>, + err: bool, +} + +impl<'a> Iterator for OperatorsIterator<'a> { + type Item = Result<Operator<'a>>; + + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.reader.eof() { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + Some(result) + } +} + +pub struct OperatorsIteratorWithOffsets<'a> { + reader: OperatorsReader<'a>, + err: bool, +} + +impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> { + type Item = Result<(Operator<'a>, usize)>; + + /// Reads content of the code section with offsets. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, /* offset = 23 */ 0x01, 0x0b]; + /// use wasmparser::{ModuleReader, Result, Operator}; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("code section"); + /// let mut code_reader = section.get_code_section_reader().expect("code section reader"); + /// for _ in 0..code_reader.get_count() { + /// let body = code_reader.read().expect("function body"); + /// let mut op_reader = body.get_operators_reader().expect("op reader"); + /// let ops = op_reader.into_iter_with_offsets().collect::<Result<Vec<(Operator, usize)>>>().expect("ops"); + /// assert!( + /// if let [(Operator::Nop, 23), (Operator::End, 24)] = ops.as_slice() { true } else { false }, + /// "found {:?}", + /// ops + /// ); + /// } + /// ``` + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.reader.eof() { + return None; + } + let result = self.reader.read_with_offset(); + self.err = result.is_err(); + Some(result) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/producers_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/producers_section.rs new file mode 100644 index 0000000000..a65769c1d9 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/producers_section.rs @@ -0,0 +1,192 @@ +/* Copyright 2019 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. + */ + +use super::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; + +#[derive(Debug, Copy, Clone)] +pub struct ProducersFieldValue<'a> { + pub name: &'a str, + pub version: &'a str, +} + +pub struct ProducersFieldValuesReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ProducersFieldValuesReader<'a> { + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + fn skip(reader: &mut BinaryReader, values_count: u32) -> Result<()> { + for _ in 0..values_count { + reader.skip_string()?; + reader.skip_string()?; + } + Ok(()) + } + + pub fn read<'b>(&mut self) -> Result<ProducersFieldValue<'b>> + where + 'a: 'b, + { + let name = self.reader.read_string()?; + let version = self.reader.read_string()?; + Ok(ProducersFieldValue { name, version }) + } +} + +impl<'a> IntoIterator for ProducersFieldValuesReader<'a> { + type Item = Result<ProducersFieldValue<'a>>; + type IntoIter = ProducersFieldValuesIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + let count = self.count; + ProducersFieldValuesIterator { + reader: self, + left: count, + err: false, + } + } +} + +pub struct ProducersFieldValuesIterator<'a> { + reader: ProducersFieldValuesReader<'a>, + left: u32, + err: bool, +} + +impl<'a> Iterator for ProducersFieldValuesIterator<'a> { + type Item = Result<ProducersFieldValue<'a>>; + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.left == 0 { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + self.left -= 1; + Some(result) + } + fn size_hint(&self) -> (usize, Option<usize>) { + let count = self.reader.get_count() as usize; + (count, Some(count)) + } +} + +#[derive(Debug, Copy, Clone)] +pub struct ProducersField<'a> { + pub name: &'a str, + values_count: u32, + values_data: &'a [u8], + values_offset: usize, +} + +impl<'a> ProducersField<'a> { + pub fn get_producer_field_values_reader<'b>(&self) -> Result<ProducersFieldValuesReader<'b>> + where + 'a: 'b, + { + Ok(ProducersFieldValuesReader { + reader: BinaryReader::new_with_offset(self.values_data, self.values_offset), + count: self.values_count, + }) + } +} + +pub struct ProducersSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ProducersSectionReader<'a> { + /// Creates reader for the producers section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x01, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, + /// # 0x02, 0x03, 0x77, 0x61, 0x74, 0x01, 0x31, 0x01, 0x43, 0x03, 0x39, 0x2e, 0x30]; + /// use wasmparser::{ProducersSectionReader, ProducersFieldValue, Result}; + /// let mut reader = ProducersSectionReader::new(data, 0).expect("producers reader"); + /// let field = reader.read().expect("producers field"); + /// assert!(field.name == "language"); + /// let mut values_reader = field.get_producer_field_values_reader().expect("values reader"); + /// let value = values_reader.into_iter().collect::<Result<Vec<ProducersFieldValue>>>().expect("values"); + /// assert!(value.len() == 2); + /// assert!(value[0].name == "wat" && value[0].version == "1"); + /// assert!(value[1].name == "C" && value[1].version == "9.0"); + /// ``` + pub fn new(data: &'a [u8], offset: usize) -> Result<ProducersSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ProducersSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn read<'b>(&mut self) -> Result<ProducersField<'b>> + where + 'a: 'b, + { + let name = self.reader.read_string()?; + let values_count = self.reader.read_var_u32()?; + let values_start = self.reader.position; + ProducersFieldValuesReader::skip(&mut self.reader, values_count)?; + let values_end = self.reader.position; + Ok(ProducersField { + name, + values_count, + values_data: &self.reader.buffer[values_start..values_end], + values_offset: self.reader.original_offset + values_start, + }) + } +} + +impl<'a> SectionReader for ProducersSectionReader<'a> { + type Item = ProducersField<'a>; + fn read(&mut self) -> Result<Self::Item> { + ProducersSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + ProducersSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for ProducersSectionReader<'a> { + fn get_count(&self) -> u32 { + ProducersSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for ProducersSectionReader<'a> { + type Item = Result<ProducersField<'a>>; + type IntoIter = SectionIteratorLimited<ProducersSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/reloc_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/reloc_section.rs new file mode 100644 index 0000000000..2758294cb0 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/reloc_section.rs @@ -0,0 +1,115 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, RelocType, Result, SectionCode, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Reloc { + pub ty: RelocType, + pub offset: u32, + pub index: u32, + pub addend: Option<u32>, +} + +pub struct RelocSectionReader<'a> { + reader: BinaryReader<'a>, + section_code: SectionCode<'a>, + count: u32, +} + +impl<'a> RelocSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<RelocSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + + let section_id_position = reader.position; + let section_id = reader.read_var_u7()?; + let section_code = reader.read_section_code(section_id, section_id_position)?; + + let count = reader.read_var_u32()?; + Ok(RelocSectionReader { + reader, + section_code, + count, + }) + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn get_section_code<'b>(&self) -> SectionCode<'b> + where + 'a: 'b, + { + self.section_code + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn read(&mut self) -> Result<Reloc> { + let ty = self.reader.read_reloc_type()?; + let offset = self.reader.read_var_u32()?; + let index = self.reader.read_var_u32()?; + let addend = match ty { + RelocType::FunctionIndexLEB + | RelocType::TableIndexSLEB + | RelocType::TableIndexI32 + | RelocType::TypeIndexLEB + | RelocType::GlobalIndexLEB => None, + RelocType::GlobalAddrLEB | RelocType::GlobalAddrSLEB | RelocType::GlobalAddrI32 => { + Some(self.reader.read_var_u32()?) + } + }; + Ok(Reloc { + ty, + offset, + index, + addend, + }) + } +} + +impl<'a> SectionReader for RelocSectionReader<'a> { + type Item = Reloc; + fn read(&mut self) -> Result<Self::Item> { + RelocSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + RelocSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for RelocSectionReader<'a> { + fn get_count(&self) -> u32 { + RelocSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for RelocSectionReader<'a> { + type Item = Result<Reloc>; + type IntoIter = SectionIteratorLimited<RelocSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/section_reader.rs b/third_party/rust/wasmparser-0.48.2/src/readers/section_reader.rs new file mode 100644 index 0000000000..6ec9cd791d --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/section_reader.rs @@ -0,0 +1,123 @@ +/* Copyright 2018 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. + */ + +use super::{BinaryReaderError, Result}; + +pub trait SectionReader { + type Item; + fn read(&mut self) -> Result<Self::Item>; + fn eof(&self) -> bool; + fn original_position(&self) -> usize; + fn ensure_end(&self) -> Result<()> { + if self.eof() { + return Ok(()); + } + Err(BinaryReaderError { + message: "Unexpected data at the end of the section", + offset: self.original_position(), + }) + } +} + +pub trait SectionWithLimitedItems { + fn get_count(&self) -> u32; +} + +pub struct SectionIterator<R> +where + R: SectionReader, +{ + reader: R, + err: bool, +} + +impl<R> SectionIterator<R> +where + R: SectionReader, +{ + pub fn new(reader: R) -> SectionIterator<R> { + SectionIterator { reader, err: false } + } +} + +impl<R> Iterator for SectionIterator<R> +where + R: SectionReader, +{ + type Item = Result<R::Item>; + + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.reader.eof() { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + Some(result) + } +} + +pub struct SectionIteratorLimited<R> +where + R: SectionReader + SectionWithLimitedItems, +{ + reader: R, + left: u32, + end: bool, +} + +impl<R> SectionIteratorLimited<R> +where + R: SectionReader + SectionWithLimitedItems, +{ + pub fn new(reader: R) -> SectionIteratorLimited<R> { + let left = reader.get_count(); + SectionIteratorLimited { + reader, + left, + end: false, + } + } +} + +impl<R> Iterator for SectionIteratorLimited<R> +where + R: SectionReader + SectionWithLimitedItems, +{ + type Item = Result<R::Item>; + + fn next(&mut self) -> Option<Self::Item> { + if self.end { + return None; + } + if self.left == 0 { + return match self.reader.ensure_end() { + Ok(()) => None, + Err(err) => { + self.end = true; + Some(Err(err)) + } + }; + } + let result = self.reader.read(); + self.end = result.is_err(); + self.left -= 1; + Some(result) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + let count = self.reader.get_count() as usize; + (count, Some(count)) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/sourcemappingurl_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/sourcemappingurl_section.rs new file mode 100644 index 0000000000..6f6e5eef21 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/sourcemappingurl_section.rs @@ -0,0 +1,31 @@ +/* Copyright 2018 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. + */ + +use super::{BinaryReader, BinaryReaderError, Result}; + +pub(crate) fn read_sourcemappingurl_section_content<'a>( + data: &'a [u8], + offset: usize, +) -> Result<&'a str> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let url = reader.read_string()?; + if !reader.eof() { + return Err(BinaryReaderError { + message: "Unexpected content in the sourceMappingURL section", + offset: offset + reader.position, + }); + } + Ok(url) +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/start_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/start_section.rs new file mode 100644 index 0000000000..81da40b58f --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/start_section.rs @@ -0,0 +1,28 @@ +/* Copyright 2018 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. + */ + +use super::{BinaryReader, BinaryReaderError, Result}; + +pub(crate) fn read_start_section_content(data: &[u8], offset: usize) -> Result<u32> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let start_index = reader.read_var_u32()?; + if !reader.eof() { + return Err(BinaryReaderError { + message: "Unexpected content in the start section", + offset: offset + reader.position, + }); + } + Ok(start_index) +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/table_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/table_section.rs new file mode 100644 index 0000000000..322e23656f --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/table_section.rs @@ -0,0 +1,90 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, TableType, +}; + +pub struct TableSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> TableSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<TableSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(TableSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the table section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x04, 0x05, 0x01, 0x70, 0x01, 0x01, 0x01, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("table section"); + /// let mut table_reader = section.get_table_section_reader().expect("table section reader"); + /// for _ in 0..table_reader.get_count() { + /// let table = table_reader.read().expect("table"); + /// println!("Table: {:?}", table); + /// } + /// ``` + pub fn read(&mut self) -> Result<TableType> { + self.reader.read_table_type() + } +} + +impl<'a> SectionReader for TableSectionReader<'a> { + type Item = TableType; + fn read(&mut self) -> Result<Self::Item> { + TableSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + TableSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for TableSectionReader<'a> { + fn get_count(&self) -> u32 { + TableSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for TableSectionReader<'a> { + type Item = Result<TableType>; + type IntoIter = SectionIteratorLimited<TableSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/type_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/type_section.rs new file mode 100644 index 0000000000..51fd6eea36 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/type_section.rs @@ -0,0 +1,103 @@ +/* Copyright 2018 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. + */ + +use super::{ + BinaryReader, FuncType, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, +}; + +pub struct TypeSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> TypeSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<TypeSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(TypeSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the type section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("section"); + /// let mut type_reader = section.get_type_section_reader().expect("type section reader"); + /// for _ in 0..type_reader.get_count() { + /// let ty = type_reader.read().expect("type"); + /// println!("Type {:?}", ty); + /// } + /// ``` + pub fn read(&mut self) -> Result<FuncType> { + self.reader.read_func_type() + } +} + +impl<'a> SectionReader for TypeSectionReader<'a> { + type Item = FuncType; + fn read(&mut self) -> Result<Self::Item> { + TypeSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + TypeSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for TypeSectionReader<'a> { + fn get_count(&self) -> u32 { + TypeSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for TypeSectionReader<'a> { + type Item = Result<FuncType>; + type IntoIter = SectionIteratorLimited<TypeSectionReader<'a>>; + + /// Implements iterator over the type section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// use wasmparser::{Result, FuncType}; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("section"); + /// let mut type_reader = section.get_type_section_reader().expect("type section reader"); + /// for ty in type_reader { + /// println!("Type {:?}", ty); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/tests.rs b/third_party/rust/wasmparser-0.48.2/src/tests.rs new file mode 100644 index 0000000000..527ace1993 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/tests.rs @@ -0,0 +1,529 @@ +/* Copyright 2017 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. + */ + +#[cfg(test)] +mod simple_tests { + use crate::operators_validator::OperatorValidatorConfig; + use crate::parser::{Parser, ParserInput, ParserState, WasmDecoder}; + use crate::primitives::{Operator, SectionCode}; + use crate::validator::{ValidatingParser, ValidatingParserConfig}; + use std::fs::{read_dir, File}; + use std::io::prelude::*; + use std::path::PathBuf; + + const VALIDATOR_CONFIG: Option<ValidatingParserConfig> = Some(ValidatingParserConfig { + operator_config: OperatorValidatorConfig { + enable_threads: true, + enable_reference_types: true, + enable_simd: true, + enable_bulk_memory: true, + enable_multi_value: true, + + #[cfg(feature = "deterministic")] + deterministic_only: true, + }, + }); + + fn read_file_data(path: &PathBuf) -> Vec<u8> { + println!("Parsing {:?}", path); + let mut data = Vec::new(); + let mut f = File::open(path).ok().unwrap(); + f.read_to_end(&mut data).unwrap(); + data + } + + #[allow(dead_code)] + fn scan_tests_files(prefix: &str) -> Vec<PathBuf> { + let mut files = Vec::new(); + + for entry in read_dir("tests/").unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() { + continue; + } + + let path = dir.path(); + let file = path.to_str().unwrap(); + + if file.starts_with(prefix) { + files.push(path); + } + } + + return files; + } + + #[test] + fn it_works() { + for entry in read_dir("tests").unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() { + continue; + } + let data = read_file_data(&dir.path()); + let mut parser = Parser::new(data.as_slice()); + let mut max_iteration = 100000000; + loop { + let state = parser.read(); + match *state { + ParserState::EndWasm => break, + ParserState::Error(err) => panic!("Error: {:?}", err), + _ => (), + } + max_iteration -= 1; + if max_iteration == 0 { + panic!("Max iterations exceeded"); + } + } + } + } + + #[test] + fn validator_not_fails() { + for entry in read_dir("tests").unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() { + continue; + } + let data = read_file_data(&dir.path()); + let mut parser = ValidatingParser::new(data.as_slice(), VALIDATOR_CONFIG); + let mut max_iteration = 100000000; + loop { + let state = parser.read(); + match *state { + ParserState::EndWasm => break, + ParserState::Error(err) => panic!("Error: {:?}", err), + _ => (), + } + max_iteration -= 1; + if max_iteration == 0 { + panic!("Max iterations exceeded"); + } + } + } + } + + #[test] + fn validator_fails() { + for entry in read_dir("tests/invalid").unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() { + continue; + } + let data = read_file_data(&dir.path()); + let mut parser = ValidatingParser::new(data.as_slice(), VALIDATOR_CONFIG); + let mut max_iteration = 100000000; + let mut error = false; + loop { + let state = parser.read(); + if let ParserState::Error(_) = *state { + error = true; + break; + } + if let ParserState::EndWasm = *state { + break; + } + max_iteration -= 1; + if max_iteration == 0 { + panic!("Max iterations exceeded"); + } + } + if !error { + panic!("fail is expected"); + } + } + } + + macro_rules! expect_state { + ($state:expr, $expected:pat) => {{ + { + let state: &ParserState = $state; + match *state { + $expected => (), + _ => panic!("Unexpected state during testing: {:?}", state), + } + } + }}; + } + + #[test] + fn default_read() { + let data = read_file_data(&PathBuf::from("tests/simple.wasm")); + let mut parser = Parser::new(data.as_slice()); + + expect_state!(parser.read(), ParserState::BeginWasm { .. }); + expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Type, .. }); + expect_state!(parser.read(), ParserState::TypeSectionEntry(_)); + expect_state!(parser.read(), ParserState::EndSection); + expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Function, .. }); + expect_state!(parser.read(), ParserState::FunctionSectionEntry(_)); + expect_state!(parser.read(), ParserState::EndSection); + expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Code, .. }); + expect_state!(parser.read(), ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read(), ParserState::FunctionBodyLocals { .. }); + expect_state!(parser.read(), ParserState::CodeOperator(_)); + expect_state!(parser.read(), ParserState::CodeOperator(Operator::End)); + expect_state!(parser.read(), ParserState::EndFunctionBody); + expect_state!(parser.read(), ParserState::EndSection); + expect_state!(parser.read(), ParserState::EndWasm); + } + + #[test] + fn default_read_with_input() { + let data = read_file_data(&PathBuf::from("tests/simple.wasm")); + let mut parser = Parser::new(data.as_slice()); + + expect_state!(parser.read(), ParserState::BeginWasm { .. }); + expect_state!(parser.read_with_input(ParserInput::Default), + ParserState::BeginSection { code: SectionCode::Type, .. }); + expect_state!(parser.read(), ParserState::TypeSectionEntry(_)); + expect_state!(parser.read(), ParserState::EndSection); + expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Function, ..}); + expect_state!( + parser.read_with_input(ParserInput::ReadSectionRawData), + ParserState::SectionRawData(_) + ); + expect_state!(parser.read(), ParserState::EndSection); + expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Code, .. }); + expect_state!(parser.read(), ParserState::BeginFunctionBody { .. }); + expect_state!( + parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::EndSection + ); + expect_state!(parser.read(), ParserState::EndWasm); + } + + #[test] + fn skipping() { + let data = read_file_data(&PathBuf::from("tests/naming.wasm")); + let mut parser = Parser::new(data.as_slice()); + + expect_state!(parser.read(), + ParserState::BeginWasm { .. }); + expect_state!(parser.read_with_input(ParserInput::Default), + ParserState::BeginSection { code: SectionCode::Type, .. }); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Import, ..}); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Function, ..}); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Global, ..}); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Export, ..}); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Element, ..}); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Code, .. }); + expect_state!(parser.read(), + ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::BeginFunctionBody { .. }); + expect_state!( + parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::EndSection + ); + expect_state!(parser.read(), + ParserState::BeginSection { code: SectionCode::Custom { .. }, ..}); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Custom { .. }, .. }); + expect_state!( + parser.read_with_input(ParserInput::SkipSection), + ParserState::EndWasm + ); + } + + #[cfg(feature = "deterministic")] + fn run_deterministic_enabled_test(path: &PathBuf) { + let data = read_file_data(path); + + let config = Some(ValidatingParserConfig { + operator_config: OperatorValidatorConfig { + deterministic_only: false, + enable_threads: true, + enable_reference_types: true, + enable_simd: true, + enable_bulk_memory: true, + enable_multi_value: true, + }, + }); + + let mut parser = ValidatingParser::new(data.as_slice(), config); + let mut error = false; + + loop { + let state = parser.read(); + if let ParserState::Error(_) = *state { + error = true; + break; + } + if let ParserState::EndWasm = *state { + break; + } + } + + assert!(error); + } + + #[cfg(feature = "deterministic")] + #[test] + fn deterministic_enabled() { + // `float_exprs.*.wasm` + let mut tests_count = 0; + for path in scan_tests_files("tests/float_exprs.") { + run_deterministic_enabled_test(&path); + tests_count += 1; + } + assert_eq!(96, tests_count); + + // `float_memory.*.wasm` + let mut tests_count = 0; + for path in scan_tests_files("tests/float_memory.") { + run_deterministic_enabled_test(&path); + tests_count += 1; + } + assert_eq!(6, tests_count); + + // `float_misc.*.wasm` + let mut tests_count = 0; + for path in scan_tests_files("tests/float_misc.") { + run_deterministic_enabled_test(&path); + tests_count += 1; + } + assert_eq!(1, tests_count); + } +} + +#[cfg(test)] +mod wast_tests { + use crate::operators_validator::OperatorValidatorConfig; + use crate::parser::{ParserState, WasmDecoder}; + use crate::validator::{ValidatingParser, ValidatingParserConfig}; + use crate::BinaryReaderError; + use std::fs::{read, read_dir}; + use std::str; + + const SPEC_TESTS_PATH: &str = "testsuite"; + + fn default_config() -> ValidatingParserConfig { + ValidatingParserConfig { + operator_config: OperatorValidatorConfig { + enable_threads: false, + enable_reference_types: false, + enable_simd: false, + enable_bulk_memory: false, + enable_multi_value: false, + + #[cfg(feature = "deterministic")] + deterministic_only: true, + }, + } + } + + fn validate_module( + mut module: wast::Module, + config: ValidatingParserConfig, + ) -> Result<(), BinaryReaderError> { + let data = module.encode().unwrap(); + let mut parser = ValidatingParser::new(data.as_slice(), Some(config)); + let mut max_iteration = 100000000; + loop { + let state = parser.read(); + match *state { + ParserState::EndWasm => break, + ParserState::Error(err) => return Err(err), + _ => (), + } + max_iteration -= 1; + if max_iteration == 0 { + panic!("Max iterations exceeded"); + } + } + Ok(()) + } + + fn run_wabt_scripts<F>( + filename: &str, + wast: &[u8], + config: ValidatingParserConfig, + skip_test: F, + ) where + F: Fn(&str, u64) -> bool, + { + println!("Parsing {:?}", filename); + // Check if we need to skip entire wast file test/parsing. + if skip_test(filename, /* line = */ 0) { + println!("{}: skipping", filename); + return; + } + + let contents = str::from_utf8(wast).unwrap(); + let buf = wast::parser::ParseBuffer::new(&contents) + .map_err(|mut e| { + e.set_path(filename.as_ref()); + e + }) + .unwrap(); + let wast = wast::parser::parse::<wast::Wast>(&buf) + .map_err(|mut e| { + e.set_path(filename.as_ref()); + e + }) + .unwrap(); + + for directive in wast.directives { + use wast::WastDirective::*; + let (line, _col) = directive.span().linecol_in(&contents); + let line = line + 1; + if skip_test(filename, line as u64) { + println!("{}:{}: skipping", filename, line); + continue; + } + match directive { + Module(module) | AssertUnlinkable { module, .. } => { + if let Err(err) = validate_module(module, config.clone()) { + panic!("{}:{}: invalid module: {}", filename, line, err.message); + } + } + AssertInvalid { module, .. } + | AssertMalformed { + module: wast::QuoteModule::Module(module), + .. + } => { + // TODO diffentiate between assert_invalid and assert_malformed + if let Ok(_) = validate_module(module, config.clone()) { + panic!( + "{}:{}: invalid module was successfully parsed", + filename, line + ); + } + // TODO: Check the assert_invalid or assert_malformed message + } + + AssertMalformed { + module: wast::QuoteModule::Quote(_), + .. + } + | Register { .. } + | Invoke { .. } + | AssertTrap { .. } + | AssertReturn { .. } + | AssertReturnFunc { .. } + | AssertExhaustion { .. } => {} + } + } + } + + fn run_proposal_tests<F>(name: &str, config: ValidatingParserConfig, skip_test: F) + where + F: Fn(&str, u64) -> bool, + { + let proposal_dir = format!("{}/proposals/{}", SPEC_TESTS_PATH, name); + for entry in read_dir(&proposal_dir).unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() + || dir.path().extension().map(|s| s.to_str().unwrap()) != Some("wast") + { + continue; + } + + let data = read(&dir.path()).expect("wast data"); + run_wabt_scripts( + dir.file_name().to_str().expect("name"), + &data, + config, + |name, line| skip_test(name, line), + ); + } + } + + #[test] + fn run_proposals_tests() { + run_proposal_tests( + "simd", + { + let mut config: ValidatingParserConfig = default_config(); + config.operator_config.enable_simd = true; + config + }, + |name, line| match (name, line) { + // FIXME(WebAssembly/simd#140) needs a few updates to the + // `*.wast` file to successfully parse it (or so I think) + ("simd_lane.wast", _) => true, + ("simd_load_extend.wast", _) => true, + ("simd_f32x4_arith.wast", _) => true, + ("simd_f64x2_arith.wast", _) => true, + ("simd_f32x4.wast", _) => true, + ("simd_f64x2.wast", _) => true, + ("simd_const.wast", _) => true, + ("simd_load_splat.wast", _) => true, + _ => false, + }, + ); + + run_proposal_tests( + "multi-value", + { + let mut config: ValidatingParserConfig = default_config(); + config.operator_config.enable_multi_value = true; + config + }, + |_name, _line| false, + ); + + run_proposal_tests( + "reference-types", + { + let mut config: ValidatingParserConfig = default_config(); + config.operator_config.enable_reference_types = true; + config.operator_config.enable_bulk_memory = true; + config + }, + |name, line| match (name, line) { + ("br_table.wast", _) | ("select.wast", _) => true, + _ => false, + }, + ); + } + + #[test] + fn run_spec_tests() { + for entry in read_dir(SPEC_TESTS_PATH).unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() + || dir.path().extension().map(|s| s.to_str().unwrap()) != Some("wast") + { + continue; + } + + let data = read(&dir.path()).expect("wast data"); + run_wabt_scripts( + dir.file_name().to_str().expect("name"), + &data, + default_config(), + |_, _| false, + ); + } + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/validator.rs b/third_party/rust/wasmparser-0.48.2/src/validator.rs new file mode 100644 index 0000000000..2fae3112bd --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/validator.rs @@ -0,0 +1,946 @@ +/* Copyright 2018 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. + */ + +use std::collections::HashSet; +use std::result; +use std::str; + +use crate::limits::{ + MAX_WASM_FUNCTIONS, MAX_WASM_FUNCTION_LOCALS, MAX_WASM_GLOBALS, MAX_WASM_MEMORIES, + MAX_WASM_MEMORY_PAGES, MAX_WASM_TABLES, MAX_WASM_TYPES, +}; + +use crate::binary_reader::BinaryReader; + +use crate::primitives::{ + BinaryReaderError, ExternalKind, FuncType, GlobalType, ImportSectionEntryType, MemoryType, + Operator, ResizableLimits, Result, SectionCode, TableType, Type, +}; + +use crate::operators_validator::{ + is_subtype_supertype, FunctionEnd, OperatorValidator, OperatorValidatorConfig, + DEFAULT_OPERATOR_VALIDATOR_CONFIG, +}; +use crate::parser::{Parser, ParserInput, ParserState, WasmDecoder}; +use crate::{ElemSectionEntryTable, ElementItem}; +use crate::{WasmFuncType, WasmGlobalType, WasmMemoryType, WasmModuleResources, WasmTableType}; + +use crate::readers::FunctionBody; + +type ValidatorResult<'a, T> = result::Result<T, ParserState<'a>>; + +struct InitExpressionState { + ty: Type, + global_count: usize, + function_count: usize, + validated: bool, +} + +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] +enum SectionOrderState { + Initial, + Type, + Import, + Function, + Table, + Memory, + Global, + Export, + Start, + Element, + DataCount, + Code, + Data, +} + +impl SectionOrderState { + pub fn from_section_code(code: &SectionCode) -> Option<SectionOrderState> { + match *code { + SectionCode::Type => Some(SectionOrderState::Type), + SectionCode::Import => Some(SectionOrderState::Import), + SectionCode::Function => Some(SectionOrderState::Function), + SectionCode::Table => Some(SectionOrderState::Table), + SectionCode::Memory => Some(SectionOrderState::Memory), + SectionCode::Global => Some(SectionOrderState::Global), + SectionCode::Export => Some(SectionOrderState::Export), + SectionCode::Start => Some(SectionOrderState::Start), + SectionCode::Element => Some(SectionOrderState::Element), + SectionCode::Code => Some(SectionOrderState::Code), + SectionCode::Data => Some(SectionOrderState::Data), + SectionCode::DataCount => Some(SectionOrderState::DataCount), + _ => None, + } + } +} + +#[derive(Copy, Clone)] +pub struct ValidatingParserConfig { + pub operator_config: OperatorValidatorConfig, +} + +const DEFAULT_VALIDATING_PARSER_CONFIG: ValidatingParserConfig = ValidatingParserConfig { + operator_config: DEFAULT_OPERATOR_VALIDATOR_CONFIG, +}; + +struct ValidatingParserResources { + types: Vec<FuncType>, + tables: Vec<TableType>, + memories: Vec<MemoryType>, + globals: Vec<GlobalType>, + element_count: u32, + data_count: Option<u32>, + func_type_indices: Vec<u32>, +} + +impl<'a> WasmModuleResources for ValidatingParserResources { + type FuncType = crate::FuncType; + type TableType = crate::TableType; + type MemoryType = crate::MemoryType; + type GlobalType = crate::GlobalType; + + fn type_at(&self, at: u32) -> Option<&Self::FuncType> { + self.types.get(at as usize) + } + + fn table_at(&self, at: u32) -> Option<&Self::TableType> { + self.tables.get(at as usize) + } + + fn memory_at(&self, at: u32) -> Option<&Self::MemoryType> { + self.memories.get(at as usize) + } + + fn global_at(&self, at: u32) -> Option<&Self::GlobalType> { + self.globals.get(at as usize) + } + + fn func_type_id_at(&self, at: u32) -> Option<u32> { + self.func_type_indices.get(at as usize).copied() + } + + fn element_count(&self) -> u32 { + self.element_count + } + + fn data_count(&self) -> u32 { + self.data_count.unwrap_or(0) + } +} + +pub struct ValidatingParser<'a> { + parser: Parser<'a>, + validation_error: Option<ParserState<'a>>, + read_position: Option<usize>, + section_order_state: SectionOrderState, + resources: ValidatingParserResources, + current_func_index: u32, + func_imports_count: u32, + init_expression_state: Option<InitExpressionState>, + data_found: u32, + exported_names: HashSet<String>, + current_operator_validator: Option<OperatorValidator>, + config: ValidatingParserConfig, +} + +impl<'a> ValidatingParser<'a> { + pub fn new(bytes: &[u8], config: Option<ValidatingParserConfig>) -> ValidatingParser { + ValidatingParser { + parser: Parser::new(bytes), + validation_error: None, + read_position: None, + section_order_state: SectionOrderState::Initial, + resources: ValidatingParserResources { + types: Vec::new(), + tables: Vec::new(), + memories: Vec::new(), + globals: Vec::new(), + element_count: 0, + data_count: None, + func_type_indices: Vec::new(), + }, + current_func_index: 0, + func_imports_count: 0, + current_operator_validator: None, + init_expression_state: None, + data_found: 0, + exported_names: HashSet::new(), + config: config.unwrap_or(DEFAULT_VALIDATING_PARSER_CONFIG), + } + } + + pub fn get_resources( + &self, + ) -> &dyn WasmModuleResources< + FuncType = crate::FuncType, + TableType = crate::TableType, + MemoryType = crate::MemoryType, + GlobalType = crate::GlobalType, + > { + &self.resources + } + + fn set_validation_error(&mut self, message: &'static str) { + self.validation_error = Some(ParserState::Error(BinaryReaderError { + message, + offset: self.read_position.unwrap(), + })) + } + + fn create_error<T>(&self, message: &'static str) -> ValidatorResult<'a, T> { + Err(ParserState::Error(BinaryReaderError { + message, + offset: self.read_position.unwrap(), + })) + } + + fn check_value_type(&self, ty: Type) -> ValidatorResult<'a, ()> { + match ty { + Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()), + Type::NullRef | Type::AnyFunc | Type::AnyRef => { + if !self.config.operator_config.enable_reference_types { + return self.create_error("reference types support is not enabled"); + } + Ok(()) + } + Type::V128 => { + if !self.config.operator_config.enable_simd { + return self.create_error("SIMD support is not enabled"); + } + Ok(()) + } + _ => self.create_error("invalid value type"), + } + } + + fn check_value_types(&self, types: &[Type]) -> ValidatorResult<'a, ()> { + for ty in types { + self.check_value_type(*ty)?; + } + Ok(()) + } + + fn check_limits(&self, limits: &ResizableLimits) -> ValidatorResult<'a, ()> { + if limits.maximum.is_some() && limits.initial > limits.maximum.unwrap() { + return self.create_error("maximum limits less than initial"); + } + Ok(()) + } + + fn check_func_type(&self, func_type: &FuncType) -> ValidatorResult<'a, ()> { + if let Type::Func = func_type.form { + self.check_value_types(&*func_type.params)?; + self.check_value_types(&*func_type.returns)?; + if !self.config.operator_config.enable_multi_value && func_type.returns.len() > 1 { + self.create_error("func type returns multiple values") + } else { + Ok(()) + } + } else { + self.create_error("type signature is not a func") + } + } + + fn check_table_type(&self, table_type: &TableType) -> ValidatorResult<'a, ()> { + match table_type.element_type { + Type::AnyFunc => {} + _ => { + if !self.config.operator_config.enable_reference_types { + return self.create_error("element is not anyfunc"); + } + } + } + self.check_limits(&table_type.limits) + } + + fn check_memory_type(&self, memory_type: &MemoryType) -> ValidatorResult<'a, ()> { + self.check_limits(&memory_type.limits)?; + let initial = memory_type.limits.initial; + if initial as usize > MAX_WASM_MEMORY_PAGES { + return self.create_error("memory initial value exceeds limit"); + } + let maximum = memory_type.limits.maximum; + if maximum.is_some() && maximum.unwrap() as usize > MAX_WASM_MEMORY_PAGES { + return self.create_error("memory maximum value exceeds limit"); + } + Ok(()) + } + + fn check_global_type(&self, global_type: GlobalType) -> ValidatorResult<'a, ()> { + self.check_value_type(global_type.content_type) + } + + fn check_import_entry(&self, import_type: &ImportSectionEntryType) -> ValidatorResult<'a, ()> { + match *import_type { + ImportSectionEntryType::Function(type_index) => { + if self.resources.func_type_indices.len() >= MAX_WASM_FUNCTIONS { + return self.create_error("functions count out of bounds"); + } + if type_index as usize >= self.resources.types.len() { + return self.create_error("type index out of bounds"); + } + Ok(()) + } + ImportSectionEntryType::Table(ref table_type) => { + if !self.config.operator_config.enable_reference_types + && self.resources.tables.len() >= MAX_WASM_TABLES + { + return self.create_error("tables count must be at most 1"); + } + self.check_table_type(table_type) + } + ImportSectionEntryType::Memory(ref memory_type) => { + if self.resources.memories.len() >= MAX_WASM_MEMORIES { + return self.create_error("memory count must be at most 1"); + } + self.check_memory_type(memory_type) + } + ImportSectionEntryType::Global(global_type) => { + if self.resources.globals.len() >= MAX_WASM_GLOBALS { + return self.create_error("functions count out of bounds"); + } + self.check_global_type(global_type) + } + } + } + + fn check_init_expression_operator(&self, operator: &Operator) -> ValidatorResult<'a, ()> { + let state = self.init_expression_state.as_ref().unwrap(); + if state.validated { + return self.create_error("only one init_expr operator is expected"); + } + let ty = match *operator { + Operator::I32Const { .. } => Type::I32, + Operator::I64Const { .. } => Type::I64, + Operator::F32Const { .. } => Type::F32, + Operator::F64Const { .. } => Type::F64, + Operator::RefNull => { + if !self.config.operator_config.enable_reference_types { + return self.create_error("reference types support is not enabled"); + } + Type::NullRef + } + Operator::V128Const { .. } => { + if !self.config.operator_config.enable_simd { + return self.create_error("SIMD support is not enabled"); + } + Type::V128 + } + Operator::GlobalGet { global_index } => { + if global_index as usize >= state.global_count { + return self.create_error("init_expr global index out of bounds"); + } + self.resources.globals[global_index as usize].content_type + } + Operator::RefFunc { function_index } => { + if function_index as usize >= state.function_count { + return self.create_error("init_expr function index out of bounds"); + } + Type::AnyFunc + } + _ => return self.create_error("invalid init_expr operator"), + }; + if !is_subtype_supertype(ty, state.ty) { + return self.create_error("invalid init_expr type"); + } + Ok(()) + } + + fn check_export_entry( + &self, + field: &str, + kind: ExternalKind, + index: u32, + ) -> ValidatorResult<'a, ()> { + if self.exported_names.contains(field) { + return self.create_error("non-unique export name"); + } + match kind { + ExternalKind::Function => { + if index as usize >= self.resources.func_type_indices.len() { + return self.create_error("exported function index out of bounds"); + } + } + ExternalKind::Table => { + if index as usize >= self.resources.tables.len() { + return self.create_error("exported table index out of bounds"); + } + } + ExternalKind::Memory => { + if index as usize >= self.resources.memories.len() { + return self.create_error("exported memory index out of bounds"); + } + } + ExternalKind::Global => { + if index as usize >= self.resources.globals.len() { + return self.create_error("exported global index out of bounds"); + } + } + }; + Ok(()) + } + + fn check_start(&self, func_index: u32) -> ValidatorResult<'a, ()> { + if func_index as usize >= self.resources.func_type_indices.len() { + return self.create_error("start function index out of bounds"); + } + let type_index = self.resources.func_type_indices[func_index as usize]; + let ty = &self.resources.types[type_index as usize]; + if !ty.params.is_empty() || !ty.returns.is_empty() { + return self.create_error("invlid start function type"); + } + Ok(()) + } + + fn process_begin_section(&self, code: &SectionCode) -> ValidatorResult<'a, SectionOrderState> { + let order_state = SectionOrderState::from_section_code(code); + Ok(match self.section_order_state { + SectionOrderState::Initial => match order_state { + Some(section) => section, + _ => SectionOrderState::Initial, + }, + previous => { + if let Some(order_state_unwraped) = order_state { + if previous >= order_state_unwraped { + return self.create_error("section out of order"); + } + order_state_unwraped + } else { + previous + } + } + }) + } + + fn process_state(&mut self) { + match *self.parser.last_state() { + ParserState::BeginWasm { version } => { + if version != 1 { + self.set_validation_error("bad wasm file version"); + } + } + ParserState::BeginSection { ref code, .. } => { + let check = self.process_begin_section(code); + if check.is_err() { + self.validation_error = check.err(); + } else { + self.section_order_state = check.ok().unwrap(); + } + } + ParserState::TypeSectionEntry(ref func_type) => { + let check = self.check_func_type(func_type); + if check.is_err() { + self.validation_error = check.err(); + } else if self.resources.types.len() > MAX_WASM_TYPES { + self.set_validation_error("types count is out of bounds"); + } else { + self.resources.types.push(func_type.clone()); + } + } + ParserState::ImportSectionEntry { ref ty, .. } => { + let check = self.check_import_entry(ty); + if check.is_err() { + self.validation_error = check.err(); + } else { + match *ty { + ImportSectionEntryType::Function(type_index) => { + self.func_imports_count += 1; + self.resources.func_type_indices.push(type_index); + } + ImportSectionEntryType::Table(ref table_type) => { + self.resources.tables.push(table_type.clone()); + } + ImportSectionEntryType::Memory(ref memory_type) => { + self.resources.memories.push(memory_type.clone()); + } + ImportSectionEntryType::Global(ref global_type) => { + self.resources.globals.push(global_type.clone()); + } + } + } + } + ParserState::FunctionSectionEntry(type_index) => { + if type_index as usize >= self.resources.types.len() { + self.set_validation_error("func type index out of bounds"); + } else if self.resources.func_type_indices.len() >= MAX_WASM_FUNCTIONS { + self.set_validation_error("functions count out of bounds"); + } else { + self.resources.func_type_indices.push(type_index); + } + } + ParserState::TableSectionEntry(ref table_type) => { + if !self.config.operator_config.enable_reference_types + && self.resources.tables.len() >= MAX_WASM_TABLES + { + self.set_validation_error("tables count must be at most 1"); + } else { + self.validation_error = self.check_table_type(table_type).err(); + self.resources.tables.push(table_type.clone()); + } + } + ParserState::MemorySectionEntry(ref memory_type) => { + if self.resources.memories.len() >= MAX_WASM_MEMORIES { + self.set_validation_error("memories count must be at most 1"); + } else { + self.validation_error = self.check_memory_type(memory_type).err(); + self.resources.memories.push(memory_type.clone()); + } + } + ParserState::BeginGlobalSectionEntry(global_type) => { + if self.resources.globals.len() >= MAX_WASM_GLOBALS { + self.set_validation_error("globals count out of bounds"); + } else { + self.validation_error = self.check_global_type(global_type).err(); + self.init_expression_state = Some(InitExpressionState { + ty: global_type.content_type, + global_count: self.resources.globals.len(), + function_count: self.resources.func_type_indices.len(), + validated: false, + }); + self.resources.globals.push(global_type); + } + } + ParserState::BeginInitExpressionBody => { + assert!(self.init_expression_state.is_some()); + } + ParserState::InitExpressionOperator(ref operator) => { + self.validation_error = self.check_init_expression_operator(operator).err(); + self.init_expression_state.as_mut().unwrap().validated = true; + } + ParserState::EndInitExpressionBody => { + if !self.init_expression_state.as_ref().unwrap().validated { + self.set_validation_error("init_expr is empty"); + } + self.init_expression_state = None; + } + ParserState::ExportSectionEntry { field, kind, index } => { + self.validation_error = self.check_export_entry(field, kind, index).err(); + self.exported_names.insert(String::from(field)); + } + ParserState::StartSectionEntry(func_index) => { + self.validation_error = self.check_start(func_index).err(); + } + ParserState::DataCountSectionEntry(count) => { + self.resources.data_count = Some(count); + } + ParserState::BeginElementSectionEntry { table, ty } => { + self.resources.element_count += 1; + if let ElemSectionEntryTable::Active(table_index) = table { + let table = match self.resources.tables.get(table_index as usize) { + Some(t) => t, + None => { + self.set_validation_error("element section table index out of bounds"); + return; + } + }; + if !is_subtype_supertype(ty, table.element_type) { + self.set_validation_error("element_type != table type"); + return; + } + if !self.config.operator_config.enable_reference_types && ty != Type::AnyFunc { + self.set_validation_error("element_type != anyfunc is not supported yet"); + return; + } + self.init_expression_state = Some(InitExpressionState { + ty: Type::I32, + global_count: self.resources.globals.len(), + function_count: self.resources.func_type_indices.len(), + validated: false, + }); + } + } + ParserState::ElementSectionEntryBody(ref indices) => { + for item in &**indices { + if let ElementItem::Func(func_index) = item { + if *func_index as usize >= self.resources.func_type_indices.len() { + self.set_validation_error("element func index out of bounds"); + break; + } + } + } + } + ParserState::BeginFunctionBody { .. } => { + let index = (self.current_func_index + self.func_imports_count) as usize; + if index as usize >= self.resources.func_type_indices.len() { + self.set_validation_error("func type is not defined"); + } + } + ParserState::FunctionBodyLocals { ref locals } => { + let index = (self.current_func_index + self.func_imports_count) as usize; + let func_type = + &self.resources.types[self.resources.func_type_indices[index] as usize]; + let operator_config = self.config.operator_config; + self.current_operator_validator = + Some(OperatorValidator::new(func_type, locals, operator_config)); + } + ParserState::CodeOperator(ref operator) => { + let check = self + .current_operator_validator + .as_mut() + .unwrap() + .process_operator(operator, &self.resources); + + if let Err(err) = check { + self.set_validation_error(err); + } + } + ParserState::EndFunctionBody => { + let check = self + .current_operator_validator + .as_ref() + .unwrap() + .process_end_function(); + if let Err(err) = check { + self.set_validation_error(err); + } + self.current_func_index += 1; + self.current_operator_validator = None; + } + ParserState::BeginDataSectionEntryBody(_) => { + self.data_found += 1; + } + ParserState::BeginActiveDataSectionEntry(memory_index) => { + if memory_index as usize >= self.resources.memories.len() { + self.set_validation_error("data section memory index out of bounds"); + } else { + self.init_expression_state = Some(InitExpressionState { + ty: Type::I32, + global_count: self.resources.globals.len(), + function_count: self.resources.func_type_indices.len(), + validated: false, + }); + } + } + ParserState::EndWasm => { + if self.resources.func_type_indices.len() + != self.current_func_index as usize + self.func_imports_count as usize + { + self.set_validation_error( + "function and code section have inconsistent lengths", + ); + } + if let Some(data_count) = self.resources.data_count { + if data_count != self.data_found { + self.set_validation_error("data count section and passive data mismatch"); + } + } + } + _ => (), + }; + } + + pub fn create_validating_operator_parser<'b>(&mut self) -> ValidatingOperatorParser<'b> + where + 'a: 'b, + { + let func_body_offset = match *self.last_state() { + ParserState::BeginFunctionBody { .. } => self.parser.current_position(), + _ => panic!("Invalid reader state"), + }; + self.read(); + let operator_validator = match *self.last_state() { + ParserState::FunctionBodyLocals { ref locals } => { + let index = (self.current_func_index + self.func_imports_count) as usize; + let func_type = + &self.resources.types[self.resources.func_type_indices[index] as usize]; + let operator_config = self.config.operator_config; + OperatorValidator::new(func_type, locals, operator_config) + } + _ => panic!("Invalid reader state"), + }; + let reader = self.create_binary_reader(); + ValidatingOperatorParser::new(operator_validator, reader, func_body_offset) + } +} + +impl<'a> WasmDecoder<'a> for ValidatingParser<'a> { + fn read(&mut self) -> &ParserState<'a> { + if self.validation_error.is_some() { + panic!("Parser in error state: validation"); + } + self.read_position = Some(self.parser.current_position()); + self.parser.read(); + self.process_state(); + self.last_state() + } + + fn push_input(&mut self, input: ParserInput) { + match input { + ParserInput::SkipSection => panic!("Not supported"), + ParserInput::ReadSectionRawData => panic!("Not supported"), + ParserInput::SkipFunctionBody => { + self.current_func_index += 1; + self.parser.push_input(input); + } + _ => self.parser.push_input(input), + } + } + + fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a> { + self.push_input(input); + self.read() + } + + fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b> + where + 'a: 'b, + { + if let ParserState::BeginSection { .. } = *self.parser.last_state() { + panic!("Not supported"); + } + self.parser.create_binary_reader() + } + + fn last_state(&self) -> &ParserState<'a> { + if self.validation_error.is_some() { + self.validation_error.as_ref().unwrap() + } else { + self.parser.last_state() + } + } +} + +pub struct ValidatingOperatorParser<'b> { + operator_validator: OperatorValidator, + reader: BinaryReader<'b>, + func_body_offset: usize, + end_function: bool, +} + +impl<'b> ValidatingOperatorParser<'b> { + pub(crate) fn new<'c>( + operator_validator: OperatorValidator, + reader: BinaryReader<'c>, + func_body_offset: usize, + ) -> ValidatingOperatorParser<'c> + where + 'b: 'c, + { + ValidatingOperatorParser { + operator_validator, + reader, + func_body_offset, + end_function: false, + } + } + + pub fn eof(&self) -> bool { + self.end_function + } + + pub fn current_position(&self) -> usize { + self.reader.current_position() + } + + pub fn is_dead_code(&self) -> bool { + self.operator_validator.is_dead_code() + } + + /// Creates a BinaryReader when current state is ParserState::BeginSection + /// or ParserState::BeginFunctionBody. + /// + /// # Examples + /// ``` + /// # let data = &[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x84, + /// # 0x80, 0x80, 0x80, 0x0, 0x1, 0x60, 0x0, 0x0, 0x3, 0x83, + /// # 0x80, 0x80, 0x80, 0x0, 0x2, 0x0, 0x0, 0x6, 0x81, 0x80, + /// # 0x80, 0x80, 0x0, 0x0, 0xa, 0x91, 0x80, 0x80, 0x80, 0x0, + /// # 0x2, 0x83, 0x80, 0x80, 0x80, 0x0, 0x0, 0x1, 0xb, 0x83, + /// # 0x80, 0x80, 0x80, 0x0, 0x0, 0x0, 0xb]; + /// use wasmparser::{WasmDecoder, ParserState, ValidatingParser}; + /// let mut parser = ValidatingParser::new(data, None); + /// let mut i = 0; + /// loop { + /// { + /// match *parser.read() { + /// ParserState::Error(_) | + /// ParserState::EndWasm => break, + /// ParserState::BeginFunctionBody {..} => (), + /// _ => continue + /// } + /// } + /// let mut reader = parser.create_validating_operator_parser(); + /// println!("Function {}", i); + /// i += 1; + /// while !reader.eof() { + /// let read = reader.next(parser.get_resources()); + /// if let Ok(ref op) = read { + /// println!(" {:?}", op); + /// } else { + /// panic!(" Bad wasm code {:?}", read.err()); + /// } + /// } + /// } + /// ``` + pub fn next<'c, F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>( + &mut self, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> Result<Operator<'c>> + where + 'b: 'c, + { + let op = self.reader.read_operator()?; + match self.operator_validator.process_operator(&op, resources) { + Err(err) => { + return Err(BinaryReaderError { + message: err, + offset: self.func_body_offset + self.reader.current_position(), + }); + } + Ok(FunctionEnd::Yes) => { + self.end_function = true; + if !self.reader.eof() { + return Err(BinaryReaderError { + message: "unexpected end of function", + offset: self.func_body_offset + self.reader.current_position(), + }); + } + } + _ => (), + }; + Ok(op) + } +} + +/// Test whether the given buffer contains a valid WebAssembly function. +/// The resources parameter contains all needed data to validate the operators. +pub fn validate_function_body< + F: WasmFuncType, + T: WasmTableType, + M: WasmMemoryType, + G: WasmGlobalType, +>( + bytes: &[u8], + offset: usize, + func_index: u32, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + operator_config: Option<OperatorValidatorConfig>, +) -> Result<()> { + let operator_config = operator_config.unwrap_or(DEFAULT_OPERATOR_VALIDATOR_CONFIG); + let function_body = FunctionBody::new(offset, bytes); + let mut locals_reader = function_body.get_locals_reader()?; + let local_count = locals_reader.get_count() as usize; + if local_count > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "locals exceed maximum", + offset: locals_reader.original_position(), + }); + } + let mut locals: Vec<(u32, Type)> = Vec::with_capacity(local_count); + let mut locals_total: usize = 0; + for _ in 0..local_count { + let (count, ty) = locals_reader.read()?; + locals_total = + locals_total + .checked_add(count as usize) + .ok_or_else(|| BinaryReaderError { + message: "locals overflow", + offset: locals_reader.original_position(), + })?; + if locals_total > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "locals exceed maximum", + offset: locals_reader.original_position(), + }); + } + locals.push((count, ty)); + } + let operators_reader = function_body.get_operators_reader()?; + let func_type_index = resources + .func_type_id_at(func_index) + // Note: This was an out-of-bounds access before the change to return `Option` + // so I assumed it is considered a bug to access a non-existing function + // id here and went with panicking instead of returning a proper error. + .expect("the function index of the validated function itself is out of bounds"); + let func_type = resources + .type_at(func_type_index) + // Note: This was an out-of-bounds access before the change to return `Option` + // so I assumed it is considered a bug to access a non-existing function + // id here and went with panicking instead of returning a proper error. + .expect("the function type indexof the validated function itself is out of bounds"); + let mut operator_validator = OperatorValidator::new(func_type, &locals, operator_config); + let mut eof_found = false; + let mut last_op = 0; + for item in operators_reader.into_iter_with_offsets() { + let (ref op, offset) = item?; + match operator_validator + .process_operator(op, resources) + .map_err(|message| BinaryReaderError { message, offset })? + { + FunctionEnd::Yes => { + eof_found = true; + } + FunctionEnd::No => { + last_op = offset; + } + } + } + if !eof_found { + return Err(BinaryReaderError { + message: "end of function not found", + offset: last_op, + }); + } + Ok(()) +} + +/// Test whether the given buffer contains a valid WebAssembly module, +/// analogous to WebAssembly.validate in the JS API. +pub fn validate(bytes: &[u8], config: Option<ValidatingParserConfig>) -> Result<()> { + let mut parser = ValidatingParser::new(bytes, config); + let mut parser_input = None; + let mut func_ranges = Vec::new(); + loop { + let next_input = parser_input.take().unwrap_or(ParserInput::Default); + let state = parser.read_with_input(next_input); + match *state { + ParserState::EndWasm => break, + ParserState::Error(e) => return Err(e), + ParserState::BeginFunctionBody { range } => { + parser_input = Some(ParserInput::SkipFunctionBody); + func_ranges.push(range); + } + _ => (), + } + } + let operator_config = config.map(|c| c.operator_config); + for (i, range) in func_ranges.into_iter().enumerate() { + let function_body = range.slice(bytes); + let function_index = i as u32 + parser.func_imports_count; + validate_function_body( + function_body, + range.start, + function_index, + &parser.resources, + operator_config, + )?; + } + Ok(()) +} + +#[test] +fn test_validate() { + assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0], None).is_ok()); + assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x2, 0x0, 0x0, 0x0], None).is_err()); +} |