diff --git a/fuzzers/FRET/src/fuzzer.rs b/fuzzers/FRET/src/fuzzer.rs index 68e34746ae..125a535101 100644 --- a/fuzzers/FRET/src/fuzzer.rs +++ b/fuzzers/FRET/src/fuzzer.rs @@ -1,7 +1,7 @@ //! A fuzzer using qemu in systemmode for binary-only coverage of kernels //! use core::time::Duration; -use std::{env, path::PathBuf, process, io::Read, fs}; +use std::{env, path::PathBuf, process, io::{Read, Write}, fs::{self, OpenOptions}}; use libafl::{ bolts::{ @@ -315,19 +315,19 @@ pub fn fuzz() { println!("Iterations {}",t); let num = str::parse::(&t).expect("FUZZ_ITERS was not a number"); fuzzer - .fuzz_loop_for(&mut stages, &mut executor, &mut state, &mut mgr, num) + .fuzz_loop_for_duration(&mut stages, &mut executor, &mut state, &mut mgr, Duration::from_secs(num)) .unwrap(); - let mut strbuf = String::new(); - - unsafe { - for i in ICOUNT_HISTORY.iter() { - strbuf.push_str(&format!("{}\n",i)); - } - } - match env::var("TIME_DUMP") { - Err(_) => (), - Ok(td) => { - fs::write(td, strbuf).expect("could not write time dump"); + if let Ok(td) = env::var("TIME_DUMP") { + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .append(false) + .open(td).expect("Could not open timedump"); + unsafe { + for i in ICOUNT_HISTORY.iter() { + writeln!(file, "{}", i).expect("Write to dump failed"); + } } } }, diff --git a/libafl/src/fuzzer/mod.rs b/libafl/src/fuzzer/mod.rs index 2640d62564..b3c6c4f39b 100644 --- a/libafl/src/fuzzer/mod.rs +++ b/libafl/src/fuzzer/mod.rs @@ -229,6 +229,48 @@ where Ok(ret) } + + /// Fuzz for n iterations. + /// Returns the index of the last fuzzed corpus item. + /// (Note: An iteration represents a complete run of every stage. + /// therefore the number n is not always equal to the number of the actual harness executions, + /// because each stage could run the harness for multiple times) + /// + /// If you use this fn in a restarting scenario to only run for `n` iterations, + /// before exiting, make sure you call `event_mgr.on_restart(&mut state)?;`. + /// This way, the state will be available in the next, respawned, iteration. + fn fuzz_loop_for_duration( + &mut self, + stages: &mut ST, + executor: &mut E, + state: &mut EM::State, + manager: &mut EM, + time: Duration + ) -> Result { + if time==Duration::ZERO { + return Err(Error::illegal_argument( + "Cannot fuzz for 0 duration!".to_string(), + )); + } + + let mut ret = 0; + let mut last = current_time(); + let monitor_timeout = STATS_TIMEOUT_DEFAULT; + + let starttime = std::time::Instant::now(); + + while std::time::Instant::now().duration_since(starttime) < time { + ret = self.fuzz_one(stages, executor, state, manager)?; + last = manager.maybe_report_progress(state, last, monitor_timeout)?; + } + + // If we would assume the fuzzer loop will always exit after this, we could do this here: + // manager.on_restart(state)?; + // But as the state may grow to a few megabytes, + // for now we won' and the user has to do it (unless we find a way to do this on `Drop`). + + Ok(ret) + } } /// The corpus this input should be added to