Enable fuzzing the module linking implementation

This commit updates all the wasm-tools crates that we use and enables
fuzzing of the module linking proposal in our various fuzz targets. This
also refactors some of the dummy value generation logic to not be
fallible and to always succeed, the thinking being that we don't want to
accidentally hide errors while fuzzing. Additionally instantiation is
only allowed to fail with a `Trap`, other failure reasons are unwrapped.
This commit is contained in:
Alex Crichton
2020-12-07 15:57:35 -08:00
parent e09b9400f8
commit 25000afe69
22 changed files with 377 additions and 152 deletions

60
Cargo.lock generated
View File

@@ -394,7 +394,7 @@ dependencies = [
"souper-ir", "souper-ir",
"target-lexicon", "target-lexicon",
"thiserror", "thiserror",
"wast 28.0.0", "wast 29.0.0",
] ]
[[package]] [[package]]
@@ -597,7 +597,7 @@ dependencies = [
"smallvec", "smallvec",
"target-lexicon", "target-lexicon",
"thiserror", "thiserror",
"wasmparser 0.69.2", "wasmparser 0.70.0",
"wat", "wat",
] ]
@@ -1167,7 +1167,7 @@ dependencies = [
"smallvec", "smallvec",
"thiserror", "thiserror",
"typemap", "typemap",
"wasmparser 0.69.2", "wasmparser 0.70.0",
"wat", "wat",
] ]
@@ -1411,7 +1411,7 @@ dependencies = [
"peepmatic-test-operator", "peepmatic-test-operator",
"peepmatic-traits", "peepmatic-traits",
"serde", "serde",
"wast 28.0.0", "wast 29.0.0",
"z3", "z3",
] ]
@@ -1439,7 +1439,7 @@ dependencies = [
"peepmatic-traits", "peepmatic-traits",
"rand", "rand",
"serde", "serde",
"wast 28.0.0", "wast 29.0.0",
] ]
[[package]] [[package]]
@@ -1464,7 +1464,7 @@ dependencies = [
"serde", "serde",
"serde_test", "serde_test",
"thiserror", "thiserror",
"wast 28.0.0", "wast 29.0.0",
] ]
[[package]] [[package]]
@@ -1476,7 +1476,7 @@ dependencies = [
"peepmatic", "peepmatic",
"peepmatic-test-operator", "peepmatic-test-operator",
"souper-ir", "souper-ir",
"wast 28.0.0", "wast 29.0.0",
] ]
[[package]] [[package]]
@@ -1497,7 +1497,7 @@ version = "0.68.0"
dependencies = [ dependencies = [
"peepmatic-traits", "peepmatic-traits",
"serde", "serde",
"wast 28.0.0", "wast 29.0.0",
] ]
[[package]] [[package]]
@@ -2356,18 +2356,18 @@ dependencies = [
[[package]] [[package]]
name = "wasm-encoder" name = "wasm-encoder"
version = "0.1.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49891b7c581cf9e0090b25cd274e6498ad478f0a7819319ea96da2f253caaacb" checksum = "ed89eaf99e08b84f96e477a16588a07dd3b51dc5f07291c3706782f62a10a5e1"
dependencies = [ dependencies = [
"leb128", "leb128",
] ]
[[package]] [[package]]
name = "wasm-smith" name = "wasm-smith"
version = "0.1.12" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fdf8c9ba2fdc0d8ffe3f7e5b23b5aac377eeca817a9885c058f27c8de5c500" checksum = "cdd382e46cf44347f4d0c29122143cbab85cf248b9a8f680845c0239b6842a85"
dependencies = [ dependencies = [
"arbitrary", "arbitrary",
"leb128", "leb128",
@@ -2406,18 +2406,18 @@ checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6"
[[package]] [[package]]
name = "wasmparser" name = "wasmparser"
version = "0.69.2" version = "0.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd2dd6dadf3a723971297bcc0ec103e0aa8118bf68e23f49cb575e21621894a8" checksum = "ed1b3f9e9cf01a580b9f3281214dfdb1922b5dfb8494ee312ca03ae10036c2a2"
[[package]] [[package]]
name = "wasmprinter" name = "wasmprinter"
version = "0.2.16" version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dba006f5c5bf41a2a5c3b45e861ea6eb067382acb022b6a35a00a0390f9547f6" checksum = "f89b2b24dce17e27fe9c09c28331cbd77067fcde5c6ea2508ac84bcbd5d3e018"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"wasmparser 0.69.2", "wasmparser 0.70.0",
] ]
[[package]] [[package]]
@@ -2438,7 +2438,7 @@ dependencies = [
"smallvec", "smallvec",
"target-lexicon", "target-lexicon",
"tempfile", "tempfile",
"wasmparser 0.69.2", "wasmparser 0.70.0",
"wasmtime-cache", "wasmtime-cache",
"wasmtime-environ", "wasmtime-environ",
"wasmtime-jit", "wasmtime-jit",
@@ -2516,7 +2516,7 @@ dependencies = [
"test-programs", "test-programs",
"tracing-subscriber", "tracing-subscriber",
"wasi-common", "wasi-common",
"wasmparser 0.69.2", "wasmparser 0.70.0",
"wasmtime", "wasmtime",
"wasmtime-cache", "wasmtime-cache",
"wasmtime-debug", "wasmtime-debug",
@@ -2552,7 +2552,7 @@ dependencies = [
"object", "object",
"target-lexicon", "target-lexicon",
"thiserror", "thiserror",
"wasmparser 0.69.2", "wasmparser 0.70.0",
"wasmtime-environ", "wasmtime-environ",
] ]
@@ -2571,7 +2571,7 @@ dependencies = [
"more-asserts", "more-asserts",
"serde", "serde",
"thiserror", "thiserror",
"wasmparser 0.69.2", "wasmparser 0.70.0",
] ]
[[package]] [[package]]
@@ -2600,7 +2600,7 @@ dependencies = [
"rayon", "rayon",
"wasm-smith", "wasm-smith",
"wasmi", "wasmi",
"wasmparser 0.69.2", "wasmparser 0.70.0",
"wasmprinter", "wasmprinter",
"wasmtime", "wasmtime",
"wasmtime-wast", "wasmtime-wast",
@@ -2628,7 +2628,7 @@ dependencies = [
"serde", "serde",
"target-lexicon", "target-lexicon",
"thiserror", "thiserror",
"wasmparser 0.69.2", "wasmparser 0.70.0",
"wasmtime-cranelift", "wasmtime-cranelift",
"wasmtime-debug", "wasmtime-debug",
"wasmtime-environ", "wasmtime-environ",
@@ -2645,7 +2645,7 @@ version = "0.21.0"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"lightbeam", "lightbeam",
"wasmparser 0.69.2", "wasmparser 0.70.0",
"wasmtime-environ", "wasmtime-environ",
] ]
@@ -2752,7 +2752,7 @@ version = "0.21.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"wasmtime", "wasmtime",
"wast 28.0.0", "wast 29.0.0",
] ]
[[package]] [[package]]
@@ -2788,20 +2788,20 @@ dependencies = [
[[package]] [[package]]
name = "wast" name = "wast"
version = "28.0.0" version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c0586061bfacc035034672c8d760802b428ab4c80a92e2a392425c516df9be1" checksum = "dcf2268937131d63c3d833242bf5e075406f9ed868b4265f3280e15dac29ac18"
dependencies = [ dependencies = [
"leb128", "leb128",
] ]
[[package]] [[package]]
name = "wat" name = "wat"
version = "1.0.29" version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d55b5ec4f9d9396fa99abaafa0688597395e57827dffd89731412ae90c9bf" checksum = "0d11a88d953b298172d218d18f22853f4e6e12873b62755d05617b864d312c68"
dependencies = [ dependencies = [
"wast 28.0.0", "wast 29.0.0",
] ]
[[package]] [[package]]

View File

@@ -38,12 +38,12 @@ anyhow = "1.0.19"
target-lexicon = { version = "0.11.0", default-features = false } target-lexicon = { version = "0.11.0", default-features = false }
pretty_env_logger = "0.4.0" pretty_env_logger = "0.4.0"
file-per-thread-logger = "0.1.1" file-per-thread-logger = "0.1.1"
wat = "1.0.29" wat = "1.0.30"
libc = "0.2.60" libc = "0.2.60"
log = "0.4.8" log = "0.4.8"
rayon = "1.2.1" rayon = "1.2.1"
humantime = "2.0.0" humantime = "2.0.0"
wasmparser = "0.69.2" wasmparser = "0.70.0"
[dev-dependencies] [dev-dependencies]
env_logger = "0.8.1" env_logger = "0.8.1"

View File

@@ -30,7 +30,7 @@ peepmatic-traits = { path = "../peepmatic/crates/traits", optional = true, versi
peepmatic-runtime = { path = "../peepmatic/crates/runtime", optional = true, version = "0.68.0" } peepmatic-runtime = { path = "../peepmatic/crates/runtime", optional = true, version = "0.68.0" }
regalloc = { version = "0.0.31" } regalloc = { version = "0.0.31" }
souper-ir = { version = "2.1.0", optional = true } souper-ir = { version = "2.1.0", optional = true }
wast = { version = "28.0.0", optional = true } wast = { version = "29.0.0", optional = true }
# It is a goal of the cranelift-codegen crate to have minimal external dependencies. # It is a goal of the cranelift-codegen crate to have minimal external dependencies.
# Please don't add any unless they are essential to the task of creating binary # Please don't add any unless they are essential to the task of creating binary
# machine code. Integration tests that need external dependencies can be # machine code. Integration tests that need external dependencies can be

View File

@@ -15,7 +15,7 @@ peepmatic-macro = { version = "0.68.0", path = "crates/macro" }
peepmatic-runtime = { version = "0.68.0", path = "crates/runtime", features = ["construct"] } peepmatic-runtime = { version = "0.68.0", path = "crates/runtime", features = ["construct"] }
peepmatic-traits = { version = "0.68.0", path = "crates/traits" } peepmatic-traits = { version = "0.68.0", path = "crates/traits" }
serde = { version = "1.0.105", features = ["derive"] } serde = { version = "1.0.105", features = ["derive"] }
wast = "28.0.0" wast = "29.0.0"
z3 = { version = "0.7.1", features = ["static-link-z3"] } z3 = { version = "0.7.1", features = ["static-link-z3"] }
[dev-dependencies] [dev-dependencies]

View File

@@ -21,4 +21,4 @@ peepmatic-test-operator = { path = "../test-operator" }
peepmatic-traits = { path = "../traits" } peepmatic-traits = { path = "../traits" }
rand = { version = "0.7.3", features = ["small_rng"] } rand = { version = "0.7.3", features = ["small_rng"] }
serde = "1.0.106" serde = "1.0.106"
wast = "28.0.0" wast = "29.0.0"

View File

@@ -16,7 +16,7 @@ peepmatic-automata = { version = "0.68.0", path = "../automata", features = ["se
peepmatic-traits = { version = "0.68.0", path = "../traits" } peepmatic-traits = { version = "0.68.0", path = "../traits" }
serde = { version = "1.0.105", features = ["derive"] } serde = { version = "1.0.105", features = ["derive"] }
thiserror = "1.0.15" thiserror = "1.0.15"
wast = { version = "28.0.0", optional = true } wast = { version = "29.0.0", optional = true }
[dev-dependencies] [dev-dependencies]
peepmatic-test-operator = { version = "0.68.0", path = "../test-operator" } peepmatic-test-operator = { version = "0.68.0", path = "../test-operator" }

View File

@@ -16,4 +16,4 @@ log = "0.4.8"
[dev-dependencies] [dev-dependencies]
peepmatic = { path = "../..", version = "0.68.0" } peepmatic = { path = "../..", version = "0.68.0" }
peepmatic-test-operator = { version = "0.68.0", path = "../test-operator" } peepmatic-test-operator = { version = "0.68.0", path = "../test-operator" }
wast = "28.0.0" wast = "29.0.0"

View File

@@ -9,4 +9,4 @@ edition = "2018"
[dependencies] [dependencies]
peepmatic-traits = { version = "0.68.0", path = "../traits" } peepmatic-traits = { version = "0.68.0", path = "../traits" }
serde = { version = "1.0.105", features = ["derive"] } serde = { version = "1.0.105", features = ["derive"] }
wast = "28.0.0" wast = "29.0.0"

View File

@@ -12,7 +12,7 @@ keywords = ["webassembly", "wasm"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
wasmparser = { version = "0.69.2", default-features = false } wasmparser = { version = "0.70", default-features = false }
cranelift-codegen = { path = "../codegen", version = "0.68.0", default-features = false } cranelift-codegen = { path = "../codegen", version = "0.68.0", default-features = false }
cranelift-entity = { path = "../entity", version = "0.68.0" } cranelift-entity = { path = "../entity", version = "0.68.0" }
cranelift-frontend = { path = "../frontend", version = "0.68.0", default-features = false } cranelift-frontend = { path = "../frontend", version = "0.68.0", default-features = false }

View File

@@ -538,10 +538,10 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
} }
/********************************** Exception handing **********************************/ /********************************** Exception handing **********************************/
Operator::Try { .. } Operator::Try { .. }
| Operator::Catch | Operator::Catch { .. }
| Operator::BrOnExn { .. }
| Operator::Throw { .. } | Operator::Throw { .. }
| Operator::Rethrow => { | Operator::Unwind
| Operator::Rethrow { .. } => {
return Err(wasm_unsupported!( return Err(wasm_unsupported!(
"proposed exception handling operator {:?}", "proposed exception handling operator {:?}",
op op

View File

@@ -13,7 +13,7 @@ edition = "2018"
[dependencies] [dependencies]
gimli = "0.23.0" gimli = "0.23.0"
wasmparser = "0.69.2" wasmparser = "0.70"
object = { version = "0.22.0", default-features = false, features = ["read", "write"] } object = { version = "0.22.0", default-features = false, features = ["read", "write"] }
wasmtime-environ = { path = "../environ", version = "0.21.0" } wasmtime-environ = { path = "../environ", version = "0.21.0" }
target-lexicon = { version = "0.11.0", default-features = false } target-lexicon = { version = "0.11.0", default-features = false }

View File

@@ -16,7 +16,7 @@ anyhow = "1.0"
cranelift-codegen = { path = "../../cranelift/codegen", version = "0.68.0", features = ["enable-serde"] } cranelift-codegen = { path = "../../cranelift/codegen", version = "0.68.0", features = ["enable-serde"] }
cranelift-entity = { path = "../../cranelift/entity", version = "0.68.0", features = ["enable-serde"] } cranelift-entity = { path = "../../cranelift/entity", version = "0.68.0", features = ["enable-serde"] }
cranelift-wasm = { path = "../../cranelift/wasm", version = "0.68.0", features = ["enable-serde"] } cranelift-wasm = { path = "../../cranelift/wasm", version = "0.68.0", features = ["enable-serde"] }
wasmparser = "0.69.2" wasmparser = "0.70"
indexmap = { version = "1.0.2", features = ["serde-1"] } indexmap = { version = "1.0.2", features = ["serde-1"] }
thiserror = "1.0.4" thiserror = "1.0.4"
serde = { version = "1.0.94", features = ["derive"] } serde = { version = "1.0.94", features = ["derive"] }

View File

@@ -12,11 +12,11 @@ arbitrary = { version = "0.4.1", features = ["derive"] }
env_logger = "0.8.1" env_logger = "0.8.1"
log = "0.4.8" log = "0.4.8"
rayon = "1.2.1" rayon = "1.2.1"
wasmparser = "0.69.2" wasmparser = "0.70"
wasmprinter = "0.2.16" wasmprinter = "0.2.17"
wasmtime = { path = "../wasmtime" } wasmtime = { path = "../wasmtime" }
wasmtime-wast = { path = "../wast" } wasmtime-wast = { path = "../wast" }
wasm-smith = "0.1.12" wasm-smith = "0.2.0"
wasmi = "0.7.0" wasmi = "0.7.0"
[dev-dependencies] [dev-dependencies]

View File

@@ -38,6 +38,7 @@ pub fn fuzz_default_config(strategy: wasmtime::Strategy) -> anyhow::Result<wasmt
.cranelift_nan_canonicalization(true) .cranelift_nan_canonicalization(true)
.wasm_bulk_memory(true) .wasm_bulk_memory(true)
.wasm_reference_types(true) .wasm_reference_types(true)
.wasm_module_linking(true)
.strategy(strategy)?; .strategy(strategy)?;
Ok(config) Ok(config)
} }

View File

@@ -91,26 +91,15 @@ pub fn instantiate_with_config(wasm: &[u8], mut config: Config, timeout: Option<
} }
log_wasm(wasm); log_wasm(wasm);
let module = match Module::new(&engine, wasm) { let module = Module::new(&engine, wasm).unwrap();
Ok(module) => module, let imports = dummy_imports(&store, module.imports());
Err(_) => return,
};
let imports = match dummy_imports(&store, module.imports()) { match Instance::new(&store, &module, &imports) {
Ok(imps) => imps, Ok(_) => {}
Err(_) => { // Allow traps which can happen normally with `unreachable`
// There are some value types that we can't synthesize a Err(e) if e.downcast_ref::<Trap>().is_some() => {}
// dummy value for (e.g. externrefs) and for modules that Err(e) => panic!("failed to instantiate {}", e),
// import things of these types we skip instantiation. }
return;
}
};
// Don't unwrap this: there can be instantiation-/link-time errors that
// aren't caught during validation or compilation. For example, an imported
// table might not have room for an element segment that we want to
// initialize into it.
let _result = Instance::new(&store, &module, &imports);
} }
/// Compile the Wasm buffer, and implicitly fail if we have an unexpected /// Compile the Wasm buffer, and implicitly fail if we have an unexpected
@@ -162,31 +151,14 @@ pub fn differential_execution(
let engine = Engine::new(config); let engine = Engine::new(config);
let store = Store::new(&engine); let store = Store::new(&engine);
let module = match Module::new(&engine, &wasm) { let module = Module::new(&engine, &wasm).unwrap();
Ok(module) => module,
// The module might rely on some feature that our config didn't
// enable or something like that.
Err(e) => {
eprintln!("Warning: failed to compile `wasm-opt -ttf` module: {}", e);
continue;
}
};
// TODO: we should implement tracing versions of these dummy imports // TODO: we should implement tracing versions of these dummy imports
// that record a trace of the order that imported functions were called // that record a trace of the order that imported functions were called
// in and with what values. Like the results of exported functions, // in and with what values. Like the results of exported functions,
// calls to imports should also yield the same values for each // calls to imports should also yield the same values for each
// configuration, and we should assert that. // configuration, and we should assert that.
let imports = match dummy_imports(&store, module.imports()) { let imports = dummy_imports(&store, module.imports());
Ok(imps) => imps,
Err(e) => {
// There are some value types that we can't synthesize a
// dummy value for (e.g. externrefs) and for modules that
// import things of these types we skip instantiation.
eprintln!("Warning: failed to synthesize dummy imports: {}", e);
continue;
}
};
// Don't unwrap this: there can be instantiation-/link-time errors that // Don't unwrap this: there can be instantiation-/link-time errors that
// aren't caught during validation or compilation. For example, an imported // aren't caught during validation or compilation. For example, an imported
@@ -212,10 +184,7 @@ pub fn differential_execution(
init_hang_limit(&instance); init_hang_limit(&instance);
let ty = f.ty(); let ty = f.ty();
let params = match dummy::dummy_values(ty.params()) { let params = dummy::dummy_values(ty.params());
Ok(p) => p,
Err(_) => continue,
};
let this_result = f.call(&params).map_err(|e| e.downcast::<Trap>().unwrap()); let this_result = f.call(&params).map_err(|e| e.downcast::<Trap>().unwrap());
let existing_result = export_func_results let existing_result = export_func_results
@@ -353,16 +322,7 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
}; };
let store = store.as_ref().unwrap(); let store = store.as_ref().unwrap();
let imports = dummy_imports(store, module.imports());
let imports = match dummy_imports(store, module.imports()) {
Ok(imps) => imps,
Err(_) => {
// There are some value types that we can't synthesize a
// dummy value for (e.g. externrefs) and for modules that
// import things of these types we skip instantiation.
continue;
}
};
// Don't unwrap this: there can be instantiation-/link-time errors that // Don't unwrap this: there can be instantiation-/link-time errors that
// aren't caught during validation or compilation. For example, an imported // aren't caught during validation or compilation. For example, an imported
@@ -408,10 +368,7 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
let nth = nth % funcs.len(); let nth = nth % funcs.len();
let f = &funcs[nth]; let f = &funcs[nth];
let ty = f.ty(); let ty = f.ty();
let params = match dummy::dummy_values(ty.params()) { let params = dummy::dummy_values(ty.params());
Ok(p) => p,
Err(_) => continue,
};
let _ = f.call(&params); let _ = f.call(&params);
} }
} }
@@ -509,7 +466,7 @@ impl wasm_smith::Config for DifferentialWasmiModuleConfig {
1 1
} }
fn max_memories(&self) -> u32 { fn max_memories(&self) -> usize {
1 1
} }

