Skip to content

Commit

Permalink
Add typesafety for module validation
Browse files Browse the repository at this point in the history
Now modules (and the appropriate items in modules) have a `ValidatedState`
parameter, which is set to `Validated` after running through the validation
algorithm.
  • Loading branch information
jblebrun committed Jan 23, 2024
1 parent 8ade4b8 commit 3824144
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 145 deletions.
4 changes: 2 additions & 2 deletions tests-integration/src/spec/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use {
self as modulesyntax,
location::Location,
types::{NumType, RefType},
Id, Resolved, UncompiledExpr,
Id, Resolved, UncompiledExpr, Unvalidated,
},
},
};
Expand Down Expand Up @@ -489,7 +489,7 @@ pub struct CmdEntry {
/// ```
#[derive(Debug)]
pub enum Module {
Module(modulesyntax::Module<Resolved, UncompiledExpr<Resolved>>),
Module(modulesyntax::Module<Resolved, Unvalidated, UncompiledExpr<Resolved>>),
Binary(Option<Id>, Vec<WasmString>),
Quote(Option<Id>, Vec<WasmString>),
}
Expand Down
16 changes: 9 additions & 7 deletions wrausmt-format/src/binary/exports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use {
BinaryParser, ParserReader,
},
crate::{binary::read_with_location::Locate, pctx},
wrausmt_runtime::syntax::{ExportDesc, ExportField, Resolved},
wrausmt_runtime::syntax::{ExportDesc, ExportField, Resolved, Unvalidated},
};

/// A trait to allow parsing of an exports section from something implementing
Expand All @@ -18,7 +18,9 @@ impl<R: ParserReader> BinaryParser<R> {
/// 0x01 Table
/// 0x02 Memory
/// 0x03 Global
pub(in crate::binary) fn read_exports_section(&mut self) -> Result<Vec<ExportField<Resolved>>> {
pub(in crate::binary) fn read_exports_section(
&mut self,
) -> Result<Vec<ExportField<Resolved, Unvalidated>>> {
self.read_vec(|_, s| s.read_export_field())
}

Expand All @@ -34,13 +36,13 @@ impl<R: ParserReader> BinaryParser<R> {
}
}

fn read_export_field(&mut self) -> Result<ExportField<Resolved>> {
fn read_export_field(&mut self) -> Result<ExportField<Resolved, Unvalidated>> {
pctx!(self, "read exprt field");
let location = self.location();
Ok(ExportField {
name: self.read_name()?,
exportdesc: self.read_export_desc()?,
Ok(ExportField::new(
self.read_name()?,
self.read_export_desc()?,
location,
})
))
}
}
8 changes: 5 additions & 3 deletions wrausmt-format/src/binary/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use {
tracer::{TraceDropper, Tracer},
true_or::TrueOr,
},
wrausmt_runtime::syntax::{location::Location, TypeUse, UncompiledExpr},
wrausmt_runtime::syntax::{location::Location, TypeUse, UncompiledExpr, Unvalidated},
};

