From 25000afe69bd32ded541a41074b217defa03a912 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 7 Dec 2020 15:57:35 -0800 Subject: [PATCH] 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. --- Cargo.lock | 60 +-- Cargo.toml | 4 +- cranelift/codegen/Cargo.toml | 2 +- cranelift/peepmatic/Cargo.toml | 2 +- cranelift/peepmatic/crates/fuzzing/Cargo.toml | 2 +- cranelift/peepmatic/crates/runtime/Cargo.toml | 2 +- cranelift/peepmatic/crates/souper/Cargo.toml | 2 +- .../peepmatic/crates/test-operator/Cargo.toml | 2 +- cranelift/wasm/Cargo.toml | 2 +- cranelift/wasm/src/code_translator.rs | 6 +- crates/debug/Cargo.toml | 2 +- crates/environ/Cargo.toml | 2 +- crates/fuzzing/Cargo.toml | 6 +- crates/fuzzing/src/lib.rs | 1 + crates/fuzzing/src/oracles.rs | 71 +--- crates/fuzzing/src/oracles/dummy.rs | 351 +++++++++++++++--- crates/jit/Cargo.toml | 2 +- crates/lightbeam/Cargo.toml | 2 +- crates/lightbeam/wasmtime/Cargo.toml | 2 +- crates/wasmtime/Cargo.toml | 2 +- crates/wast/Cargo.toml | 2 +- fuzz/Cargo.toml | 2 +- 22 files changed, 377 insertions(+), 152 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13c13d89cf..64237674ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -394,7 +394,7 @@ dependencies = [ "souper-ir", "target-lexicon", "thiserror", - "wast 28.0.0", + "wast 29.0.0", ] [[package]] @@ -597,7 +597,7 @@ dependencies = [ "smallvec", "target-lexicon", "thiserror", - "wasmparser 0.69.2", + "wasmparser 0.70.0", "wat", ] @@ -1167,7 +1167,7 @@ dependencies = [ "smallvec", "thiserror", "typemap", - "wasmparser 0.69.2", + "wasmparser 0.70.0", "wat", ] @@ -1411,7 +1411,7 @@ dependencies = [ "peepmatic-test-operator", "peepmatic-traits", "serde", - "wast 28.0.0", + "wast 29.0.0", "z3", ] @@ -1439,7 +1439,7 @@ dependencies = [ "peepmatic-traits", "rand", "serde", - "wast 28.0.0", + "wast 29.0.0", ] [[package]] @@ -1464,7 +1464,7 @@ dependencies = [ "serde", "serde_test", "thiserror", - "wast 28.0.0", + "wast 29.0.0", ] [[package]] @@ -1476,7 +1476,7 @@ dependencies = [ "peepmatic", "peepmatic-test-operator", "souper-ir", - "wast 28.0.0", + "wast 29.0.0", ] [[package]] @@ -1497,7 +1497,7 @@ version = "0.68.0" dependencies = [ "peepmatic-traits", "serde", - "wast 28.0.0", + "wast 29.0.0", ] [[package]] @@ -2356,18 +2356,18 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49891b7c581cf9e0090b25cd274e6498ad478f0a7819319ea96da2f253caaacb" +checksum = "ed89eaf99e08b84f96e477a16588a07dd3b51dc5f07291c3706782f62a10a5e1" dependencies = [ "leb128", ] [[package]] name = "wasm-smith" -version = "0.1.12" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fdf8c9ba2fdc0d8ffe3f7e5b23b5aac377eeca817a9885c058f27c8de5c500" +checksum = "cdd382e46cf44347f4d0c29122143cbab85cf248b9a8f680845c0239b6842a85" dependencies = [ "arbitrary", "leb128", @@ -2406,18 +2406,18 @@ checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" [[package]] name = "wasmparser" -version = "0.69.2" +version = "0.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd2dd6dadf3a723971297bcc0ec103e0aa8118bf68e23f49cb575e21621894a8" +checksum = "ed1b3f9e9cf01a580b9f3281214dfdb1922b5dfb8494ee312ca03ae10036c2a2" [[package]] name = "wasmprinter" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba006f5c5bf41a2a5c3b45e861ea6eb067382acb022b6a35a00a0390f9547f6" +checksum = "f89b2b24dce17e27fe9c09c28331cbd77067fcde5c6ea2508ac84bcbd5d3e018" dependencies = [ "anyhow", - "wasmparser 0.69.2", + "wasmparser 0.70.0", ] [[package]] @@ -2438,7 +2438,7 @@ dependencies = [ "smallvec", "target-lexicon", "tempfile", - "wasmparser 0.69.2", + "wasmparser 0.70.0", "wasmtime-cache", "wasmtime-environ", "wasmtime-jit", @@ -2516,7 +2516,7 @@ dependencies = [ "test-programs", "tracing-subscriber", "wasi-common", - "wasmparser 0.69.2", + "wasmparser 0.70.0", "wasmtime", "wasmtime-cache", "wasmtime-debug", @@ -2552,7 +2552,7 @@ dependencies = [ "object", "target-lexicon", "thiserror", - "wasmparser 0.69.2", + "wasmparser 0.70.0", "wasmtime-environ", ] @@ -2571,7 +2571,7 @@ dependencies = [ "more-asserts", "serde", "thiserror", - "wasmparser 0.69.2", + "wasmparser 0.70.0", ] [[package]] @@ -2600,7 +2600,7 @@ dependencies = [ "rayon", "wasm-smith", "wasmi", - "wasmparser 0.69.2", + "wasmparser 0.70.0", "wasmprinter", "wasmtime", "wasmtime-wast", @@ -2628,7 +2628,7 @@ dependencies = [ "serde", "target-lexicon", "thiserror", - "wasmparser 0.69.2", + "wasmparser 0.70.0", "wasmtime-cranelift", "wasmtime-debug", "wasmtime-environ", @@ -2645,7 +2645,7 @@ version = "0.21.0" dependencies = [ "cranelift-codegen", "lightbeam", - "wasmparser 0.69.2", + "wasmparser 0.70.0", "wasmtime-environ", ] @@ -2752,7 +2752,7 @@ version = "0.21.0" dependencies = [ "anyhow", "wasmtime", - "wast 28.0.0", + "wast 29.0.0", ] [[package]] @@ -2788,20 +2788,20 @@ dependencies = [ [[package]] name = "wast" -version = "28.0.0" +version = "29.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c0586061bfacc035034672c8d760802b428ab4c80a92e2a392425c516df9be1" +checksum = "dcf2268937131d63c3d833242bf5e075406f9ed868b4265f3280e15dac29ac18" dependencies = [ "leb128", ] [[package]] name = "wat" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d55b5ec4f9d9396fa99abaafa0688597395e57827dffd89731412ae90c9bf" +checksum = "0d11a88d953b298172d218d18f22853f4e6e12873b62755d05617b864d312c68" dependencies = [ - "wast 28.0.0", + "wast 29.0.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 7ea112be71..42ed33eb90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,12 +38,12 @@ anyhow = "1.0.19" target-lexicon = { version = "0.11.0", default-features = false } pretty_env_logger = "0.4.0" file-per-thread-logger = "0.1.1" -wat = "1.0.29" +wat = "1.0.30" libc = "0.2.60" log = "0.4.8" rayon = "1.2.1" humantime = "2.0.0" -wasmparser = "0.69.2" +wasmparser = "0.70.0" [dev-dependencies] env_logger = "0.8.1" diff --git a/cranelift/codegen/Cargo.toml b/cranelift/codegen/Cargo.toml index cc0a6fd62d..c812c3a5cb 100644 --- a/cranelift/codegen/Cargo.toml +++ b/cranelift/codegen/Cargo.toml @@ -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" } regalloc = { version = "0.0.31" } 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. # 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 diff --git a/cranelift/peepmatic/Cargo.toml b/cranelift/peepmatic/Cargo.toml index 3691cf713e..f61e840b5d 100644 --- a/cranelift/peepmatic/Cargo.toml +++ b/cranelift/peepmatic/Cargo.toml @@ -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-traits = { version = "0.68.0", path = "crates/traits" } serde = { version = "1.0.105", features = ["derive"] } -wast = "28.0.0" +wast = "29.0.0" z3 = { version = "0.7.1", features = ["static-link-z3"] } [dev-dependencies] diff --git a/cranelift/peepmatic/crates/fuzzing/Cargo.toml b/cranelift/peepmatic/crates/fuzzing/Cargo.toml index 83a57c943f..1611b75c6d 100644 --- a/cranelift/peepmatic/crates/fuzzing/Cargo.toml +++ b/cranelift/peepmatic/crates/fuzzing/Cargo.toml @@ -21,4 +21,4 @@ peepmatic-test-operator = { path = "../test-operator" } peepmatic-traits = { path = "../traits" } rand = { version = "0.7.3", features = ["small_rng"] } serde = "1.0.106" -wast = "28.0.0" +wast = "29.0.0" diff --git a/cranelift/peepmatic/crates/runtime/Cargo.toml b/cranelift/peepmatic/crates/runtime/Cargo.toml index 2b60e7d557..deb8d9d0c3 100644 --- a/cranelift/peepmatic/crates/runtime/Cargo.toml +++ b/cranelift/peepmatic/crates/runtime/Cargo.toml @@ -16,7 +16,7 @@ peepmatic-automata = { version = "0.68.0", path = "../automata", features = ["se peepmatic-traits = { version = "0.68.0", path = "../traits" } serde = { version = "1.0.105", features = ["derive"] } thiserror = "1.0.15" -wast = { version = "28.0.0", optional = true } +wast = { version = "29.0.0", optional = true } [dev-dependencies] peepmatic-test-operator = { version = "0.68.0", path = "../test-operator" } diff --git a/cranelift/peepmatic/crates/souper/Cargo.toml b/cranelift/peepmatic/crates/souper/Cargo.toml index 84bf6f52e0..5970b40e73 100644 --- a/cranelift/peepmatic/crates/souper/Cargo.toml +++ b/cranelift/peepmatic/crates/souper/Cargo.toml @@ -16,4 +16,4 @@ log = "0.4.8" [dev-dependencies] peepmatic = { path = "../..", version = "0.68.0" } peepmatic-test-operator = { version = "0.68.0", path = "../test-operator" } -wast = "28.0.0" +wast = "29.0.0" diff --git a/cranelift/peepmatic/crates/test-operator/Cargo.toml b/cranelift/peepmatic/crates/test-operator/Cargo.toml index 59ce9a15c6..9b49020071 100644 --- a/cranelift/peepmatic/crates/test-operator/Cargo.toml +++ b/cranelift/peepmatic/crates/test-operator/Cargo.toml @@ -9,4 +9,4 @@ edition = "2018" [dependencies] peepmatic-traits = { version = "0.68.0", path = "../traits" } serde = { version = "1.0.105", features = ["derive"] } -wast = "28.0.0" +wast = "29.0.0" diff --git a/cranelift/wasm/Cargo.toml b/cranelift/wasm/Cargo.toml index d6aa8b4ced..48e19a9d57 100644 --- a/cranelift/wasm/Cargo.toml +++ b/cranelift/wasm/Cargo.toml @@ -12,7 +12,7 @@ keywords = ["webassembly", "wasm"] edition = "2018" [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-entity = { path = "../entity", version = "0.68.0" } cranelift-frontend = { path = "../frontend", version = "0.68.0", default-features = false } diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index c522feb059..cf15787c18 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -538,10 +538,10 @@ pub fn translate_operator( } /********************************** Exception handing **********************************/ Operator::Try { .. } - | Operator::Catch - | Operator::BrOnExn { .. } + | Operator::Catch { .. } | Operator::Throw { .. } - | Operator::Rethrow => { + | Operator::Unwind + | Operator::Rethrow { .. } => { return Err(wasm_unsupported!( "proposed exception handling operator {:?}", op diff --git a/crates/debug/Cargo.toml b/crates/debug/Cargo.toml index 62a07daf56..f3b5bdede7 100644 --- a/crates/debug/Cargo.toml +++ b/crates/debug/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" [dependencies] gimli = "0.23.0" -wasmparser = "0.69.2" +wasmparser = "0.70" object = { version = "0.22.0", default-features = false, features = ["read", "write"] } wasmtime-environ = { path = "../environ", version = "0.21.0" } target-lexicon = { version = "0.11.0", default-features = false } diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml index 118e319ebd..26b0ec0eaf 100644 --- a/crates/environ/Cargo.toml +++ b/crates/environ/Cargo.toml @@ -16,7 +16,7 @@ anyhow = "1.0" 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-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"] } thiserror = "1.0.4" serde = { version = "1.0.94", features = ["derive"] } diff --git a/crates/fuzzing/Cargo.toml b/crates/fuzzing/Cargo.toml index 8aa5768457..b0dd625c02 100644 --- a/crates/fuzzing/Cargo.toml +++ b/crates/fuzzing/Cargo.toml @@ -12,11 +12,11 @@ arbitrary = { version = "0.4.1", features = ["derive"] } env_logger = "0.8.1" log = "0.4.8" rayon = "1.2.1" -wasmparser = "0.69.2" -wasmprinter = "0.2.16" +wasmparser = "0.70" +wasmprinter = "0.2.17" wasmtime = { path = "../wasmtime" } wasmtime-wast = { path = "../wast" } -wasm-smith = "0.1.12" +wasm-smith = "0.2.0" wasmi = "0.7.0" [dev-dependencies] diff --git a/crates/fuzzing/src/lib.rs b/crates/fuzzing/src/lib.rs index 7e649272de..7ef3382411 100644 --- a/crates/fuzzing/src/lib.rs +++ b/crates/fuzzing/src/lib.rs @@ -38,6 +38,7 @@ pub fn fuzz_default_config(strategy: wasmtime::Strategy) -> anyhow::Result module, - Err(_) => return, - }; + let module = Module::new(&engine, wasm).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. - 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); + match Instance::new(&store, &module, &imports) { + Ok(_) => {} + // Allow traps which can happen normally with `unreachable` + Err(e) if e.downcast_ref::().is_some() => {} + Err(e) => panic!("failed to instantiate {}", e), + } } /// 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 store = Store::new(&engine); - let module = match Module::new(&engine, &wasm) { - 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; - } - }; + let module = Module::new(&engine, &wasm).unwrap(); // TODO: we should implement tracing versions of these dummy imports // that record a trace of the order that imported functions were called // in and with what values. Like the results of exported functions, // calls to imports should also yield the same values for each // configuration, and we should assert that. - let imports = match 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; - } - }; + let imports = dummy_imports(&store, module.imports()); // Don't unwrap this: there can be instantiation-/link-time errors that // aren't caught during validation or compilation. For example, an imported @@ -212,10 +184,7 @@ pub fn differential_execution( init_hang_limit(&instance); let ty = f.ty(); - let params = match dummy::dummy_values(ty.params()) { - Ok(p) => p, - Err(_) => continue, - }; + let params = dummy::dummy_values(ty.params()); let this_result = f.call(¶ms).map_err(|e| e.downcast::().unwrap()); 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 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; - } - }; + let imports = dummy_imports(store, module.imports()); // Don't unwrap this: there can be instantiation-/link-time errors that // 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 f = &funcs[nth]; let ty = f.ty(); - let params = match dummy::dummy_values(ty.params()) { - Ok(p) => p, - Err(_) => continue, - }; + let params = dummy::dummy_values(ty.params()); let _ = f.call(¶ms); } } @@ -509,7 +466,7 @@ impl wasm_smith::Config for DifferentialWasmiModuleConfig { 1 } - fn max_memories(&self) -> u32 { + fn max_memories(&self) -> usize { 1 } diff --git a/crates/fuzzing/src/oracles/dummy.rs b/crates/fuzzing/src/oracles/dummy.rs index f05a52e08e..561a8fb329 100644 --- a/crates/fuzzing/src/oracles/dummy.rs +++ b/crates/fuzzing/src/oracles/dummy.rs @@ -1,27 +1,23 @@ //! Dummy implementations of things that a Wasm module can import. -use wasmtime::{ - Extern, ExternType, Func, FuncType, Global, GlobalType, ImportType, Memory, MemoryType, Store, - Table, TableType, Trap, Val, ValType, -}; +use std::fmt::Write; +use wasmtime::*; /// Create a set of dummy functions/globals/etc for the given imports. pub fn dummy_imports<'module>( store: &Store, import_tys: impl Iterator>, -) -> Result, Trap> { +) -> Vec { import_tys - .map(|imp| { - Ok(match imp.ty() { - ExternType::Func(func_ty) => Extern::Func(dummy_func(&store, func_ty)), - ExternType::Global(global_ty) => Extern::Global(dummy_global(&store, global_ty)?), - ExternType::Table(table_ty) => Extern::Table(dummy_table(&store, table_ty)?), - ExternType::Memory(mem_ty) => Extern::Memory(dummy_memory(&store, mem_ty)), - - // FIXME(#2094) - ExternType::Instance(_) => unimplemented!(), - ExternType::Module(_) => unimplemented!(), - }) + .map(|imp| match imp.ty() { + ExternType::Func(func_ty) => Extern::Func(dummy_func(&store, func_ty)), + ExternType::Global(global_ty) => Extern::Global(dummy_global(&store, global_ty)), + ExternType::Table(table_ty) => Extern::Table(dummy_table(&store, table_ty)), + ExternType::Memory(mem_ty) => Extern::Memory(dummy_memory(&store, mem_ty)), + ExternType::Instance(instance_ty) => { + Extern::Instance(dummy_instance(&store, instance_ty)) + } + ExternType::Module(module_ty) => Extern::Module(dummy_module(&store, module_ty)), }) .collect() } @@ -30,55 +26,326 @@ pub fn dummy_imports<'module>( pub fn dummy_func(store: &Store, ty: FuncType) -> Func { Func::new(store, ty.clone(), move |_, _, results| { for (ret_ty, result) in ty.results().zip(results) { - *result = dummy_value(ret_ty)?; + *result = dummy_value(ret_ty); } Ok(()) }) } /// Construct a dummy value for the given value type. -pub fn dummy_value(val_ty: ValType) -> Result { - Ok(match val_ty { +pub fn dummy_value(val_ty: ValType) -> Val { + match val_ty { ValType::I32 => Val::I32(0), ValType::I64 => Val::I64(0), ValType::F32 => Val::F32(0), ValType::F64 => Val::F64(0), - ValType::V128 => { - return Err(Trap::new( - "dummy_value: unsupported function return type: v128".to_string(), - )) - } - 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(), - )) - } - }) + ValType::V128 => Val::V128(0), + ValType::ExternRef => Val::ExternRef(None), + ValType::FuncRef => Val::FuncRef(None), + } } /// Construct a sequence of dummy values for the given types. -pub fn dummy_values(val_tys: impl IntoIterator) -> Result, Trap> { +pub fn dummy_values(val_tys: impl IntoIterator) -> Vec { val_tys.into_iter().map(dummy_value).collect() } /// Construct a dummy global for the given global type. -pub fn dummy_global(store: &Store, ty: GlobalType) -> Result { - let val = dummy_value(ty.content().clone())?; - Ok(Global::new(store, ty, val).unwrap()) +pub fn dummy_global(store: &Store, ty: GlobalType) -> Global { + let val = dummy_value(ty.content().clone()); + Global::new(store, ty, val).unwrap() } /// Construct a dummy table for the given table type. -pub fn dummy_table(store: &Store, ty: TableType) -> Result { - let init_val = dummy_value(ty.element().clone())?; - Ok(Table::new(store, ty, init_val).unwrap()) +pub fn dummy_table(store: &Store, ty: TableType) -> Table { + let init_val = dummy_value(ty.element().clone()); + Table::new(store, ty, init_val).unwrap() } /// Construct a dummy memory for the given memory type. pub fn dummy_memory(store: &Store, ty: MemoryType) -> Memory { 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", + } +} diff --git a/crates/jit/Cargo.toml b/crates/jit/Cargo.toml index 7b357d0461..c754126d92 100644 --- a/crates/jit/Cargo.toml +++ b/crates/jit/Cargo.toml @@ -28,7 +28,7 @@ rayon = { version = "1.0", optional = true } region = "2.1.0" thiserror = "1.0.4" target-lexicon = { version = "0.11.0", default-features = false } -wasmparser = "0.69.2" +wasmparser = "0.70" more-asserts = "0.2.1" anyhow = "1.0" cfg-if = "1.0" diff --git a/crates/lightbeam/Cargo.toml b/crates/lightbeam/Cargo.toml index baf518e642..d178090cfa 100644 --- a/crates/lightbeam/Cargo.toml +++ b/crates/lightbeam/Cargo.toml @@ -24,7 +24,7 @@ more-asserts = "0.2.1" smallvec = "1.0.0" thiserror = "1.0.9" typemap = "0.3" -wasmparser = "0.69.2" +wasmparser = "0.70" [dev-dependencies] lazy_static = "1.2" diff --git a/crates/lightbeam/wasmtime/Cargo.toml b/crates/lightbeam/wasmtime/Cargo.toml index cf0bab9442..41b47115ee 100644 --- a/crates/lightbeam/wasmtime/Cargo.toml +++ b/crates/lightbeam/wasmtime/Cargo.toml @@ -13,6 +13,6 @@ edition = "2018" [dependencies] lightbeam = { path = "..", version = "0.21.0" } -wasmparser = "0.69.2" +wasmparser = "0.70" cranelift-codegen = { path = "../../../cranelift/codegen", version = "0.68.0" } wasmtime-environ = { path = "../../environ", version = "0.21.0" } diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 65ce5873c4..1fa4f012f4 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -16,7 +16,7 @@ wasmtime-jit = { path = "../jit", version = "0.21.0" } wasmtime-cache = { path = "../cache", version = "0.21.0", optional = true } wasmtime-profiling = { path = "../profiling", version = "0.21.0" } target-lexicon = { version = "0.11.0", default-features = false } -wasmparser = "0.69.2" +wasmparser = "0.70" anyhow = "1.0.19" region = "2.2.0" libc = "0.2" diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index aaa130acec..25e2bccbf1 100644 --- a/crates/wast/Cargo.toml +++ b/crates/wast/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" [dependencies] anyhow = "1.0.19" wasmtime = { path = "../wasmtime", version = "0.21.0", default-features = false } -wast = "28.0.0" +wast = "29.0.0" [badges] maintenance = { status = "actively-developed" } diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 32726a7940..6220bdcb91 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -17,7 +17,7 @@ target-lexicon = "0.11" peepmatic-fuzzing = { path = "../cranelift/peepmatic/crates/fuzzing", optional = true } wasmtime = { path = "../crates/wasmtime" } wasmtime-fuzzing = { path = "../crates/fuzzing" } -wasm-smith = "0.1.12" +wasm-smith = "0.2.0" [features] experimental_x64 = ["wasmtime-fuzzing/experimental_x64"]