diff --git a/crates/fuzzing/Cargo.toml b/crates/fuzzing/Cargo.toml index b7b264bd4f..fc7b01287f 100644 --- a/crates/fuzzing/Cargo.toml +++ b/crates/fuzzing/Cargo.toml @@ -22,7 +22,7 @@ wasmtime-wast = { path = "../wast" } wasm-encoder = "0.10.0" wasm-smith = "0.9.0" wasm-mutate = "0.2" -wasm-spec-interpreter = { path = "./wasm-spec-interpreter" } +wasm-spec-interpreter = { path = "./wasm-spec-interpreter", optional = true } wasmi = "0.7.0" # We rely on precompiled v8 binaries, but rusty-v8 doesn't have a precompiled @@ -35,7 +35,11 @@ v8 = "0.33" [dev-dependencies] wat = "1.0.37" -# We only build the library containing the OCaml spec interpreter if the OCaml -# toolchain is available--which is assumed here to be the case when fuzzing. +# Only enable the `build-libinterpret` feature when fuzzing is enabled, enabling +# commands like `cargo test --workspace` or similar to not need an ocaml +# installation and only fuzzers need it by default. [target.'cfg(fuzzing)'.dependencies] -wasm-spec-interpreter = { path = "./wasm-spec-interpreter", features = ["build-libinterpret"] } +wasm-spec-interpreter = { path = "./wasm-spec-interpreter", optional = true, features = ['build-libinterpret'] } + +[features] +fuzz-spec-interpreter = ['wasm-spec-interpreter'] diff --git a/crates/fuzzing/src/oracles.rs b/crates/fuzzing/src/oracles.rs index d2e0404954..8c7d09f625 100644 --- a/crates/fuzzing/src/oracles.rs +++ b/crates/fuzzing/src/oracles.rs @@ -13,9 +13,8 @@ pub mod dummy; use crate::generators; -use anyhow::Context; use arbitrary::Arbitrary; -use log::{debug, warn}; +use log::debug; use std::cell::Cell; use std::rc::Rc; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; @@ -790,7 +789,10 @@ pub fn differential_wasmi_execution(wasm: &[u8], config: &generators::Config) -> /// specification interpreter. /// /// May return `None` if we early-out due to a rejected fuzz config. +#[cfg(feature = "fuzz-spec-interpreter")] pub fn differential_spec_execution(wasm: &[u8], config: &generators::Config) -> Option<()> { + use anyhow::Context; + crate::init_fuzzing(); debug!("config: {:#?}", config); log_wasm(wasm); @@ -806,8 +808,30 @@ pub fn differential_spec_execution(wasm: &[u8], config: &generators::Config) -> // For now, execute with dummy (zeroed) function arguments. let spec_vals = wasm_spec_interpreter::interpret(wasm, None); debug!("spec interpreter returned: {:?}", &spec_vals); - let wasmtime_vals = run_in_wasmtime(wasm, config); - debug!("Wasmtime returned: {:?}", wasmtime_vals); + + let (wasmtime_module, mut wasmtime_store) = differential_store(wasm, config); + let wasmtime_module = match wasmtime_module { + Some(m) => m, + None => return None, + }; + + let wasmtime_vals = + Instance::new(&mut wasmtime_store, &wasmtime_module, &[]).and_then(|wasmtime_instance| { + // Find the first exported function. + let (func_name, ty) = first_exported_function(&wasmtime_module) + .context("Cannot find exported function")?; + let wasmtime_main = wasmtime_instance + .get_func(&mut wasmtime_store, &func_name[..]) + .expect("function export is present"); + + let dummy_params = dummy::dummy_values(ty.params()); + + // Execute the function and return the values. + let mut results = vec![Val::I32(0); ty.results().len()]; + wasmtime_main + .call(&mut wasmtime_store, &dummy_params, &mut results) + .map(|()| Some(results)) + }); // Match a spec interpreter value against a Wasmtime value. Eventually this // should support references and `v128` (TODO). @@ -851,9 +875,10 @@ pub fn differential_spec_execution(wasm: &[u8], config: &generators::Config) -> // beneficial to compare the error messages from both sides (TODO). // It would also be good to keep track of statistics about the // ratios of the kinds of errors the fuzzer sees (TODO). - warn!( + log::warn!( "Both sides failed: spec returned '{}'; wasmtime returned {:?}", - spec_error, wasmtime_error + spec_error, + wasmtime_error ); return None; } @@ -880,35 +905,6 @@ fn differential_store( (module, store) } -/// Helper for instantiating and running a Wasm module in Wasmtime and returning -/// its `Val` results. -fn run_in_wasmtime(wasm: &[u8], config: &generators::Config) -> anyhow::Result>> { - // Instantiate wasmtime module and instance. - let (wasmtime_module, mut wasmtime_store) = differential_store(wasm, config); - let wasmtime_module = match wasmtime_module { - Some(m) => m, - None => return Ok(None), - }; - - let wasmtime_instance = Instance::new(&mut wasmtime_store, &wasmtime_module, &[]) - .context("Wasmtime cannot instantiate module")?; - - // Find the first exported function. - let (func_name, ty) = - first_exported_function(&wasmtime_module).context("Cannot find exported function")?; - let wasmtime_main = wasmtime_instance - .get_func(&mut wasmtime_store, &func_name[..]) - .expect("function export is present"); - - let dummy_params = dummy::dummy_values(ty.params()); - - // Execute the function and return the values. - let mut results = vec![Val::I32(0); ty.results().len()]; - wasmtime_main - .call(&mut wasmtime_store, &dummy_params, &mut results) - .map(|()| Some(results)) -} - // Introspect wasmtime module to find the name of the first exported function. fn first_exported_function(module: &wasmtime::Module) -> Option<(&str, FuncType)> { for e in module.exports() { diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 73c8cf1e37..e0446eb8d4 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -21,10 +21,8 @@ wasmtime = { path = "../crates/wasmtime" } wasmtime-fuzzing = { path = "../crates/fuzzing" } [features] -# Leave a stub feature with no side-effects in place for now: the OSS-Fuzz -# config builds fuzz targets with this feature enabled and we don't want to -# break the build. -experimental_x64 = [] +default = ['fuzz-spec-interpreter'] +fuzz-spec-interpreter = ['wasmtime-fuzzing/fuzz-spec-interpreter'] [[bin]] name = "compile" @@ -61,6 +59,7 @@ name = "differential_spec" path = "fuzz_targets/differential_spec.rs" test = false doc = false +required-features = ['fuzz-spec-interpreter'] [[bin]] name = "differential_wasmi"