View File

@@ -1,27 +1,23 @@
//! Dummy implementations of things that a Wasm module can import. //! Dummy implementations of things that a Wasm module can import.
use wasmtime::{ use std::fmt::Write;
Extern, ExternType, Func, FuncType, Global, GlobalType, ImportType, Memory, MemoryType, Store, use wasmtime::*;
Table, TableType, Trap, Val, ValType,
};
/// Create a set of dummy functions/globals/etc for the given imports. /// Create a set of dummy functions/globals/etc for the given imports.
pub fn dummy_imports<'module>( pub fn dummy_imports<'module>(
store: &Store, store: &Store,
import_tys: impl Iterator<Item = ImportType<'module>>, import_tys: impl Iterator<Item = ImportType<'module>>,
) -> Result<Vec<Extern>, Trap> { ) -> Vec<Extern> {
import_tys import_tys
.map(|imp| { .map(|imp| match imp.ty() {
Ok(match imp.ty() { ExternType::Func(func_ty) => Extern::Func(dummy_func(&store, func_ty)),
ExternType::Func(func_ty) => Extern::Func(dummy_func(&store, func_ty)), ExternType::Global(global_ty) => Extern::Global(dummy_global(&store, global_ty)),
ExternType::Global(global_ty) => Extern::Global(dummy_global(&store, global_ty)?), ExternType::Table(table_ty) => Extern::Table(dummy_table(&store, table_ty)),
ExternType::Table(table_ty) => Extern::Table(dummy_table(&store, table_ty)?), ExternType::Memory(mem_ty) => Extern::Memory(dummy_memory(&store, mem_ty)),
ExternType::Memory(mem_ty) => Extern::Memory(dummy_memory(&store, mem_ty)), ExternType::Instance(instance_ty) => {
Extern::Instance(dummy_instance(&store, instance_ty))
// FIXME(#2094) }
ExternType::Instance(_) => unimplemented!(), ExternType::Module(module_ty) => Extern::Module(dummy_module(&store, module_ty)),
ExternType::Module(_) => unimplemented!(),
})
}) })
.collect() .collect()
} }
@@ -30,55 +26,326 @@ pub fn dummy_imports<'module>(
pub fn dummy_func(store: &Store, ty: FuncType) -> Func { pub fn dummy_func(store: &Store, ty: FuncType) -> Func {
Func::new(store, ty.clone(), move |_, _, results| { Func::new(store, ty.clone(), move |_, _, results| {
for (ret_ty, result) in ty.results().zip(results) { for (ret_ty, result) in ty.results().zip(results) {
*result = dummy_value(ret_ty)?; *result = dummy_value(ret_ty);
} }
Ok(()) Ok(())
}) })
} }
/// Construct a dummy value for the given value type. /// Construct a dummy value for the given value type.
pub fn dummy_value(val_ty: ValType) -> Result<Val, Trap> { pub fn dummy_value(val_ty: ValType) -> Val {
Ok(match val_ty { match val_ty {
ValType::I32 => Val::I32(0), ValType::I32 => Val::I32(0),
ValType::I64 => Val::I64(0), ValType::I64 => Val::I64(0),
ValType::F32 => Val::F32(0), ValType::F32 => Val::F32(0),
ValType::F64 => Val::F64(0), ValType::F64 => Val::F64(0),
ValType::V128 => { ValType::V128 => Val::V128(0),
return Err(Trap::new( ValType::ExternRef => Val::ExternRef(None),
"dummy_value: unsupported function return type: v128".to_string(), ValType::FuncRef => Val::FuncRef(None),
)) }
}
ValType::ExternRef => {
return Err(Trap::new(
"dummy_value: unsupported function return type: externref".to_string(),
))
}
ValType::FuncRef => {
return Err(Trap::new(
"dummy_value: unsupported function return type: funcref".to_string(),
))
}
})
} }
/// Construct a sequence of dummy values for the given types. /// Construct a sequence of dummy values for the given types.
pub fn dummy_values(val_tys: impl IntoIterator<Item = ValType>) -> Result<Vec<Val>, Trap> { pub fn dummy_values(val_tys: impl IntoIterator<Item = ValType>) -> Vec<Val> {
val_tys.into_iter().map(dummy_value).collect() val_tys.into_iter().map(dummy_value).collect()
} }
/// Construct a dummy global for the given global type. /// Construct a dummy global for the given global type.
pub fn dummy_global(store: &Store, ty: GlobalType) -> Result<Global, Trap> { pub fn dummy_global(store: &Store, ty: GlobalType) -> Global {
let val = dummy_value(ty.content().clone())?; let val = dummy_value(ty.content().clone());
Ok(Global::new(store, ty, val).unwrap()) Global::new(store, ty, val).unwrap()
} }
/// Construct a dummy table for the given table type. /// Construct a dummy table for the given table type.
pub fn dummy_table(store: &Store, ty: TableType) -> Result<Table, Trap> { pub fn dummy_table(store: &Store, ty: TableType) -> Table {
let init_val = dummy_value(ty.element().clone())?; let init_val = dummy_value(ty.element().clone());
Ok(Table::new(store, ty, init_val).unwrap()) Table::new(store, ty, init_val).unwrap()
} }
/// Construct a dummy memory for the given memory type. /// Construct a dummy memory for the given memory type.
pub fn dummy_memory(store: &Store, ty: MemoryType) -> Memory { pub fn dummy_memory(store: &Store, ty: MemoryType) -> Memory {
Memory::new(store, ty) Memory::new(store, ty)
} }
/// Construct a dummy instance for the given instance type.
///
/// This is done by using the expected type to generate a module on-the-fly
/// which we the instantiate.
pub fn dummy_instance(store: &Store, ty: InstanceType) -> Instance {
let mut wat = WatGenerator::new();
for ty in ty.exports() {
wat.export(&ty);
}
let module = Module::new(store.engine(), &wat.finish()).unwrap();
Instance::new(store, &module, &[]).unwrap()
}
/// Construct a dummy module for the given module type.
///
/// This is done by using the expected type to generate a module on-the-fly.
pub fn dummy_module(store: &Store, ty: ModuleType) -> Module {
let mut wat = WatGenerator::new();
for ty in ty.imports() {
wat.import(&ty);
}
for ty in ty.exports() {
wat.export(&ty);
}
Module::new(store.engine(), &wat.finish()).unwrap()
}
struct WatGenerator {
tmp: usize,
dst: String,
}
impl WatGenerator {
fn new() -> WatGenerator {
WatGenerator {
tmp: 0,
dst: String::from("(module\n"),
}
}
fn finish(mut self) -> String {
self.dst.push_str(")\n");
self.dst
}
fn import(&mut self, ty: &ImportType<'_>) {
write!(self.dst, "(import ").unwrap();
self.str(ty.module());
write!(self.dst, " ").unwrap();
if let Some(field) = ty.name() {
self.str(field);
write!(self.dst, " ").unwrap();
}
self.item_ty(&ty.ty());
writeln!(self.dst, ")").unwrap();
}
fn item_ty(&mut self, ty: &ExternType) {
match ty {
ExternType::Memory(mem) => {
write!(
self.dst,
"(memory {} {})",
mem.limits().min(),
match mem.limits().max() {
Some(max) => max.to_string(),
None => String::new(),
}
)
.unwrap();
}
ExternType::Table(table) => {
write!(
self.dst,
"(table {} {} {})",
table.limits().min(),
match table.limits().max() {
Some(max) => max.to_string(),
None => String::new(),
},
wat_ty(table.element()),
)
.unwrap();
}
ExternType::Global(ty) => {
if ty.mutability() == Mutability::Const {
write!(self.dst, "(global {})", wat_ty(ty.content())).unwrap();
} else {
write!(self.dst, "(global (mut {}))", wat_ty(ty.content())).unwrap();
}
}
ExternType::Func(ty) => {
write!(self.dst, "(func ").unwrap();
self.func_sig(ty);
write!(self.dst, ")").unwrap();
}
ExternType::Instance(ty) => {
writeln!(self.dst, "(instance").unwrap();
for ty in ty.exports() {
write!(self.dst, "(export ").unwrap();
self.str(ty.name());
write!(self.dst, " ").unwrap();
self.item_ty(&ty.ty());
writeln!(self.dst, ")").unwrap();
}
write!(self.dst, ")").unwrap();
}
ExternType::Module(ty) => {
writeln!(self.dst, "(module").unwrap();
for ty in ty.imports() {
self.import(&ty);
writeln!(self.dst, "").unwrap();
}
for ty in ty.exports() {
write!(self.dst, "(export ").unwrap();
self.str(ty.name());
write!(self.dst, " ").unwrap();
self.item_ty(&ty.ty());
writeln!(self.dst, ")").unwrap();
}
write!(self.dst, ")").unwrap();
}
}
}
fn export(&mut self, ty: &ExportType<'_>) {
let wat_name = format!("item{}", self.tmp);
self.tmp += 1;
let item_ty = ty.ty();
self.item(&wat_name, &item_ty);
write!(self.dst, "(export ").unwrap();
self.str(ty.name());
write!(self.dst, " (").unwrap();
match item_ty {
ExternType::Memory(_) => write!(self.dst, "memory").unwrap(),
ExternType::Global(_) => write!(self.dst, "global").unwrap(),
ExternType::Func(_) => write!(self.dst, "func").unwrap(),
ExternType::Instance(_) => write!(self.dst, "instance").unwrap(),
ExternType::Table(_) => write!(self.dst, "table").unwrap(),
ExternType::Module(_) => write!(self.dst, "module").unwrap(),
}
writeln!(self.dst, " ${}))", wat_name).unwrap();
}
fn item(&mut self, name: &str, ty: &ExternType) {
match ty {
ExternType::Memory(mem) => {
write!(
self.dst,
"(memory ${} {} {})\n",
name,
mem.limits().min(),
match mem.limits().max() {
Some(max) => max.to_string(),
None => String::new(),
}
)
.unwrap();
}
ExternType::Table(table) => {
write!(
self.dst,
"(table ${} {} {} {})\n",
name,
table.limits().min(),
match table.limits().max() {
Some(max) => max.to_string(),
None => String::new(),
},
wat_ty(table.element()),
)
.unwrap();
}
ExternType::Global(ty) => {
write!(self.dst, "(global ${} ", name).unwrap();
if ty.mutability() == Mutability::Var {
write!(self.dst, "(mut ").unwrap();
}
write!(self.dst, "{}", wat_ty(ty.content())).unwrap();
if ty.mutability() == Mutability::Var {
write!(self.dst, ")").unwrap();
}
write!(self.dst, " (").unwrap();
self.value(ty.content());
writeln!(self.dst, "))").unwrap();
}
ExternType::Func(ty) => {
write!(self.dst, "(func ${} ", name).unwrap();
self.func_sig(ty);
for ty in ty.results() {
writeln!(self.dst, "").unwrap();
self.value(&ty);
}
writeln!(self.dst, ")").unwrap();
}
ExternType::Module(ty) => {
writeln!(self.dst, "(module ${}", name).unwrap();
for ty in ty.imports() {
self.import(&ty);
}
for ty in ty.exports() {
self.export(&ty);
}
self.dst.push_str(")\n");
}
ExternType::Instance(ty) => {
writeln!(self.dst, "(module ${}_module", name).unwrap();
for ty in ty.exports() {
self.export(&ty);
}
self.dst.push_str(")\n");
writeln!(self.dst, "(instance ${} (instantiate ${0}_module))", name).unwrap();
}
}
}
fn func_sig(&mut self, ty: &FuncType) {
write!(self.dst, "(param ").unwrap();
for ty in ty.params() {
write!(self.dst, "{} ", wat_ty(&ty)).unwrap();
}
write!(self.dst, ") (result ").unwrap();
for ty in ty.results() {
write!(self.dst, "{} ", wat_ty(&ty)).unwrap();
}
write!(self.dst, ")").unwrap();
}
fn value(&mut self, ty: &ValType) {
match ty {
ValType::I32 => write!(self.dst, "i32.const 0").unwrap(),
ValType::I64 => write!(self.dst, "i64.const 0").unwrap(),
ValType::F32 => write!(self.dst, "f32.const 0").unwrap(),
ValType::F64 => write!(self.dst, "f64.const 0").unwrap(),
ValType::V128 => write!(self.dst, "v128.const i32x4 0 0 0 0").unwrap(),
ValType::ExternRef => write!(self.dst, "ref.null extern").unwrap(),
ValType::FuncRef => write!(self.dst, "ref.null func").unwrap(),
}
}
fn str(&mut self, name: &str) {
let mut bytes = [0; 4];
self.dst.push_str("\"");
for c in name.chars() {
let v = c as u32;
if v >= 0x20 && v < 0x7f && c != '"' && c != '\\' && v < 0xff {
self.dst.push(c);
} else {
for byte in c.encode_utf8(&mut bytes).as_bytes() {
self.hex_byte(*byte);
}
}
}
self.dst.push_str("\"");
}
fn hex_byte(&mut self, byte: u8) {
fn to_hex(b: u8) -> char {
if b < 10 {
(b'0' + b) as char
} else {
(b'a' + b - 10) as char
}
}
self.dst.push('\\');
self.dst.push(to_hex((byte >> 4) & 0xf));
self.dst.push(to_hex(byte & 0xf));
}
}
fn wat_ty(ty: &ValType) -> &'static str {
match ty {
ValType::I32 => "i32",
ValType::I64 => "i64",
ValType::F32 => "f32",
ValType::F64 => "f64",
ValType::V128 => "v128",
ValType::ExternRef => "externref",
ValType::FuncRef => "funcref",
}
}

