(fuzzer: &mut Fuzzer, stats: &mut monitor::LocalStats)
| 261 | |
| 262 | impl FuzzerStage for MultiStreamExtendStage { |
| 263 | fn run(fuzzer: &mut Fuzzer, stats: &mut monitor::LocalStats) -> anyhow::Result<StageExit> { |
| 264 | let mut state = match MultiStreamExtendStage::start(fuzzer) { |
| 265 | Ok(data) => data, |
| 266 | Err(err) => return Ok(err.into()), |
| 267 | }; |
| 268 | |
| 269 | loop { |
| 270 | if state.attempts == 0 { |
| 271 | // Check if there any pending partial extensions to try. |
| 272 | if let Err(exit) = state.prepare_new_input(fuzzer) { |
| 273 | // Done with this stage. |
| 274 | fuzzer.prefix_snapshot = None; |
| 275 | return Ok(exit); |
| 276 | } |
| 277 | } |
| 278 | state.attempts -= 1; |
| 279 | |
| 280 | let Some(exit) = state.exec_one(fuzzer) |
| 281 | else { |
| 282 | return Ok(StageExit::Interrupted); |
| 283 | }; |
| 284 | |
| 285 | let mut new_mmio_addr = false; |
| 286 | if matches!(exit, VmExit::UnhandledException((ExceptionCode::ReadWatch, _))) { |
| 287 | // If the mutated input ends at a new location then consider saving it, for a second |
| 288 | // multi-stream extension stage. |
| 289 | let end_addr = fuzzer.vm.cpu.read_pc(); |
| 290 | if state.end_addrs.insert(end_addr) { |
| 291 | state.rare_input = Some((end_addr, fuzzer.state.input.clone())); |
| 292 | } |
| 293 | else if state.rare_input.as_ref().map_or(false, |(addr, _)| *addr == end_addr) { |
| 294 | // We found the same ending point again (meaning this was not a rare input). |
| 295 | state.rare_input = None; |
| 296 | } |
| 297 | |
| 298 | // If fuzzing stops because a different stream was read from, added to the list of |
| 299 | // streams we are extending. |
| 300 | if let Some(addr) = fuzzer.state.input.last_read { |
| 301 | // Record metadata for the input causing the exit. This is used to increase |
| 302 | // the size of extensions on inputs with a large number of exits. |
| 303 | let metadata = fuzzer.corpus.metadata.streams.entry(addr).or_default(); |
| 304 | metadata.reached_end_of_stream += 1; |
| 305 | |
| 306 | if let Some(id) = fuzzer.input_id { |
| 307 | *fuzzer.corpus[id] |
| 308 | .stage_data::<LengthExtData>(Stage::MultiStreamExtend) |
| 309 | .stream_exits |
| 310 | .entry(addr) |
| 311 | .or_default() += 1; |
| 312 | } |
| 313 | |
| 314 | state.streams_to_mutate.entry(addr).or_insert_with(|| { |
| 315 | new_mmio_addr = true; |
| 316 | fuzzer.get_extension_factor(addr) |
| 317 | }); |
| 318 | }; |
| 319 | } |
| 320 |
nothing calls this directly
no test coverage detected