use core::marker::PhantomData;
#[cfg(feature = "introspection")]
use crate::monitors::PerfFeature;
use crate::{
bolts::rands::Rand,
corpus::{Corpus, CorpusId, Testcase},
fuzzer::Evaluator,
inputs::Input,
mark_feature_time,
mutators::Mutator,
stages::Stage,
start_timer,
state::{HasClientPerfMonitor, HasCorpus, HasRand, UsesState},
Error,
};
#[allow(unused_variables)]
pub trait MutatedTransformPost<S>: Sized {
#[inline]
fn post_exec(
self,
state: &mut S,
stage_idx: i32,
corpus_idx: Option<CorpusId>,
) -> Result<(), Error> {
Ok(())
}
}
impl<S> MutatedTransformPost<S> for () {}
pub trait MutatedTransform<I, S>: Sized
where
I: Input,
{
type Post: MutatedTransformPost<S>;
fn try_transform_from(
base: &Testcase<I>,
state: &S,
corpus_idx: CorpusId,
) -> Result<Self, Error>;
fn try_transform_into(self, state: &S) -> Result<(I, Self::Post), Error>;
}
impl<I, S> MutatedTransform<I, S> for I
where
I: Input + Clone,
{
type Post = ();
#[inline]
fn try_transform_from(
base: &Testcase<I>,
_state: &S,
_corpus_idx: CorpusId,
) -> Result<Self, Error> {
Ok(base.input().as_ref().unwrap().clone())
}
#[inline]
fn try_transform_into(self, _state: &S) -> Result<(I, Self::Post), Error> {
Ok((self, ()))
}
}
pub trait MutationalStage<E, EM, I, M, Z>: Stage<E, EM, Z>
where
E: UsesState<State = Self::State>,
M: Mutator<I, Self::State>,
EM: UsesState<State = Self::State>,
Z: Evaluator<E, EM, State = Self::State>,
Self::State: HasClientPerfMonitor + HasCorpus,
I: MutatedTransform<Self::Input, Self::State> + Clone,
{
fn mutator(&self) -> &M;
fn mutator_mut(&mut self) -> &mut M;
fn iterations(&self, state: &mut Z::State, corpus_idx: CorpusId) -> Result<u64, Error>;
#[allow(clippy::cast_possible_wrap)] fn perform_mutational(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut Z::State,
manager: &mut EM,
corpus_idx: CorpusId,
) -> Result<(), Error> {
let num = self.iterations(state, corpus_idx)?;
start_timer!(state);
let testcase = state.corpus().get(corpus_idx)?.borrow();
let Ok(input) = I::try_transform_from(&testcase, state, corpus_idx) else { return Ok(()); };
drop(testcase);
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
for i in 0..num {
let mut input = input.clone();
start_timer!(state);
self.mutator_mut().mutate(state, &mut input, i as i32)?;
mark_feature_time!(state, PerfFeature::Mutate);
let (untransformed, post) = input.try_transform_into(state)?;
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, untransformed)?;
start_timer!(state);
self.mutator_mut().post_exec(state, i as i32, corpus_idx)?;
post.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<E, EM, I, M, Z> {
mutator: M,
#[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, I, Z)>,
}
impl<E, EM, I, M, Z> MutationalStage<E, EM, I, M, Z> for StdMutationalStage<E, EM, I, M, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
I: MutatedTransform<Self::Input, Self::State> + Clone,
{
#[inline]
fn mutator(&self) -> &M {
&self.mutator
}
#[inline]
fn mutator_mut(&mut self) -> &mut M {
&mut self.mutator
}
fn iterations(&self, state: &mut Z::State, _corpus_idx: CorpusId) -> Result<u64, Error> {
Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS))
}
}
impl<E, EM, I, M, Z> UsesState for StdMutationalStage<E, EM, I, M, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
{
type State = Z::State;
}
impl<E, EM, I, M, Z> Stage<E, EM, Z> for StdMutationalStage<E, EM, I, M, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
I: MutatedTransform<Self::Input, Self::State> + Clone,
{
#[inline]
#[allow(clippy::let_and_return)]
fn perform(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut Z::State,
manager: &mut EM,
corpus_idx: CorpusId,
) -> Result<(), Error> {
let ret = self.perform_mutational(fuzzer, executor, state, manager, corpus_idx);
#[cfg(feature = "introspection")]
state.introspection_monitor_mut().finish_stage();
ret
}
}
impl<E, EM, M, Z> StdMutationalStage<E, EM, Z::Input, M, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
M: Mutator<Z::Input, Z::State>,
Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
{
pub fn new(mutator: M) -> Self {
Self::transforming(mutator)
}
}
impl<E, EM, I, M, Z> StdMutationalStage<E, EM, I, M, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
{
pub fn transforming(mutator: M) -> Self {
Self {
mutator,
phantom: PhantomData,
}
}
}
#[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind {
use pyo3::prelude::*;
use crate::{
events::pybind::PythonEventManager,
executors::pybind::PythonExecutor,
fuzzer::pybind::PythonStdFuzzer,
inputs::BytesInput,
mutators::pybind::PythonMutator,
stages::{pybind::PythonStage, StdMutationalStage},
};
#[pyclass(unsendable, name = "StdMutationalStage")]
#[derive(Debug)]
pub struct PythonStdMutationalStage {
pub inner: StdMutationalStage<
PythonExecutor,
PythonEventManager,
BytesInput,
PythonMutator,
PythonStdFuzzer,
>,
}
#[pymethods]
impl PythonStdMutationalStage {
#[new]
fn new(mutator: PythonMutator) -> Self {
Self {
inner: StdMutationalStage::new(mutator),
}
}
fn as_stage(slf: Py<Self>) -> PythonStage {
PythonStage::new_std_mutational(slf)
}
}
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStdMutationalStage>()?;
Ok(())
}
}