(fuzzer: &mut crate::Fuzzer, exit: crate::VmExit)
| 9 | use crate::{input::MultiStream, utils}; |
| 10 | |
| 11 | pub(crate) fn validate_last_exec(fuzzer: &mut crate::Fuzzer, exit: crate::VmExit) -> Option<()> { |
| 12 | tracing::info!("validating input with new coverage: {:?}", fuzzer.state.new_bits); |
| 13 | let expected_new_bits = fuzzer.state.new_bits.clone(); |
| 14 | |
| 15 | let icount = fuzzer.vm.cpu.icount; |
| 16 | let pc = fuzzer.vm.cpu.read_pc(); |
| 17 | let trace = fuzzer.path_tracer.map(|x| x.get_last_blocks(&mut fuzzer.vm)); |
| 18 | tracing::info!( |
| 19 | "[{}] validating exit @ {pc:#x} {exit:?}", |
| 20 | fuzzer.input_id.unwrap_or(usize::MAX) |
| 21 | ); |
| 22 | |
| 23 | crate::Snapshot::restore_initial(fuzzer); |
| 24 | fuzzer.reset_input_cursor().unwrap(); |
| 25 | fuzzer.write_input_to_target().unwrap(); |
| 26 | tracing::info!("PC reset to: {:#x}", fuzzer.vm.cpu.read_pc()); |
| 27 | let root_exit = fuzzer.execute()?; |
| 28 | tracing::info!("Ended with exit: {root_exit:?}"); |
| 29 | |
| 30 | if !(icount == fuzzer.vm.cpu.icount && pc == fuzzer.vm.cpu.read_pc() && exit == root_exit) { |
| 31 | eprintln!( |
| 32 | "Execution diverged when executing from snapshot (starting at icount={}): |
| 33 | snapshot: icount={icount}, pc={pc:#x}, exit={exit:?}, input_bytes={} (read={}), |
| 34 | root : icount={}, pc={:#x}, exit={root_exit:?}", |
| 35 | fuzzer.prefix_snapshot.as_ref().map_or(0, |x| x.vm.cpu.icount), |
| 36 | fuzzer.state.input.total_bytes(), |
| 37 | fuzzer.state.input.bytes_read(), |
| 38 | fuzzer.vm.cpu.icount, |
| 39 | fuzzer.vm.cpu.read_pc(), |
| 40 | ); |
| 41 | |
| 42 | let root_trace = fuzzer.path_tracer.map(|x| x.get_last_blocks(&mut fuzzer.vm)); |
| 43 | if let (Some(snapshot), Some(root)) = (trace, root_trace) { |
| 44 | if let Some((a, b)) = snapshot.iter().zip(&root).find(|(a, b)| a != b) { |
| 45 | eprintln!("Diverged at:\n snapshot: {a:x?}\n root : {b:x?}"); |
| 46 | } |
| 47 | else { |
| 48 | eprintln!("No divergance? One of the traces was shorter."); |
| 49 | } |
| 50 | |
| 51 | trace::save_path_trace(&fuzzer.workdir.join("snapshot_trace.txt"), &snapshot); |
| 52 | trace::save_path_trace(&fuzzer.workdir.join("root_trace.txt"), &root); |
| 53 | } |
| 54 | else { |
| 55 | eprintln!("Missing traces for executions (run with `ICICLE_TRACK_PATH=1` to obtain)"); |
| 56 | } |
| 57 | |
| 58 | let _ = std::fs::write( |
| 59 | fuzzer.workdir.join("disasm.asm"), |
| 60 | icicle_vm::debug::dump_disasm(&fuzzer.vm).unwrap(), |
| 61 | ); |
| 62 | |
| 63 | let _ = std::fs::write( |
| 64 | fuzzer.workdir.join("diverging_input.bin"), |
| 65 | fuzzer.state.input.to_bytes(), |
| 66 | ); |
| 67 | panic!(); |
| 68 | } |
no test coverage detected