pub mod mutational;
use alloc::rc::Rc;
use core::{
cell::{Cell, RefCell},
marker::PhantomData,
time::Duration,
};
pub use mutational::StdMutationalPushStage;
use crate::{
corpus::CorpusId,
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
executors::ExitKind,
inputs::UsesInput,
observers::ObserversTuple,
schedulers::Scheduler,
state::{HasCorpus, HasExecutions, HasLastReportTime, HasMetadata, HasRand},
Error, EvaluatorObservers, ExecutionProcessor, HasScheduler,
};
const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15);
#[derive(Clone, Debug)]
pub struct PushStageSharedState<CS, EM, OT, Z>
where
CS: Scheduler,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
OT: ObserversTuple<CS::State>,
CS::State: HasRand + HasCorpus,
Z: ExecutionProcessor<OT, State = CS::State>
+ EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>,
{
pub state: CS::State,
pub fuzzer: Z,
pub event_mgr: EM,
pub observers: OT,
phantom: PhantomData<(CS, Z)>,
}
impl<CS, EM, OT, Z> PushStageSharedState<CS, EM, OT, Z>
where
CS: Scheduler,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
OT: ObserversTuple<CS::State>,
CS::State: HasRand + HasCorpus,
Z: ExecutionProcessor<OT, State = CS::State>
+ EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>,
{
#[must_use]
pub fn new(fuzzer: Z, state: CS::State, observers: OT, event_mgr: EM) -> Self {
Self {
state,
fuzzer,
event_mgr,
observers,
phantom: PhantomData,
}
}
}
#[derive(Clone, Debug)]
pub struct PushStageHelper<CS, EM, OT, Z>
where
CS: Scheduler,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
OT: ObserversTuple<CS::State>,
CS::State: HasRand + HasCorpus,
Z: ExecutionProcessor<OT, State = CS::State>
+ EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>,
{
pub initialized: bool,
#[allow(clippy::type_complexity)]
pub shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, OT, Z>>>>,
pub errored: bool,
pub current_corpus_idx: Option<CorpusId>,
pub current_input: Option<<CS::State as UsesInput>::Input>, #[allow(clippy::type_complexity)]
phantom: PhantomData<(CS, EM, OT, Z)>,
exit_kind: Rc<Cell<Option<ExitKind>>>,
}
impl<CS, EM, OT, Z> PushStageHelper<CS, EM, OT, Z>
where
CS: Scheduler,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
OT: ObserversTuple<CS::State>,
CS::State: HasRand + HasCorpus,
Z: ExecutionProcessor<OT, State = CS::State>
+ EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>,
{
#[must_use]
#[allow(clippy::type_complexity)]
pub fn new(
shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, OT, Z>>>>,
exit_kind_ref: Rc<Cell<Option<ExitKind>>>,
) -> Self {
Self {
shared_state,
initialized: false,
phantom: PhantomData,
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, OT, 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, OT, 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, OT, 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, OT, Z>: Iterator
where
CS: Scheduler,
CS::State: HasRand + HasExecutions + HasMetadata + HasCorpus + HasLastReportTime,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter,
OT: ObserversTuple<CS::State>,
Z: ExecutionProcessor<OT, State = CS::State>
+ EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>,
{
fn push_stage_helper(&self) -> &PushStageHelper<CS, EM, OT, Z>;
fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<CS, EM, OT, Z>;
fn set_current_corpus_idx(&mut self, corpus_idx: CorpusId) {
self.push_stage_helper_mut().current_corpus_idx = Some(corpus_idx);
}
#[inline]
fn init(
&mut self,
_fuzzer: &mut Z,
_state: &mut CS::State,
_event_mgr: &mut EM,
_observers: &mut OT,
) -> Result<(), Error> {
Ok(())
}
fn pre_exec(
&mut self,
_fuzzer: &mut Z,
_state: &mut CS::State,
_event_mgr: &mut EM,
_observers: &mut OT,
) -> Option<Result<<CS::State as UsesInput>::Input, Error>>;
#[inline]
fn post_exec(
&mut self,
_fuzzer: &mut Z,
_state: &mut CS::State,
_event_mgr: &mut EM,
_observers: &mut OT,
_input: <CS::State as UsesInput>::Input,
_exit_kind: ExitKind,
) -> Result<(), Error> {
Ok(())
}
#[inline]
fn deinit(
&mut self,
_fuzzer: &mut Z,
_state: &mut CS::State,
_event_mgr: &mut EM,
_observers: &mut OT,
) -> Result<(), Error> {
Ok(())
}
fn next_std(&mut self) -> Option<Result<<CS::State as UsesInput>::Input, 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));
};
if let Err(err) = shared_state
.event_mgr
.maybe_report_progress(&mut shared_state.state, STATS_TIMEOUT_DEFAULT)
{
self.push_stage_helper_mut().end_of_iter(shared_state, true);
return Some(Err(err));
};
} else {
self.push_stage_helper_mut().reset_exit_kind();
}
self.push_stage_helper_mut()
.end_of_iter(shared_state, false);
ret
}
}