use core::marker::PhantomData;
use crate::{
bolts::rands::Rand,
corpus::Corpus,
fuzzer::Evaluator,
inputs::Input,
mark_feature_time,
mutators::Mutator,
stages::Stage,
start_timer,
state::{HasClientPerfStats, HasCorpus, HasRand},
Error,
};
#[cfg(feature = "introspection")]
use crate::stats::PerfFeature;
pub trait MutationalStage<C, E, EM, I, M, S, Z>: Stage<E, EM, S, Z>
where
C: Corpus<I>,
M: Mutator<I, S>,
I: Input,
S: HasClientPerfStats + HasCorpus<C, I>,
Z: Evaluator<E, EM, I, S>,
{
fn mutator(&self) -> &M;
fn mutator_mut(&mut self) -> &mut M;
fn iterations(&self, state: &mut S, corpus_idx: usize) -> Result<usize, Error>;
#[allow(clippy::cast_possible_wrap)] fn perform_mutational(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut S,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), Error> {
let num = self.iterations(state, corpus_idx)?;
for i in 0..num {
start_timer!(state);
let mut input = state
.corpus()
.get(corpus_idx)?
.borrow_mut()
.load_input()?
.clone();
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
start_timer!(state);
self.mutator_mut().mutate(state, &mut input, i as i32)?;
mark_feature_time!(state, PerfFeature::Mutate);
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, input)?;
start_timer!(state);
self.mutator_mut().post_exec(state, i as i32, corpus_idx)?;
mark_feature_time!(state, PerfFeature::MutatePostExec);
}
Ok(())
}
}
pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128;
#[derive(Clone, Debug)]
pub struct StdMutationalStage<C, E, EM, I, M, R, S, Z>
where
C: Corpus<I>,
M: Mutator<I, S>,
I: Input,
R: Rand,
S: HasClientPerfStats + HasCorpus<C, I> + HasRand<R>,
Z: Evaluator<E, EM, I, S>,
{
mutator: M,
#[allow(clippy::type_complexity)]
phantom: PhantomData<(C, E, EM, I, R, S, Z)>,
}
impl<C, E, EM, I, M, R, S, Z> MutationalStage<C, E, EM, I, M, S, Z>
for StdMutationalStage<C, E, EM, I, M, R, S, Z>
where
C: Corpus<I>,
M: Mutator<I, S>,
I: Input,
R: Rand,
S: HasClientPerfStats + HasCorpus<C, I> + HasRand<R>,
Z: Evaluator<E, EM, I, S>,
{
#[inline]
fn mutator(&self) -> &M {
&self.mutator
}
#[inline]
fn mutator_mut(&mut self) -> &mut M {
&mut self.mutator
}
fn iterations(&self, state: &mut S, _corpus_idx: usize) -> Result<usize, Error> {
Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize)
}
}
impl<C, E, EM, I, M, R, S, Z> Stage<E, EM, S, Z> for StdMutationalStage<C, E, EM, I, M, R, S, Z>
where
C: Corpus<I>,
M: Mutator<I, S>,
I: Input,
R: Rand,
S: HasClientPerfStats + HasCorpus<C, I> + HasRand<R>,
Z: Evaluator<E, EM, I, S>,
{
#[inline]
#[allow(clippy::let_and_return)]
fn perform(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut S,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), Error> {
let ret = self.perform_mutational(fuzzer, executor, state, manager, corpus_idx);
#[cfg(feature = "introspection")]
state.introspection_stats_mut().finish_stage();
ret
}
}
impl<C, E, EM, I, M, R, S, Z> StdMutationalStage<C, E, EM, I, M, R, S, Z>
where
C: Corpus<I>,
M: Mutator<I, S>,
I: Input,
R: Rand,
S: HasClientPerfStats + HasCorpus<C, I> + HasRand<R>,
Z: Evaluator<E, EM, I, S>,
{
pub fn new(mutator: M) -> Self {
Self {
mutator,
phantom: PhantomData,
}
}
}