Use [`wasm-mutate`][wasm-mutate] to mutate a fuzz input. [wasm-mutate]: https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-mutate
(
data: &mut [u8],
size: usize,
max_size: usize,
seed: u32,
libfuzzer_mutate: fn(data: &mut [u8], size: usize, max_size: usize) -> usize,
)
| 12 | /// |
| 13 | /// [wasm-mutate]: https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-mutate |
| 14 | pub fn wasm_mutate( |
| 15 | data: &mut [u8], |
| 16 | size: usize, |
| 17 | max_size: usize, |
| 18 | seed: u32, |
| 19 | libfuzzer_mutate: fn(data: &mut [u8], size: usize, max_size: usize) -> usize, |
| 20 | ) -> usize { |
| 21 | const MUTATION_FUEL: u64 = 100; |
| 22 | const MUTATION_ITERS: usize = 100; |
| 23 | |
| 24 | let wasm = &data[..size]; |
| 25 | |
| 26 | if wasmparser::validate(wasm).is_ok() { |
| 27 | let mut wasm_mutate = wasm_mutate::WasmMutate::default(); |
| 28 | wasm_mutate |
| 29 | .seed(seed.into()) |
| 30 | .fuel(MUTATION_FUEL) |
| 31 | .reduce(max_size < size) |
| 32 | .raw_mutate_func(Some(Arc::new(move |data, max_size| { |
| 33 | let len = data.len(); |
| 34 | |
| 35 | // The given max could be very large, so clamp it to no more |
| 36 | // than `len * 2` in any single, given mutation. This way we |
| 37 | // don't over-allocate a bunch of space. |
| 38 | let max_size = std::cmp::min(max_size, len * 2); |
| 39 | // Also, the max must always be greater than zero (`libfuzzer` |
| 40 | // asserts this). |
| 41 | let max_size = std::cmp::max(max_size, 1); |
| 42 | |
| 43 | // Make sure we have capacity in case `libfuzzer` decides to |
| 44 | // grow this data. |
| 45 | if max_size > len { |
| 46 | data.resize(max_size, 0); |
| 47 | } |
| 48 | |
| 49 | // Finally, have `libfuzzer` mutate the data! |
| 50 | let new_len = libfuzzer_mutate(data, len, max_size); |
| 51 | |
| 52 | // Resize the data to the mutated size, releasing any extra |
| 53 | // capacity that we don't need anymore. |
| 54 | data.resize(new_len, 0); |
| 55 | data.shrink_to_fit(); |
| 56 | |
| 57 | Ok(()) |
| 58 | }))); |
| 59 | |
| 60 | let wasm = wasm.to_vec(); |
| 61 | let mutations = wasm_mutate.run(&wasm); |
| 62 | if let Ok(mutations) = mutations { |
| 63 | for mutation in mutations.take(MUTATION_ITERS) { |
| 64 | if let Ok(mutated_wasm) = mutation { |
| 65 | if mutated_wasm.len() <= max_size { |
| 66 | data[..mutated_wasm.len()].copy_from_slice(&mutated_wasm); |
| 67 | return mutated_wasm.len(); |
| 68 | } |
| 69 | } |
| 70 | } |
| 71 | } |
nothing calls this directly
no test coverage detected