A fuzz bug was hit last night where the root of the fuzz bug appears to be exhaustion of the virtual address space. The specific case in question instantiated a module with ~100 memories ~100 times, and each memory reserved ~8gb of the virtual address space. This takes around 47 bits of addressable memory which is mighty close to the limit of what can be done on x86_64, so this commit reduces the number of memories that an instance may have when coming out of `wasm-smith`.
65 lines
2.5 KiB
Rust
65 lines
2.5 KiB
Rust
//! This fuzz target is used to test multiple concurrent instantiations from
|
|
//! multiple modules.
|
|
|
|
#![no_main]
|
|
|
|
use libfuzzer_sys::arbitrary::{Result, Unstructured};
|
|
use libfuzzer_sys::fuzz_target;
|
|
use wasmtime_fuzzing::{generators, oracles};
|
|
|
|
const MAX_MODULES: usize = 5;
|
|
|
|
fuzz_target!(|data: &[u8]| {
|
|
// errors in `run` have to do with not enough input in `data`, which we
|
|
// ignore here since it doesn't affect how we'd like to fuzz.
|
|
drop(run(data));
|
|
});
|
|
|
|
fn run(data: &[u8]) -> Result<()> {
|
|
let mut u = Unstructured::new(data);
|
|
let mut config: generators::Config = u.arbitrary()?;
|
|
|
|
// Don't generate start functions
|
|
// No wasm code execution is necessary for this fuzz target and thus we don't
|
|
// use timeouts or ensure that the generated wasm code will terminate.
|
|
config.module_config.config.allow_start_export = false;
|
|
|
|
// Wasm linear memories take roughly ~8gb of virtual address space. Down
|
|
// below we could instantiate up to 300 modules. Conservatively estimating
|
|
// that we have 46 bits of address space to work with (technically 48 on
|
|
// x86_64, but take some out for kernel stuff and some for asan stuff) that
|
|
// gives us a budget of ~27 memories per instance. Reduce that a bit further
|
|
// and make sure that no instance has more than 10 linear memories to ensure
|
|
// that even if the maximum were created it should still fit in the linear
|
|
// address space.
|
|
config.module_config.config.max_memories = config.module_config.config.max_memories.min(10);
|
|
|
|
// Create the modules to instantiate
|
|
let modules = (0..u.int_in_range(1..=MAX_MODULES)?)
|
|
.map(|_| Ok(config.generate(&mut u, None)?.to_bytes()))
|
|
.collect::<Result<Vec<_>>>()?;
|
|
|
|
let max_instances = match &config.wasmtime.strategy {
|
|
generators::InstanceAllocationStrategy::OnDemand => u.int_in_range(1..=100)?,
|
|
generators::InstanceAllocationStrategy::Pooling {
|
|
instance_limits, ..
|
|
} => instance_limits.count,
|
|
};
|
|
|
|
// Front-load with instantiation commands
|
|
let mut commands: Vec<oracles::Command> = (0..u.int_in_range(1..=max_instances)?)
|
|
.map(|_| Ok(oracles::Command::Instantiate(u.arbitrary()?)))
|
|
.collect::<Result<_>>()?;
|
|
|
|
// Then add some more arbitrary commands
|
|
commands.extend(
|
|
(0..u.int_in_range(0..=2 * max_instances)?)
|
|
.map(|_| u.arbitrary())
|
|
.collect::<Result<Vec<_>>>()?,
|
|
);
|
|
|
|
oracles::instantiate_many(&modules, true, &config, &commands);
|
|
|
|
Ok(())
|
|
}
|