diff --git a/src/lib.rs b/src/lib.rs index 4e7ead5..b71af66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,10 +10,15 @@ extern crate byteorder; use std::fmt; use std::error; +use std::path::Path; +use std::collections::HashMap; +use parity_wasm::elements::Module; /// Internal interpreter error. #[derive(Debug)] pub enum Error { + /// Module validation error. Might occur only at load time. + Validation(String), /// Error while instantiating a module. Might occur when provided /// with incorrect exports (i.e. linkage failure). Instantiation(String), @@ -38,6 +43,7 @@ pub enum Error { impl Into for Error { fn into(self) -> String { match self { + Error::Validation(s) => s, Error::Instantiation(s) => s, Error::Function(s) => s, Error::Table(s) => s, @@ -54,6 +60,7 @@ impl Into for Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { + Error::Validation(ref s) => write!(f, "Validation: {}", s), Error::Instantiation(ref s) => write!(f, "Instantiation: {}", s), Error::Function(ref s) => write!(f, "Function: {}", s), Error::Table(ref s) => write!(f, "Table: {}", s), @@ -72,6 +79,7 @@ impl fmt::Display for Error { impl error::Error for Error { fn description(&self) -> &str { match *self { + Error::Validation(ref s) => s, Error::Instantiation(ref s) => s, Error::Function(ref s) => s, Error::Table(ref s) => s, @@ -85,12 +93,19 @@ impl error::Error for Error { } } + impl From for Error where U: host::HostError + Sized { fn from(e: U) -> Self { Error::Host(Box::new(e)) } } +impl From for Error { + fn from(e: validation::Error) -> Error { + Error::Validation(e.to_string()) + } +} + impl From<::common::stack::Error> for Error { fn from(e: ::common::stack::Error) -> Self { Error::Stack(e.to_string()) @@ -122,3 +137,41 @@ pub use self::module::{ModuleInstance, ModuleRef, ExternVal, NotStartedModuleRef pub use self::global::{GlobalInstance, GlobalRef}; pub use self::func::{FuncInstance, FuncRef}; pub use self::types::{Signature, ValueType}; + +pub struct LoadedModule { + labels: HashMap>, + module: Module, +} + +impl LoadedModule { + pub(crate) fn module(&self) -> &Module { + &self.module + } + + pub(crate) fn labels(&self) -> &HashMap> { + &self.labels + } + + pub fn into_module(self) -> Module { + self.module + } +} + +pub fn load_from_module(module: Module) -> Result { + use validation::{validate_module, ValidatedModule}; + let ValidatedModule { + labels, + module, + } = validate_module(module)?; + + Ok(LoadedModule { + labels, + module, + }) +} + +pub fn load_from_buffer>(buffer: B) -> Result { + let module = parity_wasm::elements::deserialize_buffer(buffer.as_ref()) + .map_err(|e: parity_wasm::elements::Error| Error::Validation(e.to_string()))?; + load_from_module(module) +} diff --git a/src/module.rs b/src/module.rs index 629304c..857bbe3 100644 --- a/src/module.rs +++ b/src/module.rs @@ -4,14 +4,13 @@ use std::fmt; use std::collections::HashMap; use std::borrow::Cow; use parity_wasm::elements::{External, InitExpr, Internal, Opcode, ResizableLimits, Type}; -use {Error, Signature, MemoryInstance, RuntimeValue, TableInstance}; +use {LoadedModule, Error, Signature, MemoryInstance, RuntimeValue, TableInstance}; use imports::ImportResolver; use global::{GlobalInstance, GlobalRef}; use func::{FuncRef, FuncBody, FuncInstance}; use table::TableRef; use memory::MemoryRef; use host::Externals; -use validation::ValidatedModule; use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; #[derive(Clone, Debug)] @@ -158,10 +157,10 @@ impl ModuleInstance { } fn alloc_module( - validated_module: &ValidatedModule, + loaded_module: &LoadedModule, extern_vals: &[ExternVal] ) -> Result { - let module = validated_module.module(); + let module = loaded_module.module(); let instance = ModuleRef(Rc::new(ModuleInstance::default())); for &Type::Function(ref ty) in module.type_section().map(|ts| ts.types()).unwrap_or(&[]) { @@ -227,7 +226,7 @@ impl ModuleInstance { } } - let labels = validated_module.labels(); + let labels = loaded_module.labels(); { let funcs = module.function_section().map(|fs| fs.entries()).unwrap_or( &[], @@ -327,12 +326,12 @@ impl ModuleInstance { } fn instantiate_with_externvals( - validated_module: &ValidatedModule, + loaded_module: &LoadedModule, extern_vals: &[ExternVal], ) -> Result { - let module = validated_module.module(); + let module = loaded_module.module(); - let module_ref = ModuleInstance::alloc_module(validated_module, extern_vals)?; + let module_ref = ModuleInstance::alloc_module(loaded_module, extern_vals)?; for element_segment in module.elements_section().map(|es| es.entries()).unwrap_or( &[], @@ -371,10 +370,10 @@ impl ModuleInstance { } pub fn new<'m, I: ImportResolver>( - validated_module: &'m ValidatedModule, + loaded_module: &'m LoadedModule, imports: &I, ) -> Result, Error> { - let module = validated_module.module(); + let module = loaded_module.module(); let mut extern_vals = Vec::new(); for import_entry in module.import_section().map(|s| s.entries()).unwrap_or(&[]) { @@ -406,9 +405,9 @@ impl ModuleInstance { extern_vals.push(extern_val); } - let instance = Self::instantiate_with_externvals(validated_module, &extern_vals)?; + let instance = Self::instantiate_with_externvals(loaded_module, &extern_vals)?; Ok(NotStartedModuleRef { - validated_module, + loaded_module, instance, }) } @@ -439,7 +438,7 @@ impl ModuleInstance { } pub struct NotStartedModuleRef<'a> { - validated_module: &'a ValidatedModule, + loaded_module: &'a LoadedModule, instance: ModuleRef, } @@ -449,7 +448,7 @@ impl<'a> NotStartedModuleRef<'a> { } pub fn run_start<'b, E: Externals>(self, state: &'b mut E) -> Result { - if let Some(start_fn_idx) = self.validated_module.module().start_section() { + if let Some(start_fn_idx) = self.loaded_module.module().start_section() { let start_func = self.instance.func_by_index(start_fn_idx).expect( "Due to validation start function should exists", ); @@ -459,7 +458,7 @@ impl<'a> NotStartedModuleRef<'a> { } pub fn assert_no_start(self) -> ModuleRef { - assert!(self.validated_module.module().start_section().is_none()); + assert!(self.loaded_module.module().start_section().is_none()); self.instance } } diff --git a/src/tests/host.rs b/src/tests/host.rs index f76e9a2..671c982 100644 --- a/src/tests/host.rs +++ b/src/tests/host.rs @@ -1,10 +1,9 @@ use parity_wasm::elements::{deserialize_buffer, MemoryType, TableType}; -use validation::{validate_module, ValidatedModule}; use { Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef, - RuntimeValue, TryInto, + RuntimeValue, TryInto, LoadedModule, load_from_buffer, }; use types::ValueType; use wabt::wat2wasm; @@ -204,11 +203,9 @@ impl ModuleImportResolver for TestHost { } } -fn parse_wat(source: &str) -> ValidatedModule { +fn parse_wat(source: &str) -> LoadedModule { let wasm_binary = wat2wasm(source).expect("Failed to parse wat source"); - let module = deserialize_buffer(&wasm_binary).expect("Failed to deserialize module"); - let validated_module = validate_module(module).expect("Failed to validate module"); - validated_module + load_from_buffer(wasm_binary).expect("Failed to load parsed module") } #[test] diff --git a/src/tests/wasm.rs b/src/tests/wasm.rs index 22935a5..09929ba 100644 --- a/src/tests/wasm.rs +++ b/src/tests/wasm.rs @@ -1,9 +1,10 @@ -use parity_wasm::elements::deserialize_file; use parity_wasm::elements::{GlobalType, MemoryType, Module, TableType}; -use {Error, Signature, FuncRef, GlobalInstance, GlobalRef, ImportsBuilder, MemoryInstance, - MemoryRef, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue, - TableInstance, TableRef}; -use validation::validate_module; +use { + Error, Signature, FuncRef, GlobalInstance, GlobalRef, ImportsBuilder, MemoryInstance, + MemoryRef, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue, + TableInstance, TableRef, LoadedModule, load_from_buffer, +}; +use std::fs::File; struct Env { table_base: GlobalRef, @@ -69,6 +70,14 @@ impl ModuleImportResolver for Env { } } +fn load_from_file(filename: &str) -> LoadedModule { + use std::io::prelude::*; + let mut file = File::open(filename).unwrap(); + let mut buf = Vec::new(); + file.read_to_end(&mut buf).unwrap(); + load_from_buffer(buf).unwrap() +} + #[test] fn interpreter_inc_i32() { // Name of function contained in WASM file (note the leading underline) @@ -76,14 +85,12 @@ fn interpreter_inc_i32() { // The WASM file containing the module and function const WASM_FILE: &str = &"res/cases/v1/inc_i32.wasm"; - let module: Module = - deserialize_file(WASM_FILE).expect("Failed to deserialize module from buffer"); - let validated_module = validate_module(module).expect("Failed to validate module"); + let module = load_from_file(WASM_FILE); let env = Env::new(); let instance = ModuleInstance::new( - &validated_module, + &module, &ImportsBuilder::new().with_resolver("env", &env), ).expect("Failed to instantiate module") .assert_no_start(); @@ -110,13 +117,11 @@ fn interpreter_accumulate_u8() { // Load the module-structure from wasm-file and add to program - let module: Module = - deserialize_file(WASM_FILE).expect("Failed to deserialize module from buffer"); - let validated_module = validate_module(module).expect("Failed to validate module"); + let module = load_from_file(WASM_FILE); let env = Env::new(); let instance = ModuleInstance::new( - &validated_module, + &module, &ImportsBuilder::new().with_resolver("env", &env), ).expect("Failed to instantiate module") .assert_no_start(); diff --git a/src/validation/mod.rs b/src/validation/mod.rs index 9261d8c..5f56627 100644 --- a/src/validation/mod.rs +++ b/src/validation/mod.rs @@ -38,8 +38,8 @@ impl From for Error { #[derive(Clone)] pub struct ValidatedModule { - labels: HashMap>, - module: Module, + pub labels: HashMap>, + pub module: Module, } impl ValidatedModule { @@ -50,10 +50,6 @@ impl ValidatedModule { pub fn into_module(self) -> Module { self.module } - - pub(crate) fn labels(&self) -> &HashMap> { - &self.labels - } } impl ::std::ops::Deref for ValidatedModule {