View File

@@ -28,7 +28,7 @@ rayon = { version = "1.0", optional = true }
region = "2.1.0" region = "2.1.0"
thiserror = "1.0.4" thiserror = "1.0.4"
target-lexicon = { version = "0.11.0", default-features = false } target-lexicon = { version = "0.11.0", default-features = false }
wasmparser = "0.69.2" wasmparser = "0.70"
more-asserts = "0.2.1" more-asserts = "0.2.1"
anyhow = "1.0" anyhow = "1.0"
cfg-if = "1.0" cfg-if = "1.0"

View File

@@ -24,7 +24,7 @@ more-asserts = "0.2.1"
smallvec = "1.0.0" smallvec = "1.0.0"
thiserror = "1.0.9" thiserror = "1.0.9"
typemap = "0.3" typemap = "0.3"
wasmparser = "0.69.2" wasmparser = "0.70"
[dev-dependencies] [dev-dependencies]
lazy_static = "1.2" lazy_static = "1.2"

View File

@@ -13,6 +13,6 @@ edition = "2018"
[dependencies] [dependencies]
lightbeam = { path = "..", version = "0.21.0" } lightbeam = { path = "..", version = "0.21.0" }
wasmparser = "0.69.2" wasmparser = "0.70"
cranelift-codegen = { path = "../../../cranelift/codegen", version = "0.68.0" } cranelift-codegen = { path = "../../../cranelift/codegen", version = "0.68.0" }
wasmtime-environ = { path = "../../environ", version = "0.21.0" } wasmtime-environ = { path = "../../environ", version = "0.21.0" }

