From 52ad76ed7c7f737009355e9cc5064b4272947f29 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 5 Jul 2022 16:14:31 -0500 Subject: [PATCH] Update differential fuzzing configuration (#4386) * Update differential fuzzing configuration This uses some new features of `wasm-smith` and additionally tweaks the existing fuzz configuration: * More than one function is now allowed to be generated. There's no particular reason to limit differential execution to just one and we may want to explore other interesting module shapes. * More than one function type is now allowed to possibly allow more interesting `block` types. * Memories are now allowed to grow beyond one page, but still say small by staying underneath 10 pages. * Tables are now always limited in their growth to ensure consistent behavior across engines (e.g. with the pooling allocator vs v8). * The `export_everything` feature is used instead of specifying a min/max number of exports. The `wasmi` differential fuzzer was updated to still work if memory is exported, but otherwise the v8 differential fuzzer already worked if a function was exported but a memory wasn't. Both fuzzers continue to execute only the first exported function. Also notable from this update is that the `SwarmConfig` from `wasm-smith` will now include an arbitrary `allowed_instructions` configuration which may help explore the space of interesting modules more effectively. * Fix typos --- crates/fuzzing/src/generators.rs | 30 ++++++++++++++++++++---------- crates/fuzzing/src/oracles.rs | 17 +++++++++++------ 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/crates/fuzzing/src/generators.rs b/crates/fuzzing/src/generators.rs index d338fac377..7242519087 100644 --- a/crates/fuzzing/src/generators.rs +++ b/crates/fuzzing/src/generators.rs @@ -272,29 +272,38 @@ impl Config { let config = &mut self.module_config.config; config.allow_start_export = false; + // Make sure there's a type available for the function. config.min_types = 1; - config.max_types = 1; + config.max_types = config.max_types.max(1); - // Generate one and only one function + // Generate at least one function config.min_funcs = 1; - config.max_funcs = 1; + config.max_funcs = config.max_funcs.max(1); - // Give the function a memory, but keep it small - config.min_memories = 1; + // Allow a memory to be generated, but don't let it get too large. + // Additionally require the maximum size to guarantee that the growth + // behavior is consistent across engines. config.max_memories = 1; - config.max_memory_pages = 1; + config.max_memory_pages = 10; config.memory_max_size_required = true; - // While reference types are disabled below, only allow one table + // If tables are generated make sure they don't get too large to avoid + // hitting any engine-specific limit. Additionally ensure that the + // maximum size is required to guarantee consistent growth across + // engines. + // + // Note that while reference types are disabled below, only allow one + // table. config.max_tables = 1; + config.max_table_elements = 1_000; + config.table_max_size_required = true; // Don't allow any imports config.max_imports = 0; // Try to get the function and the memory exported - config.min_exports = 2; - config.max_exports = 4; + config.export_everything = true; // NaN is canonicalized at the wasm level for differential fuzzing so we // can paper over NaN differences between engines. @@ -317,9 +326,10 @@ impl Config { { // One single-page memory limits.memories = 1; - limits.memory_pages = 1; + limits.memory_pages = 10; limits.tables = 1; + limits.table_elements = 1_000; match &mut self.wasmtime.memory_config { MemoryConfig::Normal(config) => { diff --git a/crates/fuzzing/src/oracles.rs b/crates/fuzzing/src/oracles.rs index 48c082bd0f..443b339847 100644 --- a/crates/fuzzing/src/oracles.rs +++ b/crates/fuzzing/src/oracles.rs @@ -718,17 +718,11 @@ pub fn differential_wasmi_execution(wasm: &[u8], config: &generators::Config) -> // Introspect wasmtime module to find name of an exported function and of an // exported memory. let (func_name, ty) = first_exported_function(&wasmtime_module)?; - let memory_name = first_exported_memory(&wasmtime_module)?; - let wasmi_mem_export = wasmi_instance.export_by_name(memory_name).unwrap(); - let wasmi_mem = wasmi_mem_export.as_memory().unwrap(); let wasmi_main_export = wasmi_instance.export_by_name(func_name).unwrap(); let wasmi_main = wasmi_main_export.as_func().unwrap(); let wasmi_val = wasmi::FuncInstance::invoke(&wasmi_main, &[], &mut wasmi::NopExternals); - let wasmtime_mem = wasmtime_instance - .get_memory(&mut wasmtime_store, memory_name) - .expect("memory export is present"); let wasmtime_main = wasmtime_instance .get_func(&mut wasmtime_store, func_name) .expect("function export is present"); @@ -759,6 +753,17 @@ pub fn differential_wasmi_execution(wasm: &[u8], config: &generators::Config) -> } } + // Compare linear memories if there's an exported linear memory + let memory_name = match first_exported_memory(&wasmtime_module) { + Some(name) => name, + None => return Some(()), + }; + let wasmi_mem_export = wasmi_instance.export_by_name(memory_name).unwrap(); + let wasmi_mem = wasmi_mem_export.as_memory().unwrap(); + let wasmtime_mem = wasmtime_instance + .get_memory(&mut wasmtime_store, memory_name) + .expect("memory export is present"); + if wasmi_mem.current_size().0 != wasmtime_mem.size(&wasmtime_store) as usize { panic!("resulting memories are not the same size"); }