Merge TimeoutForkserverExecutor into ForkserverExecutor (#1819)

* delete timeout forkserver

* clippies

* name

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
This commit is contained in:
Dongjia "toka" Zhang 2024-01-30 17:34:39 +01:00 committed by GitHub
parent 519ea435ed
commit a4f753b0f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 86 additions and 344 deletions

View File

@ -5,10 +5,7 @@ use clap::{self, Parser};
use libafl::{
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{
forkserver::{ForkserverExecutor, TimeoutForkserverExecutor},
HasObservers,
},
executors::{forkserver::ForkserverExecutor, HasObservers},
feedback_and_fast, feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
fuzzer::{Fuzzer, StdFuzzer},
@ -165,31 +162,26 @@ pub fn main() {
let args = opt.arguments;
let mut tokens = Tokens::new();
let mut forkserver = ForkserverExecutor::builder()
let mut executor = ForkserverExecutor::builder()
.program(opt.executable)
.debug_child(debug_child)
.shmem_provider(&mut shmem_provider)
.autotokens(&mut tokens)
.parse_afl_cmdline(args)
.coverage_map_size(MAP_SIZE)
.timeout(Duration::from_millis(opt.timeout))
.kill_signal(opt.signal)
.build(tuple_list!(time_observer, edges_observer))
.unwrap();
if let Some(dynamic_map_size) = forkserver.coverage_map_size() {
forkserver
if let Some(dynamic_map_size) = executor.coverage_map_size() {
executor
.observers_mut()
.match_name_mut::<HitcountsMapObserver<StdMapObserver<'_, u8, false>>>("shared_mem")
.unwrap()
.truncate(dynamic_map_size);
}
let mut executor = TimeoutForkserverExecutor::with_signal(
forkserver,
Duration::from_millis(opt.timeout),
opt.signal,
)
.expect("Failed to create the executor.");
// In case the corpus is empty (on first run), reset
if state.must_load_initial_inputs() {
state

View File

@ -5,10 +5,7 @@ use clap::{self, Parser};
use libafl::{
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{
forkserver::{ForkserverExecutor, TimeoutForkserverExecutor},
HasObservers,
},
executors::{forkserver::ForkserverExecutor, HasObservers},
feedback_and_fast, feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
fuzzer::{Fuzzer, StdFuzzer},
@ -165,31 +162,26 @@ pub fn main() {
let args = opt.arguments;
let mut tokens = Tokens::new();
let mut forkserver = ForkserverExecutor::builder()
let mut executor = ForkserverExecutor::builder()
.program(opt.executable)
.debug_child(debug_child)
.shmem_provider(&mut shmem_provider)
.autotokens(&mut tokens)
.parse_afl_cmdline(args)
.coverage_map_size(MAP_SIZE)
.timeout(Duration::from_millis(opt.timeout))
.kill_signal(opt.signal)
.build(tuple_list!(time_observer, edges_observer))
.unwrap();
if let Some(dynamic_map_size) = forkserver.coverage_map_size() {
forkserver
if let Some(dynamic_map_size) = executor.coverage_map_size() {
executor
.observers_mut()
.match_name_mut::<HitcountsMapObserver<StdMapObserver<'_, u8, false>>>("shared_mem")
.unwrap()
.truncate(dynamic_map_size);
}
let mut executor = TimeoutForkserverExecutor::with_signal(
forkserver,
Duration::from_millis(opt.timeout),
opt.signal,
)
.expect("Failed to create the executor.");
// In case the corpus is empty (on first run), reset
if state.must_load_initial_inputs() {
state

View File

@ -11,7 +11,7 @@ use clap::{Arg, ArgAction, Command};
use libafl::{
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::forkserver::{ForkserverExecutor, TimeoutForkserverExecutor},
executors::forkserver::ForkserverExecutor,
feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
fuzzer::{Fuzzer, StdFuzzer},
@ -310,20 +310,19 @@ fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
let mut tokens = Tokens::new();
let forkserver = ForkserverExecutor::builder()
let mut executor = ForkserverExecutor::builder()
.program(executable)
.debug_child(debug_child)
.shmem_provider(&mut shmem_provider)
.autotokens(&mut tokens)
.parse_afl_cmdline(arguments)
.coverage_map_size(MAP_SIZE)
.timeout(timeout)
.kill_signal(signal)
.is_persistent(true)
.build_dynamic_map(edges_observer, tuple_list!(time_observer))
.unwrap();
let mut executor = TimeoutForkserverExecutor::with_signal(forkserver, timeout, signal)
.expect("Failed to create the executor.");
// Read tokens
if let Some(tokenfile) = tokenfile {
tokens.add_from_file(tokenfile)?;
@ -349,19 +348,17 @@ fn fuzz(
let cmplog_observer = StdCmpValuesObserver::new("cmplog", cmpmap, true);
let cmplog_forkserver = ForkserverExecutor::builder()
let cmplog_executor = ForkserverExecutor::builder()
.program(exec)
.debug_child(debug_child)
.shmem_provider(&mut shmem_provider)
.parse_afl_cmdline(arguments)
.is_persistent(true)
.timeout(timeout * 10)
.kill_signal(signal)
.build(tuple_list!(cmplog_observer))
.unwrap();
let cmplog_executor =
TimeoutForkserverExecutor::with_signal(cmplog_forkserver, timeout * 10, signal)
.expect("Failed to create the executor.");
let tracing = TracingStage::new(cmplog_executor);
// Setup a randomic Input2State stage

View File

@ -11,7 +11,7 @@ use clap::{Arg, ArgAction, Command};
use libafl::{
corpus::{Corpus, HasCurrentCorpusIdx, InMemoryOnDiskCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::forkserver::{ForkserverExecutor, TimeoutForkserverExecutor},
executors::forkserver::ForkserverExecutor,
feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
fuzzer::{Fuzzer, StdFuzzer},
@ -314,20 +314,19 @@ fn fuzz(
let colorization = ColorizationStage::new(&edges_observer);
let mut tokens = Tokens::new();
let forkserver = ForkserverExecutor::builder()
let mut executor = ForkserverExecutor::builder()
.program(executable)
.debug_child(debug_child)
.shmem_provider(&mut shmem_provider)
.autotokens(&mut tokens)
.parse_afl_cmdline(arguments)
.coverage_map_size(MAP_SIZE)
.timeout(timeout)
.kill_signal(signal)
.is_persistent(true)
.build_dynamic_map(edges_observer, tuple_list!(time_observer))
.unwrap();
let mut executor = TimeoutForkserverExecutor::with_signal(forkserver, timeout, signal)
.expect("Failed to create the executor.");
// Read tokens
if let Some(tokenfile) = tokenfile {
tokens.add_from_file(tokenfile)?;
@ -353,19 +352,17 @@ fn fuzz(
let cmplog_observer = AFLppCmpLogObserver::new("cmplog", cmpmap, true);
let cmplog_forkserver = ForkserverExecutor::builder()
let cmplog_executor = ForkserverExecutor::builder()
.program(exec)
.debug_child(debug_child)
.shmem_provider(&mut shmem_provider)
.parse_afl_cmdline(arguments)
.is_persistent(true)
.timeout(timeout * 10)
.kill_signal(signal)
.build(tuple_list!(cmplog_observer))
.unwrap();
let cmplog_executor =
TimeoutForkserverExecutor::with_signal(cmplog_forkserver, timeout * 10, signal)
.expect("Failed to create the executor.");
let tracing = AFLppCmplogTracingStage::with_cmplog_observer_name(cmplog_executor, "cmplog");
// Setup a randomic Input2State stage

View File

@ -4,7 +4,6 @@ use alloc::{borrow::ToOwned, string::ToString, vec::Vec};
use core::{
fmt::{self, Debug, Formatter},
marker::PhantomData,
sync::atomic::{compiler_fence, Ordering},
time::Duration,
};
use std::{
@ -19,14 +18,14 @@ use libafl_bolts::{
fs::{get_unique_std_input_file, InputFile},
os::{dup2, pipes::Pipe},
shmem::{ShMem, ShMemProvider, UnixShMemProvider},
tuples::{MatchName, Prepend},
tuples::Prepend,
AsMutSlice, AsSlice, Truncate,
};
use nix::{
sys::{
select::{pselect, FdSet},
signal::{kill, SigSet, Signal},
time::{TimeSpec, TimeValLike},
time::TimeSpec,
wait::waitpid,
},
unistd::Pid,
@ -466,175 +465,6 @@ impl Forkserver {
}
}
/// A struct that has a forkserver
pub trait HasForkserver {
/// The [`ShMemProvider`] used for this forkserver's map
type SP: ShMemProvider;
/// The forkserver
fn forkserver(&self) -> &Forkserver;
/// The forkserver, mutable
fn forkserver_mut(&mut self) -> &mut Forkserver;
/// The file the forkserver is reading from
fn input_file(&self) -> &InputFile;
/// The file the forkserver is reading from, mutable
fn input_file_mut(&mut self) -> &mut InputFile;
/// The map of the fuzzer
fn shmem(&self) -> &Option<<<Self as HasForkserver>::SP as ShMemProvider>::ShMem>;
/// The map of the fuzzer, mutable
fn shmem_mut(&mut self) -> &mut Option<<<Self as HasForkserver>::SP as ShMemProvider>::ShMem>;
/// Whether testcases are expected in shared memory
fn uses_shmem_testcase(&self) -> bool;
}
/// The timeout forkserver executor that wraps around the standard forkserver executor and sets a timeout before each run.
#[derive(Debug)]
pub struct TimeoutForkserverExecutor<E> {
executor: E,
timeout: TimeSpec,
signal: Signal,
}
impl<E> TimeoutForkserverExecutor<E> {
/// Create a new [`TimeoutForkserverExecutor`]
pub fn new(executor: E, exec_tmout: Duration) -> Result<Self, Error> {
let signal = Signal::SIGKILL;
Self::with_signal(executor, exec_tmout, signal)
}
/// Create a new [`TimeoutForkserverExecutor`] that sends a user-defined signal to the timed-out process
pub fn with_signal(executor: E, exec_tmout: Duration, signal: Signal) -> Result<Self, Error> {
let milli_sec = exec_tmout.as_millis() as i64;
let timeout = TimeSpec::milliseconds(milli_sec);
Ok(Self {
executor,
timeout,
signal,
})
}
}
impl<E, EM, Z> Executor<EM, Z> for TimeoutForkserverExecutor<E>
where
E: Executor<EM, Z> + HasForkserver + HasObservers,
E::Input: HasTargetBytes,
E::State: HasExecutions,
EM: UsesState<State = E::State>,
Z: UsesState<State = E::State>,
{
#[inline]
fn run_target(
&mut self,
_fuzzer: &mut Z,
state: &mut Self::State,
_mgr: &mut EM,
input: &Self::Input,
) -> Result<ExitKind, Error> {
*state.executions_mut() += 1;
let mut exit_kind = ExitKind::Ok;
let last_run_timed_out = self.executor.forkserver().last_run_timed_out_raw();
if self.executor.uses_shmem_testcase() {
debug_assert!(
self.executor.shmem_mut().is_some(),
"The uses_shmem_testcase() bool can only exist when a map is set"
);
// # Safety
// Struct can never be created when uses_shmem_testcase is true and map is none.
let map = unsafe { self.executor.shmem_mut().as_mut().unwrap_unchecked() };
let target_bytes = input.target_bytes();
let mut size = target_bytes.as_slice().len();
let max_size = map.len() - SHMEM_FUZZ_HDR_SIZE;
if size > max_size {
// Truncate like AFL++ does
size = max_size;
}
let size_in_bytes = size.to_ne_bytes();
// The first four bytes tells the size of the shmem.
map.as_mut_slice()[..SHMEM_FUZZ_HDR_SIZE]
.copy_from_slice(&size_in_bytes[..SHMEM_FUZZ_HDR_SIZE]);
map.as_mut_slice()[SHMEM_FUZZ_HDR_SIZE..(SHMEM_FUZZ_HDR_SIZE + size)]
.copy_from_slice(&target_bytes.as_slice()[..size]);
} else {
self.executor
.input_file_mut()
.write_buf(input.target_bytes().as_slice())?;
}
let send_len = self
.executor
.forkserver_mut()
.write_ctl(last_run_timed_out)?;
self.executor.forkserver_mut().set_last_run_timed_out(false);
if send_len != 4 {
return Err(Error::unknown(
"Unable to request new process from fork server (OOM?)".to_string(),
));
}
let (recv_pid_len, pid) = self.executor.forkserver_mut().read_st()?;
if recv_pid_len != 4 {
return Err(Error::unknown(
"Unable to request new process from fork server (OOM?)".to_string(),
));
}
if pid <= 0 {
return Err(Error::unknown(
"Fork server is misbehaving (OOM?)".to_string(),
));
}
self.executor
.forkserver_mut()
.set_child_pid(Pid::from_raw(pid));
if let Some(status) = self
.executor
.forkserver_mut()
.read_st_timed(&self.timeout)?
{
self.executor.forkserver_mut().set_status(status);
if libc::WIFSIGNALED(self.executor.forkserver().status()) {
exit_kind = ExitKind::Crash;
#[cfg(feature = "regex")]
if let Some(asan_observer) = self
.observers_mut()
.match_name_mut::<AsanBacktraceObserver>("AsanBacktraceObserver")
{
asan_observer.parse_asan_output_from_asan_log_file(pid)?;
}
}
} else {
self.executor.forkserver_mut().set_last_run_timed_out(true);
// We need to kill the child in case he has timed out, or we can't get the correct pid in the next call to self.executor.forkserver_mut().read_st()?
let _ = kill(self.executor.forkserver().child_pid(), self.signal);
let (recv_status_len, _) = self.executor.forkserver_mut().read_st()?;
if recv_status_len != 4 {
return Err(Error::unknown("Could not kill timed-out child".to_string()));
}
exit_kind = ExitKind::Timeout;
}
if !libc::WIFSTOPPED(self.executor.forkserver().status()) {
self.executor.forkserver_mut().reset_child_pid();
}
Ok(exit_kind)
}
}
/// This [`Executor`] can run binaries compiled for AFL/AFL++ that make use of a forkserver.
/// Shared memory feature is also available, but you have to set things up in your code.
/// Please refer to AFL++'s docs. <https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.persistent_mode.md>
@ -650,9 +480,8 @@ where
observers: OT,
map: Option<SP::ShMem>,
phantom: PhantomData<S>,
/// Cache that indicates if we have a `ASan` observer registered.
has_asan_observer: Option<bool>,
map_size: Option<usize>,
timeout: TimeSpec,
}
impl<OT, S, SP> Debug for ForkserverExecutor<OT, S, SP>
@ -732,6 +561,7 @@ pub struct ForkserverExecutorBuilder<'a, SP> {
map_size: Option<usize>,
real_map_size: i32,
kill_signal: Option<Signal>,
timeout: Option<Duration>,
}
impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
@ -764,6 +594,11 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
));
}
let timeout: TimeSpec = match self.timeout {
Some(t) => t.into(),
None => Duration::from_millis(5000).into(),
};
Ok(ForkserverExecutor {
target,
args: self.arguments.clone(),
@ -773,8 +608,8 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
observers,
map,
phantom: PhantomData,
has_asan_observer: None, // initialized on first use
map_size: self.map_size,
timeout,
})
}
@ -815,6 +650,11 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
));
}
let timeout: TimeSpec = match self.timeout {
Some(t) => t.into(),
None => Duration::from_millis(5000).into(),
};
Ok(ForkserverExecutor {
target,
args: self.arguments.clone(),
@ -824,8 +664,8 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
observers,
map,
phantom: PhantomData,
has_asan_observer: None, // initialized on first use
map_size: self.map_size,
timeout,
})
}
@ -976,6 +816,13 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
self
}
#[must_use]
/// set the timeout for the executor
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
#[must_use]
/// Parse afl style command line
///
@ -1177,6 +1024,7 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
real_map_size: 0,
max_input_size: MAX_INPUT_SIZE_DEFAULT,
kill_signal: None,
timeout: None,
}
}
@ -1201,6 +1049,7 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
real_map_size: self.real_map_size,
max_input_size: MAX_INPUT_SIZE_DEFAULT,
kill_signal: None,
timeout: None,
}
}
}
@ -1229,13 +1078,15 @@ where
input: &Self::Input,
) -> Result<ExitKind, Error> {
*state.executions_mut() += 1;
let mut exit_kind = ExitKind::Ok;
// Write to testcase
let last_run_timed_out = self.forkserver.last_run_timed_out_raw();
if self.uses_shmem_testcase {
debug_assert!(
self.map.is_some(),
"The uses_shmem_testcase bool can only exist when a map is set"
"The uses_shmem_testcase() bool can only exist when a map is set"
);
// # Safety
// Struct can never be created when uses_shmem_testcase is true and map is none.
@ -1257,21 +1108,19 @@ where
self.input_file.write_buf(input.target_bytes().as_slice())?;
}
// Don't tell the forkserver to spawn a new process before clearing the cov map
compiler_fence(Ordering::SeqCst);
let send_len = self.forkserver.write_ctl(last_run_timed_out)?;
self.forkserver.set_last_run_timed_out(false);
let send_len = self
.forkserver
.write_ctl(self.forkserver().last_run_timed_out_raw())?;
if send_len != 4 {
return Err(Error::illegal_state(
return Err(Error::unknown(
"Unable to request new process from fork server (OOM?)".to_string(),
));
}
let (recv_pid_len, pid) = self.forkserver.read_st()?;
if recv_pid_len != 4 {
return Err(Error::illegal_state(
return Err(Error::unknown(
"Unable to request new process from fork server (OOM?)".to_string(),
));
}
@ -1284,41 +1133,34 @@ where
self.forkserver.set_child_pid(Pid::from_raw(pid));
let (recv_status_len, status) = self.forkserver.read_st()?;
if recv_status_len != 4 {
return Err(Error::unknown(
"Unable to communicate with fork server (OOM?)".to_string(),
));
}
self.forkserver.set_status(status);
if libc::WIFSIGNALED(self.forkserver.status()) {
exit_kind = ExitKind::Crash;
#[cfg(feature = "regex")]
if self.has_asan_observer.is_none() {
self.has_asan_observer = Some(
self.observers()
.match_name::<AsanBacktraceObserver>("AsanBacktraceObserver")
.is_some(),
);
}
#[cfg(feature = "regex")]
if self.has_asan_observer.unwrap() {
self.observers_mut()
if let Some(status) = self.forkserver.read_st_timed(&self.timeout)? {
self.forkserver.set_status(status);
if libc::WIFSIGNALED(self.forkserver().status()) {
exit_kind = ExitKind::Crash;
#[cfg(feature = "regex")]
if let Some(asan_observer) = self
.observers_mut()
.match_name_mut::<AsanBacktraceObserver>("AsanBacktraceObserver")
.unwrap()
.parse_asan_output_from_asan_log_file(pid)?;
{
asan_observer.parse_asan_output_from_asan_log_file(pid)?;
}
}
} else {
self.forkserver.set_last_run_timed_out(true);
// We need to kill the child in case he has timed out, or we can't get the correct pid in the next call to self.executor.forkserver_mut().read_st()?
let _ = kill(self.forkserver().child_pid(), self.forkserver.kill_signal);
let (recv_status_len, _) = self.forkserver.read_st()?;
if recv_status_len != 4 {
return Err(Error::unknown("Could not kill timed-out child".to_string()));
}
exit_kind = ExitKind::Timeout;
}
if !libc::WIFSTOPPED(self.forkserver.status) {
if !libc::WIFSTOPPED(self.forkserver().status()) {
self.forkserver.reset_child_pid();
}
// Clear the observer map after the execution is finished
compiler_fence(Ordering::SeqCst);
Ok(exit_kind)
}
}
@ -1357,80 +1199,6 @@ where
}
}
impl<OT, S, SP> HasForkserver for ForkserverExecutor<OT, S, SP>
where
OT: ObserversTuple<S>,
S: UsesInput,
S::Input: Input + HasTargetBytes,
SP: ShMemProvider,
{
type SP = SP;
#[inline]
fn forkserver(&self) -> &Forkserver {
&self.forkserver
}
#[inline]
fn forkserver_mut(&mut self) -> &mut Forkserver {
&mut self.forkserver
}
#[inline]
fn input_file(&self) -> &InputFile {
&self.input_file
}
#[inline]
fn input_file_mut(&mut self) -> &mut InputFile {
&mut self.input_file
}
#[inline]
fn shmem(&self) -> &Option<SP::ShMem> {
&self.map
}
#[inline]
fn shmem_mut(&mut self) -> &mut Option<SP::ShMem> {
&mut self.map
}
#[inline]
fn uses_shmem_testcase(&self) -> bool {
self.uses_shmem_testcase
}
}
impl<E> UsesState for TimeoutForkserverExecutor<E>
where
E: UsesState,
{
type State = E::State;
}
impl<E> UsesObservers for TimeoutForkserverExecutor<E>
where
E: UsesObservers,
{
type Observers = E::Observers;
}
impl<E> HasObservers for TimeoutForkserverExecutor<E>
where
E: HasObservers,
{
#[inline]
fn observers(&self) -> &Self::Observers {
self.executor.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut Self::Observers {
self.executor.observers_mut()
}
}
#[cfg(test)]
mod tests {
use std::ffi::OsString;

View File

@ -9,7 +9,7 @@ pub use combined::CombinedExecutor;
pub use command::CommandExecutor;
pub use differential::DiffExecutor;
#[cfg(all(feature = "std", feature = "fork", unix))]
pub use forkserver::{Forkserver, ForkserverExecutor, TimeoutForkserverExecutor};
pub use forkserver::{Forkserver, ForkserverExecutor};
pub use inprocess::InProcessExecutor;
#[cfg(all(feature = "std", feature = "fork", unix))]
pub use inprocess_fork::InProcessForkExecutor;

View File

@ -5,7 +5,7 @@ use std::{fs, net::SocketAddr, path::PathBuf, time::Duration};
use libafl::{
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus},
events::{launcher::Launcher, EventConfig, EventRestarter, LlmpRestartingEventManager},
executors::{forkserver::ForkserverExecutorBuilder, TimeoutForkserverExecutor},
executors::forkserver::ForkserverExecutorBuilder,
feedback_or, feedback_or_fast,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
fuzzer::{Fuzzer, StdFuzzer},
@ -179,6 +179,7 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
.is_persistent(true)
.autotokens(&mut tokens)
.coverage_map_size(MAP_SIZE)
.timeout(timeout)
.debug_child(self.debug_output)
.shmem_provider(&mut shmem_provider_client)
.build_dynamic_map(edges_observer, tuple_list!(time_observer))
@ -189,10 +190,12 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
.is_persistent(true)
.autotokens(&mut tokens)
.coverage_map_size(MAP_SIZE)
.timeout(timeout)
.debug_child(self.debug_output)
.build_dynamic_map(edges_observer, tuple_list!(time_observer))
};
let mut executor = forkserver.unwrap();
if let Some(tokens_file) = &self.tokens_file {
// if a token file is provided, load it into our set of tokens
tokens.add_from_file(tokens_file)?;
@ -203,13 +206,6 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
state.add_metadata(tokens);
}
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
let mut executor = TimeoutForkserverExecutor::new(
forkserver.expect("Failed to create the executor."),
timeout,
)
.expect("Failed to create the executor.");
// In case the corpus is empty (on first run), reset
if state.must_load_initial_inputs() {
if self.input_dirs.is_empty() {