Hide validation stuff.

This commit is contained in:
Sergey Pepyakin 2018-01-22 16:11:20 +03:00
parent 469e9ef6b1
commit aae9a3c129
5 changed files with 90 additions and 40 deletions

View File

@ -10,10 +10,15 @@ extern crate byteorder;
use std::fmt; use std::fmt;
use std::error; use std::error;
use std::path::Path;
use std::collections::HashMap;
use parity_wasm::elements::Module;
/// Internal interpreter error. /// Internal interpreter error.
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// Module validation error. Might occur only at load time.
Validation(String),
/// Error while instantiating a module. Might occur when provided /// Error while instantiating a module. Might occur when provided
/// with incorrect exports (i.e. linkage failure). /// with incorrect exports (i.e. linkage failure).
Instantiation(String), Instantiation(String),
@ -38,6 +43,7 @@ pub enum Error {
impl Into<String> for Error { impl Into<String> for Error {
fn into(self) -> String { fn into(self) -> String {
match self { match self {
Error::Validation(s) => s,
Error::Instantiation(s) => s, Error::Instantiation(s) => s,
Error::Function(s) => s, Error::Function(s) => s,
Error::Table(s) => s, Error::Table(s) => s,
@ -54,6 +60,7 @@ impl Into<String> for Error {
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
Error::Validation(ref s) => write!(f, "Validation: {}", s),
Error::Instantiation(ref s) => write!(f, "Instantiation: {}", s), Error::Instantiation(ref s) => write!(f, "Instantiation: {}", s),
Error::Function(ref s) => write!(f, "Function: {}", s), Error::Function(ref s) => write!(f, "Function: {}", s),
Error::Table(ref s) => write!(f, "Table: {}", s), Error::Table(ref s) => write!(f, "Table: {}", s),
@ -72,6 +79,7 @@ impl fmt::Display for Error {
impl error::Error for Error { impl error::Error for Error {
fn description(&self) -> &str { fn description(&self) -> &str {
match *self { match *self {
Error::Validation(ref s) => s,
Error::Instantiation(ref s) => s, Error::Instantiation(ref s) => s,
Error::Function(ref s) => s, Error::Function(ref s) => s,
Error::Table(ref s) => s, Error::Table(ref s) => s,
@ -85,12 +93,19 @@ impl error::Error for Error {
} }
} }
impl<U> From<U> for Error where U: host::HostError + Sized { impl<U> From<U> for Error where U: host::HostError + Sized {
fn from(e: U) -> Self { fn from(e: U) -> Self {
Error::Host(Box::new(e)) Error::Host(Box::new(e))
} }
} }
impl From<validation::Error> for Error {
fn from(e: validation::Error) -> Error {
Error::Validation(e.to_string())
}
}
impl From<::common::stack::Error> for Error { impl From<::common::stack::Error> for Error {
fn from(e: ::common::stack::Error) -> Self { fn from(e: ::common::stack::Error) -> Self {
Error::Stack(e.to_string()) 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::global::{GlobalInstance, GlobalRef};
pub use self::func::{FuncInstance, FuncRef}; pub use self::func::{FuncInstance, FuncRef};
pub use self::types::{Signature, ValueType}; pub use self::types::{Signature, ValueType};
pub struct LoadedModule {
labels: HashMap<usize, HashMap<usize, usize>>,
module: Module,
}
impl LoadedModule {
pub(crate) fn module(&self) -> &Module {
&self.module
}
pub(crate) fn labels(&self) -> &HashMap<usize, HashMap<usize, usize>> {
&self.labels
}
pub fn into_module(self) -> Module {
self.module
}
}
pub fn load_from_module(module: Module) -> Result<LoadedModule, Error> {
use validation::{validate_module, ValidatedModule};
let ValidatedModule {
labels,
module,
} = validate_module(module)?;
Ok(LoadedModule {
labels,
module,
})
}
pub fn load_from_buffer<B: AsRef<[u8]>>(buffer: B) -> Result<LoadedModule, Error> {
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)
}

View File

@ -4,14 +4,13 @@ use std::fmt;
use std::collections::HashMap; use std::collections::HashMap;
use std::borrow::Cow; use std::borrow::Cow;
use parity_wasm::elements::{External, InitExpr, Internal, Opcode, ResizableLimits, Type}; 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 imports::ImportResolver;
use global::{GlobalInstance, GlobalRef}; use global::{GlobalInstance, GlobalRef};
use func::{FuncRef, FuncBody, FuncInstance}; use func::{FuncRef, FuncBody, FuncInstance};
use table::TableRef; use table::TableRef;
use memory::MemoryRef; use memory::MemoryRef;
use host::Externals; use host::Externals;
use validation::ValidatedModule;
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -158,10 +157,10 @@ impl ModuleInstance {
} }
fn alloc_module( fn alloc_module(
validated_module: &ValidatedModule, loaded_module: &LoadedModule,
extern_vals: &[ExternVal] extern_vals: &[ExternVal]
) -> Result<ModuleRef, Error> { ) -> Result<ModuleRef, Error> {
let module = validated_module.module(); let module = loaded_module.module();
let instance = ModuleRef(Rc::new(ModuleInstance::default())); let instance = ModuleRef(Rc::new(ModuleInstance::default()));
for &Type::Function(ref ty) in module.type_section().map(|ts| ts.types()).unwrap_or(&[]) { 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( let funcs = module.function_section().map(|fs| fs.entries()).unwrap_or(
&[], &[],
@ -327,12 +326,12 @@ impl ModuleInstance {
} }
fn instantiate_with_externvals( fn instantiate_with_externvals(
validated_module: &ValidatedModule, loaded_module: &LoadedModule,
extern_vals: &[ExternVal], extern_vals: &[ExternVal],
) -> Result<ModuleRef, Error> { ) -> Result<ModuleRef, Error> {
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( 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>( pub fn new<'m, I: ImportResolver>(
validated_module: &'m ValidatedModule, loaded_module: &'m LoadedModule,
imports: &I, imports: &I,
) -> Result<NotStartedModuleRef<'m>, Error> { ) -> Result<NotStartedModuleRef<'m>, Error> {
let module = validated_module.module(); let module = loaded_module.module();
let mut extern_vals = Vec::new(); let mut extern_vals = Vec::new();
for import_entry in module.import_section().map(|s| s.entries()).unwrap_or(&[]) { for import_entry in module.import_section().map(|s| s.entries()).unwrap_or(&[]) {
@ -406,9 +405,9 @@ impl ModuleInstance {
extern_vals.push(extern_val); 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 { Ok(NotStartedModuleRef {
validated_module, loaded_module,
instance, instance,
}) })
} }
@ -439,7 +438,7 @@ impl ModuleInstance {
} }
pub struct NotStartedModuleRef<'a> { pub struct NotStartedModuleRef<'a> {
validated_module: &'a ValidatedModule, loaded_module: &'a LoadedModule,
instance: ModuleRef, instance: ModuleRef,
} }
@ -449,7 +448,7 @@ impl<'a> NotStartedModuleRef<'a> {
} }
pub fn run_start<'b, E: Externals>(self, state: &'b mut E) -> Result<ModuleRef, Error> { pub fn run_start<'b, E: Externals>(self, state: &'b mut E) -> Result<ModuleRef, Error> {
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( let start_func = self.instance.func_by_index(start_fn_idx).expect(
"Due to validation start function should exists", "Due to validation start function should exists",
); );
@ -459,7 +458,7 @@ impl<'a> NotStartedModuleRef<'a> {
} }
pub fn assert_no_start(self) -> ModuleRef { 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 self.instance
} }
} }

View File

@ -1,10 +1,9 @@
use parity_wasm::elements::{deserialize_buffer, MemoryType, TableType}; use parity_wasm::elements::{deserialize_buffer, MemoryType, TableType};
use validation::{validate_module, ValidatedModule};
use { use {
Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder,
MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef, MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef,
RuntimeValue, TryInto, RuntimeValue, TryInto, LoadedModule, load_from_buffer,
}; };
use types::ValueType; use types::ValueType;
use wabt::wat2wasm; 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 wasm_binary = wat2wasm(source).expect("Failed to parse wat source");
let module = deserialize_buffer(&wasm_binary).expect("Failed to deserialize module"); load_from_buffer(wasm_binary).expect("Failed to load parsed module")
let validated_module = validate_module(module).expect("Failed to validate module");
validated_module
} }
#[test] #[test]

View File

@ -1,9 +1,10 @@
use parity_wasm::elements::deserialize_file;
use parity_wasm::elements::{GlobalType, MemoryType, Module, TableType}; use parity_wasm::elements::{GlobalType, MemoryType, Module, TableType};
use {Error, Signature, FuncRef, GlobalInstance, GlobalRef, ImportsBuilder, MemoryInstance, use {
Error, Signature, FuncRef, GlobalInstance, GlobalRef, ImportsBuilder, MemoryInstance,
MemoryRef, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue, MemoryRef, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue,
TableInstance, TableRef}; TableInstance, TableRef, LoadedModule, load_from_buffer,
use validation::validate_module; };
use std::fs::File;
struct Env { struct Env {
table_base: GlobalRef, 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] #[test]
fn interpreter_inc_i32() { fn interpreter_inc_i32() {
// Name of function contained in WASM file (note the leading underline) // 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 // The WASM file containing the module and function
const WASM_FILE: &str = &"res/cases/v1/inc_i32.wasm"; const WASM_FILE: &str = &"res/cases/v1/inc_i32.wasm";
let module: Module = let module = load_from_file(WASM_FILE);
deserialize_file(WASM_FILE).expect("Failed to deserialize module from buffer");
let validated_module = validate_module(module).expect("Failed to validate module");
let env = Env::new(); let env = Env::new();
let instance = ModuleInstance::new( let instance = ModuleInstance::new(
&validated_module, &module,
&ImportsBuilder::new().with_resolver("env", &env), &ImportsBuilder::new().with_resolver("env", &env),
).expect("Failed to instantiate module") ).expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();
@ -110,13 +117,11 @@ fn interpreter_accumulate_u8() {
// Load the module-structure from wasm-file and add to program // Load the module-structure from wasm-file and add to program
let module: Module = let module = load_from_file(WASM_FILE);
deserialize_file(WASM_FILE).expect("Failed to deserialize module from buffer");
let validated_module = validate_module(module).expect("Failed to validate module");
let env = Env::new(); let env = Env::new();
let instance = ModuleInstance::new( let instance = ModuleInstance::new(
&validated_module, &module,
&ImportsBuilder::new().with_resolver("env", &env), &ImportsBuilder::new().with_resolver("env", &env),
).expect("Failed to instantiate module") ).expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();

View File

@ -38,8 +38,8 @@ impl From<stack::Error> for Error {
#[derive(Clone)] #[derive(Clone)]
pub struct ValidatedModule { pub struct ValidatedModule {
labels: HashMap<usize, HashMap<usize, usize>>, pub labels: HashMap<usize, HashMap<usize, usize>>,
module: Module, pub module: Module,
} }
impl ValidatedModule { impl ValidatedModule {
@ -50,10 +50,6 @@ impl ValidatedModule {
pub fn into_module(self) -> Module { pub fn into_module(self) -> Module {
self.module self.module
} }
pub(crate) fn labels(&self) -> &HashMap<usize, HashMap<usize, usize>> {
&self.labels
}
} }
impl ::std::ops::Deref for ValidatedModule { impl ::std::ops::Deref for ValidatedModule {