pub mod error;
Expand Down Expand Up @@ -52,7 +52,7 @@ pub trait ParserReader: Read + Locate {}
impl<R: ParserReader> BinaryParser<R> {
/// Inner parse method accepts a mutable module, so that the outer parse
/// method can return partial module results (useful for debugging).
fn parse(&mut self) -> Result<Module<Resolved, UncompiledExpr<Resolved>>> {
fn parse(&mut self) -> Result<Module<Resolved, Unvalidated, UncompiledExpr<Resolved>>> {
let mut module = Module::default();

self.read_magic()
Expand Down Expand Up @@ -207,7 +207,9 @@ impl<T: ParserReader> ParserReader for BinaryParser<T> {}
/// Attempt to interpret the data in the provided std::io:Read as a WASM binary
/// module. If an error occurs, a ParseError will be returned containing the
/// portion of the module that was successfully decoded.
pub fn parse_wasm_data(src: &mut impl Read) -> Result<Module<Resolved, UncompiledExpr<Resolved>>> {
pub fn parse_wasm_data(
src: &mut impl Read,
) -> Result<Module<Resolved, Unvalidated, UncompiledExpr<Resolved>>> {
let reader = ReadWithLocation::new(src);
let mut parser = BinaryParser::new(reader);
parser.parse()
Expand Down
11 changes: 5 additions & 6 deletions wrausmt-format/src/binary/start.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
use {
super::{error::Result, BinaryParser, ParserReader},
crate::{binary::read_with_location::Locate, pctx},
wrausmt_runtime::syntax::{Resolved, StartField},
wrausmt_runtime::syntax::{Resolved, StartField, Unvalidated},
};

/// Read the tables section of a binary module from a std::io::Read.
impl<R: ParserReader> BinaryParser<R> {
/// Read a funcs section. This is just a vec(TypeIndex).
/// The values here don't correspond to a real module section, instead they
/// correlate with the rest of the function data in the code section.
pub(in crate::binary) fn read_start_section(&mut self) -> Result<StartField<Resolved>> {
pub(in crate::binary) fn read_start_section(
&mut self,
) -> Result<StartField<Resolved, Unvalidated>> {
pctx!(self, "read start");
let location = self.location();
Ok(StartField {
idx: self.read_index_use()?,
location,
})
Ok(StartField::new(self.read_index_use()?, location))
}
}
38 changes: 17 additions & 21 deletions wrausmt-format/src/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use {
wrausmt_runtime::syntax::{
location::Location, types::NumType, CompiledExpr, DataField, DataInit, ElemField, ElemList,
ExportDesc, ExportField, FuncField, FuncIndex, GlobalField, Index, ModeEntry, Module,
Resolved, StartField, TablePosition, UncompiledExpr,
Resolved, StartField, TablePosition, UncompiledExpr, Unvalidated, Validated,
},
};

Expand All @@ -31,8 +31,8 @@ impl<T> ToValidationError<Result<T>> for KindResult<T> {
// need to do anything else with it later.
pub fn compile_module(
validation_mode: ValidationMode,
module: Module<Resolved, UncompiledExpr<Resolved>>,
) -> Result<Module<Resolved, CompiledExpr>> {
module: Module<Resolved, Unvalidated, UncompiledExpr<Resolved>>,
) -> Result<Module<Resolved, Validated, CompiledExpr>> {
// We need to create this now and hold onto it, beacuse the module will
// change as we process its elements.
let mut funcrefs: Vec<Index<Resolved, FuncIndex>> = Vec::new();
Expand Down Expand Up @@ -62,7 +62,7 @@ pub fn compile_module(

let exports: Result<Vec<_>> = std::mem::take(&mut module.exports)
.into_iter()
.map(|e| compile_export(&module_context, &mut funcrefs, e))
.map(|e| validate_export(&module_context, &mut funcrefs, e))
.collect();
let exports = exports?;

Expand All @@ -73,7 +73,7 @@ pub fn compile_module(
.collect();
let funcs = funcs?;

let start = compile_start(&module_context, module.start)?;
let start = validate_start(&module_context, module.start)?;

Ok(Module {
id: module.id,
Expand Down Expand Up @@ -170,24 +170,23 @@ fn compile_data(
})
}

// TODO - We need to add a validated type marker as well.
fn compile_export(
fn validate_export(
module: &ModuleContext,
funcrefs: &mut Vec<Index<Resolved, FuncIndex>>,
export: ExportField<Resolved>,
) -> Result<ExportField<Resolved>> {
Ok(ExportField {
name: export.name,
exportdesc: compile_export_desc(module, funcrefs, export.exportdesc)
export: ExportField<Resolved, Unvalidated>,
) -> Result<ExportField<Resolved, Validated>> {
Ok(ExportField::new(
export.name,
compile_export_desc(module, funcrefs, export.exportdesc)
.validation_error(export.location)?,
location: export.location,
})
export.location,
))
}

fn compile_start(
fn validate_start(
module: &ModuleContext,
start: Option<StartField<Resolved>>,
) -> Result<Option<StartField<Resolved>>> {
start: Option<StartField<Resolved, Unvalidated>>,
) -> Result<Option<StartField<Resolved, Validated>>> {
match start {
Some(start) => {
let f = (module.funcs.get(start.idx.value() as usize))
Expand All @@ -196,10 +195,7 @@ fn compile_start(
(f.params.is_empty() && f.results.is_empty())
.true_or(ValidationErrorKind::WrongStartFunctionType)
.validation_error(start.location)?;
Ok(Some(StartField {
idx: start.idx,
location: start.location,
}))
Ok(Some(StartField::new(start.idx, start.location)))
}
None => Ok(None),
}
Expand Down
4 changes: 2 additions & 2 deletions wrausmt-format/src/compiler/validation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use {
location::Location,
types::{GlobalType, MemType, RefType, TableType, ValueType},
FuncIndex, ImportDesc, Index, Instruction, LocalIndex, Module, Resolved,
UncompiledExpr,
UncompiledExpr, Unvalidated,
},
},
};
Expand Down Expand Up @@ -165,7 +165,7 @@ impl ModuleContext {
/// Create a new [`ModuleContext`] for validation, using the type
/// information in the provided [`Module`]. The informatin will be copied
/// out of the module.
pub fn new(module: &Module<Resolved, UncompiledExpr<Resolved>>) -> Result<Self> {
pub fn new(module: &Module<Resolved, Unvalidated, UncompiledExpr<Resolved>>) -> Result<Self> {
let mut funcs: Vec<FunctionType> = Vec::new();
let mut tables: Vec<TableType> = Vec::new();
let mut mems: Vec<MemType> = Vec::new();
Expand Down
4 changes: 2 additions & 2 deletions wrausmt-format/src/text/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
self::parse::Parser,
super::text::parse::error::Result,
std::io::Read,
wrausmt_runtime::syntax::{Module, Resolved, UncompiledExpr, Unresolved},
wrausmt_runtime::syntax::{Module, Resolved, UncompiledExpr, Unresolved, Unvalidated},
};

pub mod lex;
Expand All @@ -17,7 +17,7 @@ pub mod string;

pub fn parse_wast_data(
reader: &mut impl Read,
) -> Result<Module<Resolved, UncompiledExpr<Resolved>>> {
) -> Result<Module<Resolved, Unvalidated, UncompiledExpr<Resolved>>> {
let mut parser = Parser::new(reader);
parser.parse_full_module()
}
Expand Down
Loading

0 comments on commit 3824144

Please sign in to comment.