No Use* from stages (#2745)
* no from stage * fixer * doc fix * how was this working???? * more fixes * delete more * rq * cargo-fuzz * m * aa
This commit is contained in:
parent
c176fee1e0
commit
3446ad974c
@ -132,7 +132,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
// Setup a lain mutator with a mutational stage
|
// Setup a lain mutator with a mutational stage
|
||||||
let mutator = LainMutator::new();
|
let mutator = LainMutator::new();
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, PacketData, _, _> =
|
let power: StdPowerMutationalStage<_, _, PacketData, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
let mut stages = tuple_list!(calibration, power);
|
let mut stages = tuple_list!(calibration, power);
|
||||||
|
@ -314,7 +314,7 @@ fn fuzz(
|
|||||||
5,
|
5,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
@ -317,7 +317,7 @@ fn fuzz(
|
|||||||
5,
|
5,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use std::{fs, marker::PhantomData, ops::Range, process, time::Duration};
|
use std::{fs, marker::PhantomData, ops::Range, path::PathBuf, process};
|
||||||
|
|
||||||
#[cfg(feature = "simplemgr")]
|
#[cfg(feature = "simplemgr")]
|
||||||
use libafl::events::SimpleEventManager;
|
use libafl::events::SimpleEventManager;
|
||||||
@ -23,8 +23,8 @@ use libafl::{
|
|||||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler,
|
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler,
|
||||||
},
|
},
|
||||||
stages::{
|
stages::{
|
||||||
calibrate::CalibrationStage, power::StdPowerMutationalStage, IfStage, ShadowTracingStage,
|
calibrate::CalibrationStage, power::StdPowerMutationalStage, AflStatsStage, IfStage,
|
||||||
StagesTuple, StatsStage, StdMutationalStage,
|
ShadowTracingStage, StagesTuple, StdMutationalStage,
|
||||||
},
|
},
|
||||||
state::{HasCorpus, StdState, UsesState},
|
state::{HasCorpus, StdState, UsesState},
|
||||||
Error, HasMetadata, NopFuzzer,
|
Error, HasMetadata, NopFuzzer,
|
||||||
@ -137,7 +137,10 @@ impl<M: Monitor> Instance<'_, M> {
|
|||||||
|
|
||||||
let stats_stage = IfStage::new(
|
let stats_stage = IfStage::new(
|
||||||
|_, _, _, _| Ok(self.options.tui),
|
|_, _, _, _| Ok(self.options.tui),
|
||||||
tuple_list!(StatsStage::new(Duration::from_secs(5))),
|
tuple_list!(AflStatsStage::builder()
|
||||||
|
.map_observer(&edges_observer)
|
||||||
|
.stats_file(PathBuf::from("stats.txt"))
|
||||||
|
.build()?),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Feedback to rate the interestingness of an input
|
// Feedback to rate the interestingness of an input
|
||||||
@ -274,7 +277,7 @@ impl<M: Monitor> Instance<'_, M> {
|
|||||||
5,
|
5,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
// The order of the stages matter!
|
// The order of the stages matter!
|
||||||
|
@ -298,7 +298,7 @@ fn fuzz(
|
|||||||
5,
|
5,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
@ -300,7 +300,7 @@ fn fuzz(
|
|||||||
5,
|
5,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
@ -371,7 +371,8 @@ fn fuzz(
|
|||||||
let tracing = AFLppCmplogTracingStage::new(cmplog_executor, cmplog_ref);
|
let tracing = AFLppCmplogTracingStage::new(cmplog_executor, cmplog_ref);
|
||||||
|
|
||||||
// Setup a randomic Input2State stage
|
// Setup a randomic Input2State stage
|
||||||
let rq = MultiMutationalStage::new(AFLppRedQueen::with_cmplog_options(true, true));
|
let rq: MultiMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
|
MultiMutationalStage::new(AFLppRedQueen::with_cmplog_options(true, true));
|
||||||
|
|
||||||
let cb = |_fuzzer: &mut _,
|
let cb = |_fuzzer: &mut _,
|
||||||
_executor: &mut _,
|
_executor: &mut _,
|
||||||
|
@ -266,7 +266,7 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, {
|
|||||||
SupportedMutationalStages::StdMutational(StdMutationalStage::new(mutation), PhantomData)
|
SupportedMutationalStages::StdMutational(StdMutationalStage::new(mutation), PhantomData)
|
||||||
} else {
|
} else {
|
||||||
SupportedMutationalStages::PowerMutational(
|
SupportedMutationalStages::PowerMutational(
|
||||||
StdPowerMutationalStage::new(mutation),
|
StdPowerMutationalStage::<_, _, BytesInput, _, _, _>::new(mutation),
|
||||||
PhantomData,
|
PhantomData,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@ -487,7 +487,9 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, {
|
|||||||
let tracing = AFLppCmplogTracingStage::new(cmplog_executor, cmplog_ref);
|
let tracing = AFLppCmplogTracingStage::new(cmplog_executor, cmplog_ref);
|
||||||
|
|
||||||
// Create a randomic Input2State stage
|
// Create a randomic Input2State stage
|
||||||
let rq = MultiMutationalStage::new(AFLppRedQueen::with_cmplog_options(true, true));
|
let rq = MultiMutationalStage::<_, _, BytesInput, _, _, _>::new(
|
||||||
|
AFLppRedQueen::with_cmplog_options(true, true),
|
||||||
|
);
|
||||||
|
|
||||||
// Create an IfStage and wrap the CmpLog stages in it.
|
// Create an IfStage and wrap the CmpLog stages in it.
|
||||||
// We run cmplog on the second fuzz run of the testcase.
|
// We run cmplog on the second fuzz run of the testcase.
|
||||||
|
@ -1,37 +1,25 @@
|
|||||||
use std::{borrow::Cow, marker::PhantomData};
|
use std::{borrow::Cow, marker::PhantomData};
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::Corpus,
|
stages::{MutationalStage, Stage},
|
||||||
inputs::Input,
|
Error,
|
||||||
mutators::Mutator,
|
|
||||||
stages::{mutational::MutatedTransform, MutationalStage, Stage},
|
|
||||||
state::{HasCorpus, HasRand, State, UsesState},
|
|
||||||
Error, Evaluator, HasNamedMetadata,
|
|
||||||
};
|
};
|
||||||
use libafl_bolts::Named;
|
use libafl_bolts::Named;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SupportedMutationalStages<S, SM, P, E, EM, M, I, Z> {
|
pub enum SupportedMutationalStages<SM, P> {
|
||||||
StdMutational(SM, PhantomData<(S, I, M, EM, Z, E)>),
|
StdMutational(SM, PhantomData<P>),
|
||||||
PowerMutational(P, PhantomData<(S, I, M, EM, Z, E)>),
|
PowerMutational(P, PhantomData<SM>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, SM, P, E, EM, M, I, Z> MutationalStage<E, EM, I, M, Z>
|
impl<S, SM, P> MutationalStage<S> for SupportedMutationalStages<SM, P>
|
||||||
for SupportedMutationalStages<S, SM, P, E, EM, M, I, Z>
|
|
||||||
where
|
where
|
||||||
E: UsesState<State = S>,
|
SM: MutationalStage<S>,
|
||||||
EM: UsesState<State = S>,
|
P: MutationalStage<S, Mutator = SM::Mutator>,
|
||||||
M: Mutator<I, S>,
|
|
||||||
Z: Evaluator<E, EM, State = S>,
|
|
||||||
I: MutatedTransform<S::Input, S> + Clone + Input,
|
|
||||||
SM: MutationalStage<E, EM, I, M, Z, State = S>,
|
|
||||||
P: MutationalStage<E, EM, I, M, Z, State = S>,
|
|
||||||
S: State<Input = I> + HasRand + HasCorpus + HasNamedMetadata,
|
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, //delete me
|
|
||||||
{
|
{
|
||||||
|
type Mutator = SM::Mutator;
|
||||||
/// The mutator, added to this stage
|
/// The mutator, added to this stage
|
||||||
#[inline]
|
fn mutator(&self) -> &Self::Mutator {
|
||||||
fn mutator(&self) -> &M {
|
|
||||||
match self {
|
match self {
|
||||||
Self::StdMutational(m, _) => m.mutator(),
|
Self::StdMutational(m, _) => m.mutator(),
|
||||||
Self::PowerMutational(p, _) => p.mutator(),
|
Self::PowerMutational(p, _) => p.mutator(),
|
||||||
@ -40,7 +28,7 @@ where
|
|||||||
|
|
||||||
/// The list of mutators, added to this stage (as mutable ref)
|
/// The list of mutators, added to this stage (as mutable ref)
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mutator_mut(&mut self) -> &mut M {
|
fn mutator_mut(&mut self) -> &mut Self::Mutator {
|
||||||
match self {
|
match self {
|
||||||
Self::StdMutational(m, _) => m.mutator_mut(),
|
Self::StdMutational(m, _) => m.mutator_mut(),
|
||||||
Self::PowerMutational(p, _) => p.mutator_mut(),
|
Self::PowerMutational(p, _) => p.mutator_mut(),
|
||||||
@ -56,14 +44,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, SM, P, E, EM, M, I, Z> UsesState for SupportedMutationalStages<S, SM, P, E, EM, M, I, Z>
|
impl<SM, P> Named for SupportedMutationalStages<SM, P>
|
||||||
where
|
|
||||||
S: State + HasRand,
|
|
||||||
{
|
|
||||||
type State = S;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S, SM, P, E, EM, M, I, Z> Named for SupportedMutationalStages<S, SM, P, E, EM, M, I, Z>
|
|
||||||
where
|
where
|
||||||
SM: Named,
|
SM: Named,
|
||||||
P: Named,
|
P: Named,
|
||||||
@ -76,18 +57,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, SM, P, E, EM, M, I, Z> Stage<E, EM, Z>
|
impl<E, EM, S, SM, P, Z> Stage<E, EM, S, Z> for SupportedMutationalStages<SM, P>
|
||||||
for SupportedMutationalStages<S, SM, P, E, EM, M, I, Z>
|
|
||||||
where
|
where
|
||||||
E: UsesState<State = S>,
|
SM: Stage<E, EM, S, Z>,
|
||||||
EM: UsesState<State = S>,
|
P: Stage<E, EM, S, Z>,
|
||||||
M: Mutator<I, S>,
|
|
||||||
Z: Evaluator<E, EM, State = S>,
|
|
||||||
I: MutatedTransform<S::Input, S> + Clone + Input,
|
|
||||||
SM: MutationalStage<E, EM, I, M, Z, State = S>,
|
|
||||||
P: MutationalStage<E, EM, I, M, Z, State = S>,
|
|
||||||
S: State<Input = I> + HasRand + HasCorpus + HasNamedMetadata,
|
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, //delete me
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(clippy::let_and_return)]
|
#[allow(clippy::let_and_return)]
|
||||||
|
@ -314,7 +314,7 @@ fn fuzz(
|
|||||||
5,
|
5,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
@ -307,7 +307,7 @@ fn fuzz(
|
|||||||
5,
|
5,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
@ -317,7 +317,7 @@ fn fuzz(
|
|||||||
5,
|
5,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
@ -374,7 +374,7 @@ fn fuzz_binary(
|
|||||||
5,
|
5,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
@ -589,7 +589,7 @@ fn fuzz_text(
|
|||||||
5,
|
5,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
let grimoire_mutator = StdScheduledMutator::with_max_stack_pow(
|
let grimoire_mutator = StdScheduledMutator::with_max_stack_pow(
|
||||||
|
@ -143,7 +143,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
|
|
||||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
let mut stages = tuple_list!(calibration, power);
|
let mut stages = tuple_list!(calibration, power);
|
||||||
|
@ -140,7 +140,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
|
|
||||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
let mut stages = tuple_list!(calibration, power);
|
let mut stages = tuple_list!(calibration, power);
|
||||||
|
@ -141,7 +141,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
|
|
||||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
let mut stages = tuple_list!(calibration, power);
|
let mut stages = tuple_list!(calibration, power);
|
||||||
|
@ -110,7 +110,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
|
|
||||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||||
|
|
||||||
let power: StdPowerMutationalStage<_, _, BytesInput, _, _> =
|
let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> =
|
||||||
StdPowerMutationalStage::new(mutator);
|
StdPowerMutationalStage::new(mutator);
|
||||||
|
|
||||||
let mut stages = tuple_list!(calibration, power);
|
let mut stages = tuple_list!(calibration, power);
|
||||||
|
@ -28,6 +28,7 @@ rustc-args = ["--cfg", "docsrs"]
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [
|
default = [
|
||||||
|
"introspection",
|
||||||
"std",
|
"std",
|
||||||
"derive",
|
"derive",
|
||||||
"llmp_compression",
|
"llmp_compression",
|
||||||
|
@ -27,7 +27,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Send a monitor update all 15 (or more) seconds
|
/// Send a monitor update all 15 (or more) seconds
|
||||||
const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15);
|
pub(crate) const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15);
|
||||||
|
|
||||||
/// Holds a scheduler
|
/// Holds a scheduler
|
||||||
pub trait HasScheduler: UsesState
|
pub trait HasScheduler: UsesState
|
||||||
|
@ -26,11 +26,12 @@ use crate::{
|
|||||||
corpus::{Corpus, HasCurrentCorpusId, SchedulerTestcaseMetadata, Testcase},
|
corpus::{Corpus, HasCurrentCorpusId, SchedulerTestcaseMetadata, Testcase},
|
||||||
events::EventFirer,
|
events::EventFirer,
|
||||||
executors::HasObservers,
|
executors::HasObservers,
|
||||||
|
inputs::UsesInput,
|
||||||
mutators::Tokens,
|
mutators::Tokens,
|
||||||
observers::MapObserver,
|
observers::MapObserver,
|
||||||
schedulers::{minimizer::IsFavoredMetadata, HasQueueCycles},
|
schedulers::{minimizer::IsFavoredMetadata, HasQueueCycles},
|
||||||
stages::{calibrate::UnstableEntriesMetadata, Stage},
|
stages::{calibrate::UnstableEntriesMetadata, Stage},
|
||||||
state::{HasCorpus, HasExecutions, HasImported, HasStartTime, Stoppable, UsesState},
|
state::{HasCorpus, HasExecutions, HasImported, HasStartTime, Stoppable},
|
||||||
std::string::ToString,
|
std::string::ToString,
|
||||||
Error, HasMetadata, HasNamedMetadata, HasScheduler,
|
Error, HasMetadata, HasNamedMetadata, HasScheduler,
|
||||||
};
|
};
|
||||||
@ -73,7 +74,7 @@ libafl_bolts::impl_serdeany!(FuzzTime);
|
|||||||
/// The [`AflStatsStage`] is a Stage that calculates and writes
|
/// The [`AflStatsStage`] is a Stage that calculates and writes
|
||||||
/// AFL++'s `fuzzer_stats` and `plot_data` information.
|
/// AFL++'s `fuzzer_stats` and `plot_data` information.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AflStatsStage<C, E, EM, O, Z> {
|
pub struct AflStatsStage<C, E, EM, O, S, Z> {
|
||||||
map_observer_handle: Handle<C>,
|
map_observer_handle: Handle<C>,
|
||||||
stats_file_path: PathBuf,
|
stats_file_path: PathBuf,
|
||||||
plot_file_path: Option<PathBuf>,
|
plot_file_path: Option<PathBuf>,
|
||||||
@ -112,7 +113,7 @@ pub struct AflStatsStage<C, E, EM, O, Z> {
|
|||||||
autotokens_enabled: bool,
|
autotokens_enabled: bool,
|
||||||
/// The core we are bound to
|
/// The core we are bound to
|
||||||
core_id: CoreId,
|
core_id: CoreId,
|
||||||
phantom_data: PhantomData<(O, E, EM, Z)>,
|
phantom_data: PhantomData<(O, E, EM, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AFL++'s `fuzzer_stats`
|
/// AFL++'s `fuzzer_stats`
|
||||||
@ -234,39 +235,31 @@ pub struct AFLPlotData<'a> {
|
|||||||
edges_found: &'a u64,
|
edges_found: &'a u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, E, EM, O, Z> UsesState for AflStatsStage<C, E, EM, O, Z>
|
impl<C, E, EM, O, S, Z> Stage<E, EM, S, Z> for AflStatsStage<C, E, EM, O, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState,
|
E: HasObservers,
|
||||||
EM: EventFirer<State = E::State>,
|
EM: EventFirer,
|
||||||
Z: UsesState<State = E::State>,
|
Z: HasScheduler<State = S>,
|
||||||
{
|
S: HasImported
|
||||||
type State = E::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C, E, EM, O, Z> Stage<E, EM, Z> for AflStatsStage<C, E, EM, O, Z>
|
|
||||||
where
|
|
||||||
E: UsesState + HasObservers,
|
|
||||||
EM: EventFirer<State = E::State>,
|
|
||||||
Z: UsesState<State = E::State> + HasScheduler,
|
|
||||||
E::State: HasImported
|
|
||||||
+ HasCorpus
|
+ HasCorpus
|
||||||
+ HasMetadata
|
+ HasMetadata
|
||||||
+ HasStartTime
|
+ HasStartTime
|
||||||
+ HasExecutions
|
+ HasExecutions
|
||||||
+ HasNamedMetadata
|
+ HasNamedMetadata
|
||||||
+ Stoppable,
|
+ Stoppable
|
||||||
|
+ HasCurrentCorpusId
|
||||||
|
+ UsesInput,
|
||||||
E::Observers: MatchNameRef,
|
E::Observers: MatchNameRef,
|
||||||
O: MapObserver,
|
O: MapObserver,
|
||||||
C: AsRef<O> + Named,
|
C: AsRef<O> + Named,
|
||||||
<Z as HasScheduler>::Scheduler: HasQueueCycles,
|
<Z as HasScheduler>::Scheduler: HasQueueCycles,
|
||||||
<<E as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = E::Input>,
|
|
||||||
{
|
{
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut E::State,
|
state: &mut S,
|
||||||
_manager: &mut EM,
|
_manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let Some(corpus_idx) = state.current_corpus_id()? else {
|
let Some(corpus_idx) = state.current_corpus_id()? else {
|
||||||
@ -413,27 +406,26 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, _state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, _state: &mut S) -> Result<bool, Error> {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, E, EM, O, Z> AflStatsStage<C, E, EM, O, Z>
|
impl<C, E, EM, O, S, Z> AflStatsStage<C, E, EM, O, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState + HasObservers,
|
E: HasObservers,
|
||||||
EM: EventFirer<State = E::State>,
|
EM: EventFirer,
|
||||||
Z: UsesState<State = E::State>,
|
S: HasImported + HasCorpus + HasMetadata + HasExecutions,
|
||||||
E::State: HasImported + HasCorpus + HasMetadata + HasExecutions,
|
|
||||||
C: AsRef<O> + Named,
|
C: AsRef<O> + Named,
|
||||||
O: MapObserver,
|
O: MapObserver,
|
||||||
{
|
{
|
||||||
/// Builder for `AflStatsStage`
|
/// Builder for `AflStatsStage`
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn builder() -> AflStatsStageBuilder<C, E, EM, O, Z> {
|
pub fn builder() -> AflStatsStageBuilder<C, E, EM, O, S, Z> {
|
||||||
AflStatsStageBuilder::new()
|
AflStatsStageBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,13 +451,13 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_update_is_favored_size(&mut self, testcase: &Testcase<E::Input>) {
|
fn maybe_update_is_favored_size(&mut self, testcase: &Testcase<<S::Corpus as Corpus>::Input>) {
|
||||||
if testcase.has_metadata::<IsFavoredMetadata>() {
|
if testcase.has_metadata::<IsFavoredMetadata>() {
|
||||||
self.is_favored_size += 1;
|
self.is_favored_size += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_update_slowest_exec(&mut self, testcase: &Testcase<E::Input>) {
|
fn maybe_update_slowest_exec(&mut self, testcase: &Testcase<<S::Corpus as Corpus>::Input>) {
|
||||||
if let Some(exec_time) = testcase.exec_time() {
|
if let Some(exec_time) = testcase.exec_time() {
|
||||||
if exec_time > &self.slowest_exec {
|
if exec_time > &self.slowest_exec {
|
||||||
self.slowest_exec = *exec_time;
|
self.slowest_exec = *exec_time;
|
||||||
@ -477,7 +469,7 @@ where
|
|||||||
self.has_fuzzed_size += 1;
|
self.has_fuzzed_size += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_update_max_depth(&mut self, testcase: &Testcase<E::Input>) {
|
fn maybe_update_max_depth(&mut self, testcase: &Testcase<<S::Corpus as Corpus>::Input>) {
|
||||||
if let Ok(metadata) = testcase.metadata::<SchedulerTestcaseMetadata>() {
|
if let Ok(metadata) = testcase.metadata::<SchedulerTestcaseMetadata>() {
|
||||||
if metadata.depth() > self.max_depth {
|
if metadata.depth() > self.max_depth {
|
||||||
self.max_depth = metadata.depth();
|
self.max_depth = metadata.depth();
|
||||||
@ -490,7 +482,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "track_hit_feedbacks")]
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
fn maybe_update_last_crash(&mut self, testcase: &Testcase<E::Input>, state: &E::State) {
|
fn maybe_update_last_crash(
|
||||||
|
&mut self,
|
||||||
|
testcase: &Testcase<<S::Corpus as Corpus>::Input>,
|
||||||
|
state: &S,
|
||||||
|
) {
|
||||||
#[cfg(feature = "track_hit_feedbacks")]
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
if testcase
|
if testcase
|
||||||
.hit_objectives()
|
.hit_objectives()
|
||||||
@ -502,7 +498,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "track_hit_feedbacks")]
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
fn maybe_update_last_hang(&mut self, testcase: &Testcase<E::Input>, state: &E::State) {
|
fn maybe_update_last_hang(
|
||||||
|
&mut self,
|
||||||
|
testcase: &Testcase<<S::Corpus as Corpus>::Input>,
|
||||||
|
state: &S,
|
||||||
|
) {
|
||||||
if testcase
|
if testcase
|
||||||
.hit_objectives()
|
.hit_objectives()
|
||||||
.contains(&Cow::Borrowed(TIMEOUT_FEEDBACK_NAME))
|
.contains(&Cow::Borrowed(TIMEOUT_FEEDBACK_NAME))
|
||||||
@ -624,7 +624,7 @@ pub fn get_run_cmdline() -> Cow<'static, str> {
|
|||||||
|
|
||||||
/// The Builder for `AflStatsStage`
|
/// The Builder for `AflStatsStage`
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AflStatsStageBuilder<C, E, EM, O, Z> {
|
pub struct AflStatsStageBuilder<C, E, EM, O, S, Z> {
|
||||||
stats_file_path: Option<PathBuf>,
|
stats_file_path: Option<PathBuf>,
|
||||||
plot_file_path: Option<PathBuf>,
|
plot_file_path: Option<PathBuf>,
|
||||||
core_id: Option<CoreId>,
|
core_id: Option<CoreId>,
|
||||||
@ -636,15 +636,14 @@ pub struct AflStatsStageBuilder<C, E, EM, O, Z> {
|
|||||||
banner: String,
|
banner: String,
|
||||||
version: String,
|
version: String,
|
||||||
target_mode: String,
|
target_mode: String,
|
||||||
phantom_data: PhantomData<(O, E, EM, Z)>,
|
phantom_data: PhantomData<(O, E, EM, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, E, EM, O, Z> AflStatsStageBuilder<C, E, EM, O, Z>
|
impl<C, E, EM, O, S, Z> AflStatsStageBuilder<C, E, EM, O, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState + HasObservers,
|
E: HasObservers,
|
||||||
EM: EventFirer<State = E::State>,
|
EM: EventFirer,
|
||||||
Z: UsesState<State = E::State>,
|
S: HasImported + HasCorpus + HasMetadata + HasExecutions,
|
||||||
E::State: HasImported + HasCorpus + HasMetadata + HasExecutions,
|
|
||||||
C: AsRef<O> + Named,
|
C: AsRef<O> + Named,
|
||||||
O: MapObserver,
|
O: MapObserver,
|
||||||
{
|
{
|
||||||
@ -758,7 +757,7 @@ where
|
|||||||
/// Cannot create the plot file (if provided)
|
/// Cannot create the plot file (if provided)
|
||||||
/// No `MapObserver` supplied to the builder
|
/// No `MapObserver` supplied to the builder
|
||||||
/// No `stats_file_path` provieded
|
/// No `stats_file_path` provieded
|
||||||
pub fn build(self) -> Result<AflStatsStage<C, E, EM, O, Z>, Error> {
|
pub fn build(self) -> Result<AflStatsStage<C, E, EM, O, S, Z>, Error> {
|
||||||
if self.stats_file_path.is_none() {
|
if self.stats_file_path.is_none() {
|
||||||
return Err(Error::illegal_argument("Must set `stats_file_path`"));
|
return Err(Error::illegal_argument("Must set `stats_file_path`"));
|
||||||
}
|
}
|
||||||
|
@ -13,17 +13,17 @@ use num_traits::Bounded;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, SchedulerTestcaseMetadata},
|
corpus::{Corpus, HasCurrentCorpusId, SchedulerTestcaseMetadata},
|
||||||
events::{Event, EventFirer, LogSeverity},
|
events::{Event, EventFirer, LogSeverity},
|
||||||
executors::{Executor, ExitKind, HasObservers},
|
executors::{Executor, ExitKind, HasObservers},
|
||||||
feedbacks::{map::MapFeedbackMetadata, HasObserverHandle},
|
feedbacks::{map::MapFeedbackMetadata, HasObserverHandle},
|
||||||
fuzzer::Evaluator,
|
fuzzer::Evaluator,
|
||||||
inputs::UsesInput,
|
inputs::{Input, UsesInput},
|
||||||
monitors::{AggregatorOps, UserStats, UserStatsValue},
|
monitors::{AggregatorOps, UserStats, UserStatsValue},
|
||||||
observers::{MapObserver, ObserversTuple},
|
observers::{MapObserver, ObserversTuple},
|
||||||
schedulers::powersched::SchedulerMetadata,
|
schedulers::powersched::SchedulerMetadata,
|
||||||
stages::{RetryCountRestartHelper, Stage},
|
stages::{RetryCountRestartHelper, Stage},
|
||||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, UsesState},
|
state::{HasCorpus, HasCurrentTestcase, HasExecutions},
|
||||||
Error, HasMetadata, HasNamedMetadata,
|
Error, HasMetadata, HasNamedMetadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,38 +73,37 @@ impl Default for UnstableEntriesMetadata {
|
|||||||
pub const CALIBRATION_STAGE_NAME: &str = "calibration";
|
pub const CALIBRATION_STAGE_NAME: &str = "calibration";
|
||||||
/// The calibration stage will measure the average exec time and the target's stability for this input.
|
/// The calibration stage will measure the average exec time and the target's stability for this input.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct CalibrationStage<C, E, O, OT> {
|
pub struct CalibrationStage<C, E, O, OT, S> {
|
||||||
map_observer_handle: Handle<C>,
|
map_observer_handle: Handle<C>,
|
||||||
map_name: Cow<'static, str>,
|
map_name: Cow<'static, str>,
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
stage_max: usize,
|
stage_max: usize,
|
||||||
/// If we should track stability
|
/// If we should track stability
|
||||||
track_stability: bool,
|
track_stability: bool,
|
||||||
phantom: PhantomData<(E, O, OT)>,
|
phantom: PhantomData<(E, O, OT, S)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1
|
const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1
|
||||||
const CAL_STAGE_MAX: usize = 8; // AFL++'s CAL_CYCLES + 1
|
const CAL_STAGE_MAX: usize = 8; // AFL++'s CAL_CYCLES + 1
|
||||||
|
|
||||||
impl<C, E, O, OT> UsesState for CalibrationStage<C, E, O, OT>
|
impl<C, E, EM, O, OT, S, Z> Stage<E, EM, S, Z> for CalibrationStage<C, E, O, OT, S>
|
||||||
where
|
where
|
||||||
E: UsesState,
|
E: Executor<EM, Z, State = S> + HasObservers<Observers = OT>,
|
||||||
{
|
EM: EventFirer<State = S>,
|
||||||
type State = E::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C, E, EM, O, OT, Z> Stage<E, EM, Z> for CalibrationStage<C, E, O, OT>
|
|
||||||
where
|
|
||||||
E: Executor<EM, Z> + HasObservers<Observers = OT>,
|
|
||||||
EM: EventFirer<State = Self::State>,
|
|
||||||
O: MapObserver,
|
O: MapObserver,
|
||||||
C: AsRef<O>,
|
C: AsRef<O>,
|
||||||
for<'de> <O as MapObserver>::Entry:
|
for<'de> <O as MapObserver>::Entry:
|
||||||
Serialize + Deserialize<'de> + 'static + Default + Debug + Bounded,
|
Serialize + Deserialize<'de> + 'static + Default + Debug + Bounded,
|
||||||
OT: ObserversTuple<Self::Input, Self::State>,
|
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||||
E::State: HasCorpus + HasMetadata + HasNamedMetadata + HasExecutions + HasCurrentTestcase,
|
S: HasCorpus
|
||||||
Z: Evaluator<E, EM, State = Self::State>,
|
+ HasMetadata
|
||||||
<<E as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, //delete me
|
+ HasNamedMetadata
|
||||||
|
+ HasExecutions
|
||||||
|
+ HasCurrentTestcase
|
||||||
|
+ HasCurrentCorpusId
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
Z: Evaluator<E, EM, State = S>,
|
||||||
|
<S::Corpus as Corpus>::Input: Input,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(
|
#[allow(
|
||||||
@ -116,7 +115,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
mgr: &mut EM,
|
mgr: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Run this stage only once for each corpus entry and only if we haven't already inspected it
|
// Run this stage only once for each corpus entry and only if we haven't already inspected it
|
||||||
@ -368,7 +367,7 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
// Calibration stage disallow restarts
|
// Calibration stage disallow restarts
|
||||||
// If a testcase that causes crash/timeout in the queue, we need to remove it from the queue immediately.
|
// If a testcase that causes crash/timeout in the queue, we need to remove it from the queue immediately.
|
||||||
RetryCountRestartHelper::no_retry(state, &self.name)
|
RetryCountRestartHelper::no_retry(state, &self.name)
|
||||||
@ -377,19 +376,19 @@ where
|
|||||||
// remove this guy from corpus queue
|
// remove this guy from corpus queue
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
// TODO: Make sure this is the correct way / there may be a better way?
|
// TODO: Make sure this is the correct way / there may be a better way?
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, E, O, OT> CalibrationStage<C, E, O, OT>
|
impl<C, E, O, OT, S> CalibrationStage<C, E, O, OT, S>
|
||||||
where
|
where
|
||||||
O: MapObserver,
|
O: MapObserver,
|
||||||
for<'it> O: AsIter<'it, Item = O::Entry>,
|
for<'it> O: AsIter<'it, Item = O::Entry>,
|
||||||
C: AsRef<O>,
|
C: AsRef<O>,
|
||||||
OT: ObserversTuple<<Self as UsesInput>::Input, <Self as UsesState>::State>,
|
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||||
E: UsesState,
|
S: HasCorpus,
|
||||||
{
|
{
|
||||||
/// Create a new [`CalibrationStage`].
|
/// Create a new [`CalibrationStage`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -422,7 +421,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, E, O, OT> Named for CalibrationStage<C, E, O, OT> {
|
impl<C, E, O, OT, S> Named for CalibrationStage<C, E, O, OT, S> {
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ use libafl_bolts::{
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
corpus::{Corpus, HasCurrentCorpusId},
|
||||||
events::EventFirer,
|
events::EventFirer,
|
||||||
executors::{Executor, HasObservers},
|
executors::{Executor, HasObservers},
|
||||||
inputs::{HasMutatorBytes, UsesInput},
|
inputs::{HasMutatorBytes, UsesInput},
|
||||||
@ -62,21 +62,14 @@ impl Ord for Earlier {
|
|||||||
pub const COLORIZATION_STAGE_NAME: &str = "colorization";
|
pub const COLORIZATION_STAGE_NAME: &str = "colorization";
|
||||||
/// The mutational stage using power schedules
|
/// The mutational stage using power schedules
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ColorizationStage<C, E, EM, O, Z> {
|
pub struct ColorizationStage<C, E, EM, O, S, Z> {
|
||||||
map_observer_handle: Handle<C>,
|
map_observer_handle: Handle<C>,
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
phantom: PhantomData<(E, EM, O, E, Z)>,
|
phantom: PhantomData<(E, EM, O, E, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, E, EM, O, Z> UsesState for ColorizationStage<C, E, EM, O, Z>
|
impl<C, E, EM, O, S, Z> Named for ColorizationStage<C, E, EM, O, S, Z>
|
||||||
where
|
|
||||||
E: UsesState,
|
|
||||||
{
|
|
||||||
type State = E::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C, E, EM, O, Z> Named for ColorizationStage<C, E, EM, O, Z>
|
|
||||||
where
|
where
|
||||||
E: UsesState,
|
E: UsesState,
|
||||||
{
|
{
|
||||||
@ -85,17 +78,21 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, E, EM, O, Z> Stage<E, EM, Z> for ColorizationStage<C, E, EM, O, Z>
|
impl<C, E, EM, O, S, Z> Stage<E, EM, S, Z> for ColorizationStage<C, E, EM, O, S, Z>
|
||||||
where
|
where
|
||||||
EM: UsesState<State = Self::State> + EventFirer,
|
EM: EventFirer<State = S>,
|
||||||
E: HasObservers + Executor<EM, Z>,
|
E: HasObservers + Executor<EM, Z, State = S>,
|
||||||
E::State: HasCorpus + HasMetadata + HasRand + HasNamedMetadata,
|
S: HasCorpus
|
||||||
E::Observers: ObserversTuple<<Self as UsesInput>::Input, <Self as UsesState>::State>,
|
+ HasMetadata
|
||||||
E::Input: HasMutatorBytes,
|
+ HasRand
|
||||||
|
+ HasNamedMetadata
|
||||||
|
+ HasCurrentCorpusId
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||||
|
<S::Corpus as Corpus>::Input: HasMutatorBytes + Clone,
|
||||||
O: MapObserver,
|
O: MapObserver,
|
||||||
C: AsRef<O> + Named,
|
C: AsRef<O> + Named,
|
||||||
Z: UsesState<State = Self::State>,
|
Z: UsesState<State = S>,
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = E::Input>, //delete me
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(clippy::let_and_return)]
|
#[allow(clippy::let_and_return)]
|
||||||
@ -103,7 +100,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E, // don't need the *main* executor for tracing
|
executor: &mut E, // don't need the *main* executor for tracing
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Run with the mutated input
|
// Run with the mutated input
|
||||||
@ -112,14 +109,14 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
// This is a deterministic stage
|
// This is a deterministic stage
|
||||||
// Once it failed, then don't retry,
|
// Once it failed, then don't retry,
|
||||||
// It will just fail again
|
// It will just fail again
|
||||||
RetryCountRestartHelper::no_retry(state, &self.name)
|
RetryCountRestartHelper::no_retry(state, &self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,27 +160,31 @@ impl TaintMetadata {
|
|||||||
|
|
||||||
libafl_bolts::impl_serdeany!(TaintMetadata);
|
libafl_bolts::impl_serdeany!(TaintMetadata);
|
||||||
|
|
||||||
impl<C, E, EM, O, Z> ColorizationStage<C, E, EM, O, Z>
|
impl<C, E, EM, O, S, Z> ColorizationStage<C, E, EM, O, S, Z>
|
||||||
where
|
where
|
||||||
EM: UsesState<State = <Self as UsesState>::State> + EventFirer,
|
EM: EventFirer<State = S>,
|
||||||
O: MapObserver,
|
O: MapObserver,
|
||||||
C: AsRef<O> + Named,
|
C: AsRef<O> + Named,
|
||||||
E: HasObservers + Executor<EM, Z>,
|
E: HasObservers + Executor<EM, Z, State = S>,
|
||||||
E::Observers: ObserversTuple<<Self as UsesInput>::Input, <Self as UsesState>::State>,
|
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||||
<E as UsesState>::State: HasCorpus + HasMetadata + HasRand,
|
S: HasCorpus
|
||||||
E::Input: HasMutatorBytes,
|
+ HasMetadata
|
||||||
Z: UsesState<State = <Self as UsesState>::State>,
|
+ HasRand
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = E::Input>, //delete me
|
+ HasCurrentCorpusId
|
||||||
|
+ HasCurrentTestcase
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
<S::Corpus as Corpus>::Input: HasMutatorBytes + Clone,
|
||||||
|
Z: UsesState<State = S>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(clippy::let_and_return)]
|
#[allow(clippy::let_and_return)]
|
||||||
fn colorize(
|
fn colorize(
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut <Self as UsesState>::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
observer_handle: &Handle<C>,
|
observer_handle: &Handle<C>,
|
||||||
) -> Result<E::Input, Error> {
|
) -> Result<<S::Corpus as Corpus>::Input, Error> {
|
||||||
let mut input = state.current_input_cloned()?;
|
let mut input = state.current_input_cloned()?;
|
||||||
// The backup of the input
|
// The backup of the input
|
||||||
let backup = input.clone();
|
let backup = input.clone();
|
||||||
@ -322,9 +323,9 @@ where
|
|||||||
fn get_raw_map_hash_run(
|
fn get_raw_map_hash_run(
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut <Self as UsesState>::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: &E::Input,
|
input: &<S::Corpus as Corpus>::Input,
|
||||||
observer_handle: &Handle<C>,
|
observer_handle: &Handle<C>,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
executor.observers_mut().pre_exec_all(state, input)?;
|
executor.observers_mut().pre_exec_all(state, input)?;
|
||||||
@ -348,7 +349,7 @@ where
|
|||||||
|
|
||||||
/// Replace bytes with random values but following certain rules
|
/// Replace bytes with random values but following certain rules
|
||||||
#[allow(clippy::needless_range_loop)]
|
#[allow(clippy::needless_range_loop)]
|
||||||
fn type_replace(bytes: &mut [u8], state: &mut <Self as UsesState>::State) {
|
fn type_replace(bytes: &mut [u8], state: &mut S) {
|
||||||
let len = bytes.len();
|
let len = bytes.len();
|
||||||
for idx in 0..len {
|
for idx in 0..len {
|
||||||
let c = match bytes[idx] {
|
let c = match bytes[idx] {
|
||||||
|
@ -14,14 +14,13 @@ use libafl_bolts::{
|
|||||||
|
|
||||||
#[cfg(all(feature = "concolic_mutation", feature = "introspection"))]
|
#[cfg(all(feature = "concolic_mutation", feature = "introspection"))]
|
||||||
use crate::monitors::PerfFeature;
|
use crate::monitors::PerfFeature;
|
||||||
#[cfg(all(feature = "introspection", feature = "concolic_mutation"))]
|
|
||||||
use crate::state::HasClientPerfMonitor;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
corpus::{Corpus, HasCurrentCorpusId},
|
||||||
executors::{Executor, HasObservers},
|
executors::{Executor, HasObservers},
|
||||||
|
inputs::UsesInput,
|
||||||
observers::{concolic::ConcolicObserver, ObserversTuple},
|
observers::{concolic::ConcolicObserver, ObserversTuple},
|
||||||
stages::{RetryCountRestartHelper, Stage, TracingStage},
|
stages::{RetryCountRestartHelper, Stage, TracingStage},
|
||||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, UsesState},
|
state::{HasCorpus, HasCurrentTestcase, HasExecutions, MaybeHasClientPerfMonitor, UsesState},
|
||||||
Error, HasMetadata, HasNamedMetadata,
|
Error, HasMetadata, HasNamedMetadata,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "concolic_mutation")]
|
#[cfg(feature = "concolic_mutation")]
|
||||||
@ -29,51 +28,46 @@ use crate::{
|
|||||||
inputs::HasMutatorBytes,
|
inputs::HasMutatorBytes,
|
||||||
mark_feature_time,
|
mark_feature_time,
|
||||||
observers::concolic::{ConcolicMetadata, SymExpr, SymExprRef},
|
observers::concolic::{ConcolicMetadata, SymExpr, SymExprRef},
|
||||||
start_timer,
|
start_timer, Evaluator,
|
||||||
state::State,
|
|
||||||
Evaluator,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Wraps a [`TracingStage`] to add concolic observing.
|
/// Wraps a [`TracingStage`] to add concolic observing.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ConcolicTracingStage<'a, EM, TE, Z> {
|
pub struct ConcolicTracingStage<'a, EM, TE, S, Z> {
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
inner: TracingStage<EM, TE, Z>,
|
inner: TracingStage<EM, TE, S, Z>,
|
||||||
observer_handle: Handle<ConcolicObserver<'a>>,
|
observer_handle: Handle<ConcolicObserver<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<EM, TE, Z> UsesState for ConcolicTracingStage<'_, EM, TE, Z>
|
|
||||||
where
|
|
||||||
TE: UsesState,
|
|
||||||
{
|
|
||||||
type State = TE::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The name for concolic tracer
|
/// The name for concolic tracer
|
||||||
pub const CONCOLIC_TRACING_STAGE_NAME: &str = "concolictracing";
|
pub const CONCOLIC_TRACING_STAGE_NAME: &str = "concolictracing";
|
||||||
|
|
||||||
impl<EM, TE, Z> Named for ConcolicTracingStage<'_, EM, TE, Z> {
|
impl<EM, TE, S, Z> Named for ConcolicTracingStage<'_, EM, TE, S, Z> {
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, TE, Z> Stage<E, EM, Z> for ConcolicTracingStage<'_, EM, TE, Z>
|
impl<E, EM, TE, S, Z> Stage<E, EM, S, Z> for ConcolicTracingStage<'_, EM, TE, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState<State = Self::State>,
|
TE: Executor<EM, Z, State = S> + HasObservers,
|
||||||
EM: UsesState<State = Self::State>,
|
TE::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||||
TE: Executor<EM, Z> + HasObservers,
|
S: HasExecutions
|
||||||
TE::Observers: ObserversTuple<TE::Input, <Self as UsesState>::State>,
|
+ HasCorpus
|
||||||
TE::State: HasExecutions + HasCorpus + HasNamedMetadata + HasCurrentTestcase,
|
+ HasNamedMetadata
|
||||||
Z: UsesState<State = Self::State>,
|
+ HasCurrentTestcase
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, //delete me
|
+ HasCurrentCorpusId
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
EM: UsesState<State = S>,
|
||||||
|
Z: UsesState<State = S>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
_executor: &mut E,
|
_executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.inner.trace(fuzzer, state, manager)?;
|
self.inner.trace(fuzzer, state, manager)?;
|
||||||
@ -87,23 +81,23 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
// This is a deterministic stage
|
// This is a deterministic stage
|
||||||
// Once it failed, then don't retry,
|
// Once it failed, then don't retry,
|
||||||
// It will just fail again
|
// It will just fail again
|
||||||
RetryCountRestartHelper::no_retry(state, &self.name)
|
RetryCountRestartHelper::no_retry(state, &self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, EM, TE, Z> ConcolicTracingStage<'a, EM, TE, Z> {
|
impl<'a, EM, TE, S, Z> ConcolicTracingStage<'a, EM, TE, S, Z> {
|
||||||
/// Creates a new default tracing stage using the given [`Executor`], observing traces from a
|
/// Creates a new default tracing stage using the given [`Executor`], observing traces from a
|
||||||
/// [`ConcolicObserver`] with the given name.
|
/// [`ConcolicObserver`] with the given name.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
inner: TracingStage<EM, TE, Z>,
|
inner: TracingStage<EM, TE, S, Z>,
|
||||||
observer_handle: Handle<ConcolicObserver<'a>>,
|
observer_handle: Handle<ConcolicObserver<'a>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let observer_name = observer_handle.name().clone();
|
let observer_name = observer_handle.name().clone();
|
||||||
@ -392,22 +386,25 @@ impl<Z> Named for SimpleConcolicMutationalStage<Z> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "concolic_mutation")]
|
#[cfg(feature = "concolic_mutation")]
|
||||||
impl<E, EM, Z> Stage<E, EM, Z> for SimpleConcolicMutationalStage<Z>
|
impl<E, EM, S, Z> Stage<E, EM, S, Z> for SimpleConcolicMutationalStage<Z>
|
||||||
where
|
where
|
||||||
E: UsesState<State = Self::State>,
|
Z: Evaluator<E, EM, State = S>,
|
||||||
EM: UsesState<State = Self::State>,
|
<S::Corpus as Corpus>::Input: HasMutatorBytes + Clone,
|
||||||
Z: Evaluator<E, EM>,
|
S: HasExecutions
|
||||||
Z::Input: HasMutatorBytes,
|
+ HasCorpus
|
||||||
Z::State:
|
+ HasMetadata
|
||||||
State + HasExecutions + HasCorpus + HasMetadata + HasNamedMetadata + HasCurrentTestcase,
|
+ HasNamedMetadata
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Z::Input>, //delete me
|
+ HasCurrentTestcase
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ HasCurrentCorpusId
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
{
|
{
|
||||||
@ -437,7 +434,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
// This is a deterministic stage
|
// This is a deterministic stage
|
||||||
// Once it failed, then don't retry,
|
// Once it failed, then don't retry,
|
||||||
// It will just fail again
|
// It will just fail again
|
||||||
@ -445,7 +442,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ use crate::{
|
|||||||
corpus::{Corpus, CorpusId, Testcase},
|
corpus::{Corpus, CorpusId, Testcase},
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
stages::Stage,
|
stages::Stage,
|
||||||
state::{HasCorpus, HasRand, HasSolutions, UsesState},
|
state::{HasCorpus, HasRand, HasSolutions},
|
||||||
Error, HasMetadata,
|
Error, HasMetadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,65 +35,53 @@ impl_serdeany!(DumpToDiskMetadata);
|
|||||||
|
|
||||||
/// The [`DumpToDiskStage`] is a stage that dumps the corpus and the solutions to disk
|
/// The [`DumpToDiskStage`] is a stage that dumps the corpus and the solutions to disk
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DumpToDiskStage<CB1, CB2, EM, Z> {
|
pub struct DumpToDiskStage<CB1, CB2, EM, S, Z> {
|
||||||
solutions_dir: PathBuf,
|
solutions_dir: PathBuf,
|
||||||
corpus_dir: PathBuf,
|
corpus_dir: PathBuf,
|
||||||
to_bytes: CB1,
|
to_bytes: CB1,
|
||||||
generate_filename: CB2,
|
generate_filename: CB2,
|
||||||
phantom: PhantomData<(EM, Z)>,
|
phantom: PhantomData<(EM, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB1, CB2, EM, Z> UsesState for DumpToDiskStage<CB1, CB2, EM, Z>
|
impl<CB1, CB2, E, EM, S, P, Z> Stage<E, EM, S, Z> for DumpToDiskStage<CB1, CB2, EM, S, Z>
|
||||||
where
|
where
|
||||||
EM: UsesState,
|
CB1: FnMut(&Testcase<<S::Corpus as Corpus>::Input>, &S) -> Vec<u8>,
|
||||||
{
|
CB2: FnMut(&Testcase<<S::Corpus as Corpus>::Input>, &CorpusId) -> P,
|
||||||
type State = EM::State;
|
S: HasCorpus + HasSolutions + HasRand + HasMetadata,
|
||||||
}
|
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
|
||||||
impl<CB1, CB2, P, E, EM, Z> Stage<E, EM, Z> for DumpToDiskStage<CB1, CB2, EM, Z>
|
|
||||||
where
|
|
||||||
CB1: FnMut(&Testcase<Self::Input>, &Self::State) -> Vec<u8>,
|
|
||||||
CB2: FnMut(&Testcase<Self::Input>, &CorpusId) -> P,
|
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
EM: UsesState,
|
|
||||||
E: UsesState<State = Self::State>,
|
|
||||||
Z: UsesState<State = Self::State>,
|
|
||||||
EM::State: HasCorpus + HasSolutions + HasRand + HasMetadata,
|
|
||||||
<<EM as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, //delete me
|
|
||||||
<<EM as UsesState>::State as HasSolutions>::Solutions: Corpus<Input = Self::Input>, //delete me
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
_fuzzer: &mut Z,
|
_fuzzer: &mut Z,
|
||||||
_executor: &mut E,
|
_executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
_manager: &mut EM,
|
_manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.dump_state_to_disk(state)
|
self.dump_state_to_disk(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn should_restart(&mut self, _state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, _state: &mut S) -> Result<bool, Error> {
|
||||||
// Not executing the target, so restart safety is not needed
|
// Not executing the target, so restart safety is not needed
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> {
|
||||||
// Not executing the target, so restart safety is not needed
|
// Not executing the target, so restart safety is not needed
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation for `DumpToDiskStage` with a default `generate_filename` function.
|
/// Implementation for `DumpToDiskStage` with a default `generate_filename` function.
|
||||||
impl<CB1, EM, Z> DumpToDiskStage<CB1, fn(&Testcase<EM::Input>, &CorpusId) -> String, EM, Z>
|
impl<CB1, EM, S, Z>
|
||||||
|
DumpToDiskStage<CB1, fn(&Testcase<<S::Corpus as Corpus>::Input>, &CorpusId) -> String, EM, S, Z>
|
||||||
where
|
where
|
||||||
EM: UsesState,
|
S: HasCorpus + HasSolutions + HasRand + HasMetadata,
|
||||||
Z: UsesState,
|
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
|
||||||
<EM as UsesState>::State: HasCorpus + HasSolutions + HasRand + HasMetadata,
|
<S::Corpus as Corpus>::Input: Input,
|
||||||
<<EM as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = EM::Input>,
|
|
||||||
<<EM as UsesState>::State as HasSolutions>::Solutions: Corpus<Input = EM::Input>,
|
|
||||||
{
|
{
|
||||||
/// Create a new [`DumpToDiskStage`] with a default `generate_filename` function.
|
/// Create a new [`DumpToDiskStage`] with a default `generate_filename` function.
|
||||||
pub fn new<A, B>(to_bytes: CB1, corpus_dir: A, solutions_dir: B) -> Result<Self, Error>
|
pub fn new<A, B>(to_bytes: CB1, corpus_dir: A, solutions_dir: B) -> Result<Self, Error>
|
||||||
@ -111,7 +99,10 @@ where
|
|||||||
|
|
||||||
/// Default `generate_filename` function.
|
/// Default `generate_filename` function.
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||||
fn generate_filename(testcase: &Testcase<EM::Input>, id: &CorpusId) -> String {
|
fn generate_filename(
|
||||||
|
testcase: &Testcase<<S::Corpus as Corpus>::Input>,
|
||||||
|
id: &CorpusId,
|
||||||
|
) -> String {
|
||||||
[
|
[
|
||||||
Some(id.0.to_string()),
|
Some(id.0.to_string()),
|
||||||
testcase.filename().clone(),
|
testcase.filename().clone(),
|
||||||
@ -128,13 +119,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB1, CB2, EM, Z> DumpToDiskStage<CB1, CB2, EM, Z>
|
impl<CB1, CB2, EM, S, Z> DumpToDiskStage<CB1, CB2, EM, S, Z>
|
||||||
where
|
where
|
||||||
EM: UsesState,
|
S: HasCorpus + HasMetadata + HasSolutions,
|
||||||
Z: UsesState,
|
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
|
||||||
<EM as UsesState>::State: HasCorpus + HasSolutions + HasRand + HasMetadata,
|
|
||||||
<<EM as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = EM::Input>,
|
|
||||||
<<EM as UsesState>::State as HasSolutions>::Solutions: Corpus<Input = EM::Input>,
|
|
||||||
{
|
{
|
||||||
/// Create a new [`DumpToDiskStage`] with a custom `generate_filename` function.
|
/// Create a new [`DumpToDiskStage`] with a custom `generate_filename` function.
|
||||||
pub fn new_with_custom_filenames<A, B>(
|
pub fn new_with_custom_filenames<A, B>(
|
||||||
@ -175,19 +163,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn dump_state_to_disk<P: AsRef<Path>>(
|
fn dump_state_to_disk<P: AsRef<Path>>(&mut self, state: &mut S) -> Result<(), Error>
|
||||||
&mut self,
|
|
||||||
state: &mut <Self as UsesState>::State,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
where
|
||||||
CB1: FnMut(
|
CB1: FnMut(&Testcase<<S::Corpus as Corpus>::Input>, &S) -> Vec<u8>,
|
||||||
&Testcase<<<<EM as UsesState>::State as HasCorpus>::Corpus as Corpus>::Input>,
|
CB2: FnMut(&Testcase<<S::Corpus as Corpus>::Input>, &CorpusId) -> P,
|
||||||
&<EM as UsesState>::State,
|
|
||||||
) -> Vec<u8>,
|
|
||||||
CB2: FnMut(
|
|
||||||
&Testcase<<<<EM as UsesState>::State as HasCorpus>::Corpus as Corpus>::Input>,
|
|
||||||
&CorpusId,
|
|
||||||
) -> P,
|
|
||||||
{
|
{
|
||||||
let (mut corpus_id, mut solutions_id) =
|
let (mut corpus_id, mut solutions_id) =
|
||||||
if let Some(meta) = state.metadata_map().get::<DumpToDiskMetadata>() {
|
if let Some(meta) = state.metadata_map().get::<DumpToDiskMetadata>() {
|
||||||
|
@ -11,6 +11,8 @@ use libafl_bolts::{
|
|||||||
AsSlice, Named,
|
AsSlice, Named,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
use crate::monitors::PerfFeature;
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, HasCurrentCorpusId},
|
corpus::{Corpus, HasCurrentCorpusId},
|
||||||
executors::{Executor, HasObservers},
|
executors::{Executor, HasObservers},
|
||||||
@ -21,11 +23,9 @@ use crate::{
|
|||||||
require_novelties_tracking,
|
require_novelties_tracking,
|
||||||
stages::{RetryCountRestartHelper, Stage},
|
stages::{RetryCountRestartHelper, Stage},
|
||||||
start_timer,
|
start_timer,
|
||||||
state::{HasCorpus, HasExecutions, UsesState},
|
state::{HasCorpus, HasExecutions, MaybeHasClientPerfMonitor, UsesState},
|
||||||
Error, HasMetadata, HasNamedMetadata,
|
Error, HasMetadata, HasNamedMetadata,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "introspection")]
|
|
||||||
use crate::{monitors::PerfFeature, state::HasClientPerfMonitor};
|
|
||||||
|
|
||||||
const MAX_GENERALIZED_LEN: usize = 8192;
|
const MAX_GENERALIZED_LEN: usize = 8192;
|
||||||
|
|
||||||
@ -48,37 +48,35 @@ pub static GENERALIZATION_STAGE_NAME: &str = "generalization";
|
|||||||
|
|
||||||
/// A stage that runs a tracer executor
|
/// A stage that runs a tracer executor
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GeneralizationStage<C, EM, O, OT, Z> {
|
pub struct GeneralizationStage<C, EM, O, OT, S, Z> {
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
map_observer_handle: Handle<C>,
|
map_observer_handle: Handle<C>,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
phantom: PhantomData<(EM, O, OT, Z)>,
|
phantom: PhantomData<(EM, O, OT, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, EM, O, OT, Z> Named for GeneralizationStage<C, EM, O, OT, Z> {
|
impl<C, EM, O, OT, S, Z> Named for GeneralizationStage<C, EM, O, OT, S, Z> {
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, EM, O, OT, Z> UsesState for GeneralizationStage<C, EM, O, OT, Z>
|
impl<C, E, EM, O, S, Z> Stage<E, EM, S, Z> for GeneralizationStage<C, EM, O, E::Observers, S, Z>
|
||||||
where
|
|
||||||
EM: UsesState,
|
|
||||||
{
|
|
||||||
type State = EM::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C, E, EM, O, Z> Stage<E, EM, Z> for GeneralizationStage<C, EM, O, E::Observers, Z>
|
|
||||||
where
|
where
|
||||||
O: MapObserver,
|
O: MapObserver,
|
||||||
C: CanTrack + AsRef<O> + Named,
|
C: CanTrack + AsRef<O> + Named,
|
||||||
E: Executor<EM, Z, State = Self::State> + HasObservers,
|
E: Executor<EM, Z, State = S> + HasObservers,
|
||||||
E::Observers: ObserversTuple<BytesInput, <Self as UsesState>::State>,
|
E::Observers: ObserversTuple<BytesInput, S>,
|
||||||
EM::State:
|
S: HasExecutions
|
||||||
UsesInput<Input = BytesInput> + HasExecutions + HasMetadata + HasCorpus + HasNamedMetadata,
|
+ HasMetadata
|
||||||
EM: UsesState,
|
+ HasCorpus
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = BytesInput>, //delete me
|
+ HasNamedMetadata
|
||||||
Z: UsesState<State = Self::State>,
|
+ HasCurrentCorpusId
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = BytesInput>,
|
||||||
|
S::Corpus: Corpus<Input = BytesInput>,
|
||||||
|
EM: UsesState<State = S>,
|
||||||
|
Z: UsesState<State = S>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
@ -86,7 +84,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let Some(corpus_id) = state.current_corpus_id()? else {
|
let Some(corpus_id) = state.current_corpus_id()? else {
|
||||||
@ -331,26 +329,30 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
// TODO: We need to be able to resume better if something crashes or times out
|
// TODO: We need to be able to resume better if something crashes or times out
|
||||||
RetryCountRestartHelper::should_restart(state, &self.name, 3)
|
RetryCountRestartHelper::should_restart(state, &self.name, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
// TODO: We need to be able to resume better if something crashes or times out
|
// TODO: We need to be able to resume better if something crashes or times out
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, EM, O, OT, Z> GeneralizationStage<C, EM, O, OT, Z>
|
impl<C, EM, O, OT, S, Z> GeneralizationStage<C, EM, O, OT, S, Z>
|
||||||
where
|
where
|
||||||
EM: UsesState,
|
|
||||||
O: MapObserver,
|
O: MapObserver,
|
||||||
C: CanTrack + AsRef<O> + Named,
|
C: CanTrack + AsRef<O> + Named,
|
||||||
<Self as UsesState>::State:
|
S: HasExecutions
|
||||||
UsesInput<Input = BytesInput> + HasExecutions + HasMetadata + HasCorpus,
|
+ HasMetadata
|
||||||
OT: ObserversTuple<BytesInput, <EM as UsesState>::State>,
|
+ HasCorpus
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = BytesInput>,
|
||||||
|
OT: ObserversTuple<BytesInput, S>,
|
||||||
|
EM: UsesState<State = S>,
|
||||||
|
Z: UsesState<State = S>,
|
||||||
{
|
{
|
||||||
/// Create a new [`GeneralizationStage`].
|
/// Create a new [`GeneralizationStage`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -370,15 +372,14 @@ where
|
|||||||
&self,
|
&self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut <Self as UsesState>::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
novelties: &[usize],
|
novelties: &[usize],
|
||||||
input: &BytesInput,
|
input: &BytesInput,
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where
|
||||||
E: Executor<EM, Z, State = <Self as UsesState>::State> + HasObservers,
|
E: Executor<EM, Z, State = S> + HasObservers,
|
||||||
E::Observers: ObserversTuple<BytesInput, <Self as UsesState>::State>,
|
E::Observers: ObserversTuple<BytesInput, S>,
|
||||||
Z: UsesState<State = EM::State>,
|
|
||||||
{
|
{
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
executor.observers_mut().pre_exec_all(state, input)?;
|
executor.observers_mut().pre_exec_all(state, input)?;
|
||||||
@ -411,7 +412,7 @@ where
|
|||||||
&self,
|
&self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut <Self as UsesState>::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
payload: &mut Vec<Option<u8>>,
|
payload: &mut Vec<Option<u8>>,
|
||||||
novelties: &[usize],
|
novelties: &[usize],
|
||||||
@ -419,8 +420,7 @@ where
|
|||||||
split_char: u8,
|
split_char: u8,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
E: Executor<EM, Z, State = <Self as UsesState>::State> + HasObservers<Observers = OT>,
|
E: Executor<EM, Z, State = S> + HasObservers<Observers = OT>,
|
||||||
Z: UsesState<State = EM::State>,
|
|
||||||
{
|
{
|
||||||
let mut start = 0;
|
let mut start = 0;
|
||||||
while start < payload.len() {
|
while start < payload.len() {
|
||||||
@ -450,7 +450,7 @@ where
|
|||||||
&self,
|
&self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut <Self as UsesState>::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
payload: &mut Vec<Option<u8>>,
|
payload: &mut Vec<Option<u8>>,
|
||||||
novelties: &[usize],
|
novelties: &[usize],
|
||||||
@ -458,8 +458,7 @@ where
|
|||||||
closing_char: u8,
|
closing_char: u8,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
E: Executor<EM, Z, State = <Self as UsesState>::State> + HasObservers<Observers = OT>,
|
E: Executor<EM, Z, State = S> + HasObservers<Observers = OT>,
|
||||||
Z: UsesState<State = EM::State>,
|
|
||||||
{
|
{
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
while index < payload.len() {
|
while index < payload.len() {
|
||||||
|
@ -7,10 +7,11 @@
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
corpus::Corpus,
|
||||||
generators::Generator,
|
generators::Generator,
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
stages::Stage,
|
stages::Stage,
|
||||||
state::{HasCorpus, HasRand, UsesState},
|
state::{HasCorpus, HasRand},
|
||||||
Error, Evaluator,
|
Error, Evaluator,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,36 +20,27 @@ use crate::{
|
|||||||
///
|
///
|
||||||
/// This stage can be used to construct black-box (e.g., grammar-based) fuzzers.
|
/// This stage can be used to construct black-box (e.g., grammar-based) fuzzers.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GenStage<G, Z>(G, PhantomData<Z>);
|
pub struct GenStage<G, S, Z>(G, PhantomData<(S, Z)>);
|
||||||
|
|
||||||
impl<G, Z> GenStage<G, Z> {
|
impl<G, S, Z> GenStage<G, S, Z> {
|
||||||
/// Create a new [`GenStage`].
|
/// Create a new [`GenStage`].
|
||||||
pub fn new(g: G) -> Self {
|
pub fn new(g: G) -> Self {
|
||||||
Self(g, PhantomData)
|
Self(g, PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G, Z> UsesState for GenStage<G, Z>
|
impl<E, EM, G, S, Z> Stage<E, EM, S, Z> for GenStage<G, S, Z>
|
||||||
where
|
where
|
||||||
Z: UsesState,
|
Z: Evaluator<E, EM, State = S>,
|
||||||
{
|
S: HasCorpus + HasRand + UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
type State = Z::State;
|
G: Generator<<S::Corpus as Corpus>::Input, S>,
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, Z, G> Stage<E, EM, Z> for GenStage<G, Z>
|
|
||||||
where
|
|
||||||
E: UsesState<State = Self::State>,
|
|
||||||
EM: UsesState<State = Self::State>,
|
|
||||||
Z: Evaluator<E, EM>,
|
|
||||||
Self::State: HasCorpus + HasRand,
|
|
||||||
G: Generator<<<Self as UsesState>::State as UsesInput>::Input, Self::State>,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let input = self.0.generate(state)?;
|
let input = self.0.generate(state)?;
|
||||||
@ -56,13 +48,13 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, _state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, _state: &mut S) -> Result<bool, Error> {
|
||||||
// It's a random generation stage
|
// It's a random generation stage
|
||||||
// so you can restart for whatever times you want
|
// so you can restart for whatever times you want
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
stages::{HasCurrentStageId, HasNestedStageStatus, Stage, StageId, StagesTuple},
|
stages::{HasNestedStageStatus, Stage, StageId, StagesTuple},
|
||||||
state::UsesState,
|
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -32,33 +31,23 @@ impl NestedStageRetryCountRestartHelper {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Perform the stage while the closure evaluates to true
|
/// Perform the stage while the closure evaluates to true
|
||||||
pub struct WhileStage<CB, E, EM, ST, Z> {
|
pub struct WhileStage<CB, E, EM, ST, S, Z> {
|
||||||
closure: CB,
|
closure: CB,
|
||||||
stages: ST,
|
stages: ST,
|
||||||
phantom: PhantomData<(E, EM, Z)>,
|
phantom: PhantomData<(E, EM, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB, E, EM, ST, Z> UsesState for WhileStage<CB, E, EM, ST, Z>
|
impl<CB, E, EM, ST, S, Z> Stage<E, EM, S, Z> for WhileStage<CB, E, EM, ST, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState,
|
CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result<bool, Error>,
|
||||||
{
|
ST: StagesTuple<E, EM, S, Z>,
|
||||||
type State = E::State;
|
S: HasNestedStageStatus,
|
||||||
}
|
|
||||||
|
|
||||||
impl<CB, E, EM, ST, Z> Stage<E, EM, Z> for WhileStage<CB, E, EM, ST, Z>
|
|
||||||
where
|
|
||||||
CB: FnMut(&mut Z, &mut E, &mut Self::State, &mut EM) -> Result<bool, Error>,
|
|
||||||
E: UsesState,
|
|
||||||
EM: UsesState<State = E::State>,
|
|
||||||
ST: StagesTuple<E, EM, Self::State, Z>,
|
|
||||||
Z: UsesState<State = Self::State>,
|
|
||||||
Self::State: HasNestedStageStatus,
|
|
||||||
{
|
{
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
while state.current_stage_id()?.is_some()
|
while state.current_stage_id()?.is_some()
|
||||||
@ -70,19 +59,18 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
NestedStageRetryCountRestartHelper::should_restart(state, self)
|
NestedStageRetryCountRestartHelper::should_restart(state, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
NestedStageRetryCountRestartHelper::clear_progress(state, self)
|
NestedStageRetryCountRestartHelper::clear_progress(state, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB, E, EM, ST, Z> WhileStage<CB, E, EM, ST, Z>
|
impl<CB, E, EM, ST, S, Z> WhileStage<CB, E, EM, ST, S, Z>
|
||||||
where
|
where
|
||||||
CB: FnMut(&mut Z, &mut E, &mut <Self as UsesState>::State, &mut EM) -> Result<bool, Error>,
|
CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result<bool, Error>,
|
||||||
E: UsesState,
|
|
||||||
{
|
{
|
||||||
/// Constructor
|
/// Constructor
|
||||||
pub fn new(closure: CB, stages: ST) -> Self {
|
pub fn new(closure: CB, stages: ST) -> Self {
|
||||||
@ -97,33 +85,23 @@ where
|
|||||||
/// A conditionally enabled stage.
|
/// A conditionally enabled stage.
|
||||||
/// If the closure returns true, the wrapped stage will be executed, else it will be skipped.
|
/// If the closure returns true, the wrapped stage will be executed, else it will be skipped.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IfStage<CB, E, EM, ST, Z> {
|
pub struct IfStage<CB, E, EM, ST, S, Z> {
|
||||||
closure: CB,
|
closure: CB,
|
||||||
if_stages: ST,
|
if_stages: ST,
|
||||||
phantom: PhantomData<(E, EM, Z)>,
|
phantom: PhantomData<(E, EM, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB, E, EM, ST, Z> UsesState for IfStage<CB, E, EM, ST, Z>
|
impl<CB, E, EM, ST, S, Z> Stage<E, EM, S, Z> for IfStage<CB, E, EM, ST, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState,
|
CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result<bool, Error>,
|
||||||
{
|
ST: StagesTuple<E, EM, S, Z>,
|
||||||
type State = E::State;
|
S: HasNestedStageStatus,
|
||||||
}
|
|
||||||
|
|
||||||
impl<CB, E, EM, ST, Z> Stage<E, EM, Z> for IfStage<CB, E, EM, ST, Z>
|
|
||||||
where
|
|
||||||
CB: FnMut(&mut Z, &mut E, &mut Self::State, &mut EM) -> Result<bool, Error>,
|
|
||||||
E: UsesState,
|
|
||||||
EM: UsesState<State = Self::State>,
|
|
||||||
ST: StagesTuple<E, EM, Self::State, Z>,
|
|
||||||
Z: UsesState<State = Self::State>,
|
|
||||||
Self::State: HasNestedStageStatus,
|
|
||||||
{
|
{
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if state.current_stage_id()?.is_some() || (self.closure)(fuzzer, executor, state, manager)?
|
if state.current_stage_id()?.is_some() || (self.closure)(fuzzer, executor, state, manager)?
|
||||||
@ -134,19 +112,18 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
NestedStageRetryCountRestartHelper::should_restart(state, self)
|
NestedStageRetryCountRestartHelper::should_restart(state, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
NestedStageRetryCountRestartHelper::clear_progress(state, self)
|
NestedStageRetryCountRestartHelper::clear_progress(state, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB, E, EM, ST, Z> IfStage<CB, E, EM, ST, Z>
|
impl<CB, E, EM, ST, S, Z> IfStage<CB, E, EM, ST, S, Z>
|
||||||
where
|
where
|
||||||
CB: FnMut(&mut Z, &mut E, &mut <Self as UsesState>::State, &mut EM) -> Result<bool, Error>,
|
CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result<bool, Error>,
|
||||||
E: UsesState,
|
|
||||||
{
|
{
|
||||||
/// Constructor for this conditionally enabled stage.
|
/// Constructor for this conditionally enabled stage.
|
||||||
/// If the closure returns true, the wrapped stage will be executed, else it will be skipped.
|
/// If the closure returns true, the wrapped stage will be executed, else it will be skipped.
|
||||||
@ -161,35 +138,25 @@ where
|
|||||||
|
|
||||||
/// Perform the stage if closure evaluates to true
|
/// Perform the stage if closure evaluates to true
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IfElseStage<CB, E, EM, ST1, ST2, Z> {
|
pub struct IfElseStage<CB, E, EM, ST1, ST2, S, Z> {
|
||||||
closure: CB,
|
closure: CB,
|
||||||
if_stages: ST1,
|
if_stages: ST1,
|
||||||
else_stages: ST2,
|
else_stages: ST2,
|
||||||
phantom: PhantomData<(E, EM, Z)>,
|
phantom: PhantomData<(E, EM, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB, E, EM, ST1, ST2, Z> UsesState for IfElseStage<CB, E, EM, ST1, ST2, Z>
|
impl<CB, E, EM, ST1, ST2, S, Z> Stage<E, EM, S, Z> for IfElseStage<CB, E, EM, ST1, ST2, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState,
|
CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result<bool, Error>,
|
||||||
{
|
ST1: StagesTuple<E, EM, S, Z>,
|
||||||
type State = E::State;
|
ST2: StagesTuple<E, EM, S, Z>,
|
||||||
}
|
S: HasNestedStageStatus,
|
||||||
|
|
||||||
impl<CB, E, EM, ST1, ST2, Z> Stage<E, EM, Z> for IfElseStage<CB, E, EM, ST1, ST2, Z>
|
|
||||||
where
|
|
||||||
CB: FnMut(&mut Z, &mut E, &mut Self::State, &mut EM) -> Result<bool, Error>,
|
|
||||||
E: UsesState,
|
|
||||||
EM: UsesState<State = Self::State>,
|
|
||||||
ST1: StagesTuple<E, EM, Self::State, Z>,
|
|
||||||
ST2: StagesTuple<E, EM, Self::State, Z>,
|
|
||||||
Z: UsesState<State = Self::State>,
|
|
||||||
Self::State: HasNestedStageStatus,
|
|
||||||
{
|
{
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let current = state.current_stage_id()?;
|
let current = state.current_stage_id()?;
|
||||||
@ -219,19 +186,18 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
NestedStageRetryCountRestartHelper::should_restart(state, self)
|
NestedStageRetryCountRestartHelper::should_restart(state, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
NestedStageRetryCountRestartHelper::clear_progress(state, self)
|
NestedStageRetryCountRestartHelper::clear_progress(state, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB, E, EM, ST1, ST2, Z> IfElseStage<CB, E, EM, ST1, ST2, Z>
|
impl<CB, E, EM, ST1, ST2, S, Z> IfElseStage<CB, E, EM, ST1, ST2, S, Z>
|
||||||
where
|
where
|
||||||
CB: FnMut(&mut Z, &mut E, &mut <Self as UsesState>::State, &mut EM) -> Result<bool, Error>,
|
CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result<bool, Error>,
|
||||||
E: UsesState,
|
|
||||||
{
|
{
|
||||||
/// Constructor
|
/// Constructor
|
||||||
pub fn new(closure: CB, if_stages: ST1, else_stages: ST2) -> Self {
|
pub fn new(closure: CB, if_stages: ST1, else_stages: ST2) -> Self {
|
||||||
@ -246,31 +212,21 @@ where
|
|||||||
|
|
||||||
/// A stage wrapper where the stages do not need to be initialized, but can be [`None`].
|
/// A stage wrapper where the stages do not need to be initialized, but can be [`None`].
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OptionalStage<E, EM, ST, Z> {
|
pub struct OptionalStage<E, EM, ST, S, Z> {
|
||||||
stages: Option<ST>,
|
stages: Option<ST>,
|
||||||
phantom: PhantomData<(E, EM, Z)>,
|
phantom: PhantomData<(E, EM, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, ST, Z> UsesState for OptionalStage<E, EM, ST, Z>
|
impl<E, EM, ST, S, Z> Stage<E, EM, S, Z> for OptionalStage<E, EM, ST, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState,
|
ST: StagesTuple<E, EM, S, Z>,
|
||||||
{
|
S: HasNestedStageStatus,
|
||||||
type State = E::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, ST, Z> Stage<E, EM, Z> for OptionalStage<E, EM, ST, Z>
|
|
||||||
where
|
|
||||||
E: UsesState,
|
|
||||||
EM: UsesState<State = Self::State>,
|
|
||||||
ST: StagesTuple<E, EM, Self::State, Z>,
|
|
||||||
Z: UsesState<State = Self::State>,
|
|
||||||
Self::State: HasNestedStageStatus,
|
|
||||||
{
|
{
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(stages) = &mut self.stages {
|
if let Some(stages) = &mut self.stages {
|
||||||
@ -280,16 +236,16 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
NestedStageRetryCountRestartHelper::should_restart(state, self)
|
NestedStageRetryCountRestartHelper::should_restart(state, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
NestedStageRetryCountRestartHelper::clear_progress(state, self)
|
NestedStageRetryCountRestartHelper::clear_progress(state, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, ST, Z> OptionalStage<E, EM, ST, Z> {
|
impl<E, EM, ST, S, Z> OptionalStage<E, EM, ST, S, Z> {
|
||||||
/// Constructor for this conditionally enabled stage.
|
/// Constructor for this conditionally enabled stage.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(stages: Option<ST>) -> Self {
|
pub fn new(stages: Option<ST>) -> Self {
|
||||||
|
@ -33,14 +33,11 @@ pub use logics::*;
|
|||||||
pub use mutational::{MutationalStage, StdMutationalStage};
|
pub use mutational::{MutationalStage, StdMutationalStage};
|
||||||
pub use power::{PowerMutationalStage, StdPowerMutationalStage};
|
pub use power::{PowerMutationalStage, StdPowerMutationalStage};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
pub use stats::StatsStage;
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use sync::*;
|
pub use sync::*;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use time_tracker::TimeTrackingStageWrapper;
|
pub use time_tracker::TimeTrackingStageWrapper;
|
||||||
pub use tmin::{
|
pub use tmin::{MapEqualityFactory, MapEqualityFeedback, StdTMinMutationalStage};
|
||||||
MapEqualityFactory, MapEqualityFeedback, StdTMinMutationalStage, TMinMutationalStage,
|
|
||||||
};
|
|
||||||
pub use tracing::{ShadowTracingStage, TracingStage};
|
pub use tracing::{ShadowTracingStage, TracingStage};
|
||||||
pub use tuneable::*;
|
pub use tuneable::*;
|
||||||
use tuple_list::NonEmptyTuple;
|
use tuple_list::NonEmptyTuple;
|
||||||
@ -51,15 +48,9 @@ pub use verify_timeouts::{TimeoutsToVerify, VerifyTimeoutsStage};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{CorpusId, HasCurrentCorpusId},
|
corpus::{CorpusId, HasCurrentCorpusId},
|
||||||
events::{EventFirer, EventProcessor, EventRestarter, HasEventManagerId, ProgressReporter},
|
events::EventProcessor,
|
||||||
executors::{Executor, HasObservers},
|
state::{HasExecutions, State, Stoppable},
|
||||||
inputs::UsesInput,
|
Error, HasNamedMetadata,
|
||||||
observers::ObserversTuple,
|
|
||||||
schedulers::Scheduler,
|
|
||||||
stages::push::PushStage,
|
|
||||||
state::{HasCorpus, HasExecutions, HasLastReportTime, HasRand, State, Stoppable, UsesState},
|
|
||||||
Error, EvaluatorObservers, ExecutesInput, ExecutionProcessor, HasMetadata, HasNamedMetadata,
|
|
||||||
HasScheduler,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Mutational stage is the normal fuzzing stage.
|
/// Mutational stage is the normal fuzzing stage.
|
||||||
@ -79,7 +70,6 @@ pub mod generalization;
|
|||||||
pub mod generation;
|
pub mod generation;
|
||||||
pub mod logics;
|
pub mod logics;
|
||||||
pub mod power;
|
pub mod power;
|
||||||
pub mod stats;
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -93,21 +83,16 @@ pub mod verify_timeouts;
|
|||||||
|
|
||||||
/// A stage is one step in the fuzzing process.
|
/// A stage is one step in the fuzzing process.
|
||||||
/// Multiple stages will be scheduled one by one for each input.
|
/// Multiple stages will be scheduled one by one for each input.
|
||||||
pub trait Stage<E, EM, Z>: UsesState
|
pub trait Stage<E, EM, S, Z> {
|
||||||
where
|
|
||||||
E: UsesState<State = Self::State>,
|
|
||||||
EM: UsesState<State = Self::State>,
|
|
||||||
Z: UsesState<State = Self::State>,
|
|
||||||
{
|
|
||||||
/// This method will be called before every call to [`Stage::perform`].
|
/// This method will be called before every call to [`Stage::perform`].
|
||||||
/// Initialize the restart tracking for this stage, _if it is not yet initialized_.
|
/// Initialize the restart tracking for this stage, _if it is not yet initialized_.
|
||||||
/// On restart, this will be called again.
|
/// On restart, this will be called again.
|
||||||
/// As long as [`Stage::clear_progress`], all subsequent calls happen on restart.
|
/// As long as [`Stage::clear_progress`], all subsequent calls happen on restart.
|
||||||
/// Returns `true`, if the stage's [`Stage::perform`] method should run, else `false`.
|
/// Returns `true`, if the stage's [`Stage::perform`] method should run, else `false`.
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error>;
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error>;
|
||||||
|
|
||||||
/// Clear the current status tracking of the associated stage
|
/// Clear the current status tracking of the associated stage
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error>;
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error>;
|
||||||
|
|
||||||
/// Run the stage.
|
/// Run the stage.
|
||||||
///
|
///
|
||||||
@ -119,7 +104,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
@ -128,7 +113,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if self.should_restart(state)? {
|
if self.should_restart(state)? {
|
||||||
@ -139,13 +124,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A tuple holding all `Stages` used for fuzzing.
|
/// A tuple holding all `Stages` used for fuzzing.
|
||||||
pub trait StagesTuple<E, EM, S, Z>
|
pub trait StagesTuple<E, EM, S, Z> {
|
||||||
where
|
|
||||||
E: UsesState<State = S>,
|
|
||||||
EM: UsesState<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
S: UsesInput + HasCurrentStageId,
|
|
||||||
{
|
|
||||||
/// Performs all `Stages` in this tuple.
|
/// Performs all `Stages` in this tuple.
|
||||||
fn perform_all(
|
fn perform_all(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -158,10 +137,7 @@ where
|
|||||||
|
|
||||||
impl<E, EM, S, Z> StagesTuple<E, EM, S, Z> for ()
|
impl<E, EM, S, Z> StagesTuple<E, EM, S, Z> for ()
|
||||||
where
|
where
|
||||||
E: UsesState<State = S>,
|
S: HasCurrentStageId,
|
||||||
EM: UsesState<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
S: UsesInput + HasCurrentStageId,
|
|
||||||
{
|
{
|
||||||
fn perform_all(
|
fn perform_all(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -180,14 +156,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Head, Tail, E, EM, Z> StagesTuple<E, EM, Head::State, Z> for (Head, Tail)
|
impl<Head, Tail, E, EM, S, Z> StagesTuple<E, EM, S, Z> for (Head, Tail)
|
||||||
where
|
where
|
||||||
Head: Stage<E, EM, Z>,
|
Head: Stage<E, EM, S, Z>,
|
||||||
Tail: StagesTuple<E, EM, Head::State, Z> + HasConstLen,
|
Tail: StagesTuple<E, EM, S, Z> + HasConstLen,
|
||||||
E: UsesState<State = Head::State>,
|
S: HasCurrentStageId + Stoppable,
|
||||||
EM: UsesState<State = Head::State> + EventProcessor<E, Z>,
|
EM: EventProcessor<E, Z>,
|
||||||
Z: UsesState<State = Head::State>,
|
|
||||||
Head::State: HasCurrentStageId,
|
|
||||||
{
|
{
|
||||||
/// Performs all stages in the tuple,
|
/// Performs all stages in the tuple,
|
||||||
/// Checks after every stage if state wants to stop
|
/// Checks after every stage if state wants to stop
|
||||||
@ -196,7 +170,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Head::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match state.current_stage_id()? {
|
match state.current_stage_id()? {
|
||||||
@ -239,66 +213,45 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Head, Tail, E, EM, Z>
|
impl<Head, Tail, E, EM, S, Z> IntoVec<Box<dyn Stage<E, EM, S, Z>>> for (Head, Tail)
|
||||||
IntoVec<Box<dyn Stage<E, EM, Z, State = Head::State, Input = Head::Input>>> for (Head, Tail)
|
|
||||||
where
|
where
|
||||||
Head: Stage<E, EM, Z> + 'static,
|
Head: Stage<E, EM, S, Z> + 'static,
|
||||||
Tail: StagesTuple<E, EM, Head::State, Z>
|
Tail: StagesTuple<E, EM, S, Z> + HasConstLen + IntoVec<Box<dyn Stage<E, EM, S, Z>>>,
|
||||||
+ HasConstLen
|
S: HasCurrentStageId,
|
||||||
+ IntoVec<Box<dyn Stage<E, EM, Z, State = Head::State, Input = Head::Input>>>,
|
|
||||||
E: UsesState<State = Head::State>,
|
|
||||||
EM: UsesState<State = Head::State>,
|
|
||||||
Z: UsesState<State = Head::State>,
|
|
||||||
Head::State: HasCurrentStageId,
|
|
||||||
{
|
{
|
||||||
fn into_vec_reversed(
|
fn into_vec_reversed(self) -> Vec<Box<dyn Stage<E, EM, S, Z>>> {
|
||||||
self,
|
|
||||||
) -> Vec<Box<dyn Stage<E, EM, Z, State = Head::State, Input = Head::Input>>> {
|
|
||||||
let (head, tail) = self.uncons();
|
let (head, tail) = self.uncons();
|
||||||
let mut ret = tail.0.into_vec_reversed();
|
let mut ret = tail.0.into_vec_reversed();
|
||||||
ret.push(Box::new(head));
|
ret.push(Box::new(head));
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_vec(self) -> Vec<Box<dyn Stage<E, EM, Z, State = Head::State, Input = Head::Input>>> {
|
fn into_vec(self) -> Vec<Box<dyn Stage<E, EM, S, Z>>> {
|
||||||
let mut ret = self.into_vec_reversed();
|
let mut ret = self.into_vec_reversed();
|
||||||
ret.reverse();
|
ret.reverse();
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Tail, E, EM, Z> IntoVec<Box<dyn Stage<E, EM, Z, State = Tail::State, Input = Tail::Input>>>
|
impl<Tail, E, EM, S, Z> IntoVec<Box<dyn Stage<E, EM, S, Z>>> for (Tail,)
|
||||||
for (Tail,)
|
|
||||||
where
|
where
|
||||||
Tail: UsesState + IntoVec<Box<dyn Stage<E, EM, Z, State = Tail::State, Input = Tail::Input>>>,
|
Tail: IntoVec<Box<dyn Stage<E, EM, S, Z>>>,
|
||||||
Z: UsesState<State = Tail::State>,
|
|
||||||
EM: UsesState<State = Tail::State>,
|
|
||||||
E: UsesState<State = Tail::State>,
|
|
||||||
{
|
{
|
||||||
fn into_vec(self) -> Vec<Box<dyn Stage<E, EM, Z, State = Tail::State, Input = Tail::Input>>> {
|
fn into_vec(self) -> Vec<Box<dyn Stage<E, EM, S, Z>>> {
|
||||||
self.0.into_vec()
|
self.0.into_vec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, Z> IntoVec<Box<dyn Stage<E, EM, Z, State = Z::State, Input = Z::Input>>>
|
impl<E, EM, S, Z> IntoVec<Box<dyn Stage<E, EM, S, Z>>> for Vec<Box<dyn Stage<E, EM, S, Z>>> {
|
||||||
for Vec<Box<dyn Stage<E, EM, Z, State = Z::State, Input = Z::Input>>>
|
fn into_vec(self) -> Vec<Box<dyn Stage<E, EM, S, Z>>> {
|
||||||
where
|
|
||||||
Z: UsesState,
|
|
||||||
EM: UsesState<State = Z::State>,
|
|
||||||
E: UsesState<State = Z::State>,
|
|
||||||
{
|
|
||||||
fn into_vec(self) -> Vec<Box<dyn Stage<E, EM, Z, State = Z::State, Input = Z::Input>>> {
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, S, Z> StagesTuple<E, EM, S, Z>
|
impl<E, EM, S, Z> StagesTuple<E, EM, S, Z> for Vec<Box<dyn Stage<E, EM, S, Z>>>
|
||||||
for Vec<Box<dyn Stage<E, EM, Z, State = S, Input = S::Input>>>
|
|
||||||
where
|
where
|
||||||
E: UsesState<State = S>,
|
EM: EventProcessor<E, Z>,
|
||||||
EM: UsesState<State = S> + EventProcessor<E, Z>,
|
S: HasCurrentStageId + State,
|
||||||
Z: UsesState<State = S>,
|
|
||||||
S: UsesInput + HasCurrentStageId + State,
|
|
||||||
{
|
{
|
||||||
/// Performs all stages in the `Vec`
|
/// Performs all stages in the `Vec`
|
||||||
/// Checks after every stage if state wants to stop
|
/// Checks after every stage if state wants to stop
|
||||||
@ -333,46 +286,36 @@ pub struct ClosureStage<CB, E, EM, Z> {
|
|||||||
phantom: PhantomData<(E, EM, Z)>,
|
phantom: PhantomData<(E, EM, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB, E, EM, Z> UsesState for ClosureStage<CB, E, EM, Z>
|
|
||||||
where
|
|
||||||
E: UsesState,
|
|
||||||
{
|
|
||||||
type State = E::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<CB, E, EM, Z> Named for ClosureStage<CB, E, EM, Z> {
|
impl<CB, E, EM, Z> Named for ClosureStage<CB, E, EM, Z> {
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB, E, EM, Z> Stage<E, EM, Z> for ClosureStage<CB, E, EM, Z>
|
impl<CB, E, EM, S, Z> Stage<E, EM, S, Z> for ClosureStage<CB, E, EM, Z>
|
||||||
where
|
where
|
||||||
CB: FnMut(&mut Z, &mut E, &mut Self::State, &mut EM) -> Result<(), Error>,
|
CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result<(), Error>,
|
||||||
E: UsesState,
|
S: HasNamedMetadata + HasCurrentCorpusId,
|
||||||
EM: UsesState<State = Self::State>,
|
|
||||||
Z: UsesState<State = Self::State>,
|
|
||||||
Self::State: HasNamedMetadata,
|
|
||||||
{
|
{
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut E::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
(self.closure)(fuzzer, executor, state, manager)
|
(self.closure)(fuzzer, executor, state, manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
// There's no restart safety in the content of the closure.
|
// There's no restart safety in the content of the closure.
|
||||||
// don't restart
|
// don't restart
|
||||||
RetryCountRestartHelper::no_retry(state, &self.name)
|
RetryCountRestartHelper::no_retry(state, &self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,132 +339,6 @@ impl<CB, E, EM, Z> ClosureStage<CB, E, EM, Z> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows us to use a [`push::PushStage`] as a normal [`Stage`]
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PushStageAdapter<CS, EM, OT, PS, Z> {
|
|
||||||
name: Cow<'static, str>,
|
|
||||||
push_stage: PS,
|
|
||||||
phantom: PhantomData<(CS, EM, OT, Z)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<CS, EM, OT, PS, Z> PushStageAdapter<CS, EM, OT, PS, Z> {
|
|
||||||
/// Create a new [`PushStageAdapter`], wrapping the given [`PushStage`]
|
|
||||||
/// to be used as a normal [`Stage`]
|
|
||||||
#[must_use]
|
|
||||||
pub fn new(push_stage: PS) -> Self {
|
|
||||||
// unsafe but impossible that you create two threads both instantiating this instance
|
|
||||||
let stage_id = unsafe {
|
|
||||||
let ret = PUSH_STAGE_ADAPTER_ID;
|
|
||||||
PUSH_STAGE_ADAPTER_ID += 1;
|
|
||||||
ret
|
|
||||||
};
|
|
||||||
Self {
|
|
||||||
name: Cow::Owned(
|
|
||||||
PUSH_STAGE_ADAPTER_NAME.to_owned() + ":" + stage_id.to_string().as_str(),
|
|
||||||
),
|
|
||||||
push_stage,
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// The unique counter for this stage
|
|
||||||
static mut PUSH_STAGE_ADAPTER_ID: usize = 0;
|
|
||||||
/// The name for push stage adapter
|
|
||||||
pub static PUSH_STAGE_ADAPTER_NAME: &str = "pushstageadapter";
|
|
||||||
|
|
||||||
impl<CS, EM, OT, PS, Z> UsesState for PushStageAdapter<CS, EM, OT, PS, Z>
|
|
||||||
where
|
|
||||||
Z: UsesState,
|
|
||||||
{
|
|
||||||
type State = Z::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<CS, EM, OT, PS, Z> Named for PushStageAdapter<CS, EM, OT, PS, Z> {
|
|
||||||
#[must_use]
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<CS, E, EM, OT, PS, Z> Stage<E, EM, Z> for PushStageAdapter<CS, EM, OT, PS, Z>
|
|
||||||
where
|
|
||||||
CS: Scheduler<Z::Input, Z::State>,
|
|
||||||
Self::State: HasExecutions
|
|
||||||
+ HasRand
|
|
||||||
+ HasCorpus
|
|
||||||
+ HasLastReportTime
|
|
||||||
+ HasCurrentCorpusId
|
|
||||||
+ HasNamedMetadata
|
|
||||||
+ HasMetadata,
|
|
||||||
E: Executor<EM, Z, State = <Self as UsesState>::State> + HasObservers<Observers = OT>,
|
|
||||||
EM: EventFirer<State = Self::State>
|
|
||||||
+ EventRestarter
|
|
||||||
+ HasEventManagerId
|
|
||||||
+ ProgressReporter<State = Self::State>,
|
|
||||||
OT: ObserversTuple<Self::Input, Self::State>,
|
|
||||||
PS: PushStage<CS, EM, OT, Z>,
|
|
||||||
Z: ExecutesInput<E, EM>
|
|
||||||
+ ExecutionProcessor<EM, OT>
|
|
||||||
+ EvaluatorObservers<EM, OT>
|
|
||||||
+ HasScheduler<Scheduler = CS>,
|
|
||||||
{
|
|
||||||
fn perform(
|
|
||||||
&mut self,
|
|
||||||
fuzzer: &mut Z,
|
|
||||||
executor: &mut E,
|
|
||||||
state: &mut Z::State,
|
|
||||||
event_mgr: &mut EM,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let push_stage = &mut self.push_stage;
|
|
||||||
|
|
||||||
let Some(corpus_id) = state.current_corpus_id()? else {
|
|
||||||
return Err(Error::illegal_state(
|
|
||||||
"state is not currently processing a corpus index",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
push_stage.set_current_corpus_id(corpus_id);
|
|
||||||
|
|
||||||
push_stage.init(fuzzer, state, event_mgr, &mut *executor.observers_mut())?;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let input =
|
|
||||||
match push_stage.pre_exec(fuzzer, state, event_mgr, &mut *executor.observers_mut())
|
|
||||||
{
|
|
||||||
Some(Ok(next_input)) => next_input,
|
|
||||||
Some(Err(err)) => return Err(err),
|
|
||||||
None => break,
|
|
||||||
};
|
|
||||||
|
|
||||||
let exit_kind = fuzzer.execute_input(state, executor, event_mgr, &input)?;
|
|
||||||
|
|
||||||
push_stage.post_exec(
|
|
||||||
fuzzer,
|
|
||||||
state,
|
|
||||||
event_mgr,
|
|
||||||
&mut *executor.observers_mut(),
|
|
||||||
input,
|
|
||||||
exit_kind,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.push_stage
|
|
||||||
.deinit(fuzzer, state, event_mgr, &mut *executor.observers_mut())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
|
||||||
// TODO: Proper restart handling - call post_exec at the right time, etc...
|
|
||||||
RetryCountRestartHelper::no_retry(state, &self.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Progress which permits a fixed amount of resumes per round of fuzzing. If this amount is ever
|
/// Progress which permits a fixed amount of resumes per round of fuzzing. If this amount is ever
|
||||||
/// exceeded, the input will no longer be executed by this stage.
|
/// exceeded, the input will no longer be executed by this stage.
|
||||||
#[derive(Clone, Deserialize, Serialize, Debug)]
|
#[derive(Clone, Deserialize, Serialize, Debug)]
|
||||||
@ -722,7 +539,7 @@ mod test {
|
|||||||
corpus::{Corpus, HasCurrentCorpusId, Testcase},
|
corpus::{Corpus, HasCurrentCorpusId, Testcase},
|
||||||
inputs::NopInput,
|
inputs::NopInput,
|
||||||
stages::{RetryCountRestartHelper, Stage},
|
stages::{RetryCountRestartHelper, Stage},
|
||||||
state::{HasCorpus, State, StdState, UsesState},
|
state::{HasCorpus, StdState},
|
||||||
HasMetadata,
|
HasMetadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -771,35 +588,25 @@ mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> UsesState for ResumeSucceededStage<S>
|
impl<E, EM, S, Z> Stage<E, EM, S, Z> for ResumeSucceededStage<S>
|
||||||
where
|
where
|
||||||
S: State,
|
S: HasMetadata,
|
||||||
{
|
|
||||||
type State = S;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, Z> Stage<E, EM, Z> for ResumeSucceededStage<Z::State>
|
|
||||||
where
|
|
||||||
E: UsesState<State = Z::State>,
|
|
||||||
EM: UsesState<State = Z::State>,
|
|
||||||
Z: UsesState,
|
|
||||||
Z::State: HasMetadata,
|
|
||||||
{
|
{
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
_fuzzer: &mut Z,
|
_fuzzer: &mut Z,
|
||||||
_executor: &mut E,
|
_executor: &mut E,
|
||||||
_state: &mut Self::State,
|
_state: &mut S,
|
||||||
_manager: &mut EM,
|
_manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
TestProgress::should_restart(state, self)
|
TestProgress::should_restart(state, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
TestProgress::clear_progress(state, self)
|
TestProgress::clear_progress(state, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,20 +9,20 @@ use core::{marker::PhantomData, num::NonZeroUsize};
|
|||||||
|
|
||||||
use libafl_bolts::{rands::Rand, Named};
|
use libafl_bolts::{rands::Rand, Named};
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
use crate::monitors::PerfFeature;
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, CorpusId, Testcase},
|
corpus::{Corpus, CorpusId, HasCurrentCorpusId, Testcase},
|
||||||
fuzzer::Evaluator,
|
fuzzer::Evaluator,
|
||||||
inputs::Input,
|
inputs::{Input, UsesInput},
|
||||||
mark_feature_time,
|
mark_feature_time,
|
||||||
mutators::{MultiMutator, MutationResult, Mutator},
|
mutators::{MultiMutator, MutationResult, Mutator},
|
||||||
nonzero,
|
nonzero,
|
||||||
stages::{RetryCountRestartHelper, Stage},
|
stages::{RetryCountRestartHelper, Stage},
|
||||||
start_timer,
|
start_timer,
|
||||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, UsesState},
|
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, MaybeHasClientPerfMonitor},
|
||||||
Error, HasMetadata, HasNamedMetadata,
|
Error, HasMetadata, HasNamedMetadata,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "introspection")]
|
|
||||||
use crate::{monitors::PerfFeature, state::HasClientPerfMonitor};
|
|
||||||
|
|
||||||
// TODO multi mutators stage
|
// TODO multi mutators stage
|
||||||
|
|
||||||
@ -81,24 +81,170 @@ where
|
|||||||
/// A Mutational stage is the stage in a fuzzing run that mutates inputs.
|
/// A Mutational stage is the stage in a fuzzing run that mutates inputs.
|
||||||
/// Mutational stages will usually have a range of mutations that are
|
/// Mutational stages will usually have a range of mutations that are
|
||||||
/// being applied to the input one by one, between executions.
|
/// being applied to the input one by one, between executions.
|
||||||
pub trait MutationalStage<E, EM, I, M, Z>: Stage<E, EM, Z>
|
pub trait MutationalStage<S> {
|
||||||
where
|
/// The mutator of this stage
|
||||||
E: UsesState<State = Self::State>,
|
type Mutator;
|
||||||
M: Mutator<I, Self::State>,
|
|
||||||
EM: UsesState<State = Self::State>,
|
|
||||||
Z: Evaluator<E, EM, State = Self::State>,
|
|
||||||
Self::State: HasCorpus + HasCurrentTestcase,
|
|
||||||
I: MutatedTransform<Self::Input, Self::State> + Clone,
|
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>,
|
|
||||||
{
|
|
||||||
/// The mutator registered for this stage
|
/// The mutator registered for this stage
|
||||||
fn mutator(&self) -> &M;
|
fn mutator(&self) -> &Self::Mutator;
|
||||||
|
|
||||||
/// The mutator registered for this stage (mutable)
|
/// The mutator registered for this stage (mutable)
|
||||||
fn mutator_mut(&mut self) -> &mut M;
|
fn mutator_mut(&mut self) -> &mut Self::Mutator;
|
||||||
|
|
||||||
/// Gets the number of iterations this mutator should run for.
|
/// Gets the number of iterations this mutator should run for.
|
||||||
fn iterations(&self, state: &mut Self::State) -> Result<usize, Error>;
|
fn iterations(&self, state: &mut S) -> Result<usize, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Default value, how many iterations each stage gets, as an upper bound.
|
||||||
|
/// It may randomly continue earlier.
|
||||||
|
pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128;
|
||||||
|
|
||||||
|
/// The default mutational stage
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct StdMutationalStage<E, EM, I, M, S, Z> {
|
||||||
|
/// The name
|
||||||
|
name: Cow<'static, str>,
|
||||||
|
/// The mutator(s) to use
|
||||||
|
mutator: M,
|
||||||
|
/// The maximum amount of iterations we should do each round
|
||||||
|
max_iterations: NonZeroUsize,
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
phantom: PhantomData<(E, EM, I, S, Z)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, EM, I, M, S, Z> MutationalStage<S> for StdMutationalStage<E, EM, I, M, S, Z>
|
||||||
|
where
|
||||||
|
S: HasRand,
|
||||||
|
{
|
||||||
|
type Mutator = M;
|
||||||
|
|
||||||
|
/// The mutator, added to this stage
|
||||||
|
#[inline]
|
||||||
|
fn mutator(&self) -> &Self::Mutator {
|
||||||
|
&self.mutator
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The list of mutators, added to this stage (as mutable ref)
|
||||||
|
#[inline]
|
||||||
|
fn mutator_mut(&mut self) -> &mut Self::Mutator {
|
||||||
|
&mut self.mutator
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the number of iterations as a random number
|
||||||
|
fn iterations(&self, state: &mut S) -> Result<usize, Error> {
|
||||||
|
Ok(1 + state.rand_mut().below(self.max_iterations))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The unique id for mutational stage
|
||||||
|
static mut MUTATIONAL_STAGE_ID: usize = 0;
|
||||||
|
/// The name for mutational stage
|
||||||
|
pub static MUTATIONAL_STAGE_NAME: &str = "mutational";
|
||||||
|
|
||||||
|
impl<E, EM, I, M, S, Z> Named for StdMutationalStage<E, EM, I, M, S, Z> {
|
||||||
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, EM, I, M, S, Z> Stage<E, EM, S, Z> for StdMutationalStage<E, EM, I, M, S, Z>
|
||||||
|
where
|
||||||
|
M: Mutator<I, S>,
|
||||||
|
Z: Evaluator<E, EM, State = S>,
|
||||||
|
S: HasCorpus
|
||||||
|
+ HasRand
|
||||||
|
+ HasMetadata
|
||||||
|
+ HasExecutions
|
||||||
|
+ HasNamedMetadata
|
||||||
|
+ HasCurrentCorpusId
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput,
|
||||||
|
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone,
|
||||||
|
<S::Corpus as Corpus>::Input: Input,
|
||||||
|
S::Corpus: Corpus<Input = S::Input>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
#[allow(clippy::let_and_return)]
|
||||||
|
fn perform(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
executor: &mut E,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let ret = self.perform_mutational(fuzzer, executor, state, manager);
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
state.introspection_monitor_mut().finish_stage();
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
|
RetryCountRestartHelper::should_restart(state, &self.name, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, EM, M, S, Z> StdMutationalStage<E, EM, <S::Corpus as Corpus>::Input, M, S, Z>
|
||||||
|
where
|
||||||
|
M: Mutator<<S::Corpus as Corpus>::Input, S>,
|
||||||
|
Z: Evaluator<E, EM, State = S>,
|
||||||
|
S: HasCorpus + HasRand + HasCurrentCorpusId + UsesInput + MaybeHasClientPerfMonitor,
|
||||||
|
<S::Corpus as Corpus>::Input: Input + Clone,
|
||||||
|
S::Corpus: Corpus<Input = S::Input>,
|
||||||
|
{
|
||||||
|
/// Creates a new default mutational stage
|
||||||
|
pub fn new(mutator: M) -> Self {
|
||||||
|
// Safe to unwrap: DEFAULT_MUTATIONAL_MAX_ITERATIONS is never 0.
|
||||||
|
Self::transforming_with_max_iterations(mutator, nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new mutational stage with the given max iterations
|
||||||
|
#[inline]
|
||||||
|
pub fn with_max_iterations(mutator: M, max_iterations: NonZeroUsize) -> Self {
|
||||||
|
Self::transforming_with_max_iterations(mutator, max_iterations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, EM, I, M, S, Z> StdMutationalStage<E, EM, I, M, S, Z>
|
||||||
|
where
|
||||||
|
M: Mutator<I, S>,
|
||||||
|
Z: Evaluator<E, EM, State = S>,
|
||||||
|
S: HasCorpus + HasRand + HasCurrentTestcase + MaybeHasClientPerfMonitor + UsesInput,
|
||||||
|
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone,
|
||||||
|
<S::Corpus as Corpus>::Input: Input,
|
||||||
|
S::Corpus: Corpus<Input = S::Input>,
|
||||||
|
{
|
||||||
|
/// Creates a new transforming mutational stage with the default max iterations
|
||||||
|
pub fn transforming(mutator: M) -> Self {
|
||||||
|
// Safe to unwrap: DEFAULT_MUTATIONAL_MAX_ITERATIONS is never 0.
|
||||||
|
Self::transforming_with_max_iterations(mutator, nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new transforming mutational stage with the given max iterations
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Will return [`Error::IllegalArgument`] for `max_iterations` of 0.
|
||||||
|
#[inline]
|
||||||
|
pub fn transforming_with_max_iterations(mutator: M, max_iterations: NonZeroUsize) -> Self {
|
||||||
|
let stage_id = unsafe {
|
||||||
|
let ret = MUTATIONAL_STAGE_ID;
|
||||||
|
MUTATIONAL_STAGE_ID += 1;
|
||||||
|
ret
|
||||||
|
};
|
||||||
|
let name =
|
||||||
|
Cow::Owned(MUTATIONAL_STAGE_NAME.to_owned() + ":" + stage_id.to_string().as_str());
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
mutator,
|
||||||
|
max_iterations,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Runs this (mutational) stage for the given testcase
|
/// Runs this (mutational) stage for the given testcase
|
||||||
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
|
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
|
||||||
@ -106,7 +252,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
@ -150,170 +296,13 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default value, how many iterations each stage gets, as an upper bound.
|
|
||||||
/// It may randomly continue earlier.
|
|
||||||
pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128;
|
|
||||||
|
|
||||||
/// The default mutational stage
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct StdMutationalStage<E, EM, I, M, Z> {
|
|
||||||
/// The name
|
|
||||||
name: Cow<'static, str>,
|
|
||||||
/// The mutator(s) to use
|
|
||||||
mutator: M,
|
|
||||||
/// The maximum amount of iterations we should do each round
|
|
||||||
max_iterations: NonZeroUsize,
|
|
||||||
#[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 = Self::State>,
|
|
||||||
EM: UsesState<State = Self::State>,
|
|
||||||
M: Mutator<I, Self::State>,
|
|
||||||
Z: Evaluator<E, EM>,
|
|
||||||
Z::State: HasCorpus + HasRand + HasExecutions + HasMetadata + HasNamedMetadata,
|
|
||||||
I: MutatedTransform<Self::Input, Self::State> + Clone,
|
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, //delete me
|
|
||||||
{
|
|
||||||
/// The mutator, added to this stage
|
|
||||||
#[inline]
|
|
||||||
fn mutator(&self) -> &M {
|
|
||||||
&self.mutator
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The list of mutators, added to this stage (as mutable ref)
|
|
||||||
#[inline]
|
|
||||||
fn mutator_mut(&mut self) -> &mut M {
|
|
||||||
&mut self.mutator
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the number of iterations as a random number
|
|
||||||
fn iterations(&self, state: &mut Self::State) -> Result<usize, Error> {
|
|
||||||
Ok(1 + state.rand_mut().below(self.max_iterations))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The unique id for mutational stage
|
|
||||||
static mut MUTATIONAL_STAGE_ID: usize = 0;
|
|
||||||
/// The name for mutational stage
|
|
||||||
pub static MUTATIONAL_STAGE_NAME: &str = "mutational";
|
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> UsesState for StdMutationalStage<E, EM, I, M, Z>
|
|
||||||
where
|
|
||||||
Z: UsesState,
|
|
||||||
{
|
|
||||||
type State = Z::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> Named for StdMutationalStage<E, EM, I, M, Z> {
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> Stage<E, EM, Z> for StdMutationalStage<E, EM, I, M, Z>
|
|
||||||
where
|
|
||||||
E: UsesState<State = Self::State>,
|
|
||||||
EM: UsesState<State = Self::State>,
|
|
||||||
M: Mutator<I, Self::State>,
|
|
||||||
Z: Evaluator<E, EM>,
|
|
||||||
Z::State: HasCorpus + HasRand + HasMetadata + HasExecutions + HasNamedMetadata,
|
|
||||||
I: MutatedTransform<Self::Input, Self::State> + Clone,
|
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, //delete me
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
#[allow(clippy::let_and_return)]
|
|
||||||
fn perform(
|
|
||||||
&mut self,
|
|
||||||
fuzzer: &mut Z,
|
|
||||||
executor: &mut E,
|
|
||||||
state: &mut Self::State,
|
|
||||||
manager: &mut EM,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let ret = self.perform_mutational(fuzzer, executor, state, manager);
|
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
|
||||||
state.introspection_monitor_mut().finish_stage();
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
|
||||||
RetryCountRestartHelper::should_restart(state, &self.name, 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, M, Z> StdMutationalStage<E, EM, Z::Input, M, Z>
|
|
||||||
where
|
|
||||||
E: UsesState<State = <Self as UsesState>::State>,
|
|
||||||
EM: UsesState<State = <Self as UsesState>::State>,
|
|
||||||
M: Mutator<Z::Input, <Self as UsesState>::State>,
|
|
||||||
Z: Evaluator<E, EM>,
|
|
||||||
<Self as UsesState>::State: HasCorpus + HasRand,
|
|
||||||
{
|
|
||||||
/// Creates a new default mutational stage
|
|
||||||
pub fn new(mutator: M) -> Self {
|
|
||||||
// Safe to unwrap: DEFAULT_MUTATIONAL_MAX_ITERATIONS is never 0.
|
|
||||||
Self::transforming_with_max_iterations(mutator, nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new mutational stage with the given max iterations
|
|
||||||
#[inline]
|
|
||||||
pub fn with_max_iterations(mutator: M, max_iterations: NonZeroUsize) -> Self {
|
|
||||||
Self::transforming_with_max_iterations(mutator, max_iterations)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> StdMutationalStage<E, EM, I, M, Z>
|
|
||||||
where
|
|
||||||
E: UsesState<State = <Self as UsesState>::State>,
|
|
||||||
EM: UsesState<State = <Self as UsesState>::State>,
|
|
||||||
M: Mutator<I, <Self as UsesState>::State>,
|
|
||||||
Z: Evaluator<E, EM>,
|
|
||||||
<Self as UsesState>::State: HasCorpus + HasRand,
|
|
||||||
{
|
|
||||||
/// Creates a new transforming mutational stage with the default max iterations
|
|
||||||
pub fn transforming(mutator: M) -> Self {
|
|
||||||
// Safe to unwrap: DEFAULT_MUTATIONAL_MAX_ITERATIONS is never 0.
|
|
||||||
Self::transforming_with_max_iterations(mutator, nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new transforming mutational stage with the given max iterations
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
/// Will return [`Error::IllegalArgument`] for `max_iterations` of 0.
|
|
||||||
#[inline]
|
|
||||||
pub fn transforming_with_max_iterations(mutator: M, max_iterations: NonZeroUsize) -> Self {
|
|
||||||
let stage_id = unsafe {
|
|
||||||
let ret = MUTATIONAL_STAGE_ID;
|
|
||||||
MUTATIONAL_STAGE_ID += 1;
|
|
||||||
ret
|
|
||||||
};
|
|
||||||
let name =
|
|
||||||
Cow::Owned(MUTATIONAL_STAGE_NAME.to_owned() + ":" + stage_id.to_string().as_str());
|
|
||||||
Self {
|
|
||||||
name,
|
|
||||||
mutator,
|
|
||||||
max_iterations,
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A mutational stage that operates on multiple inputs, as returned by [`MultiMutator::multi_mutate`].
|
/// A mutational stage that operates on multiple inputs, as returned by [`MultiMutator::multi_mutate`].
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct MultiMutationalStage<E, EM, I, M, Z> {
|
pub struct MultiMutationalStage<E, EM, I, M, S, Z> {
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
mutator: M,
|
mutator: M,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
phantom: PhantomData<(E, EM, I, Z)>,
|
phantom: PhantomData<(E, EM, I, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The unique id for multi mutational stage
|
/// The unique id for multi mutational stage
|
||||||
@ -321,37 +310,29 @@ static mut MULTI_MUTATIONAL_STAGE_ID: usize = 0;
|
|||||||
/// The name for multi mutational stage
|
/// The name for multi mutational stage
|
||||||
pub static MULTI_MUTATIONAL_STAGE_NAME: &str = "multimutational";
|
pub static MULTI_MUTATIONAL_STAGE_NAME: &str = "multimutational";
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> UsesState for MultiMutationalStage<E, EM, I, M, Z>
|
impl<E, EM, I, M, S, Z> Named for MultiMutationalStage<E, EM, I, M, S, Z> {
|
||||||
where
|
|
||||||
Z: UsesState,
|
|
||||||
{
|
|
||||||
type State = Z::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> Named for MultiMutationalStage<E, EM, I, M, Z> {
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> Stage<E, EM, Z> for MultiMutationalStage<E, EM, I, M, Z>
|
impl<E, EM, I, M, S, Z> Stage<E, EM, S, Z> for MultiMutationalStage<E, EM, I, M, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState<State = Self::State>,
|
M: MultiMutator<I, S>,
|
||||||
EM: UsesState<State = Self::State>,
|
Z: Evaluator<E, EM, State = S>,
|
||||||
M: MultiMutator<I, Self::State>,
|
S: HasCorpus + HasRand + HasNamedMetadata + HasCurrentTestcase + HasCurrentCorpusId + UsesInput,
|
||||||
Z: Evaluator<E, EM>,
|
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone,
|
||||||
Z::State: HasCorpus + HasRand + HasNamedMetadata + HasCurrentTestcase,
|
<S::Corpus as Corpus>::Input: Input,
|
||||||
I: MutatedTransform<Self::Input, Self::State> + Clone,
|
S::Corpus: Corpus<Input = S::Input>,
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, //delete me
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
// Make sure we don't get stuck crashing on a single testcase
|
// Make sure we don't get stuck crashing on a single testcase
|
||||||
RetryCountRestartHelper::should_restart(state, &self.name, 3)
|
RetryCountRestartHelper::should_restart(state, &self.name, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,7 +343,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut testcase = state.current_testcase_mut()?;
|
let mut testcase = state.current_testcase_mut()?;
|
||||||
@ -386,17 +367,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, M, Z> MultiMutationalStage<E, EM, Z::Input, M, Z>
|
impl<E, EM, I, M, S, Z> MultiMutationalStage<E, EM, I, M, S, Z> {
|
||||||
where
|
|
||||||
Z: UsesState,
|
|
||||||
{
|
|
||||||
/// Creates a new [`MultiMutationalStage`]
|
/// Creates a new [`MultiMutationalStage`]
|
||||||
pub fn new(mutator: M) -> Self {
|
pub fn new(mutator: M) -> Self {
|
||||||
Self::transforming(mutator)
|
Self::transforming(mutator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> MultiMutationalStage<E, EM, I, M, Z> {
|
impl<E, EM, I, M, S, Z> MultiMutationalStage<E, EM, I, M, S, Z> {
|
||||||
/// Creates a new transforming mutational stage
|
/// Creates a new transforming mutational stage
|
||||||
pub fn transforming(mutator: M) -> Self {
|
pub fn transforming(mutator: M) -> Self {
|
||||||
// unsafe but impossible that you create two threads both instantiating this instance
|
// unsafe but impossible that you create two threads both instantiating this instance
|
||||||
|
@ -8,15 +8,24 @@ use core::{fmt::Debug, marker::PhantomData};
|
|||||||
|
|
||||||
use libafl_bolts::Named;
|
use libafl_bolts::Named;
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
use crate::monitors::PerfFeature;
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
corpus::{Corpus, HasCurrentCorpusId},
|
||||||
executors::{Executor, HasObservers},
|
executors::{Executor, HasObservers},
|
||||||
fuzzer::Evaluator,
|
fuzzer::Evaluator,
|
||||||
inputs::Input,
|
inputs::{Input, UsesInput},
|
||||||
mutators::Mutator,
|
mark_feature_time,
|
||||||
|
mutators::{MutationResult, Mutator},
|
||||||
schedulers::{testcase_score::CorpusPowerTestcaseScore, TestcaseScore},
|
schedulers::{testcase_score::CorpusPowerTestcaseScore, TestcaseScore},
|
||||||
stages::{mutational::MutatedTransform, MutationalStage, RetryCountRestartHelper, Stage},
|
stages::{
|
||||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, UsesState},
|
mutational::{MutatedTransform, MutatedTransformPost},
|
||||||
|
MutationalStage, RetryCountRestartHelper, Stage,
|
||||||
|
},
|
||||||
|
start_timer,
|
||||||
|
state::{
|
||||||
|
HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, MaybeHasClientPerfMonitor, UsesState,
|
||||||
|
},
|
||||||
Error, HasMetadata, HasNamedMetadata,
|
Error, HasMetadata, HasNamedMetadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -26,55 +35,41 @@ static mut POWER_MUTATIONAL_STAGE_ID: usize = 0;
|
|||||||
pub const POWER_MUTATIONAL_STAGE_NAME: &str = "power";
|
pub const POWER_MUTATIONAL_STAGE_NAME: &str = "power";
|
||||||
/// The mutational stage using power schedules
|
/// The mutational stage using power schedules
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PowerMutationalStage<E, F, EM, I, M, Z> {
|
pub struct PowerMutationalStage<E, F, EM, I, M, S, Z> {
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
/// The mutators we use
|
/// The mutators we use
|
||||||
mutator: M,
|
mutator: M,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
phantom: PhantomData<(E, F, EM, I, Z)>,
|
phantom: PhantomData<(E, F, EM, I, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, F, EM, I, M, Z> UsesState for PowerMutationalStage<E, F, EM, I, M, Z>
|
impl<E, F, EM, I, M, S, Z> Named for PowerMutationalStage<E, F, EM, I, M, S, Z> {
|
||||||
where
|
|
||||||
E: UsesState,
|
|
||||||
{
|
|
||||||
type State = E::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, F, EM, I, M, Z> Named for PowerMutationalStage<E, F, EM, I, M, Z> {
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, F, EM, I, M, Z> MutationalStage<E, EM, I, M, Z> for PowerMutationalStage<E, F, EM, I, M, Z>
|
impl<E, F, EM, I, M, S, Z> MutationalStage<S> for PowerMutationalStage<E, F, EM, I, M, S, Z>
|
||||||
where
|
where
|
||||||
E: Executor<EM, Z> + HasObservers,
|
S: HasCurrentTestcase,
|
||||||
EM: UsesState<State = Self::State>,
|
F: TestcaseScore<S>,
|
||||||
F: TestcaseScore<Self::State>,
|
|
||||||
I: Input,
|
|
||||||
M: Mutator<I, Self::State>,
|
|
||||||
E::State:
|
|
||||||
HasCorpus + HasMetadata + HasRand + HasExecutions + HasNamedMetadata + HasCurrentTestcase,
|
|
||||||
Z: Evaluator<E, EM, State = Self::State>,
|
|
||||||
I: MutatedTransform<E::Input, Self::State> + Clone,
|
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, //delete me
|
|
||||||
{
|
{
|
||||||
|
type Mutator = M;
|
||||||
/// The mutator, added to this stage
|
/// The mutator, added to this stage
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mutator(&self) -> &M {
|
fn mutator(&self) -> &Self::Mutator {
|
||||||
&self.mutator
|
&self.mutator
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The list of mutators, added to this stage (as mutable ref)
|
/// The list of mutators, added to this stage (as mutable ref)
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mutator_mut(&mut self) -> &mut M {
|
fn mutator_mut(&mut self) -> &mut Self::Mutator {
|
||||||
&mut self.mutator
|
&mut self.mutator
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the number of iterations as a random number
|
/// Gets the number of iterations as a random number
|
||||||
#[allow(clippy::cast_sign_loss)]
|
#[allow(clippy::cast_sign_loss)]
|
||||||
fn iterations(&self, state: &mut Self::State) -> Result<usize, Error> {
|
fn iterations(&self, state: &mut S) -> Result<usize, Error> {
|
||||||
// Update handicap
|
// Update handicap
|
||||||
let mut testcase = state.current_testcase_mut()?;
|
let mut testcase = state.current_testcase_mut()?;
|
||||||
let score = F::compute(state, &mut testcase)? as usize;
|
let score = F::compute(state, &mut testcase)? as usize;
|
||||||
@ -83,17 +78,24 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, F, EM, I, M, Z> Stage<E, EM, Z> for PowerMutationalStage<E, F, EM, I, M, Z>
|
impl<E, F, EM, I, M, S, Z> Stage<E, EM, S, Z> for PowerMutationalStage<E, F, EM, I, M, S, Z>
|
||||||
where
|
where
|
||||||
E: Executor<EM, Z> + HasObservers,
|
E: Executor<EM, Z, State = S> + HasObservers,
|
||||||
EM: UsesState<State = Self::State>,
|
EM: UsesState<State = S>,
|
||||||
F: TestcaseScore<Self::State>,
|
F: TestcaseScore<S>,
|
||||||
M: Mutator<I, Self::State>,
|
M: Mutator<I, S>,
|
||||||
E::State:
|
S: HasCorpus
|
||||||
HasCorpus + HasMetadata + HasRand + HasExecutions + HasNamedMetadata + HasCurrentTestcase,
|
+ HasMetadata
|
||||||
Z: Evaluator<E, EM, State = Self::State>,
|
+ HasRand
|
||||||
I: MutatedTransform<Self::Input, Self::State> + Clone + Input,
|
+ HasExecutions
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, //delete me
|
+ HasNamedMetadata
|
||||||
|
+ HasCurrentTestcase
|
||||||
|
+ HasCurrentCorpusId
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
Z: Evaluator<E, EM, State = S>,
|
||||||
|
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone + Input,
|
||||||
|
<S::Corpus as Corpus>::Input: Input,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(clippy::let_and_return)]
|
#[allow(clippy::let_and_return)]
|
||||||
@ -101,32 +103,39 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let ret = self.perform_mutational(fuzzer, executor, state, manager);
|
let ret = self.perform_mutational(fuzzer, executor, state, manager);
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
// Make sure we don't get stuck crashing on a single testcase
|
// Make sure we don't get stuck crashing on a single testcase
|
||||||
RetryCountRestartHelper::should_restart(state, &self.name, 3)
|
RetryCountRestartHelper::should_restart(state, &self.name, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, F, EM, I, M, Z> PowerMutationalStage<E, F, EM, I, M, Z>
|
impl<E, F, EM, I, M, S, Z> PowerMutationalStage<E, F, EM, I, M, S, Z>
|
||||||
where
|
where
|
||||||
E: Executor<EM, Z> + HasObservers,
|
E: Executor<EM, Z, State = S> + HasObservers,
|
||||||
EM: UsesState<State = <Self as UsesState>::State>,
|
EM: UsesState<State = S>,
|
||||||
F: TestcaseScore<<Self as UsesState>::State>,
|
F: TestcaseScore<S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
M: Mutator<I, <Self as UsesState>::State>,
|
M: Mutator<I, S>,
|
||||||
<Self as UsesState>::State: HasCorpus + HasMetadata + HasRand,
|
S: HasCorpus
|
||||||
Z: Evaluator<E, EM, State = <Self as UsesState>::State>,
|
+ HasMetadata
|
||||||
|
+ HasRand
|
||||||
|
+ HasCurrentTestcase
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone + Input,
|
||||||
|
Z: Evaluator<E, EM, State = S>,
|
||||||
|
<S::Corpus as Corpus>::Input: Input,
|
||||||
{
|
{
|
||||||
/// Creates a new [`PowerMutationalStage`]
|
/// Creates a new [`PowerMutationalStage`]
|
||||||
pub fn new(mutator: M) -> Self {
|
pub fn new(mutator: M) -> Self {
|
||||||
@ -144,8 +153,58 @@ where
|
|||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Runs this (mutational) stage for the given testcase
|
||||||
|
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
|
||||||
|
fn perform_mutational(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
executor: &mut E,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
start_timer!(state);
|
||||||
|
|
||||||
|
// Here saturating_sub is needed as self.iterations() might be actually smaller than the previous value before reset.
|
||||||
|
/*
|
||||||
|
let num = self
|
||||||
|
.iterations(state)?
|
||||||
|
.saturating_sub(self.execs_since_progress_start(state)?);
|
||||||
|
*/
|
||||||
|
let num = self.iterations(state)?;
|
||||||
|
let mut testcase = state.current_testcase_mut()?;
|
||||||
|
|
||||||
|
let Ok(input) = I::try_transform_from(&mut testcase, state) else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
drop(testcase);
|
||||||
|
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
||||||
|
|
||||||
|
for _ in 0..num {
|
||||||
|
let mut input = input.clone();
|
||||||
|
|
||||||
|
start_timer!(state);
|
||||||
|
let mutated = self.mutator_mut().mutate(state, &mut input)?;
|
||||||
|
mark_feature_time!(state, PerfFeature::Mutate);
|
||||||
|
|
||||||
|
if mutated == MutationResult::Skipped {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time is measured directly the `evaluate_input` function
|
||||||
|
let (untransformed, post) = input.try_transform_into(state)?;
|
||||||
|
let (_, corpus_id) = fuzzer.evaluate_input(state, executor, manager, untransformed)?;
|
||||||
|
|
||||||
|
start_timer!(state);
|
||||||
|
self.mutator_mut().post_exec(state, corpus_id)?;
|
||||||
|
post.post_exec(state, corpus_id)?;
|
||||||
|
mark_feature_time!(state, PerfFeature::MutatePostExec);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The standard powerscheduling stage
|
/// The standard powerscheduling stage
|
||||||
pub type StdPowerMutationalStage<E, EM, I, M, Z> =
|
pub type StdPowerMutationalStage<E, EM, I, M, S, Z> =
|
||||||
PowerMutationalStage<E, CorpusPowerTestcaseScore, EM, I, M, Z>;
|
PowerMutationalStage<E, CorpusPowerTestcaseScore, EM, I, M, S, Z>;
|
||||||
|
@ -8,62 +8,51 @@
|
|||||||
|
|
||||||
/// Mutational stage is the normal fuzzing stage.
|
/// Mutational stage is the normal fuzzing stage.
|
||||||
pub mod mutational;
|
pub mod mutational;
|
||||||
use alloc::rc::Rc;
|
use alloc::{
|
||||||
|
borrow::{Cow, ToOwned},
|
||||||
|
rc::Rc,
|
||||||
|
string::ToString,
|
||||||
|
};
|
||||||
use core::{
|
use core::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
time::Duration,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use libafl_bolts::Named;
|
||||||
pub use mutational::StdMutationalPushStage;
|
pub use mutational::StdMutationalPushStage;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::CorpusId,
|
common::HasNamedMetadata,
|
||||||
|
corpus::{Corpus, CorpusId, HasCurrentCorpusId},
|
||||||
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
|
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
|
||||||
executors::ExitKind,
|
executors::{Executor, ExitKind, HasObservers},
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
observers::ObserversTuple,
|
observers::ObserversTuple,
|
||||||
schedulers::Scheduler,
|
schedulers::Scheduler,
|
||||||
|
stages::{RetryCountRestartHelper, Stage},
|
||||||
state::{HasCorpus, HasExecutions, HasLastReportTime, HasRand},
|
state::{HasCorpus, HasExecutions, HasLastReportTime, HasRand},
|
||||||
Error, EvaluatorObservers, ExecutionProcessor, HasMetadata, HasScheduler,
|
Error, EvaluatorObservers, ExecutesInput, ExecutionProcessor, HasMetadata, HasScheduler,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Send a monitor update all 15 (or more) seconds
|
|
||||||
const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15);
|
|
||||||
|
|
||||||
// The shared state for all [`PushStage`]s
|
// The shared state for all [`PushStage`]s
|
||||||
/// Should be stored inside a `[Rc<RefCell<_>>`]
|
/// Should be stored inside a `[Rc<RefCell<_>>`]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PushStageSharedState<CS, EM, OT, Z>
|
pub struct PushStageSharedState<EM, I, OT, S, Z> {
|
||||||
where
|
|
||||||
CS: Scheduler<Z::Input, Z::State>,
|
|
||||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
|
||||||
OT: ObserversTuple<Z::Input, Z::State>,
|
|
||||||
Z::State: HasRand + HasCorpus,
|
|
||||||
Z: ExecutionProcessor<EM, OT> + EvaluatorObservers<EM, OT> + HasScheduler<Scheduler = CS>,
|
|
||||||
{
|
|
||||||
/// The [`crate::state::State`]
|
/// The [`crate::state::State`]
|
||||||
pub state: Z::State,
|
pub state: S,
|
||||||
/// The [`crate::fuzzer::Fuzzer`] instance
|
/// The [`crate::fuzzer::Fuzzer`] instance
|
||||||
pub fuzzer: Z,
|
pub fuzzer: Z,
|
||||||
/// The [`crate::events::EventManager`]
|
/// The [`crate::events::EventManager`]
|
||||||
pub event_mgr: EM,
|
pub event_mgr: EM,
|
||||||
/// The [`crate::observers::ObserversTuple`]
|
/// The [`crate::observers::ObserversTuple`]
|
||||||
pub observers: OT,
|
pub observers: OT,
|
||||||
phantom: PhantomData<(CS, Z)>,
|
phantom: PhantomData<I>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, EM, OT, Z> PushStageSharedState<CS, EM, OT, Z>
|
impl<EM, I, OT, S, Z> PushStageSharedState<EM, I, OT, S, Z> {
|
||||||
where
|
|
||||||
CS: Scheduler<Z::Input, Z::State>,
|
|
||||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
|
||||||
OT: ObserversTuple<Z::Input, Z::State>,
|
|
||||||
Z::State: HasRand + HasCorpus,
|
|
||||||
Z: ExecutionProcessor<EM, OT> + EvaluatorObservers<EM, OT> + HasScheduler<Scheduler = CS>,
|
|
||||||
{
|
|
||||||
/// Create a new `PushStageSharedState` that can be used by all [`PushStage`]s
|
/// Create a new `PushStageSharedState` that can be used by all [`PushStage`]s
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(fuzzer: Z, state: Z::State, observers: OT, event_mgr: EM) -> Self {
|
pub fn new(fuzzer: Z, state: S, observers: OT, event_mgr: EM) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state,
|
state,
|
||||||
fuzzer,
|
fuzzer,
|
||||||
@ -76,20 +65,13 @@ where
|
|||||||
|
|
||||||
/// Helper class for the [`PushStage`] trait, taking care of borrowing the shared state
|
/// Helper class for the [`PushStage`] trait, taking care of borrowing the shared state
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PushStageHelper<CS, EM, OT, Z>
|
pub struct PushStageHelper<EM, I, OT, S, Z> {
|
||||||
where
|
|
||||||
CS: Scheduler<Z::Input, Z::State>,
|
|
||||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
|
||||||
OT: ObserversTuple<Z::Input, Z::State>,
|
|
||||||
Z::State: HasRand + HasCorpus,
|
|
||||||
Z: ExecutionProcessor<EM, OT> + EvaluatorObservers<EM, OT> + HasScheduler<Scheduler = CS>,
|
|
||||||
{
|
|
||||||
/// If this stage has already been initalized.
|
/// If this stage has already been initalized.
|
||||||
/// This gets reset to `false` after one iteration of the stage is done.
|
/// This gets reset to `false` after one iteration of the stage is done.
|
||||||
pub initialized: bool,
|
pub initialized: bool,
|
||||||
/// The shared state, keeping track of the corpus and the fuzzer
|
/// The shared state, keeping track of the corpus and the fuzzer
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, OT, Z>>>>,
|
pub shared_state: Rc<RefCell<Option<PushStageSharedState<EM, I, OT, S, Z>>>>,
|
||||||
/// If the last iteration failed
|
/// If the last iteration failed
|
||||||
pub errored: bool,
|
pub errored: bool,
|
||||||
|
|
||||||
@ -97,32 +79,22 @@ where
|
|||||||
pub current_corpus_id: Option<CorpusId>,
|
pub current_corpus_id: Option<CorpusId>,
|
||||||
|
|
||||||
/// The input we just ran
|
/// The input we just ran
|
||||||
pub current_input: Option<<Z::State as UsesInput>::Input>, // Todo: Get rid of copy
|
pub current_input: Option<I>, // Todo: Get rid of copy
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
phantom: PhantomData<(CS, EM, OT, Z)>,
|
|
||||||
exit_kind: Rc<Cell<Option<ExitKind>>>,
|
exit_kind: Rc<Cell<Option<ExitKind>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, EM, OT, Z> PushStageHelper<CS, EM, OT, Z>
|
impl<EM, I, OT, S, Z> PushStageHelper<EM, I, OT, S, Z> {
|
||||||
where
|
|
||||||
CS: Scheduler<Z::Input, Z::State>,
|
|
||||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
|
||||||
OT: ObserversTuple<Z::Input, Z::State>,
|
|
||||||
Z::State: HasRand + HasCorpus,
|
|
||||||
Z: ExecutionProcessor<EM, OT> + EvaluatorObservers<EM, OT> + HasScheduler<Scheduler = CS>,
|
|
||||||
{
|
|
||||||
/// Create a new [`PushStageHelper`]
|
/// Create a new [`PushStageHelper`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, OT, Z>>>>,
|
shared_state: Rc<RefCell<Option<PushStageSharedState<EM, I, OT, S, Z>>>>,
|
||||||
exit_kind_ref: Rc<Cell<Option<ExitKind>>>,
|
exit_kind_ref: Rc<Cell<Option<ExitKind>>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
shared_state,
|
shared_state,
|
||||||
initialized: false,
|
initialized: false,
|
||||||
phantom: PhantomData,
|
|
||||||
exit_kind: exit_kind_ref,
|
exit_kind: exit_kind_ref,
|
||||||
errored: false,
|
errored: false,
|
||||||
current_input: None,
|
current_input: None,
|
||||||
@ -132,14 +104,14 @@ where
|
|||||||
|
|
||||||
/// Sets the shared state for this helper (and all other helpers owning the same [`RefCell`])
|
/// Sets the shared state for this helper (and all other helpers owning the same [`RefCell`])
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_shared_state(&mut self, shared_state: PushStageSharedState<CS, EM, OT, Z>) {
|
pub fn set_shared_state(&mut self, shared_state: PushStageSharedState<EM, I, OT, S, Z>) {
|
||||||
(*self.shared_state.borrow_mut()).replace(shared_state);
|
(*self.shared_state.borrow_mut()).replace(shared_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes the shared state from this helper, replacing it with `None`
|
/// Takes the shared state from this helper, replacing it with `None`
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn take_shared_state(&mut self) -> Option<PushStageSharedState<CS, EM, OT, Z>> {
|
pub fn take_shared_state(&mut self) -> Option<PushStageSharedState<EM, I, OT, S, Z>> {
|
||||||
let shared_state_ref = &mut (*self.shared_state).borrow_mut();
|
let shared_state_ref = &mut (*self.shared_state).borrow_mut();
|
||||||
shared_state_ref.take()
|
shared_state_ref.take()
|
||||||
}
|
}
|
||||||
@ -158,7 +130,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Resets this state after a full stage iter.
|
/// Resets this state after a full stage iter.
|
||||||
fn end_of_iter(&mut self, shared_state: PushStageSharedState<CS, EM, OT, Z>, errored: bool) {
|
fn end_of_iter(&mut self, shared_state: PushStageSharedState<EM, I, OT, S, Z>, errored: bool) {
|
||||||
self.set_shared_state(shared_state);
|
self.set_shared_state(shared_state);
|
||||||
self.errored = errored;
|
self.errored = errored;
|
||||||
self.current_corpus_id = None;
|
self.current_corpus_id = None;
|
||||||
@ -171,18 +143,11 @@ where
|
|||||||
/// A push stage is a generator that returns a single testcase for each call.
|
/// A push stage is a generator that returns a single testcase for each call.
|
||||||
/// It's an iterator so we can chain it.
|
/// It's an iterator so we can chain it.
|
||||||
/// After it has finished once, we will call it agan for the next fuzzer round.
|
/// After it has finished once, we will call it agan for the next fuzzer round.
|
||||||
pub trait PushStage<CS, EM, OT, Z>: Iterator
|
pub trait PushStage<EM, I, OT, S, Z> {
|
||||||
where
|
|
||||||
CS: Scheduler<Z::Input, Z::State>,
|
|
||||||
Z::State: HasRand + HasExecutions + HasMetadata + HasCorpus + HasLastReportTime,
|
|
||||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId + ProgressReporter,
|
|
||||||
OT: ObserversTuple<Z::Input, Z::State>,
|
|
||||||
Z: ExecutionProcessor<EM, OT> + EvaluatorObservers<EM, OT> + HasScheduler<Scheduler = CS>,
|
|
||||||
{
|
|
||||||
/// Gets the [`PushStageHelper`]
|
/// Gets the [`PushStageHelper`]
|
||||||
fn push_stage_helper(&self) -> &PushStageHelper<CS, EM, OT, Z>;
|
fn push_stage_helper(&self) -> &PushStageHelper<EM, I, OT, S, Z>;
|
||||||
/// Gets the [`PushStageHelper`] (mutable)
|
/// Gets the [`PushStageHelper`] (mutable)
|
||||||
fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<CS, EM, OT, Z>;
|
fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<EM, I, OT, S, Z>;
|
||||||
|
|
||||||
/// Set the current corpus index this stage works on
|
/// Set the current corpus index this stage works on
|
||||||
fn set_current_corpus_id(&mut self, corpus_id: CorpusId) {
|
fn set_current_corpus_id(&mut self, corpus_id: CorpusId) {
|
||||||
@ -196,7 +161,7 @@ where
|
|||||||
fn init(
|
fn init(
|
||||||
&mut self,
|
&mut self,
|
||||||
_fuzzer: &mut Z,
|
_fuzzer: &mut Z,
|
||||||
_state: &mut Z::State,
|
_state: &mut S,
|
||||||
_event_mgr: &mut EM,
|
_event_mgr: &mut EM,
|
||||||
_observers: &mut OT,
|
_observers: &mut OT,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
@ -209,20 +174,20 @@ where
|
|||||||
fn pre_exec(
|
fn pre_exec(
|
||||||
&mut self,
|
&mut self,
|
||||||
_fuzzer: &mut Z,
|
_fuzzer: &mut Z,
|
||||||
_state: &mut Z::State,
|
_state: &mut S,
|
||||||
_event_mgr: &mut EM,
|
_event_mgr: &mut EM,
|
||||||
_observers: &mut OT,
|
_observers: &mut OT,
|
||||||
) -> Option<Result<<Z::State as UsesInput>::Input, Error>>;
|
) -> Option<Result<I, Error>>;
|
||||||
|
|
||||||
/// Called after the execution of a testcase finished.
|
/// Called after the execution of a testcase finished.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn post_exec(
|
fn post_exec(
|
||||||
&mut self,
|
&mut self,
|
||||||
_fuzzer: &mut Z,
|
_fuzzer: &mut Z,
|
||||||
_state: &mut Z::State,
|
_state: &mut S,
|
||||||
_event_mgr: &mut EM,
|
_event_mgr: &mut EM,
|
||||||
_observers: &mut OT,
|
_observers: &mut OT,
|
||||||
_input: <Z::State as UsesInput>::Input,
|
_input: I,
|
||||||
_exit_kind: ExitKind,
|
_exit_kind: ExitKind,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -233,80 +198,127 @@ where
|
|||||||
fn deinit(
|
fn deinit(
|
||||||
&mut self,
|
&mut self,
|
||||||
_fuzzer: &mut Z,
|
_fuzzer: &mut Z,
|
||||||
_state: &mut Z::State,
|
_state: &mut S,
|
||||||
_event_mgr: &mut EM,
|
_event_mgr: &mut EM,
|
||||||
_observers: &mut OT,
|
_observers: &mut OT,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is the default implementation for `next` for this stage
|
|
||||||
fn next_std(&mut self) -> Option<Result<<Z::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 {
|
|
||||||
// We already ran once
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//for i in 0..num {
|
/// Allows us to use a [`PushStage`] as a normal [`Stage`]
|
||||||
let ret = self.pre_exec(
|
#[allow(clippy::type_complexity)]
|
||||||
&mut shared_state.fuzzer,
|
#[derive(Debug)]
|
||||||
&mut shared_state.state,
|
pub struct PushStageAdapter<CS, EM, OT, PS, Z> {
|
||||||
&mut shared_state.event_mgr,
|
name: Cow<'static, str>,
|
||||||
&mut shared_state.observers,
|
push_stage: PS,
|
||||||
);
|
phantom: PhantomData<(CS, EM, OT, Z)>,
|
||||||
if ret.is_none() {
|
|
||||||
// We're done.
|
|
||||||
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);
|
impl<CS, EM, OT, PS, Z> PushStageAdapter<CS, EM, OT, PS, Z> {
|
||||||
|
/// Create a new [`PushStageAdapter`], wrapping the given [`PushStage`]
|
||||||
|
/// to be used as a normal [`Stage`]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(push_stage: PS) -> Self {
|
||||||
|
// unsafe but impossible that you create two threads both instantiating this instance
|
||||||
|
let stage_id = unsafe {
|
||||||
|
let ret = PUSH_STAGE_ADAPTER_ID;
|
||||||
|
PUSH_STAGE_ADAPTER_ID += 1;
|
||||||
ret
|
ret
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
name: Cow::Owned(
|
||||||
|
PUSH_STAGE_ADAPTER_NAME.to_owned() + ":" + stage_id.to_string().as_str(),
|
||||||
|
),
|
||||||
|
push_stage,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// The unique counter for this stage
|
||||||
|
static mut PUSH_STAGE_ADAPTER_ID: usize = 0;
|
||||||
|
/// The name for push stage adapter
|
||||||
|
pub static PUSH_STAGE_ADAPTER_NAME: &str = "pushstageadapter";
|
||||||
|
|
||||||
|
impl<CS, EM, OT, PS, Z> Named for PushStageAdapter<CS, EM, OT, PS, Z> {
|
||||||
|
#[must_use]
|
||||||
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<CS, E, EM, OT, PS, S, Z> Stage<E, EM, S, Z> for PushStageAdapter<CS, EM, OT, PS, Z>
|
||||||
|
where
|
||||||
|
CS: Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||||
|
S: HasExecutions
|
||||||
|
+ HasRand
|
||||||
|
+ HasCorpus
|
||||||
|
+ HasLastReportTime
|
||||||
|
+ HasCurrentCorpusId
|
||||||
|
+ HasNamedMetadata
|
||||||
|
+ HasMetadata
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
E: Executor<EM, Z, State = S> + HasObservers<Observers = OT>,
|
||||||
|
EM: EventFirer<State = S> + EventRestarter + HasEventManagerId + ProgressReporter<State = S>,
|
||||||
|
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||||
|
PS: PushStage<EM, <S::Corpus as Corpus>::Input, OT, S, Z>,
|
||||||
|
Z: ExecutesInput<E, EM, State = S>
|
||||||
|
+ ExecutionProcessor<EM, OT>
|
||||||
|
+ EvaluatorObservers<EM, OT>
|
||||||
|
+ HasScheduler<Scheduler = CS>,
|
||||||
|
{
|
||||||
|
fn perform(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
executor: &mut E,
|
||||||
|
state: &mut S,
|
||||||
|
event_mgr: &mut EM,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let push_stage = &mut self.push_stage;
|
||||||
|
|
||||||
|
let Some(corpus_id) = state.current_corpus_id()? else {
|
||||||
|
return Err(Error::illegal_state(
|
||||||
|
"state is not currently processing a corpus index",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
push_stage.set_current_corpus_id(corpus_id);
|
||||||
|
|
||||||
|
push_stage.init(fuzzer, state, event_mgr, &mut *executor.observers_mut())?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let input =
|
||||||
|
match push_stage.pre_exec(fuzzer, state, event_mgr, &mut *executor.observers_mut())
|
||||||
|
{
|
||||||
|
Some(Ok(next_input)) => next_input,
|
||||||
|
Some(Err(err)) => return Err(err),
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
|
||||||
|
let exit_kind = fuzzer.execute_input(state, executor, event_mgr, &input)?;
|
||||||
|
|
||||||
|
push_stage.post_exec(
|
||||||
|
fuzzer,
|
||||||
|
state,
|
||||||
|
event_mgr,
|
||||||
|
&mut *executor.observers_mut(),
|
||||||
|
input,
|
||||||
|
exit_kind,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.push_stage
|
||||||
|
.deinit(fuzzer, state, event_mgr, &mut *executor.observers_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
|
// TODO: Proper restart handling - call post_exec at the right time, etc...
|
||||||
|
RetryCountRestartHelper::no_retry(state, &self.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,22 +11,23 @@ use libafl_bolts::rands::Rand;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::{PushStage, PushStageHelper, PushStageSharedState};
|
use super::{PushStage, PushStageHelper, PushStageSharedState};
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
use crate::monitors::PerfFeature;
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, CorpusId},
|
corpus::{Corpus, CorpusId},
|
||||||
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
|
events::{EventFirer, ProgressReporter},
|
||||||
executors::ExitKind,
|
executors::ExitKind,
|
||||||
inputs::UsesInput,
|
fuzzer::STATS_TIMEOUT_DEFAULT,
|
||||||
|
inputs::{Input, UsesInput},
|
||||||
mark_feature_time,
|
mark_feature_time,
|
||||||
mutators::Mutator,
|
mutators::Mutator,
|
||||||
nonzero,
|
nonzero,
|
||||||
observers::ObserversTuple,
|
observers::ObserversTuple,
|
||||||
schedulers::Scheduler,
|
schedulers::Scheduler,
|
||||||
start_timer,
|
start_timer,
|
||||||
state::{HasCorpus, HasExecutions, HasLastReportTime, HasRand, UsesState},
|
state::{HasCorpus, HasExecutions, HasLastReportTime, HasRand, MaybeHasClientPerfMonitor},
|
||||||
Error, EvaluatorObservers, ExecutionProcessor, HasMetadata, HasScheduler,
|
Error, ExecutionProcessor, HasMetadata, HasScheduler,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "introspection")]
|
|
||||||
use crate::{monitors::PerfFeature, state::HasClientPerfMonitor};
|
|
||||||
|
|
||||||
/// The default maximum number of mutations to perform per input.
|
/// The default maximum number of mutations to perform per input.
|
||||||
pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128;
|
pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128;
|
||||||
@ -42,14 +43,10 @@ pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128;
|
|||||||
///
|
///
|
||||||
/// The default mutational push stage
|
/// The default mutational push stage
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct StdMutationalPushStage<CS, EM, M, OT, Z>
|
pub struct StdMutationalPushStage<EM, M, OT, S, Z>
|
||||||
where
|
where
|
||||||
CS: Scheduler<Z::Input, Z::State>,
|
S: HasCorpus,
|
||||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
<S::Corpus as Corpus>::Input: Clone + Debug,
|
||||||
M: Mutator<Z::Input, Z::State>,
|
|
||||||
OT: ObserversTuple<Z::Input, Z::State> + Serialize,
|
|
||||||
Z::State: HasRand + HasCorpus + Clone + Debug,
|
|
||||||
Z: ExecutionProcessor<EM, OT> + EvaluatorObservers<EM, OT> + HasScheduler<Scheduler = CS>,
|
|
||||||
{
|
{
|
||||||
current_corpus_id: Option<CorpusId>,
|
current_corpus_id: Option<CorpusId>,
|
||||||
testcases_to_do: usize,
|
testcases_to_do: usize,
|
||||||
@ -57,21 +54,17 @@ where
|
|||||||
|
|
||||||
mutator: M,
|
mutator: M,
|
||||||
|
|
||||||
psh: PushStageHelper<CS, EM, OT, Z>,
|
psh: PushStageHelper<EM, <S::Corpus as Corpus>::Input, OT, S, Z>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z>
|
impl<EM, M, OT, S, Z> StdMutationalPushStage<EM, M, OT, S, Z>
|
||||||
where
|
where
|
||||||
CS: Scheduler<Z::Input, Z::State>,
|
S: HasCorpus + HasRand,
|
||||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
<S::Corpus as Corpus>::Input: Clone + Debug,
|
||||||
M: Mutator<Z::Input, Z::State>,
|
|
||||||
OT: ObserversTuple<Z::Input, Z::State> + Serialize,
|
|
||||||
Z::State: HasCorpus + HasRand + Clone + Debug,
|
|
||||||
Z: ExecutionProcessor<EM, OT> + EvaluatorObservers<EM, OT> + HasScheduler<Scheduler = CS>,
|
|
||||||
{
|
{
|
||||||
/// Gets the number of iterations as a random number
|
/// Gets the number of iterations as a random number
|
||||||
#[allow(clippy::unused_self, clippy::unnecessary_wraps)] // TODO: we should put this function into a trait later
|
#[allow(clippy::unused_self, clippy::unnecessary_wraps)] // TODO: we should put this function into a trait later
|
||||||
fn iterations(&self, state: &mut Z::State, _corpus_id: CorpusId) -> Result<usize, Error> {
|
fn iterations(&self, state: &mut S, _corpus_id: CorpusId) -> Result<usize, Error> {
|
||||||
Ok(1 + state
|
Ok(1 + state
|
||||||
.rand_mut()
|
.rand_mut()
|
||||||
.below(nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS)))
|
.below(nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS)))
|
||||||
@ -83,23 +76,28 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, EM, M, OT, Z> PushStage<CS, EM, OT, Z> for StdMutationalPushStage<CS, EM, M, OT, Z>
|
impl<EM, M, OT, S, Z> PushStage<EM, <S::Corpus as Corpus>::Input, OT, S, Z>
|
||||||
|
for StdMutationalPushStage<EM, M, OT, S, Z>
|
||||||
where
|
where
|
||||||
CS: Scheduler<Z::Input, Z::State>,
|
EM: EventFirer<State = S>,
|
||||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId + ProgressReporter,
|
Z: HasScheduler<State = S> + ExecutionProcessor<EM, OT>,
|
||||||
M: Mutator<Z::Input, Z::State>,
|
S: HasCorpus
|
||||||
OT: ObserversTuple<Z::Input, Z::State> + Serialize,
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>
|
||||||
Z::State: HasCorpus + HasRand + HasExecutions + HasLastReportTime + HasMetadata + Clone + Debug,
|
+ HasRand
|
||||||
Z: ExecutionProcessor<EM, OT> + EvaluatorObservers<EM, OT> + HasScheduler<Scheduler = CS>,
|
+ MaybeHasClientPerfMonitor,
|
||||||
<<Z as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Z::Input>, //delete me
|
M: Mutator<<S::Corpus as Corpus>::Input, S>,
|
||||||
|
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||||
|
<S::Corpus as Corpus>::Input: Input + Clone,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn push_stage_helper(&self) -> &PushStageHelper<CS, EM, OT, Z> {
|
fn push_stage_helper(&self) -> &PushStageHelper<EM, <S::Corpus as Corpus>::Input, OT, S, Z> {
|
||||||
&self.psh
|
&self.psh
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<CS, EM, OT, Z> {
|
fn push_stage_helper_mut(
|
||||||
|
&mut self,
|
||||||
|
) -> &mut PushStageHelper<EM, <S::Corpus as Corpus>::Input, OT, S, Z> {
|
||||||
&mut self.psh
|
&mut self.psh
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +105,7 @@ where
|
|||||||
fn init(
|
fn init(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
state: &mut Z::State,
|
state: &mut S,
|
||||||
_event_mgr: &mut EM,
|
_event_mgr: &mut EM,
|
||||||
_observers: &mut OT,
|
_observers: &mut OT,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
@ -126,10 +124,10 @@ where
|
|||||||
fn pre_exec(
|
fn pre_exec(
|
||||||
&mut self,
|
&mut self,
|
||||||
_fuzzer: &mut Z,
|
_fuzzer: &mut Z,
|
||||||
state: &mut Z::State,
|
state: &mut S,
|
||||||
_event_mgr: &mut EM,
|
_event_mgr: &mut EM,
|
||||||
_observers: &mut OT,
|
_observers: &mut OT,
|
||||||
) -> Option<Result<<Z::State as UsesInput>::Input, Error>> {
|
) -> Option<Result<<S::Corpus as Corpus>::Input, Error>> {
|
||||||
if self.testcases_done >= self.testcases_to_do {
|
if self.testcases_done >= self.testcases_to_do {
|
||||||
// finished with this cicle.
|
// finished with this cicle.
|
||||||
return None;
|
return None;
|
||||||
@ -161,10 +159,10 @@ where
|
|||||||
fn post_exec(
|
fn post_exec(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
state: &mut Z::State,
|
state: &mut S,
|
||||||
event_mgr: &mut EM,
|
event_mgr: &mut EM,
|
||||||
observers: &mut OT,
|
observers: &mut OT,
|
||||||
last_input: <Z::State as UsesInput>::Input,
|
last_input: <S::Corpus as Corpus>::Input,
|
||||||
exit_kind: ExitKind,
|
exit_kind: ExitKind,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// todo: is_interesting, etc.
|
// todo: is_interesting, etc.
|
||||||
@ -183,7 +181,7 @@ where
|
|||||||
fn deinit(
|
fn deinit(
|
||||||
&mut self,
|
&mut self,
|
||||||
_fuzzer: &mut Z,
|
_fuzzer: &mut Z,
|
||||||
_state: &mut Z::State,
|
_state: &mut S,
|
||||||
_event_mgr: &mut EM,
|
_event_mgr: &mut EM,
|
||||||
_observers: &mut OT,
|
_observers: &mut OT,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
@ -192,38 +190,51 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, EM, M, OT, Z> Iterator for StdMutationalPushStage<CS, EM, M, OT, Z>
|
impl<EM, M, OT, S, Z> Iterator for StdMutationalPushStage<EM, M, OT, S, Z>
|
||||||
where
|
where
|
||||||
CS: Scheduler<Z::Input, Z::State>,
|
EM: ProgressReporter<State = S>,
|
||||||
EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = Z::State>,
|
S: HasCorpus
|
||||||
M: Mutator<Z::Input, Z::State>,
|
+ HasMetadata
|
||||||
OT: ObserversTuple<Z::Input, Z::State> + Serialize,
|
+ HasExecutions
|
||||||
Z::State: HasCorpus + HasRand + HasExecutions + HasMetadata + HasLastReportTime + Clone + Debug,
|
+ HasLastReportTime
|
||||||
Z: ExecutionProcessor<EM, OT> + EvaluatorObservers<EM, OT> + HasScheduler<Scheduler = CS>,
|
+ HasRand
|
||||||
<<Z as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Z::Input>, //delete me
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||||
|
M: Mutator<<S::Corpus as Corpus>::Input, S>,
|
||||||
|
<S::Corpus as Corpus>::Input: Clone + Debug + Input,
|
||||||
|
Z: HasScheduler<State = S> + ExecutionProcessor<EM, OT>,
|
||||||
{
|
{
|
||||||
type Item = Result<<Z::State as UsesInput>::Input, Error>;
|
type Item = Result<<S::Corpus as Corpus>::Input, Error>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Result<<Z::State as UsesInput>::Input, Error>> {
|
fn next(&mut self) -> Option<Result<<S::Corpus as Corpus>::Input, Error>> {
|
||||||
self.next_std()
|
self.next_std()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z>
|
impl<EM, M, OT, S, Z> StdMutationalPushStage<EM, M, OT, S, Z>
|
||||||
where
|
where
|
||||||
CS: Scheduler<Z::Input, Z::State>,
|
EM: ProgressReporter<State = S>,
|
||||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
S: HasCorpus
|
||||||
M: Mutator<Z::Input, Z::State>,
|
+ HasMetadata
|
||||||
OT: ObserversTuple<Z::Input, Z::State> + Serialize,
|
+ HasExecutions
|
||||||
Z::State: HasCorpus + HasRand + Clone + Debug,
|
+ HasLastReportTime
|
||||||
Z: ExecutionProcessor<EM, OT> + EvaluatorObservers<EM, OT> + HasScheduler<Scheduler = CS>,
|
+ HasRand
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||||
|
M: Mutator<<S::Corpus as Corpus>::Input, S>,
|
||||||
|
<S::Corpus as Corpus>::Input: Clone + Debug + Input,
|
||||||
|
Z: HasScheduler<State = S> + ExecutionProcessor<EM, OT>,
|
||||||
{
|
{
|
||||||
/// Creates a new default mutational stage
|
/// Creates a new default mutational stage
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
mutator: M,
|
mutator: M,
|
||||||
shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, OT, Z>>>>,
|
shared_state: Rc<
|
||||||
|
RefCell<Option<PushStageSharedState<EM, <S::Corpus as Corpus>::Input, OT, S, Z>>>,
|
||||||
|
>,
|
||||||
exit_kind: Rc<Cell<Option<ExitKind>>>,
|
exit_kind: Rc<Cell<Option<ExitKind>>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -234,4 +245,74 @@ where
|
|||||||
testcases_done: 0,
|
testcases_done: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is the implementation for `next` for this stage
|
||||||
|
pub fn next_std(&mut self) -> Option<Result<<S::Corpus as Corpus>::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 {
|
||||||
|
// We already ran once
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
//for i in 0..num {
|
||||||
|
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() {
|
||||||
|
// We're done.
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,181 +0,0 @@
|
|||||||
//! Stage to compute/report minimal AFL-like stats
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use alloc::{borrow::Cow, string::ToString};
|
|
||||||
use core::{marker::PhantomData, time::Duration};
|
|
||||||
|
|
||||||
use libafl_bolts::current_time;
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use serde_json::json;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
corpus::{Corpus, HasCurrentCorpusId},
|
|
||||||
events::EventFirer,
|
|
||||||
schedulers::minimizer::IsFavoredMetadata,
|
|
||||||
stages::Stage,
|
|
||||||
state::{HasCorpus, HasImported, UsesState},
|
|
||||||
Error, HasMetadata,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use crate::{
|
|
||||||
events::Event,
|
|
||||||
monitors::{AggregatorOps, UserStats, UserStatsValue},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The [`StatsStage`] is a simple stage that computes and reports some stats.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct StatsStage<E, EM, Z> {
|
|
||||||
// the number of testcases that have been fuzzed
|
|
||||||
has_fuzzed_size: usize,
|
|
||||||
// the number of "favored" testcases
|
|
||||||
is_favored_size: usize,
|
|
||||||
// the number of testcases found by itself
|
|
||||||
own_finds_size: usize,
|
|
||||||
// the number of testcases imported by other fuzzers
|
|
||||||
imported_size: usize,
|
|
||||||
// the last time that we report all stats
|
|
||||||
last_report_time: Duration,
|
|
||||||
// the interval that we report all stats
|
|
||||||
stats_report_interval: Duration,
|
|
||||||
|
|
||||||
phantom: PhantomData<(E, EM, Z)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, Z> UsesState for StatsStage<E, EM, Z>
|
|
||||||
where
|
|
||||||
E: UsesState,
|
|
||||||
{
|
|
||||||
type State = E::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, Z> Stage<E, EM, Z> for StatsStage<E, EM, Z>
|
|
||||||
where
|
|
||||||
E: UsesState,
|
|
||||||
EM: EventFirer<State = Self::State>,
|
|
||||||
Z: UsesState<State = Self::State>,
|
|
||||||
Self::State: HasImported + HasCorpus + HasMetadata,
|
|
||||||
{
|
|
||||||
fn perform(
|
|
||||||
&mut self,
|
|
||||||
_fuzzer: &mut Z,
|
|
||||||
_executor: &mut E,
|
|
||||||
state: &mut Self::State,
|
|
||||||
_manager: &mut EM,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
self.update_and_report_afl_stats(state, _manager)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn should_restart(&mut self, _state: &mut Self::State) -> Result<bool, Error> {
|
|
||||||
// Not running the target so we wont't crash/timeout and, hence, don't need to restore anything
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> {
|
|
||||||
// Not running the target so we wont't crash/timeout and, hence, don't need to restore anything
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, Z> StatsStage<E, EM, Z> {
|
|
||||||
fn update_and_report_afl_stats(
|
|
||||||
&mut self,
|
|
||||||
state: &mut <Self as UsesState>::State,
|
|
||||||
_manager: &mut EM,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
E: UsesState,
|
|
||||||
EM: EventFirer<State = E::State>,
|
|
||||||
<Self as UsesState>::State: HasCorpus + HasImported,
|
|
||||||
{
|
|
||||||
let Some(corpus_id) = state.current_corpus_id()? else {
|
|
||||||
return Err(Error::illegal_state(
|
|
||||||
"state is not currently processing a corpus index",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Report your stats every `STATS_REPORT_INTERVAL`
|
|
||||||
// compute pending, pending_favored, imported, own_finds
|
|
||||||
{
|
|
||||||
let testcase = state.corpus().get(corpus_id)?.borrow();
|
|
||||||
if testcase.scheduled_count() == 0 {
|
|
||||||
self.has_fuzzed_size += 1;
|
|
||||||
if testcase.has_metadata::<IsFavoredMetadata>() {
|
|
||||||
self.is_favored_size += 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let corpus_size = state.corpus().count();
|
|
||||||
let pending_size = corpus_size - self.has_fuzzed_size;
|
|
||||||
let pend_favored_size = corpus_size - self.is_favored_size;
|
|
||||||
self.imported_size = *state.imported();
|
|
||||||
self.own_finds_size = corpus_size - self.imported_size;
|
|
||||||
|
|
||||||
let cur = current_time();
|
|
||||||
|
|
||||||
if cur.checked_sub(self.last_report_time).unwrap_or_default() > self.stats_report_interval {
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
{
|
|
||||||
let json = json!({
|
|
||||||
"pending":pending_size,
|
|
||||||
"pend_fav":pend_favored_size,
|
|
||||||
"own_finds":self.own_finds_size,
|
|
||||||
"imported":self.imported_size,
|
|
||||||
});
|
|
||||||
_manager.fire(
|
|
||||||
state,
|
|
||||||
Event::UpdateUserStats {
|
|
||||||
name: Cow::from("Stats"),
|
|
||||||
value: UserStats::new(
|
|
||||||
UserStatsValue::String(Cow::from(json.to_string())),
|
|
||||||
AggregatorOps::None,
|
|
||||||
),
|
|
||||||
phantom: PhantomData,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
log::info!(
|
|
||||||
"pending: {}, pend_favored: {}, own_finds: {}, imported: {}",
|
|
||||||
pending_size,
|
|
||||||
pend_favored_size,
|
|
||||||
self.own_finds_size,
|
|
||||||
self.imported_size
|
|
||||||
);
|
|
||||||
self.last_report_time = cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, Z> StatsStage<E, EM, Z> {
|
|
||||||
/// create a new instance of the [`StatsStage`]
|
|
||||||
#[must_use]
|
|
||||||
pub fn new(interval: Duration) -> Self {
|
|
||||||
Self {
|
|
||||||
stats_report_interval: interval,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, Z> Default for StatsStage<E, EM, Z> {
|
|
||||||
/// the default instance of the [`StatsStage`]
|
|
||||||
#[must_use]
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
has_fuzzed_size: 0,
|
|
||||||
is_favored_size: 0,
|
|
||||||
own_finds_size: 0,
|
|
||||||
imported_size: 0,
|
|
||||||
last_report_time: current_time(),
|
|
||||||
stats_report_interval: Duration::from_secs(15),
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,16 +10,14 @@ use std::path::{Path, PathBuf};
|
|||||||
use libafl_bolts::{current_time, fs::find_new_files_rec, shmem::ShMemProvider, Named};
|
use libafl_bolts::{current_time, fs::find_new_files_rec, shmem::ShMemProvider, Named};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
|
||||||
use crate::state::HasClientPerfMonitor;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, CorpusId},
|
corpus::{Corpus, CorpusId, HasCurrentCorpusId},
|
||||||
events::{llmp::LlmpEventConverter, Event, EventConfig, EventFirer},
|
events::{llmp::LlmpEventConverter, Event, EventConfig, EventFirer},
|
||||||
executors::{Executor, ExitKind, HasObservers},
|
executors::{Executor, ExitKind, HasObservers},
|
||||||
fuzzer::{Evaluator, EvaluatorObservers, ExecutionProcessor},
|
fuzzer::{Evaluator, EvaluatorObservers, ExecutionProcessor},
|
||||||
inputs::{Input, InputConverter, UsesInput},
|
inputs::{Input, InputConverter, UsesInput},
|
||||||
stages::{RetryCountRestartHelper, Stage},
|
stages::{RetryCountRestartHelper, Stage},
|
||||||
state::{HasCorpus, HasExecutions, HasRand, State, UsesState},
|
state::{HasCorpus, HasExecutions, HasRand, MaybeHasClientPerfMonitor, State, Stoppable},
|
||||||
Error, HasMetadata, HasNamedMetadata,
|
Error, HasMetadata, HasNamedMetadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,41 +52,38 @@ impl SyncFromDiskMetadata {
|
|||||||
|
|
||||||
/// A stage that loads testcases from disk to sync with other fuzzers such as AFL++
|
/// A stage that loads testcases from disk to sync with other fuzzers such as AFL++
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SyncFromDiskStage<CB, E, EM, Z> {
|
pub struct SyncFromDiskStage<CB, E, EM, S, Z> {
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
sync_dirs: Vec<PathBuf>,
|
sync_dirs: Vec<PathBuf>,
|
||||||
load_callback: CB,
|
load_callback: CB,
|
||||||
interval: Duration,
|
interval: Duration,
|
||||||
phantom: PhantomData<(E, EM, Z)>,
|
phantom: PhantomData<(E, EM, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB, E, EM, Z> UsesState for SyncFromDiskStage<CB, E, EM, Z>
|
impl<CB, E, EM, S, Z> Named for SyncFromDiskStage<CB, E, EM, S, Z> {
|
||||||
where
|
|
||||||
Z: UsesState,
|
|
||||||
{
|
|
||||||
type State = Z::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<CB, E, EM, Z> Named for SyncFromDiskStage<CB, E, EM, Z> {
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB, E, EM, Z> Stage<E, EM, Z> for SyncFromDiskStage<CB, E, EM, Z>
|
impl<CB, E, EM, S, Z> Stage<E, EM, S, Z> for SyncFromDiskStage<CB, E, EM, S, Z>
|
||||||
where
|
where
|
||||||
CB: FnMut(&mut Z, &mut Self::State, &Path) -> Result<<Self::State as UsesInput>::Input, Error>,
|
CB: FnMut(&mut Z, &mut S, &Path) -> Result<<S::Corpus as Corpus>::Input, Error>,
|
||||||
E: UsesState<State = Self::State>,
|
Z: Evaluator<E, EM, State = S>,
|
||||||
EM: UsesState<State = Self::State>,
|
S: HasCorpus
|
||||||
Z: Evaluator<E, EM>,
|
+ HasRand
|
||||||
Self::State: HasCorpus + HasRand + HasMetadata + HasNamedMetadata,
|
+ HasMetadata
|
||||||
|
+ HasNamedMetadata
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>
|
||||||
|
+ HasCurrentCorpusId
|
||||||
|
+ MaybeHasClientPerfMonitor,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let last = state
|
let last = state
|
||||||
@ -144,19 +139,19 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
// TODO: Needs proper crash handling for when an imported testcase crashes
|
// TODO: Needs proper crash handling for when an imported testcase crashes
|
||||||
// For now, Make sure we don't get stuck crashing on this testcase
|
// For now, Make sure we don't get stuck crashing on this testcase
|
||||||
RetryCountRestartHelper::no_retry(state, &self.name)
|
RetryCountRestartHelper::no_retry(state, &self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CB, E, EM, Z> SyncFromDiskStage<CB, E, EM, Z> {
|
impl<CB, E, EM, S, Z> SyncFromDiskStage<CB, E, EM, S, Z> {
|
||||||
/// Creates a new [`SyncFromDiskStage`]
|
/// Creates a new [`SyncFromDiskStage`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(sync_dirs: Vec<PathBuf>, load_callback: CB, interval: Duration, name: &str) -> Self {
|
pub fn new(sync_dirs: Vec<PathBuf>, load_callback: CB, interval: Duration, name: &str) -> Self {
|
||||||
@ -174,10 +169,8 @@ impl<CB, E, EM, Z> SyncFromDiskStage<CB, E, EM, Z> {
|
|||||||
pub type SyncFromDiskFunction<S, Z> =
|
pub type SyncFromDiskFunction<S, Z> =
|
||||||
fn(&mut Z, &mut S, &Path) -> Result<<S as UsesInput>::Input, Error>;
|
fn(&mut Z, &mut S, &Path) -> Result<<S as UsesInput>::Input, Error>;
|
||||||
|
|
||||||
impl<E, EM, Z> SyncFromDiskStage<SyncFromDiskFunction<Z::State, Z>, E, EM, Z>
|
impl<E, EM, S, Z> SyncFromDiskStage<SyncFromDiskFunction<Z::State, Z>, E, EM, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState<State = <Self as UsesState>::State>,
|
|
||||||
EM: UsesState<State = <Self as UsesState>::State>,
|
|
||||||
Z: Evaluator<E, EM>,
|
Z: Evaluator<E, EM>,
|
||||||
{
|
{
|
||||||
/// Creates a new [`SyncFromDiskStage`] invoking `Input::from_file` to load inputs
|
/// Creates a new [`SyncFromDiskStage`] invoking `Input::from_file` to load inputs
|
||||||
@ -234,38 +227,31 @@ where
|
|||||||
client: LlmpEventConverter<DI, IC, ICB, S, SP>,
|
client: LlmpEventConverter<DI, IC, ICB, S, SP>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DI, IC, ICB, S, SP> UsesState for SyncFromBrokerStage<DI, IC, ICB, S, SP>
|
impl<E, EM, IC, ICB, DI, S, SP, Z> Stage<E, EM, S, Z> for SyncFromBrokerStage<DI, IC, ICB, S, SP>
|
||||||
where
|
where
|
||||||
SP: ShMemProvider + 'static,
|
EM: EventFirer<State = S>,
|
||||||
S: State,
|
S: HasExecutions
|
||||||
IC: InputConverter<From = S::Input, To = DI>,
|
+ HasCorpus
|
||||||
ICB: InputConverter<From = DI, To = S::Input>,
|
+ HasRand
|
||||||
DI: Input,
|
+ HasMetadata
|
||||||
{
|
+ Stoppable
|
||||||
type State = S;
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>
|
||||||
}
|
+ State,
|
||||||
|
|
||||||
impl<E, EM, IC, ICB, DI, S, SP, Z> Stage<E, EM, Z> for SyncFromBrokerStage<DI, IC, ICB, S, SP>
|
|
||||||
where
|
|
||||||
EM: UsesState<State = S> + EventFirer,
|
|
||||||
S: State + HasExecutions + HasCorpus + HasRand + HasMetadata,
|
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
E: HasObservers + Executor<EM, Z, State = S>,
|
E: HasObservers + Executor<EM, Z, State = S>,
|
||||||
for<'a> E::Observers: Deserialize<'a>,
|
for<'a> E::Observers: Deserialize<'a>,
|
||||||
Z: EvaluatorObservers<EM, E::Observers, State = S>
|
Z: EvaluatorObservers<EM, E::Observers> + ExecutionProcessor<EM, E::Observers, State = S>,
|
||||||
+ ExecutionProcessor<EM, E::Observers, State = S>,
|
IC: InputConverter<From = <S::Corpus as Corpus>::Input, To = DI>,
|
||||||
IC: InputConverter<From = S::Input, To = DI>,
|
ICB: InputConverter<From = DI, To = <S::Corpus as Corpus>::Input>,
|
||||||
ICB: InputConverter<From = DI, To = S::Input>,
|
|
||||||
DI: Input,
|
DI: Input,
|
||||||
<<S as HasCorpus>::Corpus as Corpus>::Input: Clone,
|
<<S as HasCorpus>::Corpus as Corpus>::Input: Input + Clone,
|
||||||
S::Corpus: Corpus<Input = S::Input>, // delete me
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if self.client.can_convert() {
|
if self.client.can_convert() {
|
||||||
@ -319,13 +305,13 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn should_restart(&mut self, _state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, _state: &mut S) -> Result<bool, Error> {
|
||||||
// No restart handling needed - does not execute the target.
|
// No restart handling needed - does not execute the target.
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> {
|
||||||
// Not needed - does not execute the target.
|
// Not needed - does not execute the target.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,7 @@ use std::{marker::PhantomData, time::Duration};
|
|||||||
|
|
||||||
use libafl_bolts::{current_time, Error};
|
use libafl_bolts::{current_time, Error};
|
||||||
|
|
||||||
use crate::{
|
use crate::{stages::Stage, HasMetadata};
|
||||||
inputs::UsesInput,
|
|
||||||
stages::Stage,
|
|
||||||
state::{State, UsesState},
|
|
||||||
HasMetadata,
|
|
||||||
};
|
|
||||||
/// Track an inner Stage's execution time
|
/// Track an inner Stage's execution time
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TimeTrackingStageWrapper<T, S, ST> {
|
pub struct TimeTrackingStageWrapper<T, S, ST> {
|
||||||
@ -28,27 +23,17 @@ impl<T, S, ST> TimeTrackingStageWrapper<T, S, ST> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S, ST> UsesState for TimeTrackingStageWrapper<T, S, ST>
|
impl<T, E, M, Z, S, ST> Stage<E, M, S, Z> for TimeTrackingStageWrapper<T, S, ST>
|
||||||
where
|
where
|
||||||
S: State + HasMetadata,
|
S: HasMetadata,
|
||||||
{
|
ST: Stage<E, M, S, Z>,
|
||||||
type State = S;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E, M, Z, S, ST> Stage<E, M, Z> for TimeTrackingStageWrapper<T, S, ST>
|
|
||||||
where
|
|
||||||
S: UsesInput + State + HasMetadata,
|
|
||||||
ST: Stage<E, M, Z, State = S>,
|
|
||||||
M: UsesState<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
E: UsesState<State = S>,
|
|
||||||
T: libafl_bolts::serdeany::SerdeAny + From<Duration>,
|
T: libafl_bolts::serdeany::SerdeAny + From<Duration>,
|
||||||
{
|
{
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut M,
|
manager: &mut M,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let before_run = current_time();
|
let before_run = current_time();
|
||||||
@ -59,11 +44,11 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
self.inner.should_restart(state)
|
self.inner.should_restart(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
self.inner.clear_progress(state)
|
self.inner.clear_progress(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +56,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut M,
|
manager: &mut M,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.inner
|
self.inner
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! The [`TMinMutationalStage`] is a stage which will attempt to minimize corpus entries.
|
//! The [`StdTMinMutationalStage`] is a stage which will attempt to minimize corpus entries.
|
||||||
|
|
||||||
use alloc::{
|
use alloc::{
|
||||||
borrow::{Cow, ToOwned},
|
borrow::{Cow, ToOwned},
|
||||||
@ -15,12 +15,14 @@ use serde::Serialize;
|
|||||||
|
|
||||||
#[cfg(feature = "track_hit_feedbacks")]
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
use crate::feedbacks::premature_last_result_err;
|
use crate::feedbacks::premature_last_result_err;
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
use crate::monitors::PerfFeature;
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, HasCurrentCorpusId, Testcase},
|
corpus::{Corpus, HasCurrentCorpusId, Testcase},
|
||||||
events::EventFirer,
|
events::EventFirer,
|
||||||
executors::{ExitKind, HasObservers},
|
executors::{ExitKind, HasObservers},
|
||||||
feedbacks::{Feedback, FeedbackFactory, HasObserverHandle, StateInitializer},
|
feedbacks::{Feedback, FeedbackFactory, HasObserverHandle, StateInitializer},
|
||||||
inputs::UsesInput,
|
inputs::{Input, UsesInput},
|
||||||
mark_feature_time,
|
mark_feature_time,
|
||||||
mutators::{MutationResult, Mutator},
|
mutators::{MutationResult, Mutator},
|
||||||
observers::{MapObserver, ObserversTuple},
|
observers::{MapObserver, ObserversTuple},
|
||||||
@ -31,44 +33,137 @@ use crate::{
|
|||||||
},
|
},
|
||||||
start_timer,
|
start_timer,
|
||||||
state::{
|
state::{
|
||||||
HasCorpus, HasCurrentTestcase, HasExecutions, HasMaxSize, HasSolutions, State, UsesState,
|
HasCorpus, HasCurrentTestcase, HasExecutions, HasMaxSize, HasSolutions,
|
||||||
|
MaybeHasClientPerfMonitor, State, UsesState,
|
||||||
},
|
},
|
||||||
Error, ExecutesInput, ExecutionProcessor, HasFeedback, HasMetadata, HasNamedMetadata,
|
Error, ExecutesInput, ExecutionProcessor, HasFeedback, HasMetadata, HasNamedMetadata,
|
||||||
HasScheduler,
|
HasScheduler,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "introspection")]
|
|
||||||
use crate::{monitors::PerfFeature, state::HasClientPerfMonitor};
|
/// The default corpus entry minimising mutational stage
|
||||||
/// Mutational stage which minimizes corpus entries.
|
#[derive(Clone, Debug)]
|
||||||
///
|
pub struct StdTMinMutationalStage<E, EM, F, FF, M, S, Z> {
|
||||||
/// You must provide at least one mutator that actually reduces size.
|
/// The name
|
||||||
pub trait TMinMutationalStage<E, EM, F, IP, M, Z>:
|
name: Cow<'static, str>,
|
||||||
Stage<E, EM, Z> + FeedbackFactory<F, E::Observers>
|
/// The mutator(s) this stage uses
|
||||||
|
mutator: M,
|
||||||
|
/// The factory
|
||||||
|
factory: FF,
|
||||||
|
/// The runs (=iterations) we are supposed to do
|
||||||
|
runs: usize,
|
||||||
|
/// The progress helper for this stage, keeping track of resumes after timeouts/crashes
|
||||||
|
restart_helper: ExecutionCountRestartHelper,
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
phantom: PhantomData<(E, EM, F, S, Z)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, EM, F, FF, M, S, Z> Stage<E, EM, S, Z> for StdTMinMutationalStage<E, EM, F, FF, M, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState<State = Self::State> + HasObservers,
|
Z: HasScheduler<State = S>
|
||||||
E::Observers: ObserversTuple<Self::Input, Self::State> + Serialize,
|
+ ExecutionProcessor<EM, E::Observers>
|
||||||
EM: UsesState<State = Self::State> + EventFirer,
|
|
||||||
F: Feedback<EM, Self::Input, E::Observers, Self::State>,
|
|
||||||
Self::State: HasMaxSize + HasCorpus + HasSolutions + HasExecutions + HasCurrentTestcase,
|
|
||||||
Self::Input: MutatedTransform<Self::Input, Self::State, Post = IP> + Clone + Hash + HasLen,
|
|
||||||
IP: Clone + MutatedTransformPost<Self::State>,
|
|
||||||
M: Mutator<Self::Input, Self::State>,
|
|
||||||
Z: UsesState<State = Self::State>
|
|
||||||
+ HasScheduler
|
|
||||||
+ HasFeedback
|
|
||||||
+ ExecutesInput<E, EM>
|
+ ExecutesInput<E, EM>
|
||||||
+ ExecutionProcessor<EM, E::Observers>,
|
+ HasFeedback,
|
||||||
Z::Feedback: Feedback<EM, Self::Input, E::Observers, Self::State>,
|
Z::Scheduler: RemovableScheduler<<S::Corpus as Corpus>::Input, S>,
|
||||||
Z::Scheduler: RemovableScheduler<Self::Input, Self::State>,
|
E: HasObservers + UsesState<State = S>,
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>,
|
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||||
|
EM: EventFirer<State = S>,
|
||||||
|
FF: FeedbackFactory<F, E::Observers>,
|
||||||
|
F: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
|
||||||
|
S: HasMetadata
|
||||||
|
+ HasExecutions
|
||||||
|
+ HasSolutions
|
||||||
|
+ HasCorpus
|
||||||
|
+ HasMaxSize
|
||||||
|
+ HasNamedMetadata
|
||||||
|
+ HasCurrentCorpusId
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
Z::Feedback: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
|
||||||
|
M: Mutator<<S::Corpus as Corpus>::Input, S>,
|
||||||
|
<<S as HasCorpus>::Corpus as Corpus>::Input: Input + Hash + HasLen,
|
||||||
{
|
{
|
||||||
/// The mutator registered for this stage
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
fn mutator(&self) -> &M;
|
self.restart_helper.should_restart(state, &self.name)
|
||||||
|
}
|
||||||
|
|
||||||
/// The mutator registered for this stage (mutable)
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
fn mutator_mut(&mut self) -> &mut M;
|
self.restart_helper.clear_progress(state, &self.name)
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the number of iterations this mutator should run for.
|
fn perform(
|
||||||
fn iterations(&self, state: &mut Self::State) -> Result<usize, Error>;
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
executor: &mut E,
|
||||||
|
state: &mut Z::State,
|
||||||
|
manager: &mut EM,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.perform_minification(fuzzer, executor, state, manager)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
state.introspection_monitor_mut().finish_stage();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, EM, F, FF, M, S, Z> FeedbackFactory<F, E::Observers>
|
||||||
|
for StdTMinMutationalStage<E, EM, F, FF, M, S, Z>
|
||||||
|
where
|
||||||
|
E: HasObservers,
|
||||||
|
FF: FeedbackFactory<F, E::Observers>,
|
||||||
|
{
|
||||||
|
fn create_feedback(&self, ctx: &E::Observers) -> F {
|
||||||
|
self.factory.create_feedback(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, EM, F, FF, M, S, Z> Named for StdTMinMutationalStage<E, EM, F, FF, M, S, Z> {
|
||||||
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The counter for giving this stage unique id
|
||||||
|
static mut TMIN_STAGE_ID: usize = 0;
|
||||||
|
/// The name for tmin stage
|
||||||
|
pub static TMIN_STAGE_NAME: &str = "tmin";
|
||||||
|
|
||||||
|
impl<E, EM, F, FF, M, S, Z> StdTMinMutationalStage<E, EM, F, FF, M, S, Z>
|
||||||
|
where
|
||||||
|
Z: HasScheduler<State = S>
|
||||||
|
+ ExecutionProcessor<EM, E::Observers>
|
||||||
|
+ ExecutesInput<E, EM>
|
||||||
|
+ HasFeedback,
|
||||||
|
Z::Scheduler: RemovableScheduler<<S::Corpus as Corpus>::Input, S>,
|
||||||
|
E: HasObservers + UsesState<State = Z::State>,
|
||||||
|
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||||
|
EM: EventFirer<State = Z::State>,
|
||||||
|
FF: FeedbackFactory<F, E::Observers>,
|
||||||
|
F: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
|
||||||
|
S: HasMetadata
|
||||||
|
+ HasExecutions
|
||||||
|
+ HasSolutions
|
||||||
|
+ HasCorpus
|
||||||
|
+ HasMaxSize
|
||||||
|
+ HasNamedMetadata
|
||||||
|
+ HasCurrentTestcase
|
||||||
|
+ HasCurrentCorpusId
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
Z::Feedback: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
|
||||||
|
M: Mutator<<S::Corpus as Corpus>::Input, S>,
|
||||||
|
<S::Corpus as Corpus>::Input: Hash + HasLen + Input,
|
||||||
|
{
|
||||||
|
/// The list of mutators, added to this stage (as mutable ref)
|
||||||
|
#[inline]
|
||||||
|
fn mutator_mut(&mut self) -> &mut M {
|
||||||
|
&mut self.mutator
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the number of iterations from a fixed number of runs
|
||||||
|
fn iterations(&self, _state: &mut S) -> usize {
|
||||||
|
self.runs
|
||||||
|
}
|
||||||
|
|
||||||
/// Runs this (mutational) stage for new objectives
|
/// Runs this (mutational) stage for new objectives
|
||||||
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
|
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
|
||||||
@ -76,7 +171,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let Some(base_corpus_id) = state.current_corpus_id()? else {
|
let Some(base_corpus_id) = state.current_corpus_id()? else {
|
||||||
@ -88,7 +183,7 @@ where
|
|||||||
let orig_max_size = state.max_size();
|
let orig_max_size = state.max_size();
|
||||||
// basically copy-pasted from mutational.rs
|
// basically copy-pasted from mutational.rs
|
||||||
let num = self
|
let num = self
|
||||||
.iterations(state)?
|
.iterations(state)
|
||||||
.saturating_sub(usize::try_from(self.execs_since_progress_start(state)?)?);
|
.saturating_sub(usize::try_from(self.execs_since_progress_start(state)?)?);
|
||||||
|
|
||||||
// If num is negative, then quit.
|
// If num is negative, then quit.
|
||||||
@ -97,8 +192,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
let transformed =
|
let transformed = <S::Corpus as Corpus>::Input::try_transform_from(
|
||||||
Self::Input::try_transform_from(state.current_testcase_mut()?.borrow_mut(), state)?;
|
state.current_testcase_mut()?.borrow_mut(),
|
||||||
|
state,
|
||||||
|
)?;
|
||||||
let mut base = state.current_input_cloned()?;
|
let mut base = state.current_input_cloned()?;
|
||||||
// potential post operation if base is replaced by a shorter input
|
// potential post operation if base is replaced by a shorter input
|
||||||
let mut base_post = None;
|
let mut base_post = None;
|
||||||
@ -159,7 +256,7 @@ where
|
|||||||
if feedback.is_interesting(state, manager, &input, &*observers, &exit_kind)? {
|
if feedback.is_interesting(state, manager, &input, &*observers, &exit_kind)? {
|
||||||
// we found a reduced corpus entry! use the smaller base
|
// we found a reduced corpus entry! use the smaller base
|
||||||
base = input;
|
base = input;
|
||||||
base_post = Some(post.clone());
|
base_post = Some(post);
|
||||||
|
|
||||||
// do more runs! maybe we can minify further
|
// do more runs! maybe we can minify further
|
||||||
next_i = 0;
|
next_i = 0;
|
||||||
@ -210,144 +307,13 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the number of executions this mutator already did since it got first called in this fuzz round.
|
fn execs_since_progress_start(&mut self, state: &mut S) -> Result<u64, Error> {
|
||||||
fn execs_since_progress_start(&mut self, state: &mut Self::State) -> Result<u64, Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The default corpus entry minimising mutational stage
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct StdTMinMutationalStage<E, EM, F, FF, IP, M, Z> {
|
|
||||||
/// The name
|
|
||||||
name: Cow<'static, str>,
|
|
||||||
/// The mutator(s) this stage uses
|
|
||||||
mutator: M,
|
|
||||||
/// The factory
|
|
||||||
factory: FF,
|
|
||||||
/// The runs (=iterations) we are supposed to do
|
|
||||||
runs: usize,
|
|
||||||
/// The progress helper for this stage, keeping track of resumes after timeouts/crashes
|
|
||||||
restart_helper: ExecutionCountRestartHelper,
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
phantom: PhantomData<(E, EM, F, IP, Z)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, F, FF, IP, M, Z> UsesState for StdTMinMutationalStage<E, EM, F, FF, IP, M, Z>
|
|
||||||
where
|
|
||||||
Z: UsesState,
|
|
||||||
{
|
|
||||||
type State = Z::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, F, FF, IP, M, Z> Stage<E, EM, Z> for StdTMinMutationalStage<E, EM, F, FF, IP, M, Z>
|
|
||||||
where
|
|
||||||
Z: HasScheduler + ExecutionProcessor<EM, E::Observers> + ExecutesInput<E, EM> + HasFeedback,
|
|
||||||
Z::Scheduler: RemovableScheduler<Self::Input, Self::State>,
|
|
||||||
E: HasObservers + UsesState<State = Z::State>,
|
|
||||||
E::Observers: ObserversTuple<Self::Input, Self::State> + Serialize,
|
|
||||||
EM: EventFirer<State = Self::State>,
|
|
||||||
FF: FeedbackFactory<F, E::Observers>,
|
|
||||||
F: Feedback<EM, Self::Input, E::Observers, Self::State>,
|
|
||||||
Self::Input: MutatedTransform<Self::Input, Self::State, Post = IP> + Clone + HasLen + Hash,
|
|
||||||
Z::State:
|
|
||||||
HasMetadata + HasExecutions + HasSolutions + HasCorpus + HasMaxSize + HasNamedMetadata,
|
|
||||||
Z::Feedback: Feedback<EM, Self::Input, E::Observers, Self::State>,
|
|
||||||
M: Mutator<Self::Input, Self::State>,
|
|
||||||
IP: MutatedTransformPost<Self::State> + Clone,
|
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, // delete me
|
|
||||||
{
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
|
||||||
self.restart_helper.should_restart(state, &self.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
|
||||||
self.restart_helper.clear_progress(state, &self.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn perform(
|
|
||||||
&mut self,
|
|
||||||
fuzzer: &mut Z,
|
|
||||||
executor: &mut E,
|
|
||||||
state: &mut Z::State,
|
|
||||||
manager: &mut EM,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
self.perform_minification(fuzzer, executor, state, manager)?;
|
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
|
||||||
state.introspection_monitor_mut().finish_stage();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, F, FF, IP, M, Z> FeedbackFactory<F, E::Observers>
|
|
||||||
for StdTMinMutationalStage<E, EM, F, FF, IP, M, Z>
|
|
||||||
where
|
|
||||||
E: HasObservers,
|
|
||||||
FF: FeedbackFactory<F, E::Observers>,
|
|
||||||
{
|
|
||||||
fn create_feedback(&self, ctx: &E::Observers) -> F {
|
|
||||||
self.factory.create_feedback(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, F, FF, IP, M, Z> Named for StdTMinMutationalStage<E, EM, F, FF, IP, M, Z> {
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The counter for giving this stage unique id
|
|
||||||
static mut TMIN_STAGE_ID: usize = 0;
|
|
||||||
/// The name for tmin stage
|
|
||||||
pub static TMIN_STAGE_NAME: &str = "tmin";
|
|
||||||
|
|
||||||
impl<E, EM, F, FF, IP, M, Z> TMinMutationalStage<E, EM, F, IP, M, Z>
|
|
||||||
for StdTMinMutationalStage<E, EM, F, FF, IP, M, Z>
|
|
||||||
where
|
|
||||||
Z: HasScheduler + ExecutionProcessor<EM, E::Observers> + ExecutesInput<E, EM> + HasFeedback,
|
|
||||||
Z::Scheduler: RemovableScheduler<Self::Input, Self::State>,
|
|
||||||
E: HasObservers + UsesState<State = Z::State>,
|
|
||||||
E::Observers: ObserversTuple<Self::Input, Self::State> + Serialize,
|
|
||||||
EM: EventFirer<State = Self::State>,
|
|
||||||
FF: FeedbackFactory<F, E::Observers>,
|
|
||||||
F: Feedback<EM, Self::Input, E::Observers, Self::State>,
|
|
||||||
Self::Input: MutatedTransform<Self::Input, Self::State, Post = IP> + Clone + HasLen + Hash,
|
|
||||||
Z::State: HasMetadata
|
|
||||||
+ HasExecutions
|
|
||||||
+ HasSolutions
|
|
||||||
+ HasCorpus
|
|
||||||
+ HasMaxSize
|
|
||||||
+ HasNamedMetadata
|
|
||||||
+ HasCurrentTestcase,
|
|
||||||
Z::Feedback: Feedback<EM, Self::Input, E::Observers, Self::State>,
|
|
||||||
M: Mutator<Self::Input, Self::State>,
|
|
||||||
IP: MutatedTransformPost<Self::State> + Clone,
|
|
||||||
<<Self as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, // delete me
|
|
||||||
{
|
|
||||||
/// The mutator, added to this stage
|
|
||||||
#[inline]
|
|
||||||
fn mutator(&self) -> &M {
|
|
||||||
&self.mutator
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The list of mutators, added to this stage (as mutable ref)
|
|
||||||
#[inline]
|
|
||||||
fn mutator_mut(&mut self) -> &mut M {
|
|
||||||
&mut self.mutator
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the number of iterations from a fixed number of runs
|
|
||||||
fn iterations(&self, _state: &mut Self::State) -> Result<usize, Error> {
|
|
||||||
Ok(self.runs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execs_since_progress_start(&mut self, state: &mut Self::State) -> Result<u64, Error> {
|
|
||||||
self.restart_helper
|
self.restart_helper
|
||||||
.execs_since_progress_start(state, &self.name)
|
.execs_since_progress_start(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, F, FF, IP, M, Z> StdTMinMutationalStage<E, EM, F, FF, IP, M, Z> {
|
impl<E, EM, F, FF, M, S, Z> StdTMinMutationalStage<E, EM, F, FF, M, S, Z> {
|
||||||
/// Creates a new minimizing mutational stage that will minimize provided corpus entries
|
/// Creates a new minimizing mutational stage that will minimize provided corpus entries
|
||||||
pub fn new(mutator: M, factory: FF, runs: usize) -> Self {
|
pub fn new(mutator: M, factory: FF, runs: usize) -> Self {
|
||||||
// unsafe but impossible that you create two threads both instantiating this instance
|
// unsafe but impossible that you create two threads both instantiating this instance
|
||||||
|
@ -8,54 +8,47 @@ use core::{fmt::Debug, marker::PhantomData};
|
|||||||
|
|
||||||
use libafl_bolts::Named;
|
use libafl_bolts::Named;
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
use crate::monitors::PerfFeature;
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
corpus::{Corpus, HasCurrentCorpusId},
|
||||||
executors::{Executor, HasObservers, ShadowExecutor},
|
executors::{Executor, HasObservers, ShadowExecutor},
|
||||||
|
inputs::{Input, UsesInput},
|
||||||
mark_feature_time,
|
mark_feature_time,
|
||||||
observers::ObserversTuple,
|
observers::ObserversTuple,
|
||||||
stages::{RetryCountRestartHelper, Stage},
|
stages::{RetryCountRestartHelper, Stage},
|
||||||
start_timer,
|
start_timer,
|
||||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, State, UsesState},
|
state::{HasCorpus, HasCurrentTestcase, HasExecutions, MaybeHasClientPerfMonitor, UsesState},
|
||||||
Error, HasNamedMetadata,
|
Error, HasNamedMetadata,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "introspection")]
|
|
||||||
use crate::{monitors::PerfFeature, state::HasClientPerfMonitor};
|
|
||||||
|
|
||||||
/// A stage that runs a tracer executor
|
/// A stage that runs a tracer executor
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TracingStage<EM, TE, Z> {
|
pub struct TracingStage<EM, TE, S, Z> {
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
tracer_executor: TE,
|
tracer_executor: TE,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
phantom: PhantomData<(EM, TE, Z)>,
|
phantom: PhantomData<(EM, TE, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<EM, TE, Z> UsesState for TracingStage<EM, TE, Z>
|
impl<EM, TE, S, Z> TracingStage<EM, TE, S, Z>
|
||||||
where
|
where
|
||||||
TE: UsesState,
|
TE: Executor<EM, Z, State = S> + HasObservers,
|
||||||
{
|
TE::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||||
type State = TE::State;
|
S: HasExecutions
|
||||||
}
|
+ HasCorpus
|
||||||
|
+ HasNamedMetadata
|
||||||
impl<EM, TE, Z> TracingStage<EM, TE, Z>
|
+ HasCurrentTestcase
|
||||||
where
|
+ MaybeHasClientPerfMonitor
|
||||||
TE: Executor<EM, Z> + HasObservers,
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
TE::Observers: ObserversTuple<TE::Input, <Self as UsesState>::State>,
|
EM: UsesState<State = S>, //delete me
|
||||||
<TE as UsesState>::State: HasExecutions + HasCorpus + HasNamedMetadata + HasCurrentTestcase,
|
Z: UsesState<State = S>, //delete me
|
||||||
EM: UsesState<State = <Self as UsesState>::State>,
|
|
||||||
Z: UsesState<State = <Self as UsesState>::State>,
|
|
||||||
<<TE as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = TE::Input>, // delete me
|
|
||||||
{
|
{
|
||||||
#[allow(rustdoc::broken_intra_doc_links)]
|
#[allow(rustdoc::broken_intra_doc_links)]
|
||||||
/// Perform tracing on the given `CorpusId`. Useful for if wrapping [`TracingStage`] with your
|
/// Perform tracing on the given `CorpusId`. Useful for if wrapping [`TracingStage`] with your
|
||||||
/// own stage and you need to manage [`super::NestedStageRetryCountRestartHelper`] differently
|
/// own stage and you need to manage [`super::NestedStageRetryCountRestartHelper`] differently
|
||||||
/// see [`super::ConcolicTracingStage`]'s implementation as an example of usage.
|
/// see [`super::ConcolicTracingStage`]'s implementation as an example of usage.
|
||||||
pub fn trace(
|
pub fn trace(&mut self, fuzzer: &mut Z, state: &mut S, manager: &mut EM) -> Result<(), Error> {
|
||||||
&mut self,
|
|
||||||
fuzzer: &mut Z,
|
|
||||||
state: &mut <Self as UsesState>::State,
|
|
||||||
manager: &mut EM,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
let input = state.current_input_cloned()?;
|
let input = state.current_input_cloned()?;
|
||||||
|
|
||||||
@ -83,37 +76,41 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, TE, Z> Stage<E, EM, Z> for TracingStage<EM, TE, Z>
|
impl<E, EM, TE, S, Z> Stage<E, EM, S, Z> for TracingStage<EM, TE, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState<State = <Self as UsesState>::State>,
|
TE: Executor<EM, Z, State = S> + HasObservers,
|
||||||
TE: Executor<EM, Z> + HasObservers,
|
TE::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||||
TE::Observers: ObserversTuple<TE::Input, <Self as UsesState>::State>,
|
S: HasExecutions
|
||||||
<TE as UsesState>::State: HasExecutions + HasCorpus + HasNamedMetadata,
|
+ HasCorpus
|
||||||
EM: UsesState<State = <Self as UsesState>::State>,
|
+ HasNamedMetadata
|
||||||
Z: UsesState<State = <Self as UsesState>::State>,
|
+ HasCurrentCorpusId
|
||||||
<<TE as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = TE::Input>, // delete me
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
EM: UsesState<State = S>,
|
||||||
|
Z: UsesState<State = S>,
|
||||||
|
<S::Corpus as Corpus>::Input: Input,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
_executor: &mut E,
|
_executor: &mut E,
|
||||||
state: &mut <Self as UsesState>::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.trace(fuzzer, state, manager)
|
self.trace(fuzzer, state, manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
RetryCountRestartHelper::no_retry(state, &self.name)
|
RetryCountRestartHelper::no_retry(state, &self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<EM, TE, Z> Named for TracingStage<EM, TE, Z> {
|
impl<EM, TE, S, Z> Named for TracingStage<EM, TE, S, Z> {
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
@ -124,7 +121,7 @@ static mut TRACING_STAGE_ID: usize = 0;
|
|||||||
/// The name for tracing stage
|
/// The name for tracing stage
|
||||||
pub static TRACING_STAGE_NAME: &str = "tracing";
|
pub static TRACING_STAGE_NAME: &str = "tracing";
|
||||||
|
|
||||||
impl<EM, TE, Z> TracingStage<EM, TE, Z> {
|
impl<EM, TE, S, Z> TracingStage<EM, TE, S, Z> {
|
||||||
/// Creates a new default stage
|
/// Creates a new default stage
|
||||||
pub fn new(tracer_executor: TE) -> Self {
|
pub fn new(tracer_executor: TE) -> Self {
|
||||||
// unsafe but impossible that you create two threads both instantiating this instance
|
// unsafe but impossible that you create two threads both instantiating this instance
|
||||||
@ -154,49 +151,46 @@ impl<EM, TE, Z> TracingStage<EM, TE, Z> {
|
|||||||
|
|
||||||
/// A stage that runs the shadow executor using also the shadow observers
|
/// A stage that runs the shadow executor using also the shadow observers
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ShadowTracingStage<E, EM, SOT, Z> {
|
pub struct ShadowTracingStage<E, EM, SOT, S, Z> {
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
phantom: PhantomData<(E, EM, SOT, Z)>,
|
phantom: PhantomData<(E, EM, SOT, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, SOT, Z> UsesState for ShadowTracingStage<E, EM, SOT, Z>
|
|
||||||
where
|
|
||||||
E: UsesState,
|
|
||||||
{
|
|
||||||
type State = E::State;
|
|
||||||
}
|
|
||||||
/// The counter for giving this stage unique id
|
/// The counter for giving this stage unique id
|
||||||
static mut SHADOW_TRACING_STAGE_ID: usize = 0;
|
static mut SHADOW_TRACING_STAGE_ID: usize = 0;
|
||||||
/// Name for shadow tracing stage
|
/// Name for shadow tracing stage
|
||||||
pub static SHADOW_TRACING_STAGE_NAME: &str = "shadow";
|
pub static SHADOW_TRACING_STAGE_NAME: &str = "shadow";
|
||||||
|
|
||||||
impl<E, EM, SOT, Z> Named for ShadowTracingStage<E, EM, SOT, Z>
|
impl<E, EM, SOT, S, Z> Named for ShadowTracingStage<E, EM, SOT, S, Z> {
|
||||||
where
|
|
||||||
E: UsesState,
|
|
||||||
{
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, SOT, Z> Stage<ShadowExecutor<E, SOT>, EM, Z> for ShadowTracingStage<E, EM, SOT, Z>
|
impl<E, EM, SOT, S, Z> Stage<ShadowExecutor<E, SOT>, EM, S, Z>
|
||||||
|
for ShadowTracingStage<E, EM, SOT, S, Z>
|
||||||
where
|
where
|
||||||
E: Executor<EM, Z> + HasObservers,
|
E: Executor<EM, Z, State = S> + HasObservers,
|
||||||
E::Observers: ObserversTuple<E::Input, E::State>,
|
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||||
EM: UsesState<State = <Self as UsesState>::State>,
|
SOT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||||
SOT: ObserversTuple<E::Input, E::State>,
|
S: HasExecutions
|
||||||
Z: UsesState<State = <Self as UsesState>::State>,
|
+ HasCorpus
|
||||||
<E as UsesState>::State:
|
+ HasNamedMetadata
|
||||||
State + HasExecutions + HasCorpus + HasNamedMetadata + Debug + HasCurrentTestcase,
|
+ Debug
|
||||||
<<E as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = E::Input>, // delete me
|
+ HasCurrentTestcase
|
||||||
|
+ HasCurrentCorpusId
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
EM: UsesState<State = S>,
|
||||||
|
Z: UsesState<State = S>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut ShadowExecutor<E, SOT>,
|
executor: &mut ShadowExecutor<E, SOT>,
|
||||||
state: &mut <Self as UsesState>::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
@ -227,22 +221,22 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
RetryCountRestartHelper::no_retry(state, &self.name)
|
RetryCountRestartHelper::no_retry(state, &self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, SOT, Z> ShadowTracingStage<E, EM, SOT, Z>
|
impl<E, EM, SOT, S, Z> ShadowTracingStage<E, EM, SOT, S, Z>
|
||||||
where
|
where
|
||||||
E: Executor<EM, Z> + HasObservers,
|
E: Executor<EM, Z, State = Z::State> + HasObservers,
|
||||||
<Self as UsesState>::State: State + HasExecutions + HasCorpus,
|
S: HasExecutions + HasCorpus,
|
||||||
EM: UsesState<State = <Self as UsesState>::State>,
|
SOT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||||
SOT: ObserversTuple<E::Input, E::State>,
|
EM: UsesState<State = Z::State>,
|
||||||
Z: UsesState<State = <Self as UsesState>::State>,
|
Z: UsesState,
|
||||||
{
|
{
|
||||||
/// Creates a new default stage
|
/// Creates a new default stage
|
||||||
pub fn new(_executor: &mut ShadowExecutor<E, SOT>) -> Self {
|
pub fn new(_executor: &mut ShadowExecutor<E, SOT>) -> Self {
|
||||||
|
@ -6,8 +6,11 @@ use core::{marker::PhantomData, time::Duration};
|
|||||||
use libafl_bolts::{current_time, impl_serdeany, rands::Rand};
|
use libafl_bolts::{current_time, impl_serdeany, rands::Rand};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
use crate::monitors::PerfFeature;
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
corpus::Corpus,
|
||||||
|
inputs::{Input, UsesInput},
|
||||||
mark_feature_time,
|
mark_feature_time,
|
||||||
mutators::{MutationResult, Mutator},
|
mutators::{MutationResult, Mutator},
|
||||||
nonzero,
|
nonzero,
|
||||||
@ -16,11 +19,9 @@ use crate::{
|
|||||||
ExecutionCountRestartHelper, MutationalStage, Stage,
|
ExecutionCountRestartHelper, MutationalStage, Stage,
|
||||||
},
|
},
|
||||||
start_timer,
|
start_timer,
|
||||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, UsesState},
|
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, MaybeHasClientPerfMonitor},
|
||||||
Error, Evaluator, HasMetadata, HasNamedMetadata,
|
Error, Evaluator, HasMetadata, HasNamedMetadata,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "introspection")]
|
|
||||||
use crate::{monitors::PerfFeature, state::HasClientPerfMonitor};
|
|
||||||
|
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
any(not(feature = "serdeany_autoreg"), miri),
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
@ -150,26 +151,103 @@ where
|
|||||||
|
|
||||||
/// A [`crate::stages::MutationalStage`] where the mutator iteration can be tuned at runtime
|
/// A [`crate::stages::MutationalStage`] where the mutator iteration can be tuned at runtime
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TuneableMutationalStage<E, EM, I, M, Z> {
|
pub struct TuneableMutationalStage<E, EM, I, M, S, Z> {
|
||||||
/// The mutator we use
|
/// The mutator we use
|
||||||
mutator: M,
|
mutator: M,
|
||||||
/// The name of this stage
|
/// The name of this stage
|
||||||
name: String,
|
name: String,
|
||||||
/// The progress helper we use to keep track of progress across restarts
|
/// The progress helper we use to keep track of progress across restarts
|
||||||
restart_helper: ExecutionCountRestartHelper,
|
restart_helper: ExecutionCountRestartHelper,
|
||||||
phantom: PhantomData<(E, EM, I, Z)>,
|
phantom: PhantomData<(E, EM, I, S, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> MutationalStage<E, EM, I, M, Z> for TuneableMutationalStage<E, EM, I, M, Z>
|
impl<E, EM, I, M, S, Z> MutationalStage<S> for TuneableMutationalStage<E, EM, I, M, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState<State = Self::State>,
|
M: Mutator<I, S>,
|
||||||
EM: UsesState<State = Self::State>,
|
|
||||||
M: Mutator<I, Self::State>,
|
|
||||||
Z: Evaluator<E, EM>,
|
Z: Evaluator<E, EM>,
|
||||||
Z::State:
|
S: HasCorpus + HasRand + HasNamedMetadata + HasMetadata + HasExecutions + HasCurrentTestcase,
|
||||||
HasCorpus + HasRand + HasNamedMetadata + HasMetadata + HasExecutions + HasCurrentTestcase,
|
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone,
|
||||||
I: MutatedTransform<Z::Input, Self::State> + Clone,
|
<S::Corpus as Corpus>::Input: Input,
|
||||||
<<Z as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Z::Input>, // delete me
|
{
|
||||||
|
type Mutator = M;
|
||||||
|
/// The mutator, added to this stage
|
||||||
|
#[inline]
|
||||||
|
fn mutator(&self) -> &Self::Mutator {
|
||||||
|
&self.mutator
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The list of mutators, added to this stage (as mutable ref)
|
||||||
|
#[inline]
|
||||||
|
fn mutator_mut(&mut self) -> &mut Self::Mutator {
|
||||||
|
&mut self.mutator
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the number of iterations as a random number
|
||||||
|
fn iterations(&self, state: &mut S) -> Result<usize, Error> {
|
||||||
|
Ok(
|
||||||
|
// fall back to random
|
||||||
|
1 + state
|
||||||
|
.rand_mut()
|
||||||
|
.below(nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, EM, I, M, S, Z> Stage<E, EM, S, Z> for TuneableMutationalStage<E, EM, I, M, S, Z>
|
||||||
|
where
|
||||||
|
M: Mutator<I, S>,
|
||||||
|
Z: Evaluator<E, EM, State = S>,
|
||||||
|
S: HasCorpus
|
||||||
|
+ HasRand
|
||||||
|
+ HasNamedMetadata
|
||||||
|
+ HasMetadata
|
||||||
|
+ HasExecutions
|
||||||
|
+ HasCurrentTestcase
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone,
|
||||||
|
<S::Corpus as Corpus>::Input: Input,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
#[allow(clippy::let_and_return)]
|
||||||
|
fn perform(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
executor: &mut E,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let ret = self.perform_mutational(fuzzer, executor, state, manager);
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
state.introspection_monitor_mut().finish_stage();
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
|
self.restart_helper.should_restart(state, &self.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
|
self.restart_helper.clear_progress(state, &self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, EM, I, M, S, Z> TuneableMutationalStage<E, EM, I, M, S, Z>
|
||||||
|
where
|
||||||
|
M: Mutator<I, S>,
|
||||||
|
Z: Evaluator<E, EM, State = S>,
|
||||||
|
S: HasCorpus
|
||||||
|
+ HasRand
|
||||||
|
+ HasNamedMetadata
|
||||||
|
+ HasExecutions
|
||||||
|
+ HasMetadata
|
||||||
|
+ HasCurrentTestcase
|
||||||
|
+ MaybeHasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
|
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone,
|
||||||
|
<S::Corpus as Corpus>::Input: Input,
|
||||||
{
|
{
|
||||||
/// Runs this (mutational) stage for the given `testcase`
|
/// Runs this (mutational) stage for the given `testcase`
|
||||||
/// Exactly the same functionality as [`MutationalStage::perform_mutational`], but with added timeout support.
|
/// Exactly the same functionality as [`MutationalStage::perform_mutational`], but with added timeout support.
|
||||||
@ -177,7 +255,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let fuzz_time = self.seed_fuzz_time(state)?;
|
let fuzz_time = self.seed_fuzz_time(state)?;
|
||||||
@ -233,105 +311,24 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The mutator, added to this stage
|
fn execs_since_progress_start(&mut self, state: &mut S) -> Result<u64, Error> {
|
||||||
#[inline]
|
|
||||||
fn mutator(&self) -> &M {
|
|
||||||
&self.mutator
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The list of mutators, added to this stage (as mutable ref)
|
|
||||||
#[inline]
|
|
||||||
fn mutator_mut(&mut self) -> &mut M {
|
|
||||||
&mut self.mutator
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the number of iterations as a random number
|
|
||||||
fn iterations(&self, state: &mut Self::State) -> Result<usize, Error> {
|
|
||||||
Ok(
|
|
||||||
// fall back to random
|
|
||||||
1 + state
|
|
||||||
.rand_mut()
|
|
||||||
.below(nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> UsesState for TuneableMutationalStage<E, EM, I, M, Z>
|
|
||||||
where
|
|
||||||
Z: Evaluator<E, EM>,
|
|
||||||
{
|
|
||||||
type State = Z::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> Stage<E, EM, Z> for TuneableMutationalStage<E, EM, I, M, Z>
|
|
||||||
where
|
|
||||||
E: UsesState<State = Self::State>,
|
|
||||||
EM: UsesState<State = Self::State>,
|
|
||||||
M: Mutator<I, Self::State>,
|
|
||||||
Z: Evaluator<E, EM>,
|
|
||||||
Z::State:
|
|
||||||
HasCorpus + HasRand + HasNamedMetadata + HasMetadata + HasExecutions + HasCurrentTestcase,
|
|
||||||
I: MutatedTransform<Self::Input, Self::State> + Clone,
|
|
||||||
<<Z as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Z::Input>, // delete me
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
#[allow(clippy::let_and_return)]
|
|
||||||
fn perform(
|
|
||||||
&mut self,
|
|
||||||
fuzzer: &mut Z,
|
|
||||||
executor: &mut E,
|
|
||||||
state: &mut Self::State,
|
|
||||||
manager: &mut EM,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let ret = self.perform_mutational(fuzzer, executor, state, manager);
|
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
|
||||||
state.introspection_monitor_mut().finish_stage();
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
|
||||||
self.restart_helper.should_restart(state, &self.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
|
||||||
self.restart_helper.clear_progress(state, &self.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> TuneableMutationalStage<E, EM, I, M, Z>
|
|
||||||
where
|
|
||||||
E: UsesState<State = <Self as UsesState>::State>,
|
|
||||||
EM: UsesState<State = <Self as UsesState>::State>,
|
|
||||||
M: Mutator<I, <Self as UsesState>::State>,
|
|
||||||
Z: Evaluator<E, EM>,
|
|
||||||
<Z as UsesState>::State:
|
|
||||||
HasCorpus + HasRand + HasNamedMetadata + HasExecutions + HasMetadata + HasCurrentTestcase,
|
|
||||||
I: MutatedTransform<Z::Input, <Self as UsesState>::State> + Clone,
|
|
||||||
<<Z as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Z::Input>, // delete me
|
|
||||||
{
|
|
||||||
fn execs_since_progress_start(
|
|
||||||
&mut self,
|
|
||||||
state: &mut <Self as UsesState>::State,
|
|
||||||
) -> Result<u64, Error> {
|
|
||||||
self.restart_helper
|
self.restart_helper
|
||||||
.execs_since_progress_start(state, &self.name)
|
.execs_since_progress_start(state, &self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new default tuneable mutational stage
|
/// Creates a new default tuneable mutational stage
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(state: &mut <Self as UsesState>::State, mutator: M) -> Self {
|
pub fn new(state: &mut S, mutator: M) -> Self {
|
||||||
Self::transforming(state, mutator, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
|
Self::transforming(state, mutator, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Crates a new tuneable mutational stage with the given name
|
/// Crates a new tuneable mutational stage with the given name
|
||||||
pub fn with_name(state: &mut <Self as UsesState>::State, mutator: M, name: &str) -> Self {
|
pub fn with_name(state: &mut S, mutator: M, name: &str) -> Self {
|
||||||
Self::transforming(state, mutator, name)
|
Self::transforming(state, mutator, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the number of iterations to be used by this [`TuneableMutationalStage`]
|
/// Set the number of iterations to be used by this [`TuneableMutationalStage`]
|
||||||
pub fn set_iters<S>(&self, state: &mut S, iters: u64) -> Result<(), Error>
|
pub fn set_iters(&self, state: &mut S, iters: u64) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
S: HasNamedMetadata,
|
S: HasNamedMetadata,
|
||||||
{
|
{
|
||||||
@ -339,12 +336,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set the number of iterations to be used by the std [`TuneableMutationalStage`]
|
/// Set the number of iterations to be used by the std [`TuneableMutationalStage`]
|
||||||
pub fn set_iters_std(state: &mut <Self as UsesState>::State, iters: u64) -> Result<(), Error> {
|
pub fn set_iters_std(state: &mut S, iters: u64) -> Result<(), Error> {
|
||||||
set_iters_by_name(state, iters, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
|
set_iters_by_name(state, iters, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the number of iterations to be used by the [`TuneableMutationalStage`] with the given name
|
/// Set the number of iterations to be used by the [`TuneableMutationalStage`] with the given name
|
||||||
pub fn set_iters_by_name<S>(state: &mut S, iters: u64, name: &str) -> Result<(), Error>
|
pub fn set_iters_by_name(state: &mut S, iters: u64, name: &str) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
S: HasNamedMetadata,
|
S: HasNamedMetadata,
|
||||||
{
|
{
|
||||||
@ -352,7 +349,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the set iterations for this [`TuneableMutationalStage`], if any
|
/// Get the set iterations for this [`TuneableMutationalStage`], if any
|
||||||
pub fn fixed_iters<S>(&self, state: &S) -> Result<Option<u64>, Error>
|
pub fn fixed_iters(&self, state: &S) -> Result<Option<u64>, Error>
|
||||||
where
|
where
|
||||||
S: HasNamedMetadata,
|
S: HasNamedMetadata,
|
||||||
{
|
{
|
||||||
@ -360,12 +357,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the set iterations for the std [`TuneableMutationalStage`], if any
|
/// Get the set iterations for the std [`TuneableMutationalStage`], if any
|
||||||
pub fn iters_std(state: &<Self as UsesState>::State) -> Result<Option<u64>, Error> {
|
pub fn iters_std(state: &S) -> Result<Option<u64>, Error> {
|
||||||
get_iters_by_name(state, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
|
get_iters_by_name(state, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the set iterations for the [`TuneableMutationalStage`] with the given name, if any
|
/// Get the set iterations for the [`TuneableMutationalStage`] with the given name, if any
|
||||||
pub fn iters_by_name<S>(state: &S, name: &str) -> Result<Option<u64>, Error>
|
pub fn iters_by_name(state: &S, name: &str) -> Result<Option<u64>, Error>
|
||||||
where
|
where
|
||||||
S: HasNamedMetadata,
|
S: HasNamedMetadata,
|
||||||
{
|
{
|
||||||
@ -373,7 +370,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set the time to mutate a single input in this [`TuneableMutationalStage`]
|
/// Set the time to mutate a single input in this [`TuneableMutationalStage`]
|
||||||
pub fn set_seed_fuzz_time<S>(&self, state: &mut S, fuzz_time: Duration) -> Result<(), Error>
|
pub fn set_seed_fuzz_time(&self, state: &mut S, fuzz_time: Duration) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
S: HasNamedMetadata,
|
S: HasNamedMetadata,
|
||||||
{
|
{
|
||||||
@ -381,15 +378,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set the time to mutate a single input in the std [`TuneableMutationalStage`]
|
/// Set the time to mutate a single input in the std [`TuneableMutationalStage`]
|
||||||
pub fn set_seed_fuzz_time_std(
|
pub fn set_seed_fuzz_time_std(state: &mut S, fuzz_time: Duration) -> Result<(), Error> {
|
||||||
state: &mut <Self as UsesState>::State,
|
|
||||||
fuzz_time: Duration,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
set_seed_fuzz_time_by_name(state, fuzz_time, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
|
set_seed_fuzz_time_by_name(state, fuzz_time, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the time to mutate a single input in the [`TuneableMutationalStage`] with the given name
|
/// Set the time to mutate a single input in the [`TuneableMutationalStage`] with the given name
|
||||||
pub fn set_seed_fuzz_time_by_name<S>(
|
pub fn set_seed_fuzz_time_by_name(
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
fuzz_time: Duration,
|
fuzz_time: Duration,
|
||||||
name: &str,
|
name: &str,
|
||||||
@ -401,7 +395,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set the time to mutate a single input in this [`TuneableMutationalStage`]
|
/// Set the time to mutate a single input in this [`TuneableMutationalStage`]
|
||||||
pub fn seed_fuzz_time<S>(&self, state: &S) -> Result<Option<Duration>, Error>
|
pub fn seed_fuzz_time(&self, state: &S) -> Result<Option<Duration>, Error>
|
||||||
where
|
where
|
||||||
S: HasNamedMetadata,
|
S: HasNamedMetadata,
|
||||||
{
|
{
|
||||||
@ -409,19 +403,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set the time to mutate a single input for the std [`TuneableMutationalStage`]
|
/// Set the time to mutate a single input for the std [`TuneableMutationalStage`]
|
||||||
pub fn seed_fuzz_time_std(
|
pub fn seed_fuzz_time_std(&self, state: &S) -> Result<Option<Duration>, Error> {
|
||||||
&self,
|
|
||||||
state: &<Self as UsesState>::State,
|
|
||||||
) -> Result<Option<Duration>, Error> {
|
|
||||||
get_seed_fuzz_time_by_name(state, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
|
get_seed_fuzz_time_by_name(state, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the time to mutate a single input for the [`TuneableMutationalStage`] with a given name
|
/// Set the time to mutate a single input for the [`TuneableMutationalStage`] with a given name
|
||||||
pub fn seed_fuzz_time_by_name<S>(
|
pub fn seed_fuzz_time_by_name(&self, state: &S, name: &str) -> Result<Option<Duration>, Error>
|
||||||
&self,
|
|
||||||
state: &S,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<Option<Duration>, Error>
|
|
||||||
where
|
where
|
||||||
S: HasNamedMetadata,
|
S: HasNamedMetadata,
|
||||||
{
|
{
|
||||||
@ -429,7 +416,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reset this to a normal, randomized, stage with
|
/// Reset this to a normal, randomized, stage with
|
||||||
pub fn reset<S>(&self, state: &mut S) -> Result<(), Error>
|
pub fn reset(&self, state: &mut S) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
S: HasNamedMetadata,
|
S: HasNamedMetadata,
|
||||||
{
|
{
|
||||||
@ -437,12 +424,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the std stage to a normal, randomized, stage
|
/// Reset the std stage to a normal, randomized, stage
|
||||||
pub fn reset_std(state: &mut <Self as UsesState>::State) -> Result<(), Error> {
|
pub fn reset_std(state: &mut S) -> Result<(), Error> {
|
||||||
reset_by_name(state, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
|
reset_by_name(state, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset this to a normal, randomized, stage by name
|
/// Reset this to a normal, randomized, stage by name
|
||||||
pub fn reset_by_name<S>(state: &mut S, name: &str) -> Result<(), Error>
|
pub fn reset_by_name(state: &mut S, name: &str) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
S: HasNamedMetadata,
|
S: HasNamedMetadata,
|
||||||
{
|
{
|
||||||
@ -453,7 +440,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut <Self as UsesState>::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: &I,
|
input: &I,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
@ -480,17 +467,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, I, M, Z> TuneableMutationalStage<E, EM, I, M, Z>
|
impl<E, EM, I, M, S, Z> TuneableMutationalStage<E, EM, I, M, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState<State = <Self as UsesState>::State>,
|
|
||||||
EM: UsesState<State = <Self as UsesState>::State>,
|
|
||||||
M: Mutator<I, Z::State>,
|
M: Mutator<I, Z::State>,
|
||||||
Z: Evaluator<E, EM>,
|
Z: Evaluator<E, EM>,
|
||||||
<Self as UsesState>::State: HasCorpus + HasRand + HasNamedMetadata,
|
S: HasCorpus + HasRand + HasNamedMetadata,
|
||||||
{
|
{
|
||||||
/// Creates a new transforming mutational stage
|
/// Creates a new transforming mutational stage
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn transforming(state: &mut <Self as UsesState>::State, mutator: M, name: &str) -> Self {
|
pub fn transforming(state: &mut S, mutator: M, name: &str) -> Self {
|
||||||
let _ = state.named_metadata_or_insert_with(name, TuneableMutationalStageMetadata::default);
|
let _ = state.named_metadata_or_insert_with(name, TuneableMutationalStageMetadata::default);
|
||||||
Self {
|
Self {
|
||||||
mutator,
|
mutator,
|
||||||
|
@ -11,7 +11,7 @@ use crate::{
|
|||||||
corpus::Corpus,
|
corpus::Corpus,
|
||||||
inputs::{BytesInput, HasTargetBytes},
|
inputs::{BytesInput, HasTargetBytes},
|
||||||
stages::Stage,
|
stages::Stage,
|
||||||
state::{HasCorpus, HasCurrentTestcase, State, UsesState},
|
state::{HasCorpus, HasCurrentTestcase},
|
||||||
HasMetadata,
|
HasMetadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -109,39 +109,29 @@ impl<S> UnicodeIdentificationStage<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> UsesState for UnicodeIdentificationStage<S>
|
impl<E, EM, S, Z> Stage<E, EM, S, Z> for UnicodeIdentificationStage<S>
|
||||||
where
|
where
|
||||||
S: State,
|
S: HasCorpus + HasCurrentTestcase,
|
||||||
{
|
|
||||||
type State = S;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S, E, EM, Z> Stage<E, EM, Z> for UnicodeIdentificationStage<S>
|
|
||||||
where
|
|
||||||
S: HasCorpus + State + HasCurrentTestcase,
|
|
||||||
S::Corpus: Corpus<Input = BytesInput>,
|
S::Corpus: Corpus<Input = BytesInput>,
|
||||||
E: UsesState<State = S>,
|
|
||||||
EM: UsesState<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
{
|
{
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
_fuzzer: &mut Z,
|
_fuzzer: &mut Z,
|
||||||
_executor: &mut E,
|
_executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
_manager: &mut EM,
|
_manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
UnicodeIdentificationStage::identify_unicode_in_current_testcase(state)
|
UnicodeIdentificationStage::identify_unicode_in_current_testcase(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn should_restart(&mut self, _state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, _state: &mut S) -> Result<bool, Error> {
|
||||||
// Stage does not run the target. No reset helper needed.
|
// Stage does not run the target. No reset helper needed.
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> {
|
||||||
// Stage does not run the target. No reset helper needed.
|
// Stage does not run the target. No reset helper needed.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ use crate::{
|
|||||||
inputs::{BytesInput, UsesInput},
|
inputs::{BytesInput, UsesInput},
|
||||||
observers::ObserversTuple,
|
observers::ObserversTuple,
|
||||||
stages::Stage,
|
stages::Stage,
|
||||||
state::{HasCorpus, State, UsesState},
|
state::{HasCorpus, UsesState},
|
||||||
Evaluator, HasMetadata,
|
Evaluator, HasMetadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -43,13 +43,6 @@ impl<E, S> VerifyTimeoutsStage<E, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, S> UsesState for VerifyTimeoutsStage<E, S>
|
|
||||||
where
|
|
||||||
S: State,
|
|
||||||
{
|
|
||||||
type State = S;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Timeouts that `VerifyTimeoutsStage` will read from
|
/// Timeouts that `VerifyTimeoutsStage` will read from
|
||||||
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(bound = "I: for<'a> Deserialize<'a> + Serialize")]
|
#[serde(bound = "I: for<'a> Deserialize<'a> + Serialize")]
|
||||||
@ -88,21 +81,20 @@ impl<I> TimeoutsToVerify<I> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, Z, S> Stage<E, EM, Z> for VerifyTimeoutsStage<E, S>
|
impl<E, EM, S, Z> Stage<E, EM, S, Z> for VerifyTimeoutsStage<E, S>
|
||||||
where
|
where
|
||||||
E::Observers: ObserversTuple<<Self as UsesInput>::Input, <Self as UsesState>::State>,
|
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||||
E: Executor<EM, Z, State = S> + HasObservers + HasTimeout,
|
E: Executor<EM, Z, State = S> + HasObservers + HasTimeout,
|
||||||
EM: UsesState<State = S>,
|
EM: UsesState<State = S>,
|
||||||
Z: UsesState<State = S> + Evaluator<E, EM>,
|
Z: Evaluator<E, EM, State = S>,
|
||||||
S: HasCorpus + State + HasMetadata,
|
S: HasCorpus + HasMetadata + UsesInput<Input = <S::Corpus as Corpus>::Input>,
|
||||||
Self::Input: Debug + Serialize + DeserializeOwned + Default + 'static + Clone,
|
<S::Corpus as Corpus>::Input: Debug + Serialize + DeserializeOwned + Default + 'static + Clone,
|
||||||
<<E as UsesState>::State as HasCorpus>::Corpus: Corpus<Input = Self::Input>, //delete me
|
|
||||||
{
|
{
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut timeouts = state
|
let mut timeouts = state
|
||||||
@ -118,15 +110,17 @@ where
|
|||||||
}
|
}
|
||||||
executor.set_timeout(self.original_timeout);
|
executor.set_timeout(self.original_timeout);
|
||||||
*self.capture_timeouts.borrow_mut() = true;
|
*self.capture_timeouts.borrow_mut() = true;
|
||||||
let res = state.metadata_mut::<TimeoutsToVerify<E::Input>>().unwrap();
|
let res = state
|
||||||
*res = TimeoutsToVerify::<E::Input>::new();
|
.metadata_mut::<TimeoutsToVerify<<S::Corpus as Corpus>::Input>>()
|
||||||
|
.unwrap();
|
||||||
|
*res = TimeoutsToVerify::<<S::Corpus as Corpus>::Input>::new();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn should_restart(&mut self, _state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, _state: &mut S) -> Result<bool, Error> {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ macro_rules! fuzz_with {
|
|||||||
// TODO configure with mutation stacking options from libfuzzer
|
// TODO configure with mutation stacking options from libfuzzer
|
||||||
let std_mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
let std_mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||||
|
|
||||||
let std_power: StdPowerMutationalStage<_, _, BytesInput, _, _> = StdPowerMutationalStage::new(std_mutator);
|
let std_power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(std_mutator);
|
||||||
let std_power = IfStage::new(|_, _, _, _| Ok(mutator_status.std_mutational.into()), (std_power, ()));
|
let std_power = IfStage::new(|_, _, _, _| Ok(mutator_status.std_mutational.into()), (std_power, ()));
|
||||||
|
|
||||||
// for custom mutator and crossover, each have access to the LLVMFuzzerMutate -- but it appears
|
// for custom mutator and crossover, each have access to the LLVMFuzzerMutate -- but it appears
|
||||||
@ -378,7 +378,7 @@ macro_rules! fuzz_with {
|
|||||||
// Safe to unwrap: stack pow is not 0.
|
// Safe to unwrap: stack pow is not 0.
|
||||||
let std_mutator_no_mutate = StdScheduledMutator::with_max_stack_pow(havoc_crossover(),3);
|
let std_mutator_no_mutate = StdScheduledMutator::with_max_stack_pow(havoc_crossover(),3);
|
||||||
|
|
||||||
let cm_power: StdPowerMutationalStage<_, _, BytesInput, _, _> = StdPowerMutationalStage::new(custom_mutator);
|
let cm_power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(custom_mutator);
|
||||||
let cm_power = IfStage::new(|_, _, _, _| Ok(mutator_status.custom_mutation.into()), (cm_power, ()));
|
let cm_power = IfStage::new(|_, _, _, _| Ok(mutator_status.custom_mutation.into()), (cm_power, ()));
|
||||||
let cm_std_power = StdMutationalStage::new(std_mutator_no_mutate);
|
let cm_std_power = StdMutationalStage::new(std_mutator_no_mutate);
|
||||||
let cm_std_power =
|
let cm_std_power =
|
||||||
@ -398,7 +398,7 @@ macro_rules! fuzz_with {
|
|||||||
|
|
||||||
let cc_power = StdMutationalStage::new(custom_crossover);
|
let cc_power = StdMutationalStage::new(custom_crossover);
|
||||||
let cc_power = IfStage::new(|_, _, _, _| Ok(mutator_status.custom_crossover.into()), (cc_power, ()));
|
let cc_power = IfStage::new(|_, _, _, _| Ok(mutator_status.custom_crossover.into()), (cc_power, ()));
|
||||||
let cc_std_power: StdPowerMutationalStage<_, _, BytesInput, _, _> = StdPowerMutationalStage::new(std_mutator_no_crossover);
|
let cc_std_power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(std_mutator_no_crossover);
|
||||||
let cc_std_power =
|
let cc_std_power =
|
||||||
IfStage::new(|_, _, _, _| Ok(mutator_status.std_no_crossover.into()), (cc_std_power, ()));
|
IfStage::new(|_, _, _, _| Ok(mutator_status.std_no_crossover.into()), (cc_std_power, ()));
|
||||||
|
|
||||||
|
@ -2,12 +2,12 @@ use alloc::borrow::{Cow, ToOwned};
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::Corpus,
|
corpus::{Corpus, HasCurrentCorpusId},
|
||||||
executors::{Executor, HasObservers},
|
executors::{Executor, HasObservers},
|
||||||
inputs::{BytesInput, UsesInput},
|
inputs::{BytesInput, UsesInput},
|
||||||
observers::ObserversTuple,
|
observers::ObserversTuple,
|
||||||
stages::{colorization::TaintMetadata, RetryCountRestartHelper, Stage},
|
stages::{colorization::TaintMetadata, RetryCountRestartHelper, Stage},
|
||||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, UsesState},
|
state::{HasCorpus, HasCurrentTestcase, UsesState},
|
||||||
Error, HasMetadata, HasNamedMetadata,
|
Error, HasMetadata, HasNamedMetadata,
|
||||||
};
|
};
|
||||||
use libafl_bolts::{
|
use libafl_bolts::{
|
||||||
@ -19,56 +19,42 @@ use crate::cmps::observers::AFLppCmpLogObserver;
|
|||||||
|
|
||||||
/// Trace with tainted input
|
/// Trace with tainted input
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AFLppCmplogTracingStage<'a, EM, TE, Z>
|
pub struct AFLppCmplogTracingStage<'a, EM, TE, S, Z> {
|
||||||
where
|
|
||||||
TE: UsesState,
|
|
||||||
{
|
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
tracer_executor: TE,
|
tracer_executor: TE,
|
||||||
cmplog_observer_handle: Handle<AFLppCmpLogObserver<'a>>,
|
cmplog_observer_handle: Handle<AFLppCmpLogObserver<'a>>,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
phantom: PhantomData<(EM, TE, Z)>,
|
phantom: PhantomData<(EM, TE, S, Z)>,
|
||||||
}
|
}
|
||||||
/// The name for aflpp tracing stage
|
/// The name for aflpp tracing stage
|
||||||
pub static AFLPP_CMPLOG_TRACING_STAGE_NAME: &str = "aflpptracing";
|
pub static AFLPP_CMPLOG_TRACING_STAGE_NAME: &str = "aflpptracing";
|
||||||
|
|
||||||
impl<EM, TE, Z> UsesState for AFLppCmplogTracingStage<'_, EM, TE, Z>
|
impl<EM, TE, S, Z> Named for AFLppCmplogTracingStage<'_, EM, TE, S, Z> {
|
||||||
where
|
|
||||||
TE: UsesState,
|
|
||||||
{
|
|
||||||
type State = TE::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<EM, TE, Z> Named for AFLppCmplogTracingStage<'_, EM, TE, Z>
|
|
||||||
where
|
|
||||||
TE: UsesState,
|
|
||||||
{
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, TE, Z> Stage<E, EM, Z> for AFLppCmplogTracingStage<'_, EM, TE, Z>
|
impl<E, EM, TE, S, Z> Stage<E, EM, S, Z> for AFLppCmplogTracingStage<'_, EM, TE, S, Z>
|
||||||
where
|
where
|
||||||
E: UsesState<State = Self::State>,
|
EM: UsesState<State = S>,
|
||||||
TE: Executor<EM, Z> + HasObservers,
|
Z: UsesState<State = S>,
|
||||||
TE::State: HasExecutions
|
TE: HasObservers + Executor<EM, Z, State = S>,
|
||||||
+ HasCorpus
|
TE::Observers: MatchNameRef + ObserversTuple<BytesInput, S>,
|
||||||
+ HasMetadata
|
S: HasCorpus
|
||||||
|
+ HasCurrentTestcase
|
||||||
+ UsesInput<Input = BytesInput>
|
+ UsesInput<Input = BytesInput>
|
||||||
|
+ HasMetadata
|
||||||
+ HasNamedMetadata
|
+ HasNamedMetadata
|
||||||
+ HasCurrentTestcase,
|
+ HasCurrentCorpusId,
|
||||||
TE::Observers: MatchNameRef + ObserversTuple<BytesInput, TE::State>,
|
S::Corpus: Corpus<Input = BytesInput>,
|
||||||
EM: UsesState<State = Self::State>,
|
|
||||||
Z: UsesState<State = Self::State>,
|
|
||||||
<Self::State as HasCorpus>::Corpus: Corpus<Input = BytesInput>, //delete me
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
_executor: &mut E,
|
_executor: &mut E,
|
||||||
state: &mut TE::State,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// First run with the un-mutated input
|
// First run with the un-mutated input
|
||||||
@ -131,22 +117,19 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_restart(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||||
// Tracing stage is always deterministic
|
// Tracing stage is always deterministic
|
||||||
// don't restart
|
// don't restart
|
||||||
RetryCountRestartHelper::no_retry(state, &self.name)
|
RetryCountRestartHelper::no_retry(state, &self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
// TODO: this may need better resumption? (Or is it always used with a forkserver?)
|
// TODO: this may need better resumption? (Or is it always used with a forkserver?)
|
||||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, EM, TE, Z> AFLppCmplogTracingStage<'a, EM, TE, Z>
|
impl<'a, EM, TE, S, Z> AFLppCmplogTracingStage<'a, EM, TE, S, Z> {
|
||||||
where
|
|
||||||
TE: UsesState,
|
|
||||||
{
|
|
||||||
/// With cmplog observer
|
/// With cmplog observer
|
||||||
pub fn new(tracer_executor: TE, observer_handle: Handle<AFLppCmpLogObserver<'a>>) -> Self {
|
pub fn new(tracer_executor: TE, observer_handle: Handle<AFLppCmpLogObserver<'a>>) -> Self {
|
||||||
let observer_name = observer_handle.name().clone();
|
let observer_name = observer_handle.name().clone();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user