View File

@@ -16,7 +16,7 @@ wasmtime-jit = { path = "../jit", version = "0.21.0" }
wasmtime-cache = { path = "../cache", version = "0.21.0", optional = true } wasmtime-cache = { path = "../cache", version = "0.21.0", optional = true }
wasmtime-profiling = { path = "../profiling", version = "0.21.0" } wasmtime-profiling = { path = "../profiling", version = "0.21.0" }
target-lexicon = { version = "0.11.0", default-features = false } target-lexicon = { version = "0.11.0", default-features = false }
wasmparser = "0.69.2" wasmparser = "0.70"
anyhow = "1.0.19" anyhow = "1.0.19"
region = "2.2.0" region = "2.2.0"
libc = "0.2" libc = "0.2"

View File

@@ -13,7 +13,7 @@ edition = "2018"
[dependencies] [dependencies]
anyhow = "1.0.19" anyhow = "1.0.19"
wasmtime = { path = "../wasmtime", version = "0.21.0", default-features = false } wasmtime = { path = "../wasmtime", version = "0.21.0", default-features = false }
wast = "28.0.0" wast = "29.0.0"
[badges] [badges]
maintenance = { status = "actively-developed" } maintenance = { status = "actively-developed" }

View File

@@ -17,7 +17,7 @@ target-lexicon = "0.11"
peepmatic-fuzzing = { path = "../cranelift/peepmatic/crates/fuzzing", optional = true } peepmatic-fuzzing = { path = "../cranelift/peepmatic/crates/fuzzing", optional = true }
wasmtime = { path = "../crates/wasmtime" } wasmtime = { path = "../crates/wasmtime" }
wasmtime-fuzzing = { path = "../crates/fuzzing" } wasmtime-fuzzing = { path = "../crates/fuzzing" }
wasm-smith = "0.1.12" wasm-smith = "0.2.0"
[features] [features]
experimental_x64 = ["wasmtime-fuzzing/experimental_x64"] experimental_x64 = ["wasmtime-fuzzing/experimental_x64"]