MCPcopy Create free account
hub / github.com/bytecodealliance/wasmtime / mutate

Function mutate

crates/fuzzing/src/single_module_fuzzer.rs:149–215  ·  view source on GitHub ↗

Implementation of a libfuzzer custom mutator for a single-module-fuzzer. This mutator will take the seed specified in `data` and attempt to mutate it with the provided `mutate` function. The `mutate` function may not receive the `data` as-specified, but instead may receive only the seed that was used to generate `data`.

(
    data: &mut [u8],
    mut size: usize,
    max_size: usize,
    gen_module: fn(&mut T, &mut Unstructured<'_>) -> Result<(Vec<u8>, KnownValid)>,
    mutate: fn(&mut [u8], usize, usize) -> usize,
)

Source from the content-addressed store, hash-verified

147/// receive the `data` as-specified, but instead may receive only the seed
148/// that was used to generate `data`.
149pub fn mutate<T>(
150 data: &mut [u8],
151 mut size: usize,
152 max_size: usize,
153 gen_module: fn(&mut T, &mut Unstructured<'_>) -> Result<(Vec<u8>, KnownValid)>,
154 mutate: fn(&mut [u8], usize, usize) -> usize,
155) -> usize
156where
157 T: for<'a> Arbitrary<'a>,
158{
159 // If `data` is a valid wasm module with the fuzz seed at the end, then
160 // discard the wasm module portion and instead shuffle the seed into the
161 // beginning of the `data` slice. This is the "de-envelope" part of the
162 // seed management here.
163 //
164 // After this the `data` array should contain the raw contents used to
165 // produce the module and is ripe for mutation/minimization/etc.
166 if let Ok(input) = extract_fuzz_input(&data[..size]) {
167 let start = input.fuzz_data.as_ptr() as usize - data.as_ptr() as usize;
168 size = input.fuzz_data.len();
169 data.copy_within(start..start + input.fuzz_data.len(), 0);
170 }
171
172 // Delegate to the provided mutation function for standard mutations to
173 // apply.
174 let new_size = mutate(data, size, max_size);
175
176 // Next the goal of this function is to produce a test case which is an
177 // actual wasm module. To that end this will run module generation over the
178 // input provided. If this is all successful then the custom section
179 // representing the seed is appended to the module, making it a sort of
180 // self-referential module.
181 //
182 // After all this it's copied into `data` if the it fits. If the module
183 // doesn't fit then the seed is left un-perturbed since there's not much
184 // that we can do about that.
185 let mut u = Unstructured::new(&data[..new_size]);
186 match u
187 .arbitrary()
188 .and_then(|mut config| gen_module(&mut config, &mut u))
189 {
190 Ok((module, _known_valid)) => {
191 let module = encode_module(&module, &data[..new_size]);
192
193 if module.len() < max_size {
194 log::debug!(
195 "successfully generated mutated module with \
196 appended input section"
197 );
198 data[..module.len()].copy_from_slice(&module);
199 return module.len();
200 } else {
201 log::debug!("mutated module doesn't fit in original slice");
202 }
203 }
204
205 // If our new seed can't generate a new module then that's something
206 // for the fuzzer to figure out later when it "officially" executes

Calls 9

extract_fuzz_inputFunction · 0.85
encode_moduleFunction · 0.85
copy_withinMethod · 0.80
newFunction · 0.50
gen_moduleFunction · 0.50
as_ptrMethod · 0.45
lenMethod · 0.45
arbitraryMethod · 0.45
copy_from_sliceMethod · 0.45