(&mut self, fuzzer: &mut Fuzzer)
| 66 | } |
| 67 | |
| 68 | fn fuzz_one(&mut self, fuzzer: &mut Fuzzer) -> Option<VmExit> { |
| 69 | self.attempts = self.attempts.checked_sub(1)?; |
| 70 | |
| 71 | Snapshot::restore_initial(fuzzer); |
| 72 | fuzzer.copy_current_input(); |
| 73 | fuzzer.reset_input_cursor().unwrap(); |
| 74 | |
| 75 | self.havoc_v1(fuzzer); |
| 76 | |
| 77 | // Also extend any streams that have caused us to exit because there were too small, these |
| 78 | // streams will be trimmed back to the correct length as part of `auto_trim_input` if the |
| 79 | // extension was unnecessary |
| 80 | let data = &mut fuzzer.state.input; |
| 81 | for (key, count) in &self.streams_to_extend { |
| 82 | let bytes = &mut data.streams.entry(*key).or_default().bytes; |
| 83 | if bytes.len() >= config::MAX_STREAM_LEN { |
| 84 | continue; |
| 85 | } |
| 86 | |
| 87 | let local_dict = fuzzer.dict.entry(*key).or_default(); |
| 88 | local_dict.compute_weights(); |
| 89 | let dict = DictionaryRef { local: local_dict, global: &fuzzer.global_dict }; |
| 90 | mutations::extend_input_by(&mut fuzzer.rng, dict, bytes, 4 * count); |
| 91 | } |
| 92 | |
| 93 | fuzzer.write_input_to_target().unwrap(); |
| 94 | let exit = fuzzer.execute()?; |
| 95 | |
| 96 | // Keep track of the streams that cause us to exit because they are too small. |
| 97 | if let Some(key) = fuzzer.state.input.last_read { |
| 98 | *self.streams_to_extend.entry(key).or_default() += 1; |
| 99 | } |
| 100 | |
| 101 | fuzzer.auto_trim_input().ok()?; |
| 102 | |
| 103 | if fuzzer.debug.havoc && !self.saved { |
| 104 | let _ = std::fs::write( |
| 105 | fuzzer.workdir.join(format!("queue/{}.havoc.bin", fuzzer.input_id.unwrap_or(0))), |
| 106 | fuzzer.state.input.to_bytes(), |
| 107 | ); |
| 108 | self.saved = true; |
| 109 | } |
| 110 | |
| 111 | Some(exit) |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | impl HavocStage { |
nothing calls this directly
no test coverage detected