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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/core/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,18 @@ pub enum ValidationError {
/// The mode of an element was invalid. Only values in the range 0..=7 are
/// allowed.
InvalidElementMode(u32),
/// The module contains too many functions, i.e. imported or locally-defined
/// functions. The maximum number of functions is [`u32::MAX`].
TooManyFunctions,
/// The module contains too many tables, i.e. imported or locally-defined
/// tables. The maximum number of tables is [`u32::MAX`].
TooManyTables,
/// The module contains too many memories, i.e. imported or locally-defined
/// memories. The maximum number of memories is [`u32::MAX`].
TooManyMemories,
/// The module contains too many globals, i.e. imported or locally-defined
/// globals. The maximum number of memories is [`u32::MAX`].
TooManyGlobals,
}

impl core::error::Error for ValidationError {}
Expand Down Expand Up @@ -226,6 +238,10 @@ impl Display for ValidationError {
ValidationError::MissingDataCountSection => f.write_str("Some instructions could not be validated because the data count section is missing"),
ValidationError::InvalidDataSegmentMode(mode) => write!(f, "The mode of a data segment was invalid (only 0..=2 is allowed): {mode}"),
ValidationError::InvalidElementMode(mode) => write!(f, "The mode of an element was invalid (only 0..=7 is allowed): {mode}"),
ValidationError::TooManyFunctions => f.write_str("The module contains too many functions. The maximum number of functions (either imported or locally-defined) is 2^32 - 1"),
ValidationError::TooManyTables => f.write_str("The module contains too many tables. The maximum number of tables (either imported or locally-defined) is 2^32 - 1"),
ValidationError::TooManyMemories => f.write_str("The module contains too many memories. The maximum number of memories (either imported or locally-defined) is 2^32 - 1"),
ValidationError::TooManyGlobals => f.write_str("The module contains too many globals. The maximum number of globals (either imported or locally-defined) is 2^32 - 1"),
}
}
}
Expand Down
1 change: 0 additions & 1 deletion src/core/indices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,4 @@ pub type GlobalIdx = usize;
pub type ElemIdx = usize;
pub type DataIdx = usize;
pub type LocalIdx = usize;
#[allow(dead_code)]
pub type LabelIdx = usize;
2 changes: 0 additions & 2 deletions src/core/reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ impl<'a> WasmReader<'a> {
/// more than 0 further bytes would panick. However, it can not move the [`pc`](Self::pc) any
/// further than that, instead an error is returned. For further information, refer to the
/// [field documentation of `pc`] (WasmReader::pc).
#[allow(dead_code)]
pub fn skip(&mut self, num_bytes: usize) -> Result<(), ValidationError> {
if num_bytes > self.full_wasm_binary.len() - self.pc {
return Err(ValidationError::Eof);
Expand All @@ -155,7 +154,6 @@ impl<'a> WasmReader<'a> {
///
/// The provided closure will be called with `&mut self` and its result will be returned.
/// However if the closure returns `Err(_)`, `self` will be reset as if the closure was never called.
#[allow(dead_code)]
pub fn handle_transaction<T, E>(
&mut self,
f: impl FnOnce(&mut WasmReader<'a>) -> Result<T, E>,
Expand Down
74 changes: 18 additions & 56 deletions src/core/reader/types/export.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
use alloc::borrow::ToOwned;
use alloc::string::String;

use crate::core::indices::{FuncIdx, GlobalIdx, MemIdx, TableIdx};
use crate::core::reader::types::import::ImportDesc;
use crate::core::reader::WasmReader;
Expand All @@ -9,33 +6,25 @@ use crate::{ValidationError, ValidationInfo};
use super::ExternType;

#[derive(Debug, Clone)]
pub struct Export {
#[allow(dead_code)]
pub name: String,
#[allow(dead_code)]
pub struct Export<'wasm> {
pub name: &'wasm str,
pub desc: ExportDesc,
}

impl Export {
pub fn read(wasm: &mut WasmReader) -> Result<Self, ValidationError> {
let name = wasm.read_name()?.to_owned();
impl<'wasm> Export<'wasm> {
pub fn read(wasm: &mut WasmReader<'wasm>) -> Result<Self, ValidationError> {
let name = wasm.read_name()?;
let desc = ExportDesc::read(wasm)?;
Ok(Export { name, desc })
}
}

#[derive(Debug, Clone)]
#[allow(clippy::all)]
// TODO: change enum labels from FuncIdx -> Func
pub enum ExportDesc {
#[allow(warnings)]
FuncIdx(FuncIdx),
#[allow(warnings)]
TableIdx(TableIdx),
#[allow(warnings)]
MemIdx(MemIdx),
#[allow(warnings)]
GlobalIdx(GlobalIdx),
Func(FuncIdx),
Table(TableIdx),
Mem(MemIdx),
Global(GlobalIdx),
}

impl ExportDesc {
Expand All @@ -44,11 +33,12 @@ impl ExportDesc {
///
/// Note: This method may panic if `self` does not come from the given [`ValidationInfo`].
/// <https://webassembly.github.io/spec/core/valid/modules.html#exports>
#[allow(unused)] // reason = "this function is analogous to ImportDesc::extern_type, however it is not yet clear if it is needed in the future"
pub fn extern_type(&self, validation_info: &ValidationInfo) -> ExternType {
// TODO clean up logic for checking if an exported definition is an
// import
match self {
ExportDesc::FuncIdx(func_idx) => {
ExportDesc::Func(func_idx) => {
let type_idx = match func_idx
.checked_sub(validation_info.imports_length.imported_functions)
{
Expand All @@ -70,7 +60,7 @@ impl ExportDesc {
// TODO ugly clone that should disappear when types are directly parsed from bytecode instead of vector copies
ExternType::Func(func_type.clone())
}
ExportDesc::TableIdx(table_idx) => {
ExportDesc::Table(table_idx) => {
let table_type = match table_idx
.checked_sub(validation_info.imports_length.imported_tables)
{
Expand All @@ -87,7 +77,7 @@ impl ExportDesc {
};
ExternType::Table(table_type)
}
ExportDesc::MemIdx(mem_idx) => {
ExportDesc::Mem(mem_idx) => {
let mem_type = match mem_idx
.checked_sub(validation_info.imports_length.imported_memories)
{
Expand All @@ -104,7 +94,7 @@ impl ExportDesc {
};
ExternType::Mem(mem_type)
}
ExportDesc::GlobalIdx(global_idx) => {
ExportDesc::Global(global_idx) => {
let global_type =
match global_idx.checked_sub(validation_info.imports_length.imported_globals) {
Some(local_global_idx) => {
Expand All @@ -125,34 +115,6 @@ impl ExportDesc {
}
}
}

pub fn get_function_idx(&self) -> Option<FuncIdx> {
match self {
ExportDesc::FuncIdx(func_idx) => Some(*func_idx),
_ => None,
}
}

pub fn get_global_idx(&self) -> Option<GlobalIdx> {
match self {
ExportDesc::GlobalIdx(global_idx) => Some(*global_idx),
_ => None,
}
}

pub fn get_memory_idx(&self) -> Option<MemIdx> {
match self {
ExportDesc::MemIdx(mem_idx) => Some(*mem_idx),
_ => None,
}
}

pub fn get_table_idx(&self) -> Option<TableIdx> {
match self {
ExportDesc::TableIdx(table_idx) => Some(*table_idx),
_ => None,
}
}
}

impl ExportDesc {
Expand All @@ -161,10 +123,10 @@ impl ExportDesc {
let desc_idx = wasm.read_var_u32()? as usize;

let desc = match desc_id {
0x00 => ExportDesc::FuncIdx(desc_idx),
0x01 => ExportDesc::TableIdx(desc_idx),
0x02 => ExportDesc::MemIdx(desc_idx),
0x03 => ExportDesc::GlobalIdx(desc_idx),
0x00 => ExportDesc::Func(desc_idx),
0x01 => ExportDesc::Table(desc_idx),
0x02 => ExportDesc::Mem(desc_idx),
0x03 => ExportDesc::Global(desc_idx),
other => return Err(ValidationError::MalformedExportDescDiscriminator(other)),
};
Ok(desc)
Expand Down
20 changes: 7 additions & 13 deletions src/core/reader/types/import.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
use alloc::borrow::ToOwned;
use alloc::string::String;

use crate::core::indices::TypeIdx;
use crate::core::reader::WasmReader;
use crate::{ValidationError, ValidationInfo};
Expand All @@ -9,19 +6,16 @@ use super::global::GlobalType;
use super::{ExternType, MemType, TableType};

#[derive(Debug, Clone)]
pub struct Import {
#[allow(warnings)]
pub module_name: String,
#[allow(warnings)]
pub name: String,
#[allow(warnings)]
pub struct Import<'wasm> {
pub module_name: &'wasm str,
pub name: &'wasm str,
pub desc: ImportDesc,
}

impl Import {
pub fn read(wasm: &mut WasmReader) -> Result<Self, ValidationError> {
let module_name = wasm.read_name()?.to_owned();
let name = wasm.read_name()?.to_owned();
impl<'wasm> Import<'wasm> {
pub fn read(wasm: &mut WasmReader<'wasm>) -> Result<Self, ValidationError> {
let module_name = wasm.read_name()?;
let name = wasm.read_name()?;
let desc = ImportDesc::read(wasm)?;

Ok(Self {
Expand Down
1 change: 0 additions & 1 deletion src/core/reader/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ impl RefType {
/// <https://webassembly.github.io/spec/core/binary/types.html#reference-types>
/// TODO flatten [NumType] and [RefType] enums, as they are not used individually and `wasmparser` also does it.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(clippy::all)]
pub enum ValType {
NumType(NumType),
VecType,
Expand Down
10 changes: 6 additions & 4 deletions src/core/reader/types/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const CONTINUATION_BIT: u8 = 0b10000000;

const INTEGER_BIT_FLAG: u8 = !CONTINUATION_BIT;

impl WasmReader<'_> {
impl<'wasm> WasmReader<'wasm> {
/// Tries to read one byte and fails if the end of file is reached.
pub fn read_u8(&mut self) -> Result<u8, ValidationError> {
let byte = self.peek_u8()?;
Expand Down Expand Up @@ -351,7 +351,7 @@ impl WasmReader<'_> {
}

/// Note: If `Err`, the [WasmReader] object is no longer guaranteed to be in a valid state
pub fn read_name(&mut self) -> Result<&str, ValidationError> {
pub fn read_name(&mut self) -> Result<&'wasm str, ValidationError> {
let len = self.read_var_u32()? as usize;

let utf8_str = &self
Expand All @@ -369,7 +369,8 @@ impl WasmReader<'_> {
mut read_element: F,
) -> Result<Vec<T>, ValidationError>
where
F: FnMut(&mut WasmReader, usize) -> Result<T, ValidationError>,
T: 'wasm,
F: FnMut(&mut WasmReader<'wasm>, usize) -> Result<T, ValidationError>,
{
let mut idx = 0;
self.read_vec(|wasm| {
Expand All @@ -382,7 +383,8 @@ impl WasmReader<'_> {
/// Note: If `Err`, the [WasmReader] object is no longer guaranteed to be in a valid state
pub fn read_vec<T, F>(&mut self, mut read_element: F) -> Result<Vec<T>, ValidationError>
where
F: FnMut(&mut WasmReader) -> Result<T, ValidationError>,
T: 'wasm,
F: FnMut(&mut WasmReader<'wasm>) -> Result<T, ValidationError>,
{
let len = self.read_var_u32()?;
core::iter::repeat_with(|| read_element(self))
Expand Down
2 changes: 1 addition & 1 deletion src/core/slotmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl<T> SlotMap<T> {
}
}

#[allow(unused)]
#[allow(unused)] // reason = "this function might be used in the future"
pub fn get(&self, key: &SlotMapKey<T>) -> Option<&T> {
let slot = self.slots.get(key.index)?;
if slot.generation != key.generation {
Expand Down
3 changes: 1 addition & 2 deletions src/execution/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ pub trait Config {
///
/// This allows the most intricate insight into the interpreters behavior, at the cost of a
/// hefty performance penalty
#[allow(unused_variables)]
#[inline(always)]
fn instruction_hook(&mut self, bytecode: &[u8], pc: usize) {}
fn instruction_hook(&mut self, _bytecode: &[u8], _pc: usize) {}

/// Amount of fuel to be deducted when a single byte `instr` is hit. The cost corresponding to `UNREACHABLE` and
/// `END` instructions and other bytes that do not correspond to any Wasm instruction are ignored.
Expand Down
Loading