MCPcopy Create free account
hub / github.com/MultiFuzz/MultiFuzz / run

Method run

hail-fuzz/src/trim.rs:15–105  ·  view source on GitHub ↗
(fuzzer: &mut Fuzzer, stats: &mut LocalStats)

Source from the content-addressed store, hash-verified

13
14impl FuzzerStage for TrimStage {
15 fn run(fuzzer: &mut Fuzzer, stats: &mut LocalStats) -> anyhow::Result<StageExit> {
16 let Some(input_id) = fuzzer.input_id
17 else {
18 return Ok(StageExit::Skip);
19 };
20 fuzzer.copy_current_input();
21 let initial_len = fuzzer.corpus[input_id].data.total_bytes();
22
23 // The bits that we want to ensure that the input still reaches after trimming.
24 let bits_to_keep = fuzzer.corpus[input_id].metadata.new_bits.clone();
25 tracing::debug!("[{input_id}] attempting to trim keeping {bits_to_keep:?}");
26
27 let mut trim_log = TrimLogger::new(input_id, &fuzzer.workdir);
28
29 // Keeps track of the location to trim next.
30 let Some(mut cursor) = MultiStreamTrimCursor::new(&fuzzer.state.input)
31 else {
32 return Ok(StageExit::Skip);
33 };
34
35 // The order we trim things in sometimes matter (e.g., one stream might be unable to be
36 // trimmed before another stream). We randomize the order here to ensure that the chosen
37 // order is less dependent on the ordering of the stream HashMap to avoid cases where a bad
38 // order is always chosen.
39 cursor.randomize_trim_order(&mut fuzzer.rng);
40
41 // Keep track best input we have found so far that still hits the target bits.
42 let mut attempts = 0;
43 let mut saved_input = fuzzer.state.input.clone();
44 while let Some((stream_key, offset, len)) = cursor.get(&fuzzer.state.input) {
45 // Remove part of the input
46 let stream_bytes = &mut fuzzer.state.input.streams.get_mut(&stream_key).unwrap().bytes;
47 stream_bytes.drain(offset..offset + len);
48
49 // Run the modifed input in the emulator.
50 Snapshot::restore_initial(fuzzer);
51 fuzzer.reset_input_cursor().unwrap();
52 fuzzer.write_input_to_target().unwrap();
53 let Some(exit) = fuzzer.execute()
54 else {
55 return Ok(StageExit::Interrupted);
56 };
57 attempts += 1;
58 fuzzer.auto_trim_input().unwrap();
59
60 // Check if the input finds a new path or is a crash, and update the monitor.
61 fuzzer.check_exit_state(exit)?;
62 fuzzer.update_stats(stats);
63
64 // Check whether we still hit all the target bits, and we still exit in the same way.
65 let current_bits = fuzzer.coverage.get_bits(&mut fuzzer.vm);
66 let diverges = CrashKind::from(exit).is_crash()
67 || !bits_to_keep.iter().all(|bit| is_bit_set(current_bits, *bit));
68 if diverges {
69 // Input no longer hits the target bits skip past this chunk and restore the input.
70 fuzzer.state.input.clone_from(&saved_input);
71 cursor.skip_current();
72 trim_log.log(fuzzer, stream_key, offset, len, &bits_to_keep, false);

Callers 1

find_input_for_testsFunction · 0.45

Calls 15

is_bit_setFunction · 0.85
bit_iterFunction · 0.85
copy_current_inputMethod · 0.80
total_bytesMethod · 0.80
cloneMethod · 0.80
randomize_trim_orderMethod · 0.80
get_mutMethod · 0.80
reset_input_cursorMethod · 0.80
write_input_to_targetMethod · 0.80
executeMethod · 0.80
auto_trim_inputMethod · 0.80
check_exit_stateMethod · 0.80

Tested by 1

find_input_for_testsFunction · 0.36