Browse Source

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
pull/930/head
Alex Crichton 5 years ago
committed by GitHub
parent
commit
dfef71ea5f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      crates/fuzzing/Cargo.toml
  2. 34
      crates/fuzzing/src/oracles.rs

4
crates/fuzzing/Cargo.toml

@ -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"

34
crates/fuzzing/src/oracles.rs

@ -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 => {

Loading…
Cancel
Save