Move spec interpreter fuzzing behind a Cargo feature (#3871)
* Move spec interpreter fuzzing behind a Cargo feature Building the spec interpreter requires a local installation of Ocaml and now libgmp which isn't always available, so this enables the ability to disable building the spec interpreter by using `cargo +nightly fuzz build --no-default-features`. The spec interpreter is still built by default but if fuzzers are being built locally and the spec interpreter isn't needed then this should enable it to be relatively easily opted-out of. * Tweak manifest directives
This commit is contained in:
@@ -22,7 +22,7 @@ wasmtime-wast = { path = "../wast" }
|
|||||||
wasm-encoder = "0.10.0"
|
wasm-encoder = "0.10.0"
|
||||||
wasm-smith = "0.9.0"
|
wasm-smith = "0.9.0"
|
||||||
wasm-mutate = "0.2"
|
wasm-mutate = "0.2"
|
||||||
wasm-spec-interpreter = { path = "./wasm-spec-interpreter" }
|
wasm-spec-interpreter = { path = "./wasm-spec-interpreter", optional = true }
|
||||||
wasmi = "0.7.0"
|
wasmi = "0.7.0"
|
||||||
|
|
||||||
# We rely on precompiled v8 binaries, but rusty-v8 doesn't have a precompiled
|
# We rely on precompiled v8 binaries, but rusty-v8 doesn't have a precompiled
|
||||||
@@ -35,7 +35,11 @@ v8 = "0.33"
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wat = "1.0.37"
|
wat = "1.0.37"
|
||||||
|
|
||||||
# We only build the library containing the OCaml spec interpreter if the OCaml
|
# Only enable the `build-libinterpret` feature when fuzzing is enabled, enabling
|
||||||
# toolchain is available--which is assumed here to be the case when fuzzing.
|
# commands like `cargo test --workspace` or similar to not need an ocaml
|
||||||
|
# installation and only fuzzers need it by default.
|
||||||
[target.'cfg(fuzzing)'.dependencies]
|
[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']
|
||||||
|
|||||||
@@ -13,9 +13,8 @@
|
|||||||
pub mod dummy;
|
pub mod dummy;
|
||||||
|
|
||||||
use crate::generators;
|
use crate::generators;
|
||||||
use anyhow::Context;
|
|
||||||
use arbitrary::Arbitrary;
|
use arbitrary::Arbitrary;
|
||||||
use log::{debug, warn};
|
use log::debug;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||||
@@ -790,7 +789,10 @@ pub fn differential_wasmi_execution(wasm: &[u8], config: &generators::Config) ->
|
|||||||
/// specification interpreter.
|
/// specification interpreter.
|
||||||
///
|
///
|
||||||
/// May return `None` if we early-out due to a rejected fuzz config.
|
/// 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<()> {
|
pub fn differential_spec_execution(wasm: &[u8], config: &generators::Config) -> Option<()> {
|
||||||
|
use anyhow::Context;
|
||||||
|
|
||||||
crate::init_fuzzing();
|
crate::init_fuzzing();
|
||||||
debug!("config: {:#?}", config);
|
debug!("config: {:#?}", config);
|
||||||
log_wasm(wasm);
|
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.
|
// For now, execute with dummy (zeroed) function arguments.
|
||||||
let spec_vals = wasm_spec_interpreter::interpret(wasm, None);
|
let spec_vals = wasm_spec_interpreter::interpret(wasm, None);
|
||||||
debug!("spec interpreter returned: {:?}", &spec_vals);
|
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
|
// Match a spec interpreter value against a Wasmtime value. Eventually this
|
||||||
// should support references and `v128` (TODO).
|
// 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).
|
// beneficial to compare the error messages from both sides (TODO).
|
||||||
// It would also be good to keep track of statistics about the
|
// It would also be good to keep track of statistics about the
|
||||||
// ratios of the kinds of errors the fuzzer sees (TODO).
|
// ratios of the kinds of errors the fuzzer sees (TODO).
|
||||||
warn!(
|
log::warn!(
|
||||||
"Both sides failed: spec returned '{}'; wasmtime returned {:?}",
|
"Both sides failed: spec returned '{}'; wasmtime returned {:?}",
|
||||||
spec_error, wasmtime_error
|
spec_error,
|
||||||
|
wasmtime_error
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -880,35 +905,6 @@ fn differential_store(
|
|||||||
(module, 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<Option<Vec<Val>>> {
|
|
||||||
// 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.
|
// Introspect wasmtime module to find the name of the first exported function.
|
||||||
fn first_exported_function(module: &wasmtime::Module) -> Option<(&str, FuncType)> {
|
fn first_exported_function(module: &wasmtime::Module) -> Option<(&str, FuncType)> {
|
||||||
for e in module.exports() {
|
for e in module.exports() {
|
||||||
|
|||||||
@@ -21,10 +21,8 @@ wasmtime = { path = "../crates/wasmtime" }
|
|||||||
wasmtime-fuzzing = { path = "../crates/fuzzing" }
|
wasmtime-fuzzing = { path = "../crates/fuzzing" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# Leave a stub feature with no side-effects in place for now: the OSS-Fuzz
|
default = ['fuzz-spec-interpreter']
|
||||||
# config builds fuzz targets with this feature enabled and we don't want to
|
fuzz-spec-interpreter = ['wasmtime-fuzzing/fuzz-spec-interpreter']
|
||||||
# break the build.
|
|
||||||
experimental_x64 = []
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "compile"
|
name = "compile"
|
||||||
@@ -61,6 +59,7 @@ name = "differential_spec"
|
|||||||
path = "fuzz_targets/differential_spec.rs"
|
path = "fuzz_targets/differential_spec.rs"
|
||||||
test = false
|
test = false
|
||||||
doc = false
|
doc = false
|
||||||
|
required-features = ['fuzz-spec-interpreter']
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "differential_wasmi"
|
name = "differential_wasmi"
|
||||||
|
|||||||
Reference in New Issue
Block a user