Browse Source

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
pull/4390/head
Alex Crichton 2 years ago
committed by GitHub
parent
commit
52ad76ed7c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      crates/fuzzing/src/generators.rs
  2. 17
      crates/fuzzing/src/oracles.rs

30
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) => {

17
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");
}

Loading…
Cancel
Save