pub mod mutational;
use alloc::rc::Rc;
use core::{
cell::{Cell, RefCell},
marker::PhantomData,
time::Duration,
};
pub use mutational::StdMutationalPushStage;
use crate::{
bolts::current_time,
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
executors::ExitKind,
inputs::Input,
observers::ObserversTuple,
schedulers::Scheduler,
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasRand},
Error, EvaluatorObservers, ExecutionProcessor, HasScheduler,
};
const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15);
#[derive(Clone, Debug)]
pub struct PushStageSharedState<CS, EM, I, OT, S, Z>
where
CS: Scheduler<I, S>,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId,
I: Input,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{
pub state: S,
pub fuzzer: Z,
pub event_mgr: EM,
pub observers: OT,
phantom: PhantomData<(CS, I, OT, S, Z)>,
}
impl<CS, EM, I, OT, S, Z> PushStageSharedState<CS, EM, I, OT, S, Z>
where
CS: Scheduler<I, S>,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId,
I: Input,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{
#[must_use]
pub fn new(fuzzer: Z, state: S, observers: OT, event_mgr: EM) -> Self {
Self {
state,
fuzzer,
event_mgr,
observers,
phantom: PhantomData,
}
}
}
#[derive(Clone, Debug)]
pub struct PushStageHelper<CS, EM, I, OT, S, Z>
where
CS: Scheduler<I, S>,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId,
I: Input,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{
pub initialized: bool,
pub last_monitor_time: Duration,
#[allow(clippy::type_complexity)]
pub shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, I, OT, S, Z>>>>,
pub errored: bool,
pub current_corpus_idx: Option<usize>,
pub current_input: Option<I>,
#[allow(clippy::type_complexity)]
phantom: PhantomData<(CS, (), EM, I, OT, S, Z)>,
exit_kind: Rc<Cell<Option<ExitKind>>>,
}
impl<CS, EM, I, OT, S, Z> PushStageHelper<CS, EM, I, OT, S, Z>
where
CS: Scheduler<I, S>,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId,
I: Input,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{
#[must_use]
#[allow(clippy::type_complexity)]
pub fn new(
shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, I, OT, S, Z>>>>,
exit_kind_ref: Rc<Cell<Option<ExitKind>>>,
) -> Self {
Self {
shared_state,
initialized: false,
phantom: PhantomData,
last_monitor_time: current_time(),
exit_kind: exit_kind_ref,
errored: false,
current_input: None,
current_corpus_idx: None,
}
}
#[inline]
pub fn set_shared_state(&mut self, shared_state: PushStageSharedState<CS, EM, I, OT, S, Z>) {
(*self.shared_state.borrow_mut()).replace(shared_state);
}
#[inline]
#[allow(clippy::type_complexity)]
pub fn take_shared_state(&mut self) -> Option<PushStageSharedState<CS, EM, I, OT, S, Z>> {
let shared_state_ref = &mut (*self.shared_state).borrow_mut();
shared_state_ref.take()
}
#[inline]
#[must_use]
pub fn exit_kind(&self) -> Option<ExitKind> {
self.exit_kind.get()
}
#[inline]
pub fn reset_exit_kind(&mut self) {
self.exit_kind.set(None);
}
fn end_of_iter(
&mut self,
shared_state: PushStageSharedState<CS, EM, I, OT, S, Z>,
errored: bool,
) {
self.set_shared_state(shared_state);
self.errored = errored;
self.current_corpus_idx = None;
if errored {
self.initialized = false;
}
}
}
pub trait PushStage<CS, EM, I, OT, S, Z>: Iterator
where
CS: Scheduler<I, S>,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId + ProgressReporter<I>,
I: Input,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasExecutions + HasMetadata,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{
fn push_stage_helper(&self) -> &PushStageHelper<CS, EM, I, OT, S, Z>;
fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<CS, EM, I, OT, S, Z>;
fn set_current_corpus_idx(&mut self, corpus_idx: usize) {
self.push_stage_helper_mut().current_corpus_idx = Some(corpus_idx);
}
#[inline]
fn init(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_event_mgr: &mut EM,
_observers: &mut OT,
) -> Result<(), Error> {
Ok(())
}
fn pre_exec(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_event_mgr: &mut EM,
_observers: &mut OT,
) -> Option<Result<I, Error>>;
#[inline]
fn post_exec(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_event_mgr: &mut EM,
_observers: &mut OT,
_input: I,
_exit_kind: ExitKind,
) -> Result<(), Error> {
Ok(())
}
#[inline]
fn deinit(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_event_mgr: &mut EM,
_observers: &mut OT,
) -> Result<(), Error> {
Ok(())
}
fn next_std(&mut self) -> Option<Result<I, Error>> {
let mut shared_state = {
let shared_state_ref = &mut (*self.push_stage_helper_mut().shared_state).borrow_mut();
shared_state_ref.take().unwrap()
};
let step_success = if self.push_stage_helper().initialized {
let last_input = self.push_stage_helper_mut().current_input.take().unwrap();
self.post_exec(
&mut shared_state.fuzzer,
&mut shared_state.state,
&mut shared_state.event_mgr,
&mut shared_state.observers,
last_input,
self.push_stage_helper().exit_kind().unwrap(),
)
} else {
self.init(
&mut shared_state.fuzzer,
&mut shared_state.state,
&mut shared_state.event_mgr,
&mut shared_state.observers,
)
};
if let Err(err) = step_success {
self.push_stage_helper_mut().end_of_iter(shared_state, true);
return Some(Err(err));
}
let ret = self.pre_exec(
&mut shared_state.fuzzer,
&mut shared_state.state,
&mut shared_state.event_mgr,
&mut shared_state.observers,
);
if ret.is_none() {
drop(self.push_stage_helper_mut().current_input.take());
self.push_stage_helper_mut().initialized = false;
if let Err(err) = self.deinit(
&mut shared_state.fuzzer,
&mut shared_state.state,
&mut shared_state.event_mgr,
&mut shared_state.observers,
) {
self.push_stage_helper_mut().end_of_iter(shared_state, true);
return Some(Err(err));
};
let last_monitor_time = self.push_stage_helper().last_monitor_time;
let new_monitor_time = match shared_state.event_mgr.maybe_report_progress(
&mut shared_state.state,
last_monitor_time,
STATS_TIMEOUT_DEFAULT,
) {
Ok(new_time) => new_time,
Err(err) => {
self.push_stage_helper_mut().end_of_iter(shared_state, true);
return Some(Err(err));
}
};
self.push_stage_helper_mut().last_monitor_time = new_monitor_time;
} else {
self.push_stage_helper_mut().reset_exit_kind();
}
self.push_stage_helper_mut()
.end_of_iter(shared_state, false);
ret
}
}