Make Module::new perform validation. (#621)

* Make `Module::new` perform validation.

As noticed in #602, `Module::new` did not perform validation, which
turns out to be error-prone in practice. Rename it to
`Module::new_unchecked`, and add a new `Module::new` which does
perform validation.

Preserve wasm-c-api's `wasm_module_new`'s behavior by using
`Module::new_unchecked`, and implement `wasm_module_validate`.

* Change `validate`'s store argument to `&HostRef<Store>`.

* Enable multi-value in validation.
This commit is contained in:
Dan Gohman
2019-11-27 08:58:38 -08:00
committed by Yury Delendik
parent e71ab6b846
commit 16b8b3e58d
2 changed files with 37 additions and 5 deletions

View File

@@ -4,8 +4,11 @@ use crate::types::{
ExportType, ExternType, FuncType, GlobalType, ImportType, Limits, MemoryType, Mutability, ExportType, ExternType, FuncType, GlobalType, ImportType, Limits, MemoryType, Mutability,
TableType, ValType, TableType, ValType,
}; };
use anyhow::Result; use anyhow::{Error, Result};
use wasmparser::{validate, ExternalKind, ImportSectionEntryType, ModuleReader, SectionCode}; use wasmparser::{
validate, ExternalKind, ImportSectionEntryType, ModuleReader, OperatorValidatorConfig,
SectionCode, ValidatingParserConfig,
};
fn into_memory_type(mt: wasmparser::MemoryType) -> MemoryType { fn into_memory_type(mt: wasmparser::MemoryType) -> MemoryType {
assert!(!mt.shared); assert!(!mt.shared);
@@ -184,7 +187,15 @@ pub struct Module {
} }
impl Module { impl Module {
/// Validate and decode the raw wasm data in `binary` and create a new
/// `Module` in the given `store`.
pub fn new(store: &HostRef<Store>, binary: &[u8]) -> Result<Module> { pub fn new(store: &HostRef<Store>, binary: &[u8]) -> Result<Module> {
Self::validate(store, binary)?;
Self::new_unchecked(store, binary)
}
/// Similar to `new`, but does not perform any validation. Only use this
/// on modules which are known to have been validated already!
pub fn new_unchecked(store: &HostRef<Store>, binary: &[u8]) -> Result<Module> {
let (imports, exports) = read_imports_and_exports(binary)?; let (imports, exports) = read_imports_and_exports(binary)?;
Ok(Module { Ok(Module {
store: store.clone(), store: store.clone(),
@@ -199,8 +210,17 @@ impl Module {
_ => None, _ => None,
} }
} }
pub fn validate(_store: &Store, binary: &[u8]) -> bool { pub fn validate(_store: &HostRef<Store>, binary: &[u8]) -> Result<()> {
validate(binary, None).is_ok() let config = ValidatingParserConfig {
operator_config: OperatorValidatorConfig {
enable_threads: false,
enable_reference_types: false,
enable_bulk_memory: false,
enable_simd: false,
enable_multi_value: true,
},
};
validate(binary, Some(config)).map_err(Error::new)
} }
pub fn imports(&self) -> &[ImportType] { pub fn imports(&self) -> &[ImportType] {
&self.imports &self.imports

View File

@@ -722,6 +722,8 @@ impl wasm_name_t {
} }
} }
/// Note that this function does not perform validation on the wasm
/// binary. To perform validation, use `wasm_module_validate`.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_module_new( pub unsafe extern "C" fn wasm_module_new(
store: *mut wasm_store_t, store: *mut wasm_store_t,
@@ -729,7 +731,7 @@ pub unsafe extern "C" fn wasm_module_new(
) -> *mut wasm_module_t { ) -> *mut wasm_module_t {
let binary = (*binary).as_slice(); let binary = (*binary).as_slice();
let store = &(*store).store; let store = &(*store).store;
let module = Module::new(store, binary).expect("module"); let module = Module::new_unchecked(store, binary).expect("module");
let imports = module let imports = module
.imports() .imports()
.iter() .iter()
@@ -756,6 +758,16 @@ pub unsafe extern "C" fn wasm_module_new(
Box::into_raw(module) Box::into_raw(module)
} }
#[no_mangle]
pub unsafe extern "C" fn wasm_module_validate(
store: *mut wasm_store_t,
binary: *const wasm_byte_vec_t,
) -> bool {
let binary = (*binary).as_slice();
let store = &(*store).store;
Module::validate(store, binary).is_ok()
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_store_delete(store: *mut wasm_store_t) { pub unsafe extern "C" fn wasm_store_delete(store: *mut wasm_store_t) {
let _ = Box::from_raw(store); let _ = Box::from_raw(store);