From 828ac36806de0ef1b244fb8a0e009ddd59ca3f5b Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 15 Mar 2021 11:52:38 -0700 Subject: [PATCH 01/19] Switch compilation tests to wasm-smith which always generates valid modules. Update to newer libfuzzer-sys and use a versioned crates instead of a git repository. Delete "headless_cranelift.rs" which is an older copy of native_cranelift.rs and wasn't referenced in the Cargo.toml. --- fuzz/Cargo.toml | 6 +++--- fuzz/fuzz_targets/headless_cranelift.rs | 25 ------------------------- fuzz/fuzz_targets/jit_cranelift.rs | 16 ++++++---------- fuzz/fuzz_targets/jit_llvm.rs | 16 ++++++---------- fuzz/fuzz_targets/jit_singlepass.rs | 16 ++++++---------- fuzz/fuzz_targets/native_cranelift.rs | 17 +++++++---------- fuzz/fuzz_targets/validate.rs | 7 +++---- 7 files changed, 31 insertions(+), 72 deletions(-) delete mode 100644 fuzz/fuzz_targets/headless_cranelift.rs diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 5750b219ed1..01fe4517846 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -1,4 +1,3 @@ - [package] name = "wasmer-bin-fuzz" version = "0.0.0" @@ -9,6 +8,9 @@ edition = "2018" [package.metadata] cargo-fuzz = true +[dependencies] +wasm-smith = "0.4.0" +libfuzzer-sys = "0.4.0" [dependencies.wasmer] path = "../lib/api" [dependencies.wasmer-compiler-cranelift] @@ -21,8 +23,6 @@ path = "../lib/compiler-singlepass" path = "../lib/engine-jit" [dependencies.wasmer-engine-native] path = "../lib/engine-native" -[dependencies.libfuzzer-sys] -git = "https://github.com/rust-fuzz/libfuzzer-sys.git" # Prevent this from interfering with workspaces [workspace] diff --git a/fuzz/fuzz_targets/headless_cranelift.rs b/fuzz/fuzz_targets/headless_cranelift.rs deleted file mode 100644 index bacfb5bb954..00000000000 --- a/fuzz/fuzz_targets/headless_cranelift.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![no_main] -#[macro_use] -extern crate libfuzzer_sys; - -use wasmer::{imports, Instance, Module, Store}; -use wasmer_compiler_cranelift::Cranelift; -use wasmer_engine_native::Native; - -fuzz_target!(|wasm_bytes: &[u8]| { - let serialized = { - let mut compiler = Cranelift::default(); - let store = Store::new(&Native::new(compiler).engine()); - match Module::validate(&store, wasm_bytes) { - Err(_) => return, - Ok(_) => {} - }; - let module = Module::new(&store, wasm_bytes).unwrap(); - module.serialize().unwrap(); - }; - - let engine = Native::headless().engine(); - let store = Store::new(&engine); - let module = unsafe { Module::deserialize(&store, serialized) }; - let _instance = Instance::new(&module, &imports! {}); -}); diff --git a/fuzz/fuzz_targets/jit_cranelift.rs b/fuzz/fuzz_targets/jit_cranelift.rs index 9fc47d0ae0b..7975c33e882 100644 --- a/fuzz/fuzz_targets/jit_cranelift.rs +++ b/fuzz/fuzz_targets/jit_cranelift.rs @@ -1,21 +1,17 @@ #![no_main] -#[macro_use] -extern crate libfuzzer_sys; +use libfuzzer_sys::fuzz_target; use wasmer::{imports, CompilerConfig, Instance, Module, Store}; use wasmer_compiler_cranelift::Cranelift; use wasmer_engine_jit::JIT; +use wasm_smith::Module as FuzzModule; -fuzz_target!(|wasm_bytes: &[u8]| { +fuzz_target!(|module: FuzzModule| { + let wasm_bytes = module.to_bytes(); let mut compiler = Cranelift::default(); compiler.canonicalize_nans(true); compiler.enable_verifier(); let store = Store::new(&JIT::new(compiler).engine()); - match Module::validate(&store, wasm_bytes) { - Ok(_) => { - let module = Module::new(&store, wasm_bytes).unwrap(); - let _instance = Instance::new(&module, &imports! {}); - } - Err(_) => {} - }; + let module = Module::new(&store, &wasm_bytes).unwrap(); + Instance::new(&module, &imports! {}).unwrap(); }); diff --git a/fuzz/fuzz_targets/jit_llvm.rs b/fuzz/fuzz_targets/jit_llvm.rs index 8aafe5c8c6d..dbab6361cd9 100644 --- a/fuzz/fuzz_targets/jit_llvm.rs +++ b/fuzz/fuzz_targets/jit_llvm.rs @@ -1,21 +1,17 @@ #![no_main] -#[macro_use] -extern crate libfuzzer_sys; +use libfuzzer_sys::fuzz_target; use wasmer::{imports, CompilerConfig, Instance, Module, Store}; use wasmer_compiler_llvm::LLVM; use wasmer_engine_jit::JIT; +use wasm_smith::Module as FuzzModule; -fuzz_target!(|wasm_bytes: &[u8]| { +fuzz_target!(|module: FuzzModule| { + let wasm_bytes = module.to_bytes(); let mut compiler = LLVM::default(); compiler.canonicalize_nans(true); compiler.enable_verifier(); let store = Store::new(&JIT::new(compiler).engine()); - match Module::validate(&store, wasm_bytes) { - Ok(_) => { - let module = Module::new(&store, wasm_bytes).unwrap(); - let _instance = Instance::new(&module, &imports! {}); - } - Err(_) => {} - }; + let module = Module::new(&store, &wasm_bytes).unwrap(); + Instance::new(&module, &imports! {}).unwrap(); }); diff --git a/fuzz/fuzz_targets/jit_singlepass.rs b/fuzz/fuzz_targets/jit_singlepass.rs index fc882ba46d2..81835f5bc97 100644 --- a/fuzz/fuzz_targets/jit_singlepass.rs +++ b/fuzz/fuzz_targets/jit_singlepass.rs @@ -1,19 +1,15 @@ #![no_main] -#[macro_use] -extern crate libfuzzer_sys; +use libfuzzer_sys::fuzz_target; use wasmer::{imports, Instance, Module, Store}; use wasmer_compiler_singlepass::Singlepass; use wasmer_engine_jit::JIT; +use wasm_smith::Module as FuzzModule; -fuzz_target!(|wasm_bytes: &[u8]| { +fuzz_target!(|module: FuzzModule| { + let wasm_bytes = module.to_bytes(); let compiler = Singlepass::default(); let store = Store::new(&JIT::new(compiler).engine()); - match Module::validate(&store, wasm_bytes) { - Ok(_) => { - let module = Module::new(&store, wasm_bytes).unwrap(); - let _instance = Instance::new(&module, &imports! {}); - } - Err(_) => {} - }; + let module = Module::new(&store, &wasm_bytes).unwrap(); + Instance::new(&module, &imports! {}).unwrap(); }); diff --git a/fuzz/fuzz_targets/native_cranelift.rs b/fuzz/fuzz_targets/native_cranelift.rs index 57c4926878b..a0e5b118138 100644 --- a/fuzz/fuzz_targets/native_cranelift.rs +++ b/fuzz/fuzz_targets/native_cranelift.rs @@ -1,25 +1,22 @@ #![no_main] -#[macro_use] -extern crate libfuzzer_sys; +use libfuzzer_sys::fuzz_target; use wasmer::{imports, Instance, Module, Store}; use wasmer_compiler_cranelift::Cranelift; use wasmer_engine_native::Native; +use wasm_smith::Module as FuzzModule; -fuzz_target!(|wasm_bytes: &[u8]| { +fuzz_target!(|module: FuzzModule| { let serialized = { - let mut compiler = Cranelift::default(); + let wasm_bytes = module.to_bytes(); + let compiler = Cranelift::default(); let store = Store::new(&Native::new(compiler).engine()); - match Module::validate(&store, wasm_bytes) { - Err(_) => return, - Ok(_) => {} - }; - let module = Module::new(&store, wasm_bytes).unwrap(); + let module = Module::new(&store, &wasm_bytes).unwrap(); module.serialize().unwrap() }; let engine = Native::headless().engine(); let store = Store::new(&engine); let module = unsafe { Module::deserialize(&store, serialized.as_slice()) }.unwrap(); - let _instance = Instance::new(&module, &imports! {}); + Instance::new(&module, &imports! {}).unwrap(); }); diff --git a/fuzz/fuzz_targets/validate.rs b/fuzz/fuzz_targets/validate.rs index 5109109ce41..6a7ffe1c47f 100644 --- a/fuzz/fuzz_targets/validate.rs +++ b/fuzz/fuzz_targets/validate.rs @@ -1,13 +1,12 @@ #![no_main] -#[macro_use] -extern crate libfuzzer_sys; -use wasmer::{imports, Instance, Module, Store}; +use libfuzzer_sys::fuzz_target; +use wasmer::{Module, Store}; use wasmer_compiler_cranelift::Cranelift; use wasmer_engine_jit::JIT; fuzz_target!(|wasm_bytes: &[u8]| { let compiler = Cranelift::default(); let store = Store::new(&JIT::new(compiler).engine()); - Module::validate(&store, wasm_bytes); + let _ignored = Module::validate(&store, wasm_bytes); }); From fe8a94d5312e87887bf4d81aae161b1ada0ab9d5 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 15 Mar 2021 12:46:56 -0700 Subject: [PATCH 02/19] Singlepass doesn't support multi-value returns, ignore those errors. --- fuzz/fuzz_targets/jit_singlepass.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/fuzz/fuzz_targets/jit_singlepass.rs b/fuzz/fuzz_targets/jit_singlepass.rs index 81835f5bc97..31aef0fd57e 100644 --- a/fuzz/fuzz_targets/jit_singlepass.rs +++ b/fuzz/fuzz_targets/jit_singlepass.rs @@ -1,15 +1,25 @@ #![no_main] use libfuzzer_sys::fuzz_target; +use wasm_smith::Module as FuzzModule; use wasmer::{imports, Instance, Module, Store}; use wasmer_compiler_singlepass::Singlepass; use wasmer_engine_jit::JIT; -use wasm_smith::Module as FuzzModule; fuzz_target!(|module: FuzzModule| { let wasm_bytes = module.to_bytes(); let compiler = Singlepass::default(); let store = Store::new(&JIT::new(compiler).engine()); - let module = Module::new(&store, &wasm_bytes).unwrap(); - Instance::new(&module, &imports! {}).unwrap(); + let module = Module::new(&store, &wasm_bytes); + let module = match module { + Ok(m) => m, + Err(e) => { + let error_message = format!("{}", e); + if error_message.contains("Validation error: invalid result arity: func type returns multiple values") || error_message.contains("Validation error: blocks, loops, and ifs accept no parameters when multi-value is not enabled") { + return; + } + panic!("{}", e); + } + }; + let _ignored = Instance::new(&module, &imports! {}); }); From 400d99f1b5f772779e640d8d9a8a6dd7d06d2fd9 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 15 Mar 2021 13:18:33 -0700 Subject: [PATCH 03/19] Configure wasm-smith to generate no imports to match our empty import object. --- fuzz/fuzz_targets/jit_cranelift.rs | 14 +++++++++++--- fuzz/fuzz_targets/jit_llvm.rs | 15 ++++++++++++--- fuzz/fuzz_targets/jit_singlepass.rs | 14 +++++++++++--- fuzz/fuzz_targets/native_cranelift.rs | 14 +++++++++++--- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/fuzz/fuzz_targets/jit_cranelift.rs b/fuzz/fuzz_targets/jit_cranelift.rs index 7975c33e882..f6add3349cc 100644 --- a/fuzz/fuzz_targets/jit_cranelift.rs +++ b/fuzz/fuzz_targets/jit_cranelift.rs @@ -1,12 +1,20 @@ #![no_main] -use libfuzzer_sys::fuzz_target; +use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target}; +use wasm_smith::{Config, ConfiguredModule}; use wasmer::{imports, CompilerConfig, Instance, Module, Store}; use wasmer_compiler_cranelift::Cranelift; use wasmer_engine_jit::JIT; -use wasm_smith::Module as FuzzModule; -fuzz_target!(|module: FuzzModule| { +#[derive(Arbitrary, Debug, Default, Copy, Clone)] +struct NoImportsConfig; +impl Config for NoImportsConfig { + fn max_imports(&self) -> usize { + 0 + } +} + +fuzz_target!(|module: ConfiguredModule| { let wasm_bytes = module.to_bytes(); let mut compiler = Cranelift::default(); compiler.canonicalize_nans(true); diff --git a/fuzz/fuzz_targets/jit_llvm.rs b/fuzz/fuzz_targets/jit_llvm.rs index dbab6361cd9..9dcb29fda64 100644 --- a/fuzz/fuzz_targets/jit_llvm.rs +++ b/fuzz/fuzz_targets/jit_llvm.rs @@ -1,13 +1,22 @@ #![no_main] -use libfuzzer_sys::fuzz_target; +use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target}; +use wasm_smith::{Config, ConfiguredModule}; use wasmer::{imports, CompilerConfig, Instance, Module, Store}; use wasmer_compiler_llvm::LLVM; use wasmer_engine_jit::JIT; -use wasm_smith::Module as FuzzModule; -fuzz_target!(|module: FuzzModule| { +#[derive(Arbitrary, Debug, Default, Copy, Clone)] +struct NoImportsConfig; +impl Config for NoImportsConfig { + fn max_imports(&self) -> usize { + 0 + } +} + +fuzz_target!(|module: ConfiguredModule| { let wasm_bytes = module.to_bytes(); + let mut compiler = LLVM::default(); compiler.canonicalize_nans(true); compiler.enable_verifier(); diff --git a/fuzz/fuzz_targets/jit_singlepass.rs b/fuzz/fuzz_targets/jit_singlepass.rs index 31aef0fd57e..f051a913522 100644 --- a/fuzz/fuzz_targets/jit_singlepass.rs +++ b/fuzz/fuzz_targets/jit_singlepass.rs @@ -1,12 +1,20 @@ #![no_main] -use libfuzzer_sys::fuzz_target; -use wasm_smith::Module as FuzzModule; +use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target}; +use wasm_smith::{Config, ConfiguredModule}; use wasmer::{imports, Instance, Module, Store}; use wasmer_compiler_singlepass::Singlepass; use wasmer_engine_jit::JIT; -fuzz_target!(|module: FuzzModule| { +#[derive(Arbitrary, Debug, Default, Copy, Clone)] +struct NoImportsConfig; +impl Config for NoImportsConfig { + fn max_imports(&self) -> usize { + 0 + } +} + +fuzz_target!(|module: ConfiguredModule| { let wasm_bytes = module.to_bytes(); let compiler = Singlepass::default(); let store = Store::new(&JIT::new(compiler).engine()); diff --git a/fuzz/fuzz_targets/native_cranelift.rs b/fuzz/fuzz_targets/native_cranelift.rs index a0e5b118138..5ab18b74314 100644 --- a/fuzz/fuzz_targets/native_cranelift.rs +++ b/fuzz/fuzz_targets/native_cranelift.rs @@ -1,12 +1,20 @@ #![no_main] -use libfuzzer_sys::fuzz_target; +use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target}; +use wasm_smith::{Config, ConfiguredModule}; use wasmer::{imports, Instance, Module, Store}; use wasmer_compiler_cranelift::Cranelift; use wasmer_engine_native::Native; -use wasm_smith::Module as FuzzModule; -fuzz_target!(|module: FuzzModule| { +#[derive(Arbitrary, Debug, Default, Copy, Clone)] +struct NoImportsConfig; +impl Config for NoImportsConfig { + fn max_imports(&self) -> usize { + 0 + } +} + +fuzz_target!(|module: ConfiguredModule| { let serialized = { let wasm_bytes = module.to_bytes(); let compiler = Cranelift::default(); From 34749590549d0a6ed3aacbc4eee4215d8c4373b1 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 15 Mar 2021 13:36:00 -0700 Subject: [PATCH 04/19] Update the readme to account for changes due to wasm-smith. --- fuzz/README.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/fuzz/README.md b/fuzz/README.md index 63473a500fe..60c927da7df 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -36,11 +36,11 @@ You should see output that looks something like this: #1409042 NEW cov: 115073 ft: 503951 corp: 4667/1814Kb lim: 4096 exec/s: 884 rss: 857Mb L: 174/4096 MS: 2 ChangeByte-ChangeASCIIInt- ``` -It will continue to generate random inputs forever, until it finds a bug or is terminated. The testcases for bugs it finds go into `fuzz/artifacts/jit_cranelift` and you can rerun the fuzzer on a single input by passing it on the command line `cargo fuzz run jit_cranelift my_testcase.wasm`. +It will continue to generate random inputs forever, until it finds a bug or is terminated. The testcases for bugs it finds go into `fuzz/artifacts/jit_cranelift` and you can rerun the fuzzer on a single input by passing it on the command line `cargo fuzz run jit_cranelift /path/to/testcase`. -## Seeding the corpus, optional +## The corpus -The fuzzer works best when it has examples of small Wasm files to start with. Using `wast2json` from [wabt](https://github.com/WebAssembly/wabt), we can easily produce `.wasm` files out of the WebAssembly spec tests. +Each fuzzer has an individual corpus under fuzz/corpus/test_name, created on first run if not already present. The validate fuzzer works directly with `.wasm` files as bytes and works best if seeded with examples of small Wasm file. Using `wast2json` from [wabt](https://github.com/WebAssembly/wabt), we can easily produce `.wasm` files out of the WebAssembly spec tests. ```sh mkdir spec-test-corpus @@ -49,4 +49,13 @@ mv spec-test-corpus/*.wasm fuzz/corpus/validate/ rm -r spec-test-corpus ``` -The corpus directory is created on the first run of the fuzzer. If it doesn't exist, run it first and then seed the corpus. The fuzzer will pick up new files added to the corpus while it is running. +The others fuzzers use `wasm-smith` which means that the testcase files are the input to the wasm generator, not the valid `.wasm` bytes themselves. In order to debug a testcase, you may find that you need to convert it into a `.wasm` file. Using the standalone `wasm-smith` tool doesn't work for this purpose because we use a custom configuration to our `wasm_smith::Module`. Instead, add some code to the fuzzer target: + +```rust + use std::fs::File; + use std::io::Write; + let mut file = File::create("/tmp/crash.wasm").unwrap(); + file.write_all(&wasm_bytes).unwrap(); +``` + +and run it over just the one testcase. From 0e1d4bef50bdb9efa0b264017ddb574c78d83eaf Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 15 Mar 2021 13:45:07 -0700 Subject: [PATCH 05/19] Ignore error setting data in memory out of range. This wasm module is valid: ``` (module (memory (;0;) 0) (data (;0;) (i32.const 34) "")) ``` and we want to just ignore that problem. --- fuzz/fuzz_targets/jit_cranelift.rs | 13 ++++++++++++- fuzz/fuzz_targets/jit_llvm.rs | 13 ++++++++++++- fuzz/fuzz_targets/jit_singlepass.rs | 13 ++++++++++++- fuzz/fuzz_targets/native_cranelift.rs | 13 ++++++++++++- 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/fuzz/fuzz_targets/jit_cranelift.rs b/fuzz/fuzz_targets/jit_cranelift.rs index f6add3349cc..64c0a9b00c6 100644 --- a/fuzz/fuzz_targets/jit_cranelift.rs +++ b/fuzz/fuzz_targets/jit_cranelift.rs @@ -21,5 +21,16 @@ fuzz_target!(|module: ConfiguredModule| { compiler.enable_verifier(); let store = Store::new(&JIT::new(compiler).engine()); let module = Module::new(&store, &wasm_bytes).unwrap(); - Instance::new(&module, &imports! {}).unwrap(); + match Instance::new(&module, &imports! {}) { + Ok(_) => {} + Err(e) => { + let error_message = format!("{}", e); + if error_message + .contains("RuntimeError: memory out of bounds: data segment does not fit") + { + return; + } + panic!("{}", e); + } + } }); diff --git a/fuzz/fuzz_targets/jit_llvm.rs b/fuzz/fuzz_targets/jit_llvm.rs index 9dcb29fda64..d4a1cac5ec6 100644 --- a/fuzz/fuzz_targets/jit_llvm.rs +++ b/fuzz/fuzz_targets/jit_llvm.rs @@ -22,5 +22,16 @@ fuzz_target!(|module: ConfiguredModule| { compiler.enable_verifier(); let store = Store::new(&JIT::new(compiler).engine()); let module = Module::new(&store, &wasm_bytes).unwrap(); - Instance::new(&module, &imports! {}).unwrap(); + match Instance::new(&module, &imports! {}) { + Ok(_) => {} + Err(e) => { + let error_message = format!("{}", e); + if error_message + .contains("RuntimeError: memory out of bounds: data segment does not fit") + { + return; + } + panic!("{}", e); + } + } }); diff --git a/fuzz/fuzz_targets/jit_singlepass.rs b/fuzz/fuzz_targets/jit_singlepass.rs index f051a913522..5c1ab7d7e81 100644 --- a/fuzz/fuzz_targets/jit_singlepass.rs +++ b/fuzz/fuzz_targets/jit_singlepass.rs @@ -29,5 +29,16 @@ fuzz_target!(|module: ConfiguredModule| { panic!("{}", e); } }; - let _ignored = Instance::new(&module, &imports! {}); + match Instance::new(&module, &imports! {}) { + Ok(_) => {} + Err(e) => { + let error_message = format!("{}", e); + if error_message + .contains("RuntimeError: memory out of bounds: data segment does not fit") + { + return; + } + panic!("{}", e); + } + } }); diff --git a/fuzz/fuzz_targets/native_cranelift.rs b/fuzz/fuzz_targets/native_cranelift.rs index 5ab18b74314..f5484530659 100644 --- a/fuzz/fuzz_targets/native_cranelift.rs +++ b/fuzz/fuzz_targets/native_cranelift.rs @@ -26,5 +26,16 @@ fuzz_target!(|module: ConfiguredModule| { let engine = Native::headless().engine(); let store = Store::new(&engine); let module = unsafe { Module::deserialize(&store, serialized.as_slice()) }.unwrap(); - Instance::new(&module, &imports! {}).unwrap(); + match Instance::new(&module, &imports! {}) { + Ok(_) => {} + Err(e) => { + let error_message = format!("{}", e); + if error_message + .contains("RuntimeError: memory out of bounds: data segment does not fit") + { + return; + } + panic!("{}", e); + } + } }); From d781b3e5501421b48b23744bdca0242bac052454 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 15 Mar 2021 14:12:52 -0700 Subject: [PATCH 06/19] Ignore error setting table element out of range. --- fuzz/fuzz_targets/jit_cranelift.rs | 2 ++ fuzz/fuzz_targets/jit_llvm.rs | 2 ++ fuzz/fuzz_targets/jit_singlepass.rs | 2 ++ fuzz/fuzz_targets/native_cranelift.rs | 2 ++ 4 files changed, 8 insertions(+) diff --git a/fuzz/fuzz_targets/jit_cranelift.rs b/fuzz/fuzz_targets/jit_cranelift.rs index 64c0a9b00c6..5c80bac62c7 100644 --- a/fuzz/fuzz_targets/jit_cranelift.rs +++ b/fuzz/fuzz_targets/jit_cranelift.rs @@ -27,6 +27,8 @@ fuzz_target!(|module: ConfiguredModule| { let error_message = format!("{}", e); if error_message .contains("RuntimeError: memory out of bounds: data segment does not fit") + || error_message + .contains("RuntimeError: table out of bounds: elements segment does not fit") { return; } diff --git a/fuzz/fuzz_targets/jit_llvm.rs b/fuzz/fuzz_targets/jit_llvm.rs index d4a1cac5ec6..7e400eefc4e 100644 --- a/fuzz/fuzz_targets/jit_llvm.rs +++ b/fuzz/fuzz_targets/jit_llvm.rs @@ -28,6 +28,8 @@ fuzz_target!(|module: ConfiguredModule| { let error_message = format!("{}", e); if error_message .contains("RuntimeError: memory out of bounds: data segment does not fit") + || error_message + .contains("RuntimeError: table out of bounds: elements segment does not fit") { return; } diff --git a/fuzz/fuzz_targets/jit_singlepass.rs b/fuzz/fuzz_targets/jit_singlepass.rs index 5c1ab7d7e81..d8f7e5e1743 100644 --- a/fuzz/fuzz_targets/jit_singlepass.rs +++ b/fuzz/fuzz_targets/jit_singlepass.rs @@ -35,6 +35,8 @@ fuzz_target!(|module: ConfiguredModule| { let error_message = format!("{}", e); if error_message .contains("RuntimeError: memory out of bounds: data segment does not fit") + || error_message + .contains("RuntimeError: table out of bounds: elements segment does not fit") { return; } diff --git a/fuzz/fuzz_targets/native_cranelift.rs b/fuzz/fuzz_targets/native_cranelift.rs index f5484530659..92fe86b6127 100644 --- a/fuzz/fuzz_targets/native_cranelift.rs +++ b/fuzz/fuzz_targets/native_cranelift.rs @@ -32,6 +32,8 @@ fuzz_target!(|module: ConfiguredModule| { let error_message = format!("{}", e); if error_message .contains("RuntimeError: memory out of bounds: data segment does not fit") + || error_message + .contains("RuntimeError: table out of bounds: elements segment does not fit") { return; } From 40fcc0485226c234391ab55df7ac3086533f7d82 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 15 Mar 2021 18:16:32 -0700 Subject: [PATCH 07/19] Add workaround for issue #2187 where memory type has 65536 pages. Detect and ignore more errors from singlepass about multi-value returns. --- fuzz/fuzz_targets/jit_cranelift.rs | 4 ++++ fuzz/fuzz_targets/jit_llvm.rs | 5 ++++- fuzz/fuzz_targets/jit_singlepass.rs | 9 +++++++-- fuzz/fuzz_targets/native_cranelift.rs | 4 ++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/fuzz/fuzz_targets/jit_cranelift.rs b/fuzz/fuzz_targets/jit_cranelift.rs index 5c80bac62c7..fd173f2adcc 100644 --- a/fuzz/fuzz_targets/jit_cranelift.rs +++ b/fuzz/fuzz_targets/jit_cranelift.rs @@ -12,6 +12,10 @@ impl Config for NoImportsConfig { fn max_imports(&self) -> usize { 0 } + fn max_memory_pages(&self) -> u32 { + // https://github.com/wasmerio/wasmer/issues/2187 + 65535 + } } fuzz_target!(|module: ConfiguredModule| { diff --git a/fuzz/fuzz_targets/jit_llvm.rs b/fuzz/fuzz_targets/jit_llvm.rs index 7e400eefc4e..8da826608b2 100644 --- a/fuzz/fuzz_targets/jit_llvm.rs +++ b/fuzz/fuzz_targets/jit_llvm.rs @@ -12,11 +12,14 @@ impl Config for NoImportsConfig { fn max_imports(&self) -> usize { 0 } + fn max_memory_pages(&self) -> u32 { + // https://github.com/wasmerio/wasmer/issues/2187 + 65535 + } } fuzz_target!(|module: ConfiguredModule| { let wasm_bytes = module.to_bytes(); - let mut compiler = LLVM::default(); compiler.canonicalize_nans(true); compiler.enable_verifier(); diff --git a/fuzz/fuzz_targets/jit_singlepass.rs b/fuzz/fuzz_targets/jit_singlepass.rs index d8f7e5e1743..860c69220bd 100644 --- a/fuzz/fuzz_targets/jit_singlepass.rs +++ b/fuzz/fuzz_targets/jit_singlepass.rs @@ -12,6 +12,10 @@ impl Config for NoImportsConfig { fn max_imports(&self) -> usize { 0 } + fn max_memory_pages(&self) -> u32 { + // https://github.com/wasmerio/wasmer/issues/2187 + 65535 + } } fuzz_target!(|module: ConfiguredModule| { @@ -23,7 +27,7 @@ fuzz_target!(|module: ConfiguredModule| { Ok(m) => m, Err(e) => { let error_message = format!("{}", e); - if error_message.contains("Validation error: invalid result arity: func type returns multiple values") || error_message.contains("Validation error: blocks, loops, and ifs accept no parameters when multi-value is not enabled") { + if error_message.contains("Validation error: invalid result arity: func type returns multiple values") || error_message.contains("Validation error: blocks, loops, and ifs accept no parameters when multi-value is not enabled") || error_message.contains("multi-value returns not yet implemented") { return; } panic!("{}", e); @@ -33,7 +37,8 @@ fuzz_target!(|module: ConfiguredModule| { Ok(_) => {} Err(e) => { let error_message = format!("{}", e); - if error_message + if + error_message .contains("RuntimeError: memory out of bounds: data segment does not fit") || error_message .contains("RuntimeError: table out of bounds: elements segment does not fit") diff --git a/fuzz/fuzz_targets/native_cranelift.rs b/fuzz/fuzz_targets/native_cranelift.rs index 92fe86b6127..1b45af9e08b 100644 --- a/fuzz/fuzz_targets/native_cranelift.rs +++ b/fuzz/fuzz_targets/native_cranelift.rs @@ -12,6 +12,10 @@ impl Config for NoImportsConfig { fn max_imports(&self) -> usize { 0 } + fn max_memory_pages(&self) -> u32 { + // https://github.com/wasmerio/wasmer/issues/2187 + 65535 + } } fuzz_target!(|module: ConfiguredModule| { From 83e0e7eb3ab8ba32b77611e6edad15e0c9e9f19b Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 15 Mar 2021 18:39:01 -0700 Subject: [PATCH 08/19] Generate modules without a startfunc. The start function can contain unreachable instructions which triggers a trap and looks like instantiation failed. Instantiation did fail, but not for reasons we're interested in. --- fuzz/fuzz_targets/jit_cranelift.rs | 3 +++ fuzz/fuzz_targets/jit_llvm.rs | 3 +++ fuzz/fuzz_targets/jit_singlepass.rs | 3 +++ fuzz/fuzz_targets/native_cranelift.rs | 3 +++ 4 files changed, 12 insertions(+) diff --git a/fuzz/fuzz_targets/jit_cranelift.rs b/fuzz/fuzz_targets/jit_cranelift.rs index fd173f2adcc..dfa7f52e272 100644 --- a/fuzz/fuzz_targets/jit_cranelift.rs +++ b/fuzz/fuzz_targets/jit_cranelift.rs @@ -16,6 +16,9 @@ impl Config for NoImportsConfig { // https://github.com/wasmerio/wasmer/issues/2187 65535 } + fn allow_start_export(&self) -> bool { + false + } } fuzz_target!(|module: ConfiguredModule| { diff --git a/fuzz/fuzz_targets/jit_llvm.rs b/fuzz/fuzz_targets/jit_llvm.rs index 8da826608b2..bbc2087a000 100644 --- a/fuzz/fuzz_targets/jit_llvm.rs +++ b/fuzz/fuzz_targets/jit_llvm.rs @@ -16,6 +16,9 @@ impl Config for NoImportsConfig { // https://github.com/wasmerio/wasmer/issues/2187 65535 } + fn allow_start_export(&self) -> bool { + false + } } fuzz_target!(|module: ConfiguredModule| { diff --git a/fuzz/fuzz_targets/jit_singlepass.rs b/fuzz/fuzz_targets/jit_singlepass.rs index 860c69220bd..5eb0f8b3c6b 100644 --- a/fuzz/fuzz_targets/jit_singlepass.rs +++ b/fuzz/fuzz_targets/jit_singlepass.rs @@ -16,6 +16,9 @@ impl Config for NoImportsConfig { // https://github.com/wasmerio/wasmer/issues/2187 65535 } + fn allow_start_export(&self) -> bool { + false + } } fuzz_target!(|module: ConfiguredModule| { diff --git a/fuzz/fuzz_targets/native_cranelift.rs b/fuzz/fuzz_targets/native_cranelift.rs index 1b45af9e08b..8145a84a0f0 100644 --- a/fuzz/fuzz_targets/native_cranelift.rs +++ b/fuzz/fuzz_targets/native_cranelift.rs @@ -16,6 +16,9 @@ impl Config for NoImportsConfig { // https://github.com/wasmerio/wasmer/issues/2187 65535 } + fn allow_start_export(&self) -> bool { + false + } } fuzz_target!(|module: ConfiguredModule| { From f5fc209e66d35db1140b6e4eb17883af43af5ff6 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 16 Mar 2021 14:25:11 -0700 Subject: [PATCH 09/19] Add a fuzz test that instantiates a module with metering. --- fuzz/Cargo.toml | 14 ++++++--- fuzz/fuzz_targets/metering.rs | 58 +++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 fuzz/fuzz_targets/metering.rs diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 01fe4517846..d4f00323247 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -23,15 +23,13 @@ path = "../lib/compiler-singlepass" path = "../lib/engine-jit" [dependencies.wasmer-engine-native] path = "../lib/engine-native" +[dependencies.wasmer-middlewares] +path = "../lib/middlewares" # Prevent this from interfering with workspaces [workspace] members = ["."] -[[bin]] -name = "validate" -path = "fuzz_targets/validate.rs" - [[bin]] name = "jit_cranelift" path = "fuzz_targets/jit_cranelift.rs" @@ -44,6 +42,14 @@ path = "fuzz_targets/jit_llvm.rs" name = "jit_singlepass" path = "fuzz_targets/jit_singlepass.rs" +[[bin]] +name = "metering" +path = "fuzz_targets/metering.rs" + [[bin]] name = "native_cranelift" path = "fuzz_targets/native_cranelift.rs" + +[[bin]] +name = "validate" +path = "fuzz_targets/validate.rs" diff --git a/fuzz/fuzz_targets/metering.rs b/fuzz/fuzz_targets/metering.rs new file mode 100644 index 00000000000..80b04d1a877 --- /dev/null +++ b/fuzz/fuzz_targets/metering.rs @@ -0,0 +1,58 @@ +#![no_main] + +use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target}; +use std::sync::Arc; +use wasm_smith::{Config, ConfiguredModule}; +use wasmer::{imports, CompilerConfig, Instance, Module, Store}; +use wasmer::wasmparser::Operator; +use wasmer_compiler_cranelift::Cranelift; +use wasmer_engine_jit::JIT; +use wasmer_middlewares::Metering; + +#[derive(Arbitrary, Debug, Default, Copy, Clone)] +struct NoImportsConfig; +impl Config for NoImportsConfig { + fn max_imports(&self) -> usize { + 0 + } + fn max_memory_pages(&self) -> u32 { + // https://github.com/wasmerio/wasmer/issues/2187 + 65535 + } + fn allow_start_export(&self) -> bool { + false + } +} + +fn cost(operator: &Operator) -> u64 { + match operator { + Operator::LocalGet { .. } | Operator::I32Const { .. } => 1, + Operator::I32Add { .. } => 2, + _ => 0, + } +} + +fuzz_target!(|module: ConfiguredModule| { + let wasm_bytes = module.to_bytes(); + let mut compiler = Cranelift::default(); + compiler.canonicalize_nans(true); + compiler.enable_verifier(); + let metering = Arc::new(Metering::new(10, cost)); + compiler.push_middleware(metering); + let store = Store::new(&JIT::new(compiler).engine()); + let module = Module::new(&store, &wasm_bytes).unwrap(); + match Instance::new(&module, &imports! {}) { + Ok(_) => {} + Err(e) => { + let error_message = format!("{}", e); + if error_message + .contains("RuntimeError: memory out of bounds: data segment does not fit") + || error_message + .contains("RuntimeError: table out of bounds: elements segment does not fit") + { + return; + } + panic!("{}", e); + } + } +}); From df625e7de7782d27901d5f63b652fc28ca04b0cc Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Mar 2021 01:43:10 -0700 Subject: [PATCH 10/19] Initial commit of equivalence testing across the three compilers. --- fuzz/Cargo.lock | 1329 ++++++++++++++++++++++++++ fuzz/Cargo.toml | 7 +- fuzz/fuzz_targets/equivalence_jit.rs | 146 +++ 3 files changed, 1481 insertions(+), 1 deletion(-) create mode 100644 fuzz/Cargo.lock create mode 100644 fuzz/fuzz_targets/equivalence_jit.rs diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock new file mode 100644 index 00000000000..9d6af389f66 --- /dev/null +++ b/fuzz/Cargo.lock @@ -0,0 +1,1329 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" + +[[package]] +name = "arbitrary" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "698b65a961a9d730fb45b6b0327e20207810c9f61ee421b082b27ba003f49e2b" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "backtrace" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc" +dependencies = [ + "addr2line", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bincode" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d175dfa69e619905c4c3cdb7c3c203fa3bdd5d51184e3afdb2742c0280493772" +dependencies = [ + "byteorder", + "serde", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "cc" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cranelift-bforest" +version = "0.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f782ffb172d8095cbb4c6464d85432c3bcfa8609b0bb1dc27cfd35bd90e052" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e0910022b490bd0a65d5baa1693b0475cdbeea1c26472343f2acea1f1f55b8" +dependencies = [ + "byteorder", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", + "gimli", + "log", + "regalloc", + "smallvec", + "target-lexicon", + "thiserror", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cafe95cb5ac659e113549b2794a2c8d3a14f36e1a98728a6e0ea7a773be2129" +dependencies = [ + "cranelift-codegen-shared", + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d1bd002e42cc094a131a8227d06d48df28ea3b9127e5e3bc3010e079858e9af" + +[[package]] +name = "cranelift-entity" +version = "0.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e55e9043403f0dec775f317280015150e78b2352fb947d2f37407fd4ce6311c7" +dependencies = [ + "serde", +] + +[[package]] +name = "cranelift-frontend" +version = "0.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0153680ebce89aac7cad90a5442bb136faacfc86ea62587a01b8e8e79f8249c9" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "lazy_static", +] + +[[package]] +name = "darling" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06d4a9551359071d1890820e3571252b91229e0712e7c36b08940e603c5a8fc" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b443e5fb0ddd56e0c9bfa47dc060c5306ee500cb731f2b91432dd65589a77684" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0220073ce504f12a70efc4e7cdaea9e9b1b324872e7ad96a208056d7a638b81" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "derive_arbitrary" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df89dd0d075dea5cc5fdd6d5df6b8a61172a710b3efac1d6bdb9dd8b78f82c1a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dynasm" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7d1242462849390bb2ad38aeed769499f1afc7383affa2ab0c1baa894c0200" +dependencies = [ + "bitflags", + "byteorder", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dynasmrt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dd4d1d5ca12258cef339a57a7643e8b233a42dea9bb849630ddd9dd7726aa9" +dependencies = [ + "byteorder", + "dynasm", + "memmap2", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "enumset" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbd795df6708a599abf1ee10eacc72efd052b7a5f70fdf0715e4d5151a6db9c3" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19c52f9ec503c8a68dc04daf71a04b07e690c32ab1a8b68e33897f255269d47" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "goblin" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "669cdc3826f69a51d3f8fc3f86de81c2378110254f678b8407977736122057a4" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" +dependencies = [ + "autocfg", + "hashbrown", + "serde", +] + +[[package]] +name = "inkwell" +version = "0.1.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5fe0be1e47c0c0f3da4397693e08f5d78329ae095c25d529e12ade78420fb41" +dependencies = [ + "either", + "inkwell_internals", + "libc", + "llvm-sys", + "once_cell", + "parking_lot", + "regex", +] + +[[package]] +name = "inkwell_internals" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e1f71330ccec54ee62533ae88574c4169b67fb4b95cbb1196a1322582abd11" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "itertools" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" +dependencies = [ + "either", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "leb128" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" + +[[package]] +name = "libc" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "538c092e5586f4cdd7dd8078c4a79220e3e168880218124dcbce860f0ea938c6" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86c975d637bc2a2f99440932b731491fc34c7f785d239e38af3addd3c2fd0e46" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libloading" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "llvm-sys" +version = "110.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21ede189444b8c78907e5d36da5dabcf153170fcff9c1dba48afc4b33c7e19f0" +dependencies = [ + "cc", + "lazy_static", + "libc", + "regex", + "semver 0.11.0", +] + +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "memmap2" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e3e85b970d650e2ae6d70592474087051c11c54da7f7b4949725c5735fbcc6" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "more-asserts" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" +dependencies = [ + "crc32fast", + "indexmap", +] + +[[package]] +name = "once_cell" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" + +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regalloc" +version = "0.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5" +dependencies = [ + "log", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" + +[[package]] +name = "region" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scroll" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.2", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.124" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.124" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "target-lexicon" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422045212ea98508ae3d28025bc5aaa2bd4a9cdaecd442a08da2ee620ee9ea95" + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" +dependencies = [ + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasm-encoder" +version = "0.4.0" +source = "git+https://github.com/bytecodealliance/wasm-tools#ea17086f38b3bd452a99340109bfdc9759f109a1" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-smith" +version = "0.4.0" +source = "git+https://github.com/bytecodealliance/wasm-tools#ea17086f38b3bd452a99340109bfdc9759f109a1" +dependencies = [ + "arbitrary", + "indexmap", + "leb128", + "wasm-encoder", +] + +[[package]] +name = "wasmer" +version = "1.0.2" +dependencies = [ + "cfg-if 0.1.10", + "indexmap", + "more-asserts", + "target-lexicon", + "thiserror", + "wasmer-compiler", + "wasmer-compiler-cranelift", + "wasmer-derive", + "wasmer-engine", + "wasmer-engine-jit", + "wasmer-engine-native", + "wasmer-types", + "wasmer-vm", + "wat", + "winapi", +] + +[[package]] +name = "wasmer-bin-fuzz" +version = "0.0.0" +dependencies = [ + "anyhow", + "libfuzzer-sys", + "wasm-smith", + "wasmer", + "wasmer-compiler-cranelift", + "wasmer-compiler-llvm", + "wasmer-compiler-singlepass", + "wasmer-engine-jit", + "wasmer-engine-native", + "wasmer-middlewares", +] + +[[package]] +name = "wasmer-compiler" +version = "1.0.2" +dependencies = [ + "enumset", + "serde", + "serde_bytes", + "smallvec", + "target-lexicon", + "thiserror", + "wasmer-types", + "wasmer-vm", + "wasmparser", +] + +[[package]] +name = "wasmer-compiler-cranelift" +version = "1.0.2" +dependencies = [ + "cranelift-codegen", + "cranelift-frontend", + "gimli", + "more-asserts", + "rayon", + "serde", + "smallvec", + "tracing", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", +] + +[[package]] +name = "wasmer-compiler-llvm" +version = "1.0.2" +dependencies = [ + "byteorder", + "cc", + "goblin", + "inkwell", + "itertools", + "lazy_static", + "libc", + "rayon", + "regex", + "rustc_version", + "semver 0.11.0", + "smallvec", + "target-lexicon", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", +] + +[[package]] +name = "wasmer-compiler-singlepass" +version = "1.0.2" +dependencies = [ + "byteorder", + "dynasm", + "dynasmrt", + "lazy_static", + "more-asserts", + "rayon", + "serde", + "smallvec", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", +] + +[[package]] +name = "wasmer-derive" +version = "1.0.2" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "wasmer-engine" +version = "1.0.2" +dependencies = [ + "backtrace", + "bincode", + "lazy_static", + "memmap2", + "more-asserts", + "rustc-demangle", + "serde", + "serde_bytes", + "target-lexicon", + "thiserror", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", +] + +[[package]] +name = "wasmer-engine-jit" +version = "1.0.2" +dependencies = [ + "bincode", + "cfg-if 0.1.10", + "region", + "serde", + "serde_bytes", + "wasmer-compiler", + "wasmer-engine", + "wasmer-types", + "wasmer-vm", + "winapi", +] + +[[package]] +name = "wasmer-engine-native" +version = "1.0.2" +dependencies = [ + "bincode", + "cfg-if 0.1.10", + "leb128", + "libloading", + "serde", + "tempfile", + "tracing", + "wasmer-compiler", + "wasmer-engine", + "wasmer-object", + "wasmer-types", + "wasmer-vm", + "which", +] + +[[package]] +name = "wasmer-middlewares" +version = "1.0.2" +dependencies = [ + "wasmer", + "wasmer-types", + "wasmer-vm", +] + +[[package]] +name = "wasmer-object" +version = "1.0.2" +dependencies = [ + "object", + "thiserror", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-types" +version = "1.0.2" +dependencies = [ + "cranelift-entity", + "serde", + "thiserror", +] + +[[package]] +name = "wasmer-vm" +version = "1.0.2" +dependencies = [ + "backtrace", + "cc", + "cfg-if 0.1.10", + "indexmap", + "libc", + "memoffset", + "more-asserts", + "region", + "serde", + "thiserror", + "wasmer-types", + "winapi", +] + +[[package]] +name = "wasmparser" +version = "0.74.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a4d63608421d9a22d4bce220f2841f3b609a5aaabd3ed3aeeb5fed2702c3c78" + +[[package]] +name = "wast" +version = "35.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5ae96da18bb5926341516fd409b5a8ce4e4714da7f0a1063d3b20ac9f9a1e1" +dependencies = [ + "leb128", +] + +[[package]] +name = "wat" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b0fa059022c5dabe129f02b429d67086400deb8277f89c975555dacc1dadbcc" +dependencies = [ + "wast", +] + +[[package]] +name = "which" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c14ef7e1b8b8ecfc75d5eca37949410046e66f15d185c01d70824f1f8111ef" +dependencies = [ + "libc", + "thiserror", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index d4f00323247..a573677afbc 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -9,7 +9,8 @@ edition = "2018" cargo-fuzz = true [dependencies] -wasm-smith = "0.4.0" +anyhow = "1" +wasm-smith = { git = "https://github.com/bytecodealliance/wasm-tools" } libfuzzer-sys = "0.4.0" [dependencies.wasmer] path = "../lib/api" @@ -30,6 +31,10 @@ path = "../lib/middlewares" [workspace] members = ["."] +[[bin]] +name = "equivalence_jit" +path = "fuzz_targets/equivalence_jit.rs" + [[bin]] name = "jit_cranelift" path = "fuzz_targets/jit_cranelift.rs" diff --git a/fuzz/fuzz_targets/equivalence_jit.rs b/fuzz/fuzz_targets/equivalence_jit.rs new file mode 100644 index 00000000000..bf618366fb0 --- /dev/null +++ b/fuzz/fuzz_targets/equivalence_jit.rs @@ -0,0 +1,146 @@ +#![no_main] + +use anyhow::Result; +use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target}; +use wasm_smith::{Config, ConfiguredModule}; +use wasmer::{imports, CompilerConfig, Instance, Module, Store, Val}; +use wasmer_compiler_cranelift::Cranelift; +use wasmer_compiler_llvm::LLVM; +use wasmer_compiler_singlepass::Singlepass; +use wasmer_engine_jit::JIT; + +#[derive(Arbitrary, Debug, Default, Copy, Clone)] +struct ExportedFunctionConfig; +impl Config for ExportedFunctionConfig { + fn max_imports(&self) -> usize { + 0 + } + fn max_memory_pages(&self) -> u32 { + // https://github.com/wasmerio/wasmer/issues/2187 + 65535 + } + fn min_funcs(&self) -> usize { + 1 + } + fn min_exports(&self) -> usize { + 1 + } +} + +fn maybe_instantiate_singlepass(wasm_bytes: &[u8]) -> Result> { + let compiler = Singlepass::default(); + let store = Store::new(&JIT::new(compiler).engine()); + let module = Module::new(&store, &wasm_bytes); + let module = match module { + Ok(m) => m, + Err(ref e) => { + let error_message = format!("{}", e); + if error_message.contains("Validation error: invalid result arity: func type returns multiple values") || error_message.contains("Validation error: blocks, loops, and ifs accept no parameters when multi-value is not enabled") || error_message.contains("multi-value returns not yet implemented") { + return Ok(None); + } + module?; + unreachable!(""); + } + }; + let instance = Instance::new(&module, &imports! {})?; + Ok(Some(instance)) +} + +fn maybe_instantiate_cranelift(wasm_bytes: &[u8]) -> Result> { + let mut compiler = Cranelift::default(); + compiler.canonicalize_nans(true); + compiler.enable_verifier(); + let store = Store::new(&JIT::new(compiler).engine()); + let module = Module::new(&store, &wasm_bytes)?; + let instance = Instance::new(&module, &imports! {})?; + Ok(Some(instance)) +} + +fn maybe_instantiate_llvm(wasm_bytes: &[u8]) -> Result> { + let mut compiler = LLVM::default(); + compiler.canonicalize_nans(true); + compiler.enable_verifier(); + let store = Store::new(&JIT::new(compiler).engine()); + let module = Module::new(&store, &wasm_bytes)?; + let instance = Instance::new(&module, &imports! {})?; + Ok(Some(instance)) +} + +#[derive(Debug)] +enum InstanceResult { + Error(String), + Values(Vec), +} + +impl PartialEq for InstanceResult { + fn eq(&self, other: &Self) -> bool { + match self { + InstanceResult::Error(self_message) => { + if let InstanceResult::Error(other_message) = other { + return self_message == other_message; + } + return false; + } + InstanceResult::Values(self_values) => { + if let InstanceResult::Values(other_values) = other { + return self_values == other_values; + } + return false; + } + } + } +} + +impl Eq for InstanceResult {} + +fn evaluate_instance(instance: Result) -> Vec { + let mut results = vec![]; + + if let Err(err) = instance { + let mut error_message = format!("{}", err); + // Remove the stack trace. + if error_message.starts_with("RuntimeError: unreachable\n") { + error_message = "RuntimeError: unreachable\n".into(); + } + results.push(InstanceResult::Error(error_message)); + } else { + let instance = instance.unwrap(); + for it in instance.exports.iter().functions() { + let (_, f) = it; + // TODO: support functions which take params. + if f.ty().params().is_empty() { + let result = f.call(&[]); + let result = if result.is_ok() { + let values = result.unwrap(); + InstanceResult::Values(values.into()) + } else { + let err = result.unwrap_err(); + let error_message = err.message(); + InstanceResult::Error(error_message) + }; + results.push(result); + } + } + } + results +} + +fuzz_target!(|module: ConfiguredModule| { + let mut module = module; + module.ensure_termination(100000); + let wasm_bytes = module.to_bytes(); + + let singlepass = maybe_instantiate_singlepass(&wasm_bytes).transpose().map(evaluate_instance); + let cranelift = maybe_instantiate_cranelift(&wasm_bytes).transpose().map(evaluate_instance); + let llvm = maybe_instantiate_llvm(&wasm_bytes).transpose().map(evaluate_instance); + + if singlepass.is_some() && cranelift.is_some() { + assert_eq!(singlepass.as_ref().unwrap(), cranelift.as_ref().unwrap()); + } + if singlepass.is_some() && llvm.is_some() { + assert_eq!(singlepass.as_ref().unwrap(), llvm.as_ref().unwrap()); + } + if cranelift.is_some() && llvm.is_some() { + assert_eq!(cranelift.as_ref().unwrap(), llvm.as_ref().unwrap()); + } +}); From 5e69366b1d9b1cf36299b14fcc1cc9e62489fd39 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Mar 2021 14:05:38 +0100 Subject: [PATCH 11/19] feat(types) Remove dependency to `cranelift-entity`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't be afraid, everything is cool. `cranelift-entity` is nice, but we are limited by it. We want to go further for some features. Those features are very likely to be refused by Cranelift because it's out of their scope. This patch basically copies the code from `cranelift-entity` inside `wasmer-types`. The code has been modified to fit in our own “`no_std`” strategy. The code will be modified deeper in upcoming patches and most of the entities are likely to radically change. The goal of this patch is strictly to not break our code while porting the new code. --- Cargo.lock | 4 - lib/wasmer-types/Cargo.toml | 5 +- lib/wasmer-types/src/entity/boxed_slice.rs | 316 ++++++++++++++ lib/wasmer-types/src/entity/iter.rs | 124 ++++++ lib/wasmer-types/src/entity/keys.rs | 58 +++ lib/wasmer-types/src/entity/mod.rs | 92 ++++ lib/wasmer-types/src/entity/packed_option.rs | 171 ++++++++ lib/wasmer-types/src/entity/primary_map.rs | 425 +++++++++++++++++++ lib/wasmer-types/src/entity/secondary_map.rs | 320 ++++++++++++++ lib/wasmer-types/src/lib.rs | 19 +- 10 files changed, 1517 insertions(+), 17 deletions(-) create mode 100644 lib/wasmer-types/src/entity/boxed_slice.rs create mode 100644 lib/wasmer-types/src/entity/iter.rs create mode 100644 lib/wasmer-types/src/entity/keys.rs create mode 100644 lib/wasmer-types/src/entity/mod.rs create mode 100644 lib/wasmer-types/src/entity/packed_option.rs create mode 100644 lib/wasmer-types/src/entity/primary_map.rs create mode 100644 lib/wasmer-types/src/entity/secondary_map.rs diff --git a/Cargo.lock b/Cargo.lock index eb73620585a..8a9238eefe7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,9 +426,6 @@ name = "cranelift-entity" version = "0.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e55e9043403f0dec775f317280015150e78b2352fb947d2f37407fd4ce6311c7" -dependencies = [ - "serde", -] [[package]] name = "cranelift-frontend" @@ -2602,7 +2599,6 @@ dependencies = [ name = "wasmer-types" version = "1.0.2" dependencies = [ - "cranelift-entity", "serde", "thiserror", ] diff --git a/lib/wasmer-types/Cargo.toml b/lib/wasmer-types/Cargo.toml index 9f56e3361ff..892c13ad943 100644 --- a/lib/wasmer-types/Cargo.toml +++ b/lib/wasmer-types/Cargo.toml @@ -11,9 +11,6 @@ readme = "README.md" edition = "2018" [dependencies] -# We use `cranelift-entity` here because it's a lightweight dependency and it contains -# some useful data structures -cranelift-entity = "0.70" serde = { version = "1.0", features = ["derive"], optional = true, default-features = false } thiserror = "1.0" @@ -21,4 +18,4 @@ thiserror = "1.0" default = ["std", "enable-serde"] std = ["serde/std"] core = [] -enable-serde = ["serde", "cranelift-entity/enable-serde"] +enable-serde = ["serde"] diff --git a/lib/wasmer-types/src/entity/boxed_slice.rs b/lib/wasmer-types/src/entity/boxed_slice.rs new file mode 100644 index 00000000000..277d09a9d2d --- /dev/null +++ b/lib/wasmer-types/src/entity/boxed_slice.rs @@ -0,0 +1,316 @@ +//! Boxed slices for `PrimaryMap`. + +use crate::entity::iter::{Iter, IterMut}; +use crate::entity::keys::Keys; +use crate::entity::EntityRef; +use crate::lib::std::boxed::Box; +use crate::lib::std::marker::PhantomData; +use crate::lib::std::ops::{Index, IndexMut}; +use crate::lib::std::slice; + +/// A slice mapping `K -> V` allocating dense entity references. +/// +/// The `BoxedSlice` data structure uses the dense index space to implement a map with a boxed +/// slice. +#[derive(Debug, Clone)] +pub struct BoxedSlice +where + K: EntityRef, +{ + elems: Box<[V]>, + unused: PhantomData, +} + +impl BoxedSlice +where + K: EntityRef, +{ + /// Create a new slice from a raw pointer. A safer way to create slices is + /// to use `PrimaryMap::into_boxed_slice()`. + /// + /// # Safety + /// + /// This relies on `raw` pointing to a valid slice of `V`s. + pub unsafe fn from_raw(raw: *mut [V]) -> Self { + Self { + elems: Box::from_raw(raw), + unused: PhantomData, + } + } + + /// Check if `k` is a valid key in the map. + pub fn is_valid(&self, k: K) -> bool { + k.index() < self.elems.len() + } + + /// Get the element at `k` if it exists. + pub fn get(&self, k: K) -> Option<&V> { + self.elems.get(k.index()) + } + + /// Get the element at `k` if it exists, mutable version. + pub fn get_mut(&mut self, k: K) -> Option<&mut V> { + self.elems.get_mut(k.index()) + } + + /// Is this map completely empty? + pub fn is_empty(&self) -> bool { + self.elems.is_empty() + } + + /// Get the total number of entity references created. + pub fn len(&self) -> usize { + self.elems.len() + } + + /// Iterate over all the keys in this map. + pub fn keys(&self) -> Keys { + Keys::with_len(self.elems.len()) + } + + /// Iterate over all the values in this map. + pub fn values(&self) -> slice::Iter { + self.elems.iter() + } + + /// Iterate over all the values in this map, mutable edition. + pub fn values_mut(&mut self) -> slice::IterMut { + self.elems.iter_mut() + } + + /// Iterate over all the keys and values in this map. + pub fn iter(&self) -> Iter { + Iter::new(self.elems.iter()) + } + + /// Iterate over all the keys and values in this map, mutable edition. + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(self.elems.iter_mut()) + } + + /// Returns the last element that was inserted in the map. + pub fn last(&self) -> Option<&V> { + self.elems.last() + } +} + +/// Immutable indexing into a `BoxedSlice`. +/// The indexed value must be in the map. +impl Index for BoxedSlice +where + K: EntityRef, +{ + type Output = V; + + fn index(&self, k: K) -> &V { + &self.elems[k.index()] + } +} + +/// Mutable indexing into a `BoxedSlice`. +impl IndexMut for BoxedSlice +where + K: EntityRef, +{ + fn index_mut(&mut self, k: K) -> &mut V { + &mut self.elems[k.index()] + } +} + +impl<'a, K, V> IntoIterator for &'a BoxedSlice +where + K: EntityRef, +{ + type Item = (K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + Iter::new(self.elems.iter()) + } +} + +impl<'a, K, V> IntoIterator for &'a mut BoxedSlice +where + K: EntityRef, +{ + type Item = (K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + IterMut::new(self.elems.iter_mut()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::lib::std::vec::Vec; + use crate::primary::PrimaryMap; + + // `EntityRef` impl for testing. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct E(u32); + + impl EntityRef for E { + fn new(i: usize) -> Self { + E(i as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + #[test] + fn basic() { + let r0 = E(0); + let r1 = E(1); + let p = PrimaryMap::::new(); + let m = p.into_boxed_slice(); + + let v: Vec = m.keys().collect(); + assert_eq!(v, []); + + assert!(!m.is_valid(r0)); + assert!(!m.is_valid(r1)); + } + + #[test] + fn iter() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let mut m = p.into_boxed_slice(); + + let mut i = 0; + for (key, value) in &m { + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for (key_mut, value_mut) in m.iter_mut() { + assert_eq!(key_mut.index(), i); + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn iter_rev() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let mut m = p.into_boxed_slice(); + + let mut i = 2; + for (key, value) in m.iter().rev() { + i -= 1; + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + + i = 2; + for (key, value) in m.iter_mut().rev() { + i -= 1; + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + } + #[test] + fn keys() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let m = p.into_boxed_slice(); + + let mut i = 0; + for key in m.keys() { + assert_eq!(key.index(), i); + i += 1; + } + } + + #[test] + fn keys_rev() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let m = p.into_boxed_slice(); + + let mut i = 2; + for key in m.keys().rev() { + i -= 1; + assert_eq!(key.index(), i); + } + } + + #[test] + fn values() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let mut m = p.into_boxed_slice(); + + let mut i = 0; + for value in m.values() { + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for value_mut in m.values_mut() { + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn values_rev() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let mut m = p.into_boxed_slice(); + + let mut i = 2; + for value in m.values().rev() { + i -= 1; + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + i = 2; + for value_mut in m.values_mut().rev() { + i -= 1; + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + } + } +} diff --git a/lib/wasmer-types/src/entity/iter.rs b/lib/wasmer-types/src/entity/iter.rs new file mode 100644 index 00000000000..26ee370f3f9 --- /dev/null +++ b/lib/wasmer-types/src/entity/iter.rs @@ -0,0 +1,124 @@ +//! A double-ended iterator over entity references and entities. + +use crate::entity::EntityRef; +use crate::lib::std::iter::Enumerate; +use crate::lib::std::marker::PhantomData; +use crate::lib::std::slice; +use crate::lib::std::vec; + +/// Iterate over all keys in order. +pub struct Iter<'a, K: EntityRef, V> +where + V: 'a, +{ + enumerate: Enumerate>, + unused: PhantomData, +} + +impl<'a, K: EntityRef, V> Iter<'a, K, V> { + /// Create an `Iter` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(iter: slice::Iter<'a, V>) -> Self { + Self { + enumerate: iter.enumerate(), + unused: PhantomData, + } + } +} + +impl<'a, K: EntityRef, V> Iterator for Iter<'a, K, V> { + type Item = (K, &'a V); + + fn next(&mut self) -> Option { + self.enumerate.next().map(|(i, v)| (K::new(i), v)) + } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } +} + +impl<'a, K: EntityRef, V> DoubleEndedIterator for Iter<'a, K, V> { + fn next_back(&mut self) -> Option { + self.enumerate.next_back().map(|(i, v)| (K::new(i), v)) + } +} + +impl<'a, K: EntityRef, V> ExactSizeIterator for Iter<'a, K, V> {} + +/// Iterate over all keys in order. +pub struct IterMut<'a, K: EntityRef, V> +where + V: 'a, +{ + enumerate: Enumerate>, + unused: PhantomData, +} + +impl<'a, K: EntityRef, V> IterMut<'a, K, V> { + /// Create an `IterMut` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(iter: slice::IterMut<'a, V>) -> Self { + Self { + enumerate: iter.enumerate(), + unused: PhantomData, + } + } +} + +impl<'a, K: EntityRef, V> Iterator for IterMut<'a, K, V> { + type Item = (K, &'a mut V); + + fn next(&mut self) -> Option { + self.enumerate.next().map(|(i, v)| (K::new(i), v)) + } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } +} + +impl<'a, K: EntityRef, V> DoubleEndedIterator for IterMut<'a, K, V> { + fn next_back(&mut self) -> Option { + self.enumerate.next_back().map(|(i, v)| (K::new(i), v)) + } +} + +impl<'a, K: EntityRef, V> ExactSizeIterator for IterMut<'a, K, V> {} + +/// Iterate over all keys in order. +pub struct IntoIter { + enumerate: Enumerate>, + unused: PhantomData, +} + +impl IntoIter { + /// Create an `IntoIter` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(iter: vec::IntoIter) -> Self { + Self { + enumerate: iter.enumerate(), + unused: PhantomData, + } + } +} + +impl Iterator for IntoIter { + type Item = (K, V); + + fn next(&mut self) -> Option { + self.enumerate.next().map(|(i, v)| (K::new(i), v)) + } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + self.enumerate.next_back().map(|(i, v)| (K::new(i), v)) + } +} + +impl ExactSizeIterator for IntoIter {} diff --git a/lib/wasmer-types/src/entity/keys.rs b/lib/wasmer-types/src/entity/keys.rs new file mode 100644 index 00000000000..b9892bf551f --- /dev/null +++ b/lib/wasmer-types/src/entity/keys.rs @@ -0,0 +1,58 @@ +//! A double-ended iterator over entity references. +//! +//! When `core::iter::Step` is stabilized, `Keys` could be implemented as a wrapper around +//! `core::ops::Range`, but for now, we implement it manually. + +use crate::entity::EntityRef; +use crate::lib::std::marker::PhantomData; + +/// Iterate over all keys in order. +pub struct Keys { + pos: usize, + rev_pos: usize, + unused: PhantomData, +} + +impl Keys { + /// Create a `Keys` iterator that visits `len` entities starting from 0. + pub fn with_len(len: usize) -> Self { + Self { + pos: 0, + rev_pos: len, + unused: PhantomData, + } + } +} + +impl Iterator for Keys { + type Item = K; + + fn next(&mut self) -> Option { + if self.pos < self.rev_pos { + let k = K::new(self.pos); + self.pos += 1; + Some(k) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + let size = self.rev_pos - self.pos; + (size, Some(size)) + } +} + +impl DoubleEndedIterator for Keys { + fn next_back(&mut self) -> Option { + if self.rev_pos > self.pos { + let k = K::new(self.rev_pos - 1); + self.rev_pos -= 1; + Some(k) + } else { + None + } + } +} + +impl ExactSizeIterator for Keys {} diff --git a/lib/wasmer-types/src/entity/mod.rs b/lib/wasmer-types/src/entity/mod.rs new file mode 100644 index 00000000000..cc802ef85e5 --- /dev/null +++ b/lib/wasmer-types/src/entity/mod.rs @@ -0,0 +1,92 @@ +/// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key +/// of an `SecondaryMap` or `SparseMap`. +pub trait EntityRef: Copy + Eq { + /// Create a new entity reference from a small integer. + /// This should crash if the requested index is not representable. + fn new(_: usize) -> Self; + + /// Get the index that was used to create this entity reference. + fn index(self) -> usize; +} + +/// Macro which provides the common implementation of a 32-bit entity reference. +#[macro_export] +macro_rules! entity_impl { + // Basic traits. + ($entity:ident) => { + impl $crate::entity::EntityRef for $entity { + fn new(index: usize) -> Self { + debug_assert!(index < ($crate::lib::std::u32::MAX as usize)); + $entity(index as u32) + } + + fn index(self) -> usize { + self.0 as usize + } + } + + impl $crate::entity::packed_option::ReservedValue for $entity { + fn reserved_value() -> $entity { + $entity($crate::lib::std::u32::MAX) + } + + fn is_reserved_value(&self) -> bool { + self.0 == $crate::lib::std::u32::MAX + } + } + + impl $entity { + /// Create a new instance from a `u32`. + #[allow(dead_code)] + pub fn from_u32(x: u32) -> Self { + debug_assert!(x < $crate::lib::std::u32::MAX); + $entity(x) + } + + /// Return the underlying index value as a `u32`. + #[allow(dead_code)] + pub fn as_u32(self) -> u32 { + self.0 + } + } + }; + + // Include basic `Display` impl using the given display prefix. + // Display a `Block` reference as "block12". + ($entity:ident, $display_prefix:expr) => { + entity_impl!($entity); + + impl $crate::lib::std::fmt::Display for $entity { + fn fmt( + &self, + f: &mut $crate::lib::std::fmt::Formatter, + ) -> $crate::lib::std::fmt::Result { + write!(f, concat!($display_prefix, "{}"), self.0) + } + } + + impl $crate::lib::std::fmt::Debug for $entity { + fn fmt( + &self, + f: &mut $crate::lib::std::fmt::Formatter, + ) -> $crate::lib::std::fmt::Result { + (self as &dyn $crate::lib::std::fmt::Display).fmt(f) + } + } + }; +} + +pub mod packed_option; + +mod boxed_slice; +mod iter; +mod keys; +mod primary_map; +mod secondary_map; + +pub use crate::entity_impl; +pub use boxed_slice::BoxedSlice; +pub use iter::{Iter, IterMut}; +pub use keys::Keys; +pub use primary_map::PrimaryMap; +pub use secondary_map::SecondaryMap; diff --git a/lib/wasmer-types/src/entity/packed_option.rs b/lib/wasmer-types/src/entity/packed_option.rs new file mode 100644 index 00000000000..6ba51cdf262 --- /dev/null +++ b/lib/wasmer-types/src/entity/packed_option.rs @@ -0,0 +1,171 @@ +//! Compact representation of `Option` for types with a reserved value. +//! +//! Small Cranelift types like the 32-bit entity references are often used in tables and linked +//! lists where an `Option` is needed. Unfortunately, that would double the size of the tables +//! because `Option` is twice as big as `T`. +//! +//! This module provides a `PackedOption` for types that have a reserved value that can be used +//! to represent `None`. + +use crate::lib::std::fmt; +use crate::lib::std::mem; + +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + +/// Types that have a reserved value which can't be created any other way. +pub trait ReservedValue { + /// Create an instance of the reserved value. + fn reserved_value() -> Self; + /// Checks whether value is the reserved one. + fn is_reserved_value(&self) -> bool; +} + +/// Packed representation of `Option`. +#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct PackedOption(T); + +impl PackedOption { + /// Returns `true` if the packed option is a `None` value. + pub fn is_none(&self) -> bool { + self.0.is_reserved_value() + } + + /// Returns `true` if the packed option is a `Some` value. + pub fn is_some(&self) -> bool { + !self.0.is_reserved_value() + } + + /// Expand the packed option into a normal `Option`. + pub fn expand(self) -> Option { + if self.is_none() { + None + } else { + Some(self.0) + } + } + + /// Maps a `PackedOption` to `Option` by applying a function to a contained value. + pub fn map(self, f: F) -> Option + where + F: FnOnce(T) -> U, + { + self.expand().map(f) + } + + /// Unwrap a packed `Some` value or panic. + pub fn unwrap(self) -> T { + self.expand().unwrap() + } + + /// Unwrap a packed `Some` value or panic. + pub fn expect(self, msg: &str) -> T { + self.expand().expect(msg) + } + + /// Takes the value out of the packed option, leaving a `None` in its place. + pub fn take(&mut self) -> Option { + mem::replace(self, None.into()).expand() + } +} + +impl Default for PackedOption { + /// Create a default packed option representing `None`. + fn default() -> Self { + Self(T::reserved_value()) + } +} + +impl From for PackedOption { + /// Convert `t` into a packed `Some(x)`. + fn from(t: T) -> Self { + debug_assert!( + !t.is_reserved_value(), + "Can't make a PackedOption from the reserved value." + ); + Self(t) + } +} + +impl From> for PackedOption { + /// Convert an option into its packed equivalent. + fn from(opt: Option) -> Self { + match opt { + None => Self::default(), + Some(t) => t.into(), + } + } +} + +impl Into> for PackedOption { + fn into(self) -> Option { + self.expand() + } +} + +impl fmt::Debug for PackedOption +where + T: ReservedValue + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_none() { + write!(f, "None") + } else { + write!(f, "Some({:?})", self.0) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // Dummy entity class, with no Copy or Clone. + #[derive(Debug, PartialEq, Eq)] + struct NoC(u32); + + impl ReservedValue for NoC { + fn reserved_value() -> Self { + NoC(13) + } + + fn is_reserved_value(&self) -> bool { + self.0 == 13 + } + } + + #[test] + fn moves() { + let x = NoC(3); + let somex: PackedOption = x.into(); + assert!(!somex.is_none()); + assert_eq!(somex.expand(), Some(NoC(3))); + + let none: PackedOption = None.into(); + assert!(none.is_none()); + assert_eq!(none.expand(), None); + } + + // Dummy entity class, with Copy. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct Ent(u32); + + impl ReservedValue for Ent { + fn reserved_value() -> Self { + Ent(13) + } + + fn is_reserved_value(&self) -> bool { + self.0 == 13 + } + } + + #[test] + fn copies() { + let x = Ent(2); + let some: PackedOption = x.into(); + assert_eq!(some.expand(), x.into()); + assert_eq!(some, x.into()); + } +} diff --git a/lib/wasmer-types/src/entity/primary_map.rs b/lib/wasmer-types/src/entity/primary_map.rs new file mode 100644 index 00000000000..c709afef050 --- /dev/null +++ b/lib/wasmer-types/src/entity/primary_map.rs @@ -0,0 +1,425 @@ +//! Densely numbered entity references as mapping keys. +use crate::entity::boxed_slice::BoxedSlice; +use crate::entity::iter::{IntoIter, Iter, IterMut}; +use crate::entity::keys::Keys; +use crate::entity::EntityRef; +use crate::lib::std::boxed::Box; +use crate::lib::std::iter::FromIterator; +use crate::lib::std::marker::PhantomData; +use crate::lib::std::ops::{Index, IndexMut}; +use crate::lib::std::slice; +use crate::lib::std::vec::Vec; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + +/// A primary mapping `K -> V` allocating dense entity references. +/// +/// The `PrimaryMap` data structure uses the dense index space to implement a map with a vector. +/// +/// A primary map contains the main definition of an entity, and it can be used to allocate new +/// entity references with the `push` method. +/// +/// There should only be a single `PrimaryMap` instance for a given `EntityRef` type, otherwise +/// conflicting references will be created. Using unknown keys for indexing will cause a panic. +/// +/// Note that `PrimaryMap` doesn't implement `Deref` or `DerefMut`, which would allow +/// `&PrimaryMap` to convert to `&[V]`. One of the main advantages of `PrimaryMap` is +/// that it only allows indexing with the distinct `EntityRef` key type, so converting to a +/// plain slice would make it easier to use incorrectly. To make a slice of a `PrimaryMap`, use +/// `into_boxed_slice`. +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct PrimaryMap +where + K: EntityRef, +{ + elems: Vec, + unused: PhantomData, +} + +impl PrimaryMap +where + K: EntityRef, +{ + /// Create a new empty map. + pub fn new() -> Self { + Self { + elems: Vec::new(), + unused: PhantomData, + } + } + + /// Create a new empty map with the given capacity. + pub fn with_capacity(capacity: usize) -> Self { + Self { + elems: Vec::with_capacity(capacity), + unused: PhantomData, + } + } + + /// Check if `k` is a valid key in the map. + pub fn is_valid(&self, k: K) -> bool { + k.index() < self.elems.len() + } + + /// Get the element at `k` if it exists. + pub fn get(&self, k: K) -> Option<&V> { + self.elems.get(k.index()) + } + + /// Get the element at `k` if it exists, mutable version. + pub fn get_mut(&mut self, k: K) -> Option<&mut V> { + self.elems.get_mut(k.index()) + } + + /// Is this map completely empty? + pub fn is_empty(&self) -> bool { + self.elems.is_empty() + } + + /// Get the total number of entity references created. + pub fn len(&self) -> usize { + self.elems.len() + } + + /// Iterate over all the keys in this map. + pub fn keys(&self) -> Keys { + Keys::with_len(self.elems.len()) + } + + /// Iterate over all the values in this map. + pub fn values(&self) -> slice::Iter { + self.elems.iter() + } + + /// Iterate over all the values in this map, mutable edition. + pub fn values_mut(&mut self) -> slice::IterMut { + self.elems.iter_mut() + } + + /// Iterate over all the keys and values in this map. + pub fn iter(&self) -> Iter { + Iter::new(self.elems.iter()) + } + + /// Iterate over all the keys and values in this map, mutable edition. + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(self.elems.iter_mut()) + } + + /// Remove all entries from this map. + pub fn clear(&mut self) { + self.elems.clear() + } + + /// Get the key that will be assigned to the next pushed value. + pub fn next_key(&self) -> K { + K::new(self.elems.len()) + } + + /// Append `v` to the mapping, assigning a new key which is returned. + pub fn push(&mut self, v: V) -> K { + let k = self.next_key(); + self.elems.push(v); + k + } + + /// Returns the last element that was inserted in the map. + pub fn last(&self) -> Option<&V> { + self.elems.last() + } + + /// Reserves capacity for at least `additional` more elements to be inserted. + pub fn reserve(&mut self, additional: usize) { + self.elems.reserve(additional) + } + + /// Reserves the minimum capacity for exactly `additional` more elements to be inserted. + pub fn reserve_exact(&mut self, additional: usize) { + self.elems.reserve_exact(additional) + } + + /// Shrinks the capacity of the `PrimaryMap` as much as possible. + pub fn shrink_to_fit(&mut self) { + self.elems.shrink_to_fit() + } + + /// Consumes this `PrimaryMap` and produces a `BoxedSlice`. + pub fn into_boxed_slice(self) -> BoxedSlice { + unsafe { BoxedSlice::::from_raw(Box::<[V]>::into_raw(self.elems.into_boxed_slice())) } + } +} + +impl Default for PrimaryMap +where + K: EntityRef, +{ + fn default() -> PrimaryMap { + PrimaryMap::new() + } +} + +/// Immutable indexing into an `PrimaryMap`. +/// The indexed value must be in the map. +impl Index for PrimaryMap +where + K: EntityRef, +{ + type Output = V; + + fn index(&self, k: K) -> &V { + &self.elems[k.index()] + } +} + +/// Mutable indexing into an `PrimaryMap`. +impl IndexMut for PrimaryMap +where + K: EntityRef, +{ + fn index_mut(&mut self, k: K) -> &mut V { + &mut self.elems[k.index()] + } +} + +impl IntoIterator for PrimaryMap +where + K: EntityRef, +{ + type Item = (K, V); + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.elems.into_iter()) + } +} + +impl<'a, K, V> IntoIterator for &'a PrimaryMap +where + K: EntityRef, +{ + type Item = (K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + Iter::new(self.elems.iter()) + } +} + +impl<'a, K, V> IntoIterator for &'a mut PrimaryMap +where + K: EntityRef, +{ + type Item = (K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + IterMut::new(self.elems.iter_mut()) + } +} + +impl FromIterator for PrimaryMap +where + K: EntityRef, +{ + fn from_iter(iter: T) -> Self + where + T: IntoIterator, + { + Self { + elems: Vec::from_iter(iter), + unused: PhantomData, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // `EntityRef` impl for testing. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct E(u32); + + impl EntityRef for E { + fn new(i: usize) -> Self { + E(i as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + #[test] + fn basic() { + let r0 = E(0); + let r1 = E(1); + let m = PrimaryMap::::new(); + + let v: Vec = m.keys().collect(); + assert_eq!(v, []); + + assert!(!m.is_valid(r0)); + assert!(!m.is_valid(r1)); + } + + #[test] + fn push() { + let mut m = PrimaryMap::new(); + let k0: E = m.push(12); + let k1 = m.push(33); + + assert_eq!(m[k0], 12); + assert_eq!(m[k1], 33); + + let v: Vec = m.keys().collect(); + assert_eq!(v, [k0, k1]); + } + + #[test] + fn iter() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 0; + for (key, value) in &m { + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for (key_mut, value_mut) in m.iter_mut() { + assert_eq!(key_mut.index(), i); + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn iter_rev() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 2; + for (key, value) in m.iter().rev() { + i -= 1; + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + + i = 2; + for (key, value) in m.iter_mut().rev() { + i -= 1; + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + } + #[test] + fn keys() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 0; + for key in m.keys() { + assert_eq!(key.index(), i); + i += 1; + } + } + + #[test] + fn keys_rev() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 2; + for key in m.keys().rev() { + i -= 1; + assert_eq!(key.index(), i); + } + } + + #[test] + fn values() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 0; + for value in m.values() { + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for value_mut in m.values_mut() { + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn values_rev() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 2; + for value in m.values().rev() { + i -= 1; + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + i = 2; + for value_mut in m.values_mut().rev() { + i -= 1; + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + } + } + + #[test] + fn from_iter() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let n = m.values().collect::>(); + assert!(m.len() == n.len()); + for (me, ne) in m.values().zip(n.values()) { + assert!(*me == **ne); + } + } +} diff --git a/lib/wasmer-types/src/entity/secondary_map.rs b/lib/wasmer-types/src/entity/secondary_map.rs new file mode 100644 index 00000000000..936caa24957 --- /dev/null +++ b/lib/wasmer-types/src/entity/secondary_map.rs @@ -0,0 +1,320 @@ +//! Densely numbered entity references as mapping keys. + +use crate::entity::iter::{Iter, IterMut}; +use crate::entity::keys::Keys; +use crate::entity::EntityRef; +use crate::lib::std::cmp::min; +use crate::lib::std::marker::PhantomData; +use crate::lib::std::ops::{Index, IndexMut}; +use crate::lib::std::slice; +use crate::lib::std::vec::Vec; +#[cfg(feature = "enable-serde")] +use serde::{ + de::{Deserializer, SeqAccess, Visitor}, + ser::{SerializeSeq, Serializer}, + Deserialize, Serialize, +}; + +/// A mapping `K -> V` for densely indexed entity references. +/// +/// The `SecondaryMap` data structure uses the dense index space to implement a map with a vector. +/// Unlike `PrimaryMap`, an `SecondaryMap` can't be used to allocate entity references. It is used +/// to associate secondary information with entities. +/// +/// The map does not track if an entry for a key has been inserted or not. Instead it behaves as if +/// all keys have a default entry from the beginning. +#[derive(Debug, Clone)] +pub struct SecondaryMap +where + K: EntityRef, + V: Clone, +{ + elems: Vec, + default: V, + unused: PhantomData, +} + +/// Shared `SecondaryMap` implementation for all value types. +impl SecondaryMap +where + K: EntityRef, + V: Clone, +{ + /// Create a new empty map. + pub fn new() -> Self + where + V: Default, + { + Self { + elems: Vec::new(), + default: Default::default(), + unused: PhantomData, + } + } + + /// Create a new, empty map with the specified capacity. + /// + /// The map will be able to hold exactly `capacity` elements without reallocating. + pub fn with_capacity(capacity: usize) -> Self + where + V: Default, + { + Self { + elems: Vec::with_capacity(capacity), + default: Default::default(), + unused: PhantomData, + } + } + + /// Create a new empty map with a specified default value. + /// + /// This constructor does not require V to implement Default. + pub fn with_default(default: V) -> Self { + Self { + elems: Vec::new(), + default, + unused: PhantomData, + } + } + + /// Returns the number of elements the map can hold without reallocating. + pub fn capacity(&self) -> usize { + self.elems.capacity() + } + + /// Get the element at `k` if it exists. + #[inline(always)] + pub fn get(&self, k: K) -> Option<&V> { + self.elems.get(k.index()) + } + + /// Is this map completely empty? + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.elems.is_empty() + } + + /// Remove all entries from this map. + #[inline(always)] + pub fn clear(&mut self) { + self.elems.clear() + } + + /// Iterate over all the keys and values in this map. + pub fn iter(&self) -> Iter { + Iter::new(self.elems.iter()) + } + + /// Iterate over all the keys and values in this map, mutable edition. + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(self.elems.iter_mut()) + } + + /// Iterate over all the keys in this map. + pub fn keys(&self) -> Keys { + Keys::with_len(self.elems.len()) + } + + /// Iterate over all the values in this map. + pub fn values(&self) -> slice::Iter { + self.elems.iter() + } + + /// Iterate over all the values in this map, mutable edition. + pub fn values_mut(&mut self) -> slice::IterMut { + self.elems.iter_mut() + } + + /// Resize the map to have `n` entries by adding default entries as needed. + pub fn resize(&mut self, n: usize) { + self.elems.resize(n, self.default.clone()); + } +} + +impl Default for SecondaryMap +where + K: EntityRef, + V: Clone + Default, +{ + fn default() -> SecondaryMap { + SecondaryMap::new() + } +} + +/// Immutable indexing into an `SecondaryMap`. +/// +/// All keys are permitted. Untouched entries have the default value. +impl Index for SecondaryMap +where + K: EntityRef, + V: Clone, +{ + type Output = V; + + #[inline(always)] + fn index(&self, k: K) -> &V { + self.elems.get(k.index()).unwrap_or(&self.default) + } +} + +/// Mutable indexing into an `SecondaryMap`. +/// +/// The map grows as needed to accommodate new keys. +impl IndexMut for SecondaryMap +where + K: EntityRef, + V: Clone, +{ + #[inline(always)] + fn index_mut(&mut self, k: K) -> &mut V { + let i = k.index(); + if i >= self.elems.len() { + self.elems.resize(i + 1, self.default.clone()); + } + &mut self.elems[i] + } +} + +impl PartialEq for SecondaryMap +where + K: EntityRef, + V: Clone + PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + let min_size = min(self.elems.len(), other.elems.len()); + self.default == other.default + && self.elems[..min_size] == other.elems[..min_size] + && self.elems[min_size..].iter().all(|e| *e == self.default) + && other.elems[min_size..].iter().all(|e| *e == other.default) + } +} + +impl Eq for SecondaryMap +where + K: EntityRef, + V: Clone + PartialEq + Eq, +{ +} + +#[cfg(feature = "enable-serde")] +impl Serialize for SecondaryMap +where + K: EntityRef, + V: Clone + PartialEq + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + // TODO: bincode encodes option as "byte for Some/None" and then optionally the content + // TODO: we can actually optimize it by encoding manually bitmask, then elements + let mut elems_cnt = self.elems.len(); + while elems_cnt > 0 && self.elems[elems_cnt - 1] == self.default { + elems_cnt -= 1; + } + let mut seq = serializer.serialize_seq(Some(1 + elems_cnt))?; + seq.serialize_element(&Some(self.default.clone()))?; + for e in self.elems.iter().take(elems_cnt) { + let some_e = Some(e); + seq.serialize_element(if *e == self.default { &None } else { &some_e })?; + } + seq.end() + } +} + +#[cfg(feature = "enable-serde")] +impl<'de, K, V> Deserialize<'de> for SecondaryMap +where + K: EntityRef, + V: Clone + Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use crate::lib::std::fmt; + + struct SecondaryMapVisitor { + unused: PhantomData V>, + } + + impl<'de, K, V> Visitor<'de> for SecondaryMapVisitor + where + K: EntityRef, + V: Clone + Deserialize<'de>, + { + type Value = SecondaryMap; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct SecondaryMap") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + match seq.next_element()? { + Some(Some(default_val)) => { + let default_val: V = default_val; // compiler can't infer the type + let mut m = SecondaryMap::with_default(default_val.clone()); + let mut idx = 0; + while let Some(val) = seq.next_element()? { + let val: Option<_> = val; // compiler can't infer the type + m[K::new(idx)] = val.unwrap_or_else(|| default_val.clone()); + idx += 1; + } + Ok(m) + } + _ => Err(serde::de::Error::custom("Default value required")), + } + } + } + + deserializer.deserialize_seq(SecondaryMapVisitor { + unused: PhantomData {}, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // `EntityRef` impl for testing. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct E(u32); + + impl EntityRef for E { + fn new(i: usize) -> Self { + E(i as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + #[test] + fn basic() { + let r0 = E(0); + let r1 = E(1); + let r2 = E(2); + let mut m = SecondaryMap::new(); + + let v: Vec = m.keys().collect(); + assert_eq!(v, []); + + m[r2] = 3; + m[r1] = 5; + + assert_eq!(m[r1], 5); + assert_eq!(m[r2], 3); + + let v: Vec = m.keys().collect(); + assert_eq!(v, [r0, r1, r2]); + + let shared = &m; + assert_eq!(shared[r0], 0); + assert_eq!(shared[r1], 5); + assert_eq!(shared[r2], 3); + } +} diff --git a/lib/wasmer-types/src/lib.rs b/lib/wasmer-types/src/lib.rs index c197486dc4c..d08c1a47e4e 100644 --- a/lib/wasmer-types/src/lib.rs +++ b/lib/wasmer-types/src/lib.rs @@ -34,18 +34,22 @@ compile_error!("Both the `std` and `core` features are disabled. Please enable o #[cfg(feature = "core")] extern crate alloc; -mod lib { +/// The `lib` module defines a `std` module that is identical whether +/// the `core` or the `std` feature is enabled. +pub mod lib { + /// Custom `std` module. #[cfg(feature = "core")] pub mod std { - pub use alloc::{borrow, boxed, format, rc, slice, string, vec}; - pub use core::{any, cell, convert, fmt, hash, marker, ops, ptr, sync}; + pub use alloc::{borrow, boxed, format, iter, rc, slice, string, vec}; + pub use core::{any, cell, cmp, convert, fmt, hash, marker, mem, ops, ptr, sync, u32}; } + /// Custom `std` module. #[cfg(feature = "std")] pub mod std { pub use std::{ - any, borrow, boxed, cell, convert, fmt, format, hash, marker, ops, ptr, rc, slice, - string, sync, vec, + any, borrow, boxed, cell, cmp, convert, fmt, format, hash, iter, marker, mem, ops, ptr, + rc, slice, string, sync, u32, vec, }; } } @@ -61,10 +65,7 @@ mod units; mod values; /// The entity module, with common helpers for Rust structures -pub mod entity { - pub use cranelift_entity::*; -} - +pub mod entity; pub use crate::features::Features; pub use crate::indexes::{ CustomSectionIndex, DataIndex, ElemIndex, ExportIndex, FunctionIndex, GlobalIndex, ImportIndex, From 9c1ec38a9aa540b73956450bd135f54f88978c0b Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Mar 2021 14:41:37 +0100 Subject: [PATCH 12/19] feat(compiler-cranelift) Migrate to the recent changes in `wasmer-types`. --- lib/compiler-cranelift/Cargo.toml | 3 ++- lib/compiler-cranelift/src/sink.rs | 1 + lib/compiler-cranelift/src/translator/translation_utils.rs | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/compiler-cranelift/Cargo.toml b/lib/compiler-cranelift/Cargo.toml index 9a2c809f55c..017daca3731 100644 --- a/lib/compiler-cranelift/Cargo.toml +++ b/lib/compiler-cranelift/Cargo.toml @@ -15,6 +15,7 @@ edition = "2018" wasmer-compiler = { path = "../compiler", version = "1.0.2", features = ["translator"], default-features = false } wasmer-vm = { path = "../vm", version = "1.0.2" } wasmer-types = { path = "../wasmer-types", version = "1.0.2", default-features = false, features = ["std"] } +cranelift-entity = { version = "0.70", default-features = false } cranelift-codegen = { version = "0.70", default-features = false, features = ["x86", "arm64"] } cranelift-frontend = { version = "0.70", default-features = false } tracing = "0.1" @@ -36,7 +37,7 @@ maintenance = { status = "actively-developed" } [features] default = ["std", "enable-serde", "unwind"] unwind = ["cranelift-codegen/unwind", "gimli"] -enable-serde = ["wasmer-compiler/enable-serde", "wasmer-types/enable-serde"] +enable-serde = ["wasmer-compiler/enable-serde", "wasmer-types/enable-serde", "cranelift-entity/enable-serde"] std = ["cranelift-codegen/std", "cranelift-frontend/std", "wasmer-compiler/std", "wasmer-types/std"] core = ["hashbrown", "cranelift-codegen/core", "cranelift-frontend/core"] diff --git a/lib/compiler-cranelift/src/sink.rs b/lib/compiler-cranelift/src/sink.rs index 12f93adbce7..54f802912bc 100644 --- a/lib/compiler-cranelift/src/sink.rs +++ b/lib/compiler-cranelift/src/sink.rs @@ -3,6 +3,7 @@ use crate::translator::{irlibcall_to_libcall, irreloc_to_relocationkind}; use cranelift_codegen::binemit; use cranelift_codegen::ir::{self, ExternalName}; +use cranelift_entity::EntityRef as CraneliftEntityRef; use wasmer_compiler::{JumpTable, Relocation, RelocationTarget, TrapInformation}; use wasmer_types::entity::EntityRef; use wasmer_types::{FunctionIndex, LocalFunctionIndex}; diff --git a/lib/compiler-cranelift/src/translator/translation_utils.rs b/lib/compiler-cranelift/src/translator/translation_utils.rs index 4b4c77e2522..69d40937520 100644 --- a/lib/compiler-cranelift/src/translator/translation_utils.rs +++ b/lib/compiler-cranelift/src/translator/translation_utils.rs @@ -6,6 +6,7 @@ use core::u32; use cranelift_codegen::binemit::Reloc; use cranelift_codegen::ir::{self, AbiParam}; use cranelift_codegen::isa::TargetFrontendConfig; +use cranelift_entity::{EntityRef as CraneliftEntityRef, SecondaryMap as CraneliftSecondaryMap}; use cranelift_frontend::FunctionBuilder; use wasmer_compiler::wasm_unsupported; use wasmer_compiler::wasmparser; @@ -148,7 +149,7 @@ pub fn get_vmctx_value_label() -> ir::ValueLabel { /// Transforms Cranelift JumpTable's into runtime JumpTables pub fn transform_jump_table( - jt_offsets: SecondaryMap, + jt_offsets: CraneliftSecondaryMap, ) -> SecondaryMap { let mut func_jt_offsets = SecondaryMap::with_capacity(jt_offsets.capacity()); From ae4939c4cd75f222cdc349f3aeb74f97356c2248 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Mar 2021 14:41:53 +0100 Subject: [PATCH 13/19] chore(cargo) Update `Cargo.lock`. --- Cargo.lock | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 8a9238eefe7..04786340550 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,6 +426,9 @@ name = "cranelift-entity" version = "0.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e55e9043403f0dec775f317280015150e78b2352fb947d2f37407fd4ce6311c7" +dependencies = [ + "serde", +] [[package]] name = "cranelift-frontend" @@ -2402,6 +2405,7 @@ name = "wasmer-compiler-cranelift" version = "1.0.2" dependencies = [ "cranelift-codegen", + "cranelift-entity", "cranelift-frontend", "gimli", "hashbrown", From 896f86540e7562b0b03f2fa62d7afe7d51d112fa Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Mar 2021 15:00:24 +0100 Subject: [PATCH 14/19] test(types) Fix an import issue. --- lib/wasmer-types/src/entity/boxed_slice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wasmer-types/src/entity/boxed_slice.rs b/lib/wasmer-types/src/entity/boxed_slice.rs index 277d09a9d2d..6405126db2c 100644 --- a/lib/wasmer-types/src/entity/boxed_slice.rs +++ b/lib/wasmer-types/src/entity/boxed_slice.rs @@ -144,8 +144,8 @@ where #[cfg(test)] mod tests { use super::*; + use crate::entity::PrimaryMap; use crate::lib::std::vec::Vec; - use crate::primary::PrimaryMap; // `EntityRef` impl for testing. #[derive(Clone, Copy, Debug, PartialEq, Eq)] From b09b85ada57d50e79d300166e63b137982485e88 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 18 Mar 2021 07:51:34 -0700 Subject: [PATCH 15/19] Update `memory` Wasm C API example --- lib/c-api/examples/memory.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/c-api/examples/memory.c b/lib/c-api/examples/memory.c index 0f954a32459..325a41cba1c 100644 --- a/lib/c-api/examples/memory.c +++ b/lib/c-api/examples/memory.c @@ -23,6 +23,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_new(&wat, strlen(wat_string), wat_string); wasm_byte_vec_t wasm_bytes; wat2wasm(&wat, &wasm_bytes); + wasm_byte_vec_delete(&wat); printf("Creating the store...\n"); wasm_engine_t* engine = wasm_engine_new(); @@ -102,6 +103,7 @@ int main(int argc, const char* argv[]) { wasm_func_delete(mem_size); wasm_func_delete(set_at); wasm_func_delete(get_at); + wasm_extern_vec_delete(&exports); wasm_module_delete(module); wasm_instance_delete(instance); wasm_store_delete(store); From 1a56ff2cc8caef281d14bb3cbf2fdbd37975bb1b Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 18 Mar 2021 08:16:17 -0700 Subject: [PATCH 16/19] Fix wat and exports memory leak in all examples --- lib/c-api/examples/exports-function.c | 2 ++ lib/c-api/examples/exports-global.c | 2 ++ lib/c-api/examples/features.c | 4 +++- lib/c-api/examples/imports-exports.c | 2 ++ lib/c-api/examples/instance.c | 1 + 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/c-api/examples/exports-function.c b/lib/c-api/examples/exports-function.c index 4231abb726b..e9c1653c050 100644 --- a/lib/c-api/examples/exports-function.c +++ b/lib/c-api/examples/exports-function.c @@ -15,6 +15,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_new(&wat, strlen(wat_string), wat_string); wasm_byte_vec_t wasm_bytes; wat2wasm(&wat, &wasm_bytes); + wasm_byte_vec_delete(&wat); printf("Creating the store...\n"); wasm_engine_t* engine = wasm_engine_new(); @@ -79,6 +80,7 @@ int main(int argc, const char* argv[]) { wasm_func_delete(sum_func); wasm_module_delete(module); wasm_instance_delete(instance); + wasm_extern_vec_delete(&exports); wasm_store_delete(store); wasm_engine_delete(engine); } diff --git a/lib/c-api/examples/exports-global.c b/lib/c-api/examples/exports-global.c index f6a13b7a98c..7673e39fe1d 100644 --- a/lib/c-api/examples/exports-global.c +++ b/lib/c-api/examples/exports-global.c @@ -14,6 +14,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_new(&wat, strlen(wat_string), wat_string); wasm_byte_vec_t wasm_bytes; wat2wasm(&wat, &wasm_bytes); + wasm_byte_vec_delete(&wat); printf("Creating the store...\n"); wasm_engine_t* engine = wasm_engine_new(); @@ -111,6 +112,7 @@ int main(int argc, const char* argv[]) { wasm_global_delete(some); wasm_global_delete(one); wasm_module_delete(module); + wasm_extern_vec_delete(&exports); wasm_instance_delete(instance); wasm_store_delete(store); wasm_engine_delete(engine); diff --git a/lib/c-api/examples/features.c b/lib/c-api/examples/features.c index 72b10a9965f..fe518815b25 100644 --- a/lib/c-api/examples/features.c +++ b/lib/c-api/examples/features.c @@ -14,6 +14,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_new(&wat, strlen(wat_string), wat_string); wasm_byte_vec_t wasm_bytes; wat2wasm(&wat, &wasm_bytes); + wasm_byte_vec_delete(&wat); printf("Creating the config and the features...\n"); wasm_config_t* config = wasm_config_new(); @@ -81,7 +82,8 @@ int main(int argc, const char* argv[]) { } printf("Got `(2, 1)`!\n"); - + + wasm_extern_vec_delete(&exports); wasm_module_delete(module); wasm_instance_delete(instance); wasm_store_delete(store); diff --git a/lib/c-api/examples/imports-exports.c b/lib/c-api/examples/imports-exports.c index de668d74554..aad86104e18 100644 --- a/lib/c-api/examples/imports-exports.c +++ b/lib/c-api/examples/imports-exports.c @@ -26,6 +26,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_new(&wat, strlen(wat_string), wat_string); wasm_byte_vec_t wasm_bytes; wat2wasm(&wat, &wasm_bytes); + wasm_byte_vec_delete(&wat); printf("Creating the store...\n"); wasm_engine_t* engine = wasm_engine_new(); @@ -128,6 +129,7 @@ int main(int argc, const char* argv[]) { wasm_table_delete(table); wasm_memory_delete(memory); wasm_module_delete(module); + wasm_extern_vec_delete(&exports); wasm_instance_delete(instance); wasm_store_delete(store); wasm_engine_delete(engine); diff --git a/lib/c-api/examples/instance.c b/lib/c-api/examples/instance.c index dff2035c7fd..e7a8e599baf 100644 --- a/lib/c-api/examples/instance.c +++ b/lib/c-api/examples/instance.c @@ -77,6 +77,7 @@ int main(int argc, const char* argv[]) { printf("Results of `add_one`: %d\n", results_val[0].of.i32); + wasm_extern_vec_delete(&exports); wasm_store_delete(store); wasm_engine_delete(engine); } From 5650e12f40e20e8306a2a436c3d8180436ea0dee Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 18 Mar 2021 08:30:11 -0700 Subject: [PATCH 17/19] Fix `wasm_instance_exports` exports memory leak in C API tests --- lib/c-api/README.md | 2 ++ lib/c-api/src/wasm_c_api/externals/global.rs | 1 + lib/c-api/src/wasm_c_api/externals/mod.rs | 1 + lib/c-api/src/wasm_c_api/instance.rs | 2 ++ lib/c-api/src/wasm_c_api/unstable/middlewares/metering.rs | 3 ++- 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/c-api/README.md b/lib/c-api/README.md index 85af51175d8..c1bd61411bb 100644 --- a/lib/c-api/README.md +++ b/lib/c-api/README.md @@ -43,6 +43,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_new(&wat, strlen(wat_string), wat_string); wasm_byte_vec_t wasm_bytes; wat2wasm(&wat, &wasm_bytes); + wasm_byte_vec_delete(&wat); printf("Creating the store...\n"); wasm_engine_t* engine = wasm_engine_new(); @@ -102,6 +103,7 @@ int main(int argc, const char* argv[]) { wasm_func_delete(sum_func); wasm_module_delete(module); + wasm_extern_vec_delete(&exports); wasm_instance_delete(instance); wasm_store_delete(store); wasm_engine_delete(engine); diff --git a/lib/c-api/src/wasm_c_api/externals/global.rs b/lib/c-api/src/wasm_c_api/externals/global.rs index b7b53b3e5cc..624d4620fdd 100644 --- a/lib/c-api/src/wasm_c_api/externals/global.rs +++ b/lib/c-api/src/wasm_c_api/externals/global.rs @@ -145,6 +145,7 @@ mod tests { wasm_instance_delete(instance); wasm_byte_vec_delete(&wasm_bytes); wasm_byte_vec_delete(&wat); + wasm_extern_vec_delete(&exports); wasm_store_delete(store); wasm_engine_delete(engine); diff --git a/lib/c-api/src/wasm_c_api/externals/mod.rs b/lib/c-api/src/wasm_c_api/externals/mod.rs index 23dff955ef1..869ae4b6e2a 100644 --- a/lib/c-api/src/wasm_c_api/externals/mod.rs +++ b/lib/c-api/src/wasm_c_api/externals/mod.rs @@ -179,6 +179,7 @@ mod tests { assert(wasm_extern_kind(function_copy) == WASM_EXTERN_FUNC); wasm_extern_delete(function_copy); + wasm_extern_vec_delete(&exports); wasm_instance_delete(instance); wasm_module_delete(module); wasm_byte_vec_delete(&wasm); diff --git a/lib/c-api/src/wasm_c_api/instance.rs b/lib/c-api/src/wasm_c_api/instance.rs index c562daa415b..9f7bc384243 100644 --- a/lib/c-api/src/wasm_c_api/instance.rs +++ b/lib/c-api/src/wasm_c_api/instance.rs @@ -154,6 +154,7 @@ pub unsafe extern "C" fn wasm_instance_delete(_instance: Option Date: Thu, 18 Mar 2021 17:15:15 +0100 Subject: [PATCH 18/19] chore(types) Add correct attributions. --- lib/wasmer-types/README.md | 7 +++++++ lib/wasmer-types/src/entity/boxed_slice.rs | 3 +++ lib/wasmer-types/src/entity/iter.rs | 3 +++ lib/wasmer-types/src/entity/keys.rs | 3 +++ lib/wasmer-types/src/entity/mod.rs | 3 +++ lib/wasmer-types/src/entity/packed_option.rs | 7 +++++-- lib/wasmer-types/src/entity/primary_map.rs | 3 +++ lib/wasmer-types/src/entity/secondary_map.rs | 3 +++ 8 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/wasmer-types/README.md b/lib/wasmer-types/README.md index 26e66882008..3bcae53b9ce 100644 --- a/lib/wasmer-types/README.md +++ b/lib/wasmer-types/README.md @@ -1,3 +1,10 @@ # `wasmer-types` [![Build Status](https://github.com/wasmerio/wasmer/workflows/build/badge.svg?style=flat-square)](https://github.com/wasmerio/wasmer/actions?query=workflow%3Abuild) [![Join Wasmer Slack](https://img.shields.io/static/v1?label=Slack&message=join%20chat&color=brighgreen&style=flat-square)](https://slack.wasmer.io) [![MIT License](https://img.shields.io/github/license/wasmerio/wasmer.svg?style=flat-square)](https://github.com/wasmerio/wasmer/blob/master/LICENSE) This crate provides the basic structures to use WebAssembly easily anywhere. + +### Acknowledgments + +This project borrowed some of the code for the entity structure from [cranelift-entity](https://crates.io/crates/cranelift-entity). +We decided to move it here to help on serialization/deserialization and also to ease the integration with other tools like `loupe`. + +Please check [Wasmer ATTRIBUTIONS](https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md) to further see licenses and other attributions of the project. diff --git a/lib/wasmer-types/src/entity/boxed_slice.rs b/lib/wasmer-types/src/entity/boxed_slice.rs index 6405126db2c..4f9aa95eaf8 100644 --- a/lib/wasmer-types/src/entity/boxed_slice.rs +++ b/lib/wasmer-types/src/entity/boxed_slice.rs @@ -1,3 +1,6 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + //! Boxed slices for `PrimaryMap`. use crate::entity::iter::{Iter, IterMut}; diff --git a/lib/wasmer-types/src/entity/iter.rs b/lib/wasmer-types/src/entity/iter.rs index 26ee370f3f9..a157abef8f1 100644 --- a/lib/wasmer-types/src/entity/iter.rs +++ b/lib/wasmer-types/src/entity/iter.rs @@ -1,3 +1,6 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + //! A double-ended iterator over entity references and entities. use crate::entity::EntityRef; diff --git a/lib/wasmer-types/src/entity/keys.rs b/lib/wasmer-types/src/entity/keys.rs index b9892bf551f..08d5a225c18 100644 --- a/lib/wasmer-types/src/entity/keys.rs +++ b/lib/wasmer-types/src/entity/keys.rs @@ -1,3 +1,6 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + //! A double-ended iterator over entity references. //! //! When `core::iter::Step` is stabilized, `Keys` could be implemented as a wrapper around diff --git a/lib/wasmer-types/src/entity/mod.rs b/lib/wasmer-types/src/entity/mod.rs index cc802ef85e5..f654bdaff21 100644 --- a/lib/wasmer-types/src/entity/mod.rs +++ b/lib/wasmer-types/src/entity/mod.rs @@ -1,3 +1,6 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + /// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key /// of an `SecondaryMap` or `SparseMap`. pub trait EntityRef: Copy + Eq { diff --git a/lib/wasmer-types/src/entity/packed_option.rs b/lib/wasmer-types/src/entity/packed_option.rs index 6ba51cdf262..ceadbf70008 100644 --- a/lib/wasmer-types/src/entity/packed_option.rs +++ b/lib/wasmer-types/src/entity/packed_option.rs @@ -1,7 +1,10 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + //! Compact representation of `Option` for types with a reserved value. //! -//! Small Cranelift types like the 32-bit entity references are often used in tables and linked -//! lists where an `Option` is needed. Unfortunately, that would double the size of the tables +//! Small types are often used in tables and linked lists where an +//! `Option` is needed. Unfortunately, that would double the size of the tables //! because `Option` is twice as big as `T`. //! //! This module provides a `PackedOption` for types that have a reserved value that can be used diff --git a/lib/wasmer-types/src/entity/primary_map.rs b/lib/wasmer-types/src/entity/primary_map.rs index c709afef050..c82bf4d5ad4 100644 --- a/lib/wasmer-types/src/entity/primary_map.rs +++ b/lib/wasmer-types/src/entity/primary_map.rs @@ -1,3 +1,6 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + //! Densely numbered entity references as mapping keys. use crate::entity::boxed_slice::BoxedSlice; use crate::entity::iter::{IntoIter, Iter, IterMut}; diff --git a/lib/wasmer-types/src/entity/secondary_map.rs b/lib/wasmer-types/src/entity/secondary_map.rs index 936caa24957..9fd474d4d1f 100644 --- a/lib/wasmer-types/src/entity/secondary_map.rs +++ b/lib/wasmer-types/src/entity/secondary_map.rs @@ -1,3 +1,6 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + //! Densely numbered entity references as mapping keys. use crate::entity::iter::{Iter, IterMut}; From cd645baa12bd170b08246061486aa92dfc2f24e9 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Mar 2021 10:16:57 -0700 Subject: [PATCH 19/19] Return an error, rather than using Try + unreachable!. --- fuzz/fuzz_targets/equivalence_jit.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fuzz/fuzz_targets/equivalence_jit.rs b/fuzz/fuzz_targets/equivalence_jit.rs index bf618366fb0..b2e87a7669c 100644 --- a/fuzz/fuzz_targets/equivalence_jit.rs +++ b/fuzz/fuzz_targets/equivalence_jit.rs @@ -33,13 +33,12 @@ fn maybe_instantiate_singlepass(wasm_bytes: &[u8]) -> Result> { let module = Module::new(&store, &wasm_bytes); let module = match module { Ok(m) => m, - Err(ref e) => { + Err(e) => { let error_message = format!("{}", e); if error_message.contains("Validation error: invalid result arity: func type returns multiple values") || error_message.contains("Validation error: blocks, loops, and ifs accept no parameters when multi-value is not enabled") || error_message.contains("multi-value returns not yet implemented") { return Ok(None); } - module?; - unreachable!(""); + return Err(e.into()); } }; let instance = Instance::new(&module, &imports! {})?;