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:
Dongjia "toka" Zhang 2024-12-12 16:50:17 +01:00 committed by GitHub
parent c176fee1e0
commit 3446ad974c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 1316 additions and 1775 deletions

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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!

View File

@ -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

View File

@ -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 _,

View File

@ -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.

View File

@ -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)]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -28,6 +28,7 @@ rustc-args = ["--cfg", "docsrs"]
[features] [features]
default = [ default = [
"introspection",
"std", "std",
"derive", "derive",
"llmp_compression", "llmp_compression",

View File

@ -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

View File

@ -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`"));
} }

View File

@ -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
} }

View File

@ -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] {

View File

@ -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)
} }
} }

View File

@ -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>() {

View File

@ -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() {

View File

@ -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(())
} }
} }

View File

@ -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 {

View File

@ -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)
} }
} }

View File

@ -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

View File

@ -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>;

View File

@ -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)
} }
} }

View File

@ -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
}
} }

View File

@ -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,
}
}
}

View File

@ -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(())
} }

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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,

View File

@ -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(())
} }

View File

@ -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(())
} }
} }

View File

@ -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, ()));

View File

@ -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();