Add some debug logging to fuzzers (#923)
* Add some debug logging to fuzzers This is useful when trying to figure out what happened locally when debugging fuzz test cases. By setting `RUST_LOG=wasmtime_fuzzing=debug` you can get wasm files written to disk and for the API calls test case see what API calls are being made. * Also write out `*.wat` files * rustfmt * Remove return value from `log_wasm` * Remove unused import
This commit is contained in:
@@ -6,13 +6,11 @@ name = "wasmtime-fuzzing"
|
|||||||
publish = false
|
publish = false
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.22"
|
anyhow = "1.0.22"
|
||||||
arbitrary = { version = "0.3.2", features = ["derive"] }
|
arbitrary = { version = "0.3.2", features = ["derive"] }
|
||||||
binaryen = "0.10.0"
|
binaryen = "0.10.0"
|
||||||
env_logger = { version = "0.7.1", optional = true }
|
env_logger = "0.7.1"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
wasmparser = "0.51.0"
|
wasmparser = "0.51.0"
|
||||||
wasmprinter = "0.2.0"
|
wasmprinter = "0.2.0"
|
||||||
|
|||||||
@@ -14,9 +14,11 @@ pub mod dummy;
|
|||||||
|
|
||||||
use dummy::{dummy_imports, dummy_values};
|
use dummy::{dummy_imports, dummy_values};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||||
use wasmtime::*;
|
use wasmtime::*;
|
||||||
|
|
||||||
fn fuzz_default_config(strategy: Strategy) -> Config {
|
fn fuzz_default_config(strategy: Strategy) -> Config {
|
||||||
|
drop(env_logger::try_init());
|
||||||
let mut config = Config::new();
|
let mut config = Config::new();
|
||||||
config
|
config
|
||||||
.cranelift_debug_verifier(true)
|
.cranelift_debug_verifier(true)
|
||||||
@@ -26,6 +28,22 @@ fn fuzz_default_config(strategy: Strategy) -> Config {
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn log_wasm(wasm: &[u8]) {
|
||||||
|
static CNT: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
if !log::log_enabled!(log::Level::Debug) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = CNT.fetch_add(1, SeqCst);
|
||||||
|
let name = format!("testcase{}.wasm", i);
|
||||||
|
std::fs::write(&name, wasm).expect("failed to write wasm file");
|
||||||
|
log::debug!("wrote wasm file to `{}`", name);
|
||||||
|
if let Ok(s) = wasmprinter::print_bytes(wasm) {
|
||||||
|
let name = format!("testcase{}.wat", i);
|
||||||
|
std::fs::write(&name, s).expect("failed to write wat file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Instantiate the Wasm buffer, and implicitly fail if we have an unexpected
|
/// Instantiate the Wasm buffer, and implicitly fail if we have an unexpected
|
||||||
/// panic or segfault or anything else that can be detected "passively".
|
/// panic or segfault or anything else that can be detected "passively".
|
||||||
///
|
///
|
||||||
@@ -46,6 +64,7 @@ pub fn instantiate_with_config(wasm: &[u8], config: Config) {
|
|||||||
let engine = Engine::new(&config);
|
let engine = Engine::new(&config);
|
||||||
let store = Store::new(&engine);
|
let store = Store::new(&engine);
|
||||||
|
|
||||||
|
log_wasm(wasm);
|
||||||
let module = match Module::new(&store, wasm) {
|
let module = match Module::new(&store, wasm) {
|
||||||
Ok(module) => module,
|
Ok(module) => module,
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
@@ -77,6 +96,7 @@ pub fn instantiate_with_config(wasm: &[u8], config: Config) {
|
|||||||
pub fn compile(wasm: &[u8], strategy: Strategy) {
|
pub fn compile(wasm: &[u8], strategy: Strategy) {
|
||||||
let engine = Engine::new(&fuzz_default_config(strategy));
|
let engine = Engine::new(&fuzz_default_config(strategy));
|
||||||
let store = Store::new(&engine);
|
let store = Store::new(&engine);
|
||||||
|
log_wasm(wasm);
|
||||||
let _ = Module::new(&store, wasm);
|
let _ = Module::new(&store, wasm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +108,7 @@ pub fn differential_execution(
|
|||||||
ttf: &crate::generators::WasmOptTtf,
|
ttf: &crate::generators::WasmOptTtf,
|
||||||
configs: &[crate::generators::DifferentialConfig],
|
configs: &[crate::generators::DifferentialConfig],
|
||||||
) {
|
) {
|
||||||
|
drop(env_logger::try_init());
|
||||||
// We need at least two configs.
|
// We need at least two configs.
|
||||||
if configs.len() < 2
|
if configs.len() < 2
|
||||||
// And all the configs should be unique.
|
// And all the configs should be unique.
|
||||||
@@ -104,6 +125,7 @@ pub fn differential_execution(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut export_func_results: HashMap<String, Result<Box<[Val]>, Trap>> = Default::default();
|
let mut export_func_results: HashMap<String, Result<Box<[Val]>, Trap>> = Default::default();
|
||||||
|
log_wasm(&ttf.wasm);
|
||||||
|
|
||||||
for config in &configs {
|
for config in &configs {
|
||||||
let engine = Engine::new(config);
|
let engine = Engine::new(config);
|
||||||
@@ -258,6 +280,8 @@ fn assert_same_export_func_result(
|
|||||||
pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
||||||
use crate::generators::api::ApiCall;
|
use crate::generators::api::ApiCall;
|
||||||
|
|
||||||
|
drop(env_logger::try_init());
|
||||||
|
|
||||||
let mut config: Option<Config> = None;
|
let mut config: Option<Config> = None;
|
||||||
let mut engine: Option<Engine> = None;
|
let mut engine: Option<Engine> = None;
|
||||||
let mut store: Option<Store> = None;
|
let mut store: Option<Store> = None;
|
||||||
@@ -267,6 +291,7 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
|||||||
for call in api.calls {
|
for call in api.calls {
|
||||||
match call {
|
match call {
|
||||||
ApiCall::ConfigNew => {
|
ApiCall::ConfigNew => {
|
||||||
|
log::trace!("creating config");
|
||||||
assert!(config.is_none());
|
assert!(config.is_none());
|
||||||
let mut cfg = Config::new();
|
let mut cfg = Config::new();
|
||||||
cfg.cranelift_debug_verifier(true);
|
cfg.cranelift_debug_verifier(true);
|
||||||
@@ -274,20 +299,25 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ApiCall::ConfigDebugInfo(b) => {
|
ApiCall::ConfigDebugInfo(b) => {
|
||||||
|
log::trace!("enabling debuginfo");
|
||||||
config.as_mut().unwrap().debug_info(b);
|
config.as_mut().unwrap().debug_info(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiCall::EngineNew => {
|
ApiCall::EngineNew => {
|
||||||
|
log::trace!("creating engine");
|
||||||
assert!(engine.is_none());
|
assert!(engine.is_none());
|
||||||
engine = Some(Engine::new(config.as_ref().unwrap()));
|
engine = Some(Engine::new(config.as_ref().unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiCall::StoreNew => {
|
ApiCall::StoreNew => {
|
||||||
|
log::trace!("creating store");
|
||||||
assert!(store.is_none());
|
assert!(store.is_none());
|
||||||
store = Some(Store::new(engine.as_ref().unwrap()));
|
store = Some(Store::new(engine.as_ref().unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiCall::ModuleNew { id, wasm } => {
|
ApiCall::ModuleNew { id, wasm } => {
|
||||||
|
log::debug!("creating module: {}", id);
|
||||||
|
log_wasm(&wasm.wasm);
|
||||||
let module = match Module::new(store.as_ref().unwrap(), &wasm.wasm) {
|
let module = match Module::new(store.as_ref().unwrap(), &wasm.wasm) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
@@ -297,10 +327,12 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ApiCall::ModuleDrop { id } => {
|
ApiCall::ModuleDrop { id } => {
|
||||||
|
log::trace!("dropping module: {}", id);
|
||||||
drop(modules.remove(&id));
|
drop(modules.remove(&id));
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiCall::InstanceNew { id, module } => {
|
ApiCall::InstanceNew { id, module } => {
|
||||||
|
log::trace!("instantiating module {} as {}", module, id);
|
||||||
let module = match modules.get(&module) {
|
let module = match modules.get(&module) {
|
||||||
Some(m) => m,
|
Some(m) => m,
|
||||||
None => continue,
|
None => continue,
|
||||||
@@ -326,10 +358,12 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ApiCall::InstanceDrop { id } => {
|
ApiCall::InstanceDrop { id } => {
|
||||||
|
log::trace!("dropping instance {}", id);
|
||||||
drop(instances.remove(&id));
|
drop(instances.remove(&id));
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiCall::CallExportedFunc { instance, nth } => {
|
ApiCall::CallExportedFunc { instance, nth } => {
|
||||||
|
log::trace!("calling instance export {} / {}", instance, nth);
|
||||||
let instance = match instances.get(&instance) {
|
let instance = match instances.get(&instance) {
|
||||||
Some(i) => i,
|
Some(i) => i,
|
||||||
None => {
|
None => {
|
||||||
|
|||||||
Reference in New Issue
Block a user