No Uses* (again) (#2537)

* ihatethislanguageihatethislanguageihatethislanguageihatethislanguage

* 1

* a

* fuck

* FMTFMTFMTFMTFMTFMT

* 👍

* afasdfadsfs

* lol

* aa

* a bit more
This commit is contained in:
Dongjia "toka" Zhang 2024-09-23 14:03:24 +02:00 committed by GitHub
parent e370e2f852
commit 93fdbb604c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 436 additions and 554 deletions

View File

@ -15,7 +15,7 @@ use libafl::{
inputs::UsesInput, inputs::UsesInput,
mutators::Tokens, mutators::Tokens,
observers::MapObserver, observers::MapObserver,
schedulers::{minimizer::IsFavoredMetadata, HasQueueCycles, Scheduler}, 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, UsesState},
Error, HasMetadata, HasNamedMetadata, HasScheduler, SerdeAny, Error, HasMetadata, HasNamedMetadata, HasScheduler, SerdeAny,
@ -240,7 +240,7 @@ where
+ HasTestcase, + HasTestcase,
O: MapObserver, O: MapObserver,
C: AsRef<O> + Named, C: AsRef<O> + Named,
<Z as HasScheduler>::Scheduler: Scheduler + HasQueueCycles, <Z as HasScheduler>::Scheduler: HasQueueCycles,
{ {
fn perform( fn perform(
&mut self, &mut self,

View File

@ -2,45 +2,39 @@ use std::marker::PhantomData;
use libafl::{ use libafl::{
corpus::{Corpus, CorpusId, HasTestcase, SchedulerTestcaseMetadata, Testcase}, corpus::{Corpus, CorpusId, HasTestcase, SchedulerTestcaseMetadata, Testcase},
inputs::UsesInput, inputs::{Input, UsesInput},
observers::{CanTrack, ObserversTuple}, observers::{CanTrack, ObserversTuple},
schedulers::{ schedulers::{
HasQueueCycles, MinimizerScheduler, RemovableScheduler, Scheduler, TestcaseScore, HasQueueCycles, MinimizerScheduler, RemovableScheduler, Scheduler, TestcaseScore,
}, },
state::{HasCorpus, HasRand, State, UsesState}, state::{HasCorpus, HasRand, State},
Error, HasMetadata, Error, HasMetadata,
}; };
use libafl_bolts::{serdeany::SerdeAny, AsIter, HasRefCnt}; use libafl_bolts::{serdeany::SerdeAny, AsIter, HasRefCnt};
pub enum SupportedSchedulers<S, Q, CS, F, M, O> { pub enum SupportedSchedulers<CS, F, I, M, O, S, Q> {
Queue(Q, PhantomData<(S, Q, CS, F, M, O)>), Queue(Q, PhantomData<(CS, F, I, M, O, S, Q)>),
Weighted( Weighted(
MinimizerScheduler<CS, F, M, O>, MinimizerScheduler<CS, F, I, M, O, S>,
PhantomData<(S, Q, CS, F, M, O)>, PhantomData<(CS, F, I, M, O, S, Q)>,
), ),
} }
impl<S, Q, CS, F, M, O> UsesState for SupportedSchedulers<S, Q, CS, F, M, O> impl<CS, F, I, M, O, S, Q> RemovableScheduler<I, S> for SupportedSchedulers<CS, F, I, M, O, S, Q>
where where
S: State + HasRand + HasCorpus + HasMetadata + HasTestcase, CS: Scheduler<I, S> + RemovableScheduler<I, S>,
{ F: TestcaseScore<I, S>,
type State = S; I: Input,
}
impl<S, Q, CS, F, M, O> RemovableScheduler for SupportedSchedulers<S, Q, CS, F, M, O>
where
S: UsesInput + HasTestcase + HasMetadata + HasCorpus + HasRand + State,
Q: Scheduler<State = S> + RemovableScheduler,
CS: RemovableScheduler<State = S>,
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
O: CanTrack, O: CanTrack,
F: TestcaseScore<S>, Q: Scheduler<I, S> + RemovableScheduler<I, S>,
S: UsesInput + HasTestcase + HasMetadata + HasCorpus<Input = I> + HasRand + State,
{ {
fn on_remove( fn on_remove(
&mut self, &mut self,
state: &mut Self::State, state: &mut S,
id: CorpusId, id: CorpusId,
testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>, testcase: &Option<Testcase<I>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
match self { match self {
Self::Queue(queue, _) => queue.on_remove(state, id, testcase), Self::Queue(queue, _) => queue.on_remove(state, id, testcase),
@ -48,12 +42,7 @@ where
} }
} }
fn on_replace( fn on_replace(&mut self, state: &mut S, id: CorpusId, prev: &Testcase<I>) -> Result<(), Error> {
&mut self,
state: &mut Self::State,
id: CorpusId,
prev: &Testcase<<Self::State as UsesInput>::Input>,
) -> Result<(), Error> {
match self { match self {
Self::Queue(queue, _) => queue.on_replace(state, id, prev), Self::Queue(queue, _) => queue.on_replace(state, id, prev),
Self::Weighted(weighted, _) => weighted.on_replace(state, id, prev), Self::Weighted(weighted, _) => weighted.on_replace(state, id, prev),
@ -61,16 +50,17 @@ where
} }
} }
impl<S, Q, CS, F, M, O> Scheduler for SupportedSchedulers<S, Q, CS, F, M, O> impl<CS, F, I, M, O, S, Q> Scheduler<I, S> for SupportedSchedulers<CS, F, I, M, O, S, Q>
where where
S: UsesInput + HasTestcase + HasMetadata + HasCorpus + HasRand + State, CS: Scheduler<I, S>,
Q: Scheduler<State = S>, F: TestcaseScore<I, S>,
CS: Scheduler<State = S>, I: Input,
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
O: CanTrack, O: CanTrack,
F: TestcaseScore<S>, Q: Scheduler<I, S>,
S: UsesInput + HasTestcase + HasMetadata + HasCorpus<Input = I> + HasRand + State,
{ {
fn on_add(&mut self, state: &mut Self::State, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
match self { match self {
// We need to manually set the depth // We need to manually set the depth
// since we want to avoid implementing `AflScheduler` for `QueueScheduler` // since we want to avoid implementing `AflScheduler` for `QueueScheduler`
@ -94,20 +84,15 @@ where
} }
/// Gets the next entry in the queue /// Gets the next entry in the queue
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut S) -> Result<CorpusId, Error> {
match self { match self {
Self::Queue(queue, _) => queue.next(state), Self::Queue(queue, _) => queue.next(state),
Self::Weighted(weighted, _) => weighted.next(state), Self::Weighted(weighted, _) => weighted.next(state),
} }
} }
fn on_evaluation<OTB>( fn on_evaluation<OTB>(&mut self, state: &mut S, input: &I, observers: &OTB) -> Result<(), Error>
&mut self,
state: &mut Self::State,
input: &<Self::State as UsesInput>::Input,
observers: &OTB,
) -> Result<(), Error>
where where
OTB: ObserversTuple<Self::State>, OTB: ObserversTuple<S>,
{ {
match self { match self {
Self::Queue(queue, _) => queue.on_evaluation(state, input, observers), Self::Queue(queue, _) => queue.on_evaluation(state, input, observers),
@ -117,7 +102,7 @@ where
fn set_current_scheduled( fn set_current_scheduled(
&mut self, &mut self,
state: &mut Self::State, state: &mut S,
next_id: Option<CorpusId>, next_id: Option<CorpusId>,
) -> Result<(), Error> { ) -> Result<(), Error> {
match self { match self {
@ -127,14 +112,16 @@ where
} }
} }
impl<S, Q, CS, F, M, O> HasQueueCycles for SupportedSchedulers<S, Q, CS, F, M, O> impl<CS, F, I, M, O, S, Q> HasQueueCycles for SupportedSchedulers<CS, F, I, M, O, S, Q>
where where
S: UsesInput + HasTestcase + HasMetadata + HasCorpus + HasRand + State, CS: Scheduler<I, S> + HasQueueCycles,
Q: Scheduler<State = S> + HasQueueCycles, F: TestcaseScore<I, S>,
CS: Scheduler<State = S> + HasQueueCycles, I: Input,
O: CanTrack,
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
F: TestcaseScore<S>,
O: CanTrack,
Q: Scheduler<I, S> + HasQueueCycles,
S: UsesInput + HasTestcase + HasMetadata + HasCorpus<Input = I> + HasRand + State,
{ {
fn queue_cycles(&self) -> u64 { fn queue_cycles(&self) -> u64 {
match self { match self {

View File

@ -22,7 +22,7 @@ pub struct PacketLenMetadata {
pub struct PacketLenTestcaseScore {} pub struct PacketLenTestcaseScore {}
impl<S> TestcaseScore<S> for PacketLenTestcaseScore impl<S> TestcaseScore<PacketData, S> for PacketLenTestcaseScore
where where
S: HasCorpus<Input = PacketData> + HasMetadata, S: HasCorpus<Input = PacketData> + HasMetadata,
{ {
@ -34,8 +34,8 @@ where
} }
} }
pub type PacketLenMinimizerScheduler<CS, O> = pub type PacketLenMinimizerScheduler<CS, O, S> =
MinimizerScheduler<CS, PacketLenTestcaseScore, MapIndexesMetadata, O>; MinimizerScheduler<CS, PacketLenTestcaseScore, PacketData, MapIndexesMetadata, O, S>;
#[derive(Serialize, Deserialize, Default, Clone, Debug)] #[derive(Serialize, Deserialize, Default, Clone, Debug)]
pub struct PacketLenFeedback { pub struct PacketLenFeedback {

View File

@ -17,6 +17,7 @@ use crate::{
corpus::Corpus, corpus::Corpus,
events::{Event, EventFirer, LogSeverity}, events::{Event, EventFirer, LogSeverity},
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
inputs::UsesInput,
monitors::{AggregatorOps, UserStats, UserStatsValue}, monitors::{AggregatorOps, UserStats, UserStatsValue},
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
schedulers::{LenTimeMulTestcaseScore, RemovableScheduler, Scheduler, TestcaseScore}, schedulers::{LenTimeMulTestcaseScore, RemovableScheduler, Scheduler, TestcaseScore},
@ -41,7 +42,7 @@ where
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
CS: Scheduler<State = E::State> + RemovableScheduler, // schedulers that has on_remove/on_replace only! CS: Scheduler<E::Input, E::State> + RemovableScheduler<E::Input, E::State>, // schedulers that has on_remove/on_replace only!
EM: EventFirer<State = E::State>, EM: EventFirer<State = E::State>,
Z: HasScheduler<Scheduler = CS, State = E::State>; Z: HasScheduler<Scheduler = CS, State = E::State>;
} }
@ -56,14 +57,19 @@ pub struct MapCorpusMinimizer<C, E, O, T, TS> {
} }
/// Standard corpus minimizer, which weights inputs by length and time. /// Standard corpus minimizer, which weights inputs by length and time.
pub type StdCorpusMinimizer<C, E, O, T> = pub type StdCorpusMinimizer<C, E, O, T> = MapCorpusMinimizer<
MapCorpusMinimizer<C, E, O, T, LenTimeMulTestcaseScore<<E as UsesState>::State>>; C,
E,
O,
T,
LenTimeMulTestcaseScore<<E as UsesInput>::Input, <E as UsesState>::State>,
>;
impl<C, E, O, T, TS> MapCorpusMinimizer<C, E, O, T, TS> impl<C, E, O, T, TS> MapCorpusMinimizer<C, E, O, T, TS>
where where
E: UsesState, E: UsesState,
E::State: HasCorpus + HasMetadata, E::State: HasCorpus + HasMetadata,
TS: TestcaseScore<E::State>, TS: TestcaseScore<E::Input, E::State>,
C: Named, C: Named,
{ {
/// Constructs a new `MapCorpusMinimizer` from a provided observer. This observer will be used /// Constructs a new `MapCorpusMinimizer` from a provided observer. This observer will be used
@ -83,7 +89,7 @@ where
C: AsRef<O>, C: AsRef<O>,
E::State: HasMetadata + HasCorpus + HasExecutions, E::State: HasMetadata + HasCorpus + HasExecutions,
T: Copy + Hash + Eq, T: Copy + Hash + Eq,
TS: TestcaseScore<E::State>, TS: TestcaseScore<E::Input, E::State>,
{ {
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
fn minimize<CS, EM, Z>( fn minimize<CS, EM, Z>(
@ -95,7 +101,7 @@ where
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
CS: Scheduler<State = E::State> + RemovableScheduler, CS: Scheduler<E::Input, E::State> + RemovableScheduler<E::Input, E::State>,
EM: EventFirer<State = E::State>, EM: EventFirer<State = E::State>,
Z: HasScheduler<Scheduler = CS, State = E::State>, Z: HasScheduler<Scheduler = CS, State = E::State>,
{ {

View File

@ -560,7 +560,7 @@ mod tests {
let mut mgr = NopEventManager::new(); let mut mgr = NopEventManager::new();
let mut state = let mut state =
StdState::new(rand, corpus, solutions, &mut feedback, &mut objective).unwrap(); StdState::new(rand, corpus, solutions, &mut feedback, &mut objective).unwrap();
let mut fuzzer = StdFuzzer::<_, _, _>::new(sche, feedback, objective); let mut fuzzer = StdFuzzer::<_, _, _, _>::new(sche, feedback, objective);
let mut in_process_executor = InProcessExecutor::new( let mut in_process_executor = InProcessExecutor::new(
&mut harness, &mut harness,

View File

@ -6,6 +6,8 @@ use core::{fmt::Debug, marker::PhantomData, time::Duration};
use libafl_bolts::current_time; use libafl_bolts::current_time;
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
#[cfg(feature = "introspection")]
use crate::monitors::PerfFeature;
use crate::{ use crate::{
corpus::{Corpus, CorpusId, HasCurrentCorpusId, HasTestcase, Testcase}, corpus::{Corpus, CorpusId, HasCurrentCorpusId, HasTestcase, Testcase},
events::{Event, EventConfig, EventFirer, EventProcessor, ProgressReporter}, events::{Event, EventConfig, EventFirer, EventProcessor, ProgressReporter},
@ -23,8 +25,6 @@ use crate::{
}, },
Error, HasMetadata, Error, HasMetadata,
}; };
#[cfg(feature = "introspection")]
use crate::{monitors::PerfFeature, state::HasClientPerfMonitor};
/// 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); const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15);
@ -35,7 +35,7 @@ where
Self::State: HasCorpus, Self::State: HasCorpus,
{ {
/// The [`Scheduler`] for this fuzzer /// The [`Scheduler`] for this fuzzer
type Scheduler: Scheduler<State = Self::State>; type Scheduler: Scheduler<Self::Input, Self::State>;
/// The scheduler /// The scheduler
fn scheduler(&self) -> &Self::Scheduler; fn scheduler(&self) -> &Self::Scheduler;
@ -303,24 +303,24 @@ pub enum ExecuteInputResult {
/// Your default fuzzer instance, for everyday use. /// Your default fuzzer instance, for everyday use.
#[derive(Debug)] #[derive(Debug)]
pub struct StdFuzzer<CS, F, OF> { pub struct StdFuzzer<CS, F, OF, S> {
scheduler: CS, scheduler: CS,
feedback: F, feedback: F,
objective: OF, objective: OF,
phantom: PhantomData<S>,
} }
impl<CS, F, OF> UsesState for StdFuzzer<CS, F, OF> impl<CS, F, OF, S> UsesState for StdFuzzer<CS, F, OF, S>
where where
CS: Scheduler, S: State,
CS::State: HasCorpus,
{ {
type State = CS::State; type State = S;
} }
impl<CS, F, OF> HasScheduler for StdFuzzer<CS, F, OF> impl<CS, F, OF, S> HasScheduler for StdFuzzer<CS, F, OF, S>
where where
CS: Scheduler, S: State + HasCorpus,
CS::State: HasCorpus, CS: Scheduler<S::Input, S>,
{ {
type Scheduler = CS; type Scheduler = CS;
@ -333,12 +333,11 @@ where
} }
} }
impl<CS, F, OF> HasFeedback for StdFuzzer<CS, F, OF> impl<CS, F, OF, S> HasFeedback for StdFuzzer<CS, F, OF, S>
where where
CS: Scheduler, S: State,
F: Feedback<Self::State>, F: Feedback<S>,
OF: Feedback<Self::State>, OF: Feedback<S>,
CS::State: HasCorpus,
{ {
type Feedback = F; type Feedback = F;
@ -351,12 +350,11 @@ where
} }
} }
impl<CS, F, OF> HasObjective for StdFuzzer<CS, F, OF> impl<CS, F, OF, S> HasObjective for StdFuzzer<CS, F, OF, S>
where where
CS: Scheduler, S: State,
F: Feedback<Self::State>, F: Feedback<S>,
OF: Feedback<Self::State>, OF: Feedback<S>,
CS::State: HasCorpus,
{ {
type Objective = OF; type Objective = OF;
@ -369,23 +367,24 @@ where
} }
} }
impl<CS, F, OF> ExecutionProcessor for StdFuzzer<CS, F, OF> impl<CS, F, OF, S> ExecutionProcessor for StdFuzzer<CS, F, OF, S>
where where
CS: Scheduler, CS: Scheduler<S::Input, S>,
F: Feedback<Self::State>, F: Feedback<S>,
OF: Feedback<Self::State>, OF: Feedback<S>,
CS::State: HasCorpus S: HasCorpus
+ HasSolutions + HasSolutions
+ HasExecutions + HasExecutions
+ HasCorpus + HasCorpus
+ HasCurrentTestcase<<Self::State as UsesInput>::Input> + HasCurrentTestcase<S::Input>
+ HasCurrentCorpusId, + HasCurrentCorpusId
+ State,
{ {
fn check_results<EM, OT>( fn check_results<EM, OT>(
&mut self, &mut self,
state: &mut Self::State, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &<Self::State as UsesInput>::Input, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<ExecuteInputResult, Error> ) -> Result<ExecuteInputResult, Error>
@ -590,27 +589,27 @@ where
} }
} }
impl<CS, F, OF, OT> EvaluatorObservers<OT> for StdFuzzer<CS, F, OF> impl<CS, F, OF, OT, S> EvaluatorObservers<OT> for StdFuzzer<CS, F, OF, S>
where where
CS: Scheduler, CS: Scheduler<S::Input, S>,
OT: ObserversTuple<Self::State> + Serialize + DeserializeOwned, OT: ObserversTuple<S> + Serialize + DeserializeOwned,
F: Feedback<Self::State>, F: Feedback<S>,
OF: Feedback<Self::State>, OF: Feedback<S>,
CS::State: HasCorpus + HasSolutions + HasExecutions, S: HasCorpus + HasSolutions + HasExecutions + State,
{ {
/// Process one input, adding to the respective corpora if needed and firing the right events /// Process one input, adding to the respective corpora if needed and firing the right events
#[inline] #[inline]
fn evaluate_input_with_observers<E, EM>( fn evaluate_input_with_observers<E, EM>(
&mut self, &mut self,
state: &mut Self::State, state: &mut S,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: <Self::State as UsesInput>::Input, input: S::Input,
send_events: bool, send_events: bool,
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> ) -> Result<(ExecuteInputResult, Option<CorpusId>), Error>
where where
E: Executor<EM, Self> + HasObservers<Observers = OT, State = Self::State>, E: Executor<EM, Self> + HasObservers<Observers = OT, State = S>,
EM: EventFirer<State = Self::State>, EM: EventFirer<State = S>,
{ {
let exit_kind = self.execute_input(state, executor, manager, &input)?; let exit_kind = self.execute_input(state, executor, manager, &input)?;
let observers = executor.observers(); let observers = executor.observers();
@ -621,15 +620,15 @@ where
} }
} }
impl<CS, E, EM, F, OF, OT> Evaluator<E, EM> for StdFuzzer<CS, F, OF> impl<CS, E, EM, F, OF, OT, S> Evaluator<E, EM> for StdFuzzer<CS, F, OF, S>
where where
CS: Scheduler, CS: Scheduler<S::Input, S>,
E: HasObservers<State = Self::State, Observers = OT> + Executor<EM, Self>, E: HasObservers<State = S, Observers = OT> + Executor<EM, Self>,
EM: EventFirer<State = Self::State>, EM: EventFirer<State = S>,
F: Feedback<Self::State>, F: Feedback<S>,
OF: Feedback<Self::State>, OF: Feedback<S>,
OT: ObserversTuple<Self::State> + Serialize + DeserializeOwned, OT: ObserversTuple<S> + Serialize + DeserializeOwned,
CS::State: HasCorpus + HasSolutions + HasExecutions + HasLastFoundTime, S: HasCorpus + HasSolutions + HasExecutions + HasLastFoundTime + State,
{ {
/// Process one input, adding to the respective corpora if needed and firing the right events /// Process one input, adding to the respective corpora if needed and firing the right events
#[inline] #[inline]
@ -756,21 +755,22 @@ where
} }
} }
impl<CS, E, EM, F, OF, ST> Fuzzer<E, EM, ST> for StdFuzzer<CS, F, OF> impl<CS, E, EM, F, OF, S, ST> Fuzzer<E, EM, ST> for StdFuzzer<CS, F, OF, S>
where where
CS: Scheduler, CS: Scheduler<S::Input, S>,
E: UsesState<State = Self::State>, E: UsesState<State = S>,
EM: ProgressReporter + EventProcessor<E, Self, State = Self::State>, EM: ProgressReporter + EventProcessor<E, Self, State = S>,
F: Feedback<Self::State>, F: Feedback<S>,
OF: Feedback<Self::State>, OF: Feedback<S>,
CS::State: HasExecutions S: HasExecutions
+ HasMetadata + HasMetadata
+ HasCorpus + HasCorpus
+ HasTestcase + HasTestcase
+ HasLastReportTime + HasLastReportTime
+ HasCurrentCorpusId + HasCurrentCorpusId
+ HasCurrentStageId, + HasCurrentStageId
ST: StagesTuple<E, EM, Self::State, Self>, + State,
ST: StagesTuple<E, EM, S, Self>,
{ {
fn fuzz_one( fn fuzz_one(
&mut self, &mut self,
@ -834,12 +834,12 @@ where
} }
} }
impl<CS, F, OF> StdFuzzer<CS, F, OF> impl<CS, F, OF, S> StdFuzzer<CS, F, OF, S>
where where
CS: Scheduler, CS: Scheduler<S::Input, S>,
F: Feedback<<Self as UsesState>::State>, F: Feedback<<Self as UsesState>::State>,
OF: Feedback<<Self as UsesState>::State>, OF: Feedback<<Self as UsesState>::State>,
CS::State: UsesInput + HasExecutions + HasCorpus, S: UsesInput + HasExecutions + HasCorpus + State,
{ {
/// Create a new `StdFuzzer` with standard behavior. /// Create a new `StdFuzzer` with standard behavior.
pub fn new(scheduler: CS, feedback: F, objective: OF) -> Self { pub fn new(scheduler: CS, feedback: F, objective: OF) -> Self {
@ -847,6 +847,7 @@ where
scheduler, scheduler,
feedback, feedback,
objective, objective,
phantom: PhantomData,
} }
} }
@ -896,22 +897,22 @@ where
) -> Result<ExitKind, Error>; ) -> Result<ExitKind, Error>;
} }
impl<CS, E, EM, F, OF> ExecutesInput<E, EM> for StdFuzzer<CS, F, OF> impl<CS, E, EM, F, OF, S> ExecutesInput<E, EM> for StdFuzzer<CS, F, OF, S>
where where
CS: Scheduler, CS: Scheduler<S::Input, S>,
F: Feedback<<Self as UsesState>::State>, F: Feedback<<Self as UsesState>::State>,
OF: Feedback<<Self as UsesState>::State>, OF: Feedback<<Self as UsesState>::State>,
E: Executor<EM, Self> + HasObservers<State = Self::State>, E: Executor<EM, Self> + HasObservers<State = Self::State>,
EM: UsesState<State = Self::State>, EM: UsesState<State = Self::State>,
CS::State: UsesInput + HasExecutions + HasCorpus, S: UsesInput + HasExecutions + HasCorpus + State,
{ {
/// Runs the input and triggers observers and feedback /// Runs the input and triggers observers and feedback
fn execute_input( fn execute_input(
&mut self, &mut self,
state: &mut <Self as UsesState>::State, state: &mut S,
executor: &mut E, executor: &mut E,
event_mgr: &mut EM, event_mgr: &mut EM,
input: &<<Self as UsesState>::State as UsesInput>::Input, input: &S::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
start_timer!(state); start_timer!(state);
executor.observers_mut().pre_exec_all(state, input)?; executor.observers_mut().pre_exec_all(state, input)?;

View File

@ -13,13 +13,13 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
corpus::{Corpus, CorpusId}, corpus::{Corpus, CorpusId},
feedbacks::MapIndexesMetadata, feedbacks::MapIndexesMetadata,
inputs::UsesInput, inputs::Input,
observers::{CanTrack, ObserversTuple}, observers::{CanTrack, ObserversTuple},
schedulers::{ schedulers::{
minimizer::{IsFavoredMetadata, MinimizerScheduler, DEFAULT_SKIP_NON_FAVORED_PROB}, minimizer::{IsFavoredMetadata, MinimizerScheduler, DEFAULT_SKIP_NON_FAVORED_PROB},
LenTimeMulTestcaseScore, Scheduler, LenTimeMulTestcaseScore, Scheduler,
}, },
state::{HasCorpus, HasRand, UsesState}, state::{HasCorpus, HasRand},
Error, HasMetadata, Error, HasMetadata,
}; };
@ -105,55 +105,32 @@ impl TopAccountingMetadata {
/// A minimizer scheduler using coverage accounting /// A minimizer scheduler using coverage accounting
#[derive(Debug)] #[derive(Debug)]
pub struct CoverageAccountingScheduler<'a, CS, O> pub struct CoverageAccountingScheduler<'a, CS, I, O, S> {
where
CS: UsesState,
CS::State: Debug,
{
accounting_map: &'a [u32], accounting_map: &'a [u32],
skip_non_favored_prob: f64, skip_non_favored_prob: f64,
inner: MinimizerScheduler< inner: MinimizerScheduler<CS, LenTimeMulTestcaseScore<I, S>, I, MapIndexesMetadata, O, S>,
CS,
LenTimeMulTestcaseScore<<CS as UsesState>::State>,
MapIndexesMetadata,
O,
>,
} }
impl<'a, CS, O> UsesState for CoverageAccountingScheduler<'a, CS, O> impl<'a, CS, I, O, S> Scheduler<I, S> for CoverageAccountingScheduler<'a, CS, I, O, S>
where where
CS: UsesState, CS: Scheduler<I, S>,
CS::State: Debug, S: HasCorpus<Input = I> + HasMetadata + HasRand + Debug,
{ I: HasLen + Input,
type State = CS::State;
}
impl<'a, CS, O> Scheduler for CoverageAccountingScheduler<'a, CS, O>
where
CS: Scheduler,
Self::State: HasCorpus + HasMetadata + HasRand,
CS::State: Debug,
<Self::State as UsesInput>::Input: HasLen,
O: CanTrack, O: CanTrack,
{ {
fn on_add(&mut self, state: &mut Self::State, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
self.update_accounting_score(state, id)?; self.update_accounting_score(state, id)?;
self.inner.on_add(state, id) self.inner.on_add(state, id)
} }
fn on_evaluation<OT>( fn on_evaluation<OT>(&mut self, state: &mut S, input: &I, observers: &OT) -> Result<(), Error>
&mut self,
state: &mut Self::State,
input: &<Self::State as UsesInput>::Input,
observers: &OT,
) -> Result<(), Error>
where where
OT: ObserversTuple<Self::State>, OT: ObserversTuple<S>,
{ {
self.inner.on_evaluation(state, input, observers) self.inner.on_evaluation(state, input, observers)
} }
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut S) -> Result<CorpusId, Error> {
if state if state
.metadata_map() .metadata_map()
.get::<TopAccountingMetadata>() .get::<TopAccountingMetadata>()
@ -184,7 +161,7 @@ where
/// Set current fuzzed corpus id and `scheduled_count` /// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled( fn set_current_scheduled(
&mut self, &mut self,
_state: &mut Self::State, _state: &mut S,
_next_id: Option<CorpusId>, _next_id: Option<CorpusId>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// We do nothing here, the inner scheduler will take care of it // We do nothing here, the inner scheduler will take care of it
@ -192,21 +169,17 @@ where
} }
} }
impl<'a, CS, O> CoverageAccountingScheduler<'a, CS, O> impl<'a, CS, I, O, S> CoverageAccountingScheduler<'a, CS, I, O, S>
where where
CS: Scheduler, CS: Scheduler<I, S>,
CS::State: HasCorpus + HasMetadata + HasRand + Debug, S: HasCorpus<Input = I> + HasMetadata + HasRand + Debug,
<CS::State as UsesInput>::Input: HasLen, I: HasLen + Input,
O: CanTrack, O: CanTrack,
{ {
/// Update the `Corpus` score /// Update the `Corpus` score
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
#[allow(clippy::cast_possible_wrap)] #[allow(clippy::cast_possible_wrap)]
pub fn update_accounting_score( pub fn update_accounting_score(&self, state: &mut S, id: CorpusId) -> Result<(), Error> {
&self,
state: &mut CS::State,
id: CorpusId,
) -> Result<(), Error> {
let mut indexes = vec![]; let mut indexes = vec![];
let mut new_favoreds = vec![]; let mut new_favoreds = vec![];
{ {
@ -291,7 +264,7 @@ where
/// Cull the `Corpus` /// Cull the `Corpus`
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn accounting_cull(&self, state: &CS::State) -> Result<(), Error> { pub fn accounting_cull(&self, state: &S) -> Result<(), Error> {
let Some(top_rated) = state.metadata_map().get::<TopAccountingMetadata>() else { let Some(top_rated) = state.metadata_map().get::<TopAccountingMetadata>() else {
return Ok(()); return Ok(());
}; };
@ -312,7 +285,7 @@ where
/// and has a default probability to skip non-faved Testcases of [`DEFAULT_SKIP_NON_FAVORED_PROB`]. /// and has a default probability to skip non-faved Testcases of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
/// ///
/// Provide the observer responsible for determining new indexes. /// Provide the observer responsible for determining new indexes.
pub fn new(observer: &O, state: &mut CS::State, base: CS, accounting_map: &'a [u32]) -> Self { pub fn new(observer: &O, state: &mut S, base: CS, accounting_map: &'a [u32]) -> Self {
match state.metadata_map().get::<TopAccountingMetadata>() { match state.metadata_map().get::<TopAccountingMetadata>() {
Some(meta) => { Some(meta) => {
if meta.max_accounting.len() != accounting_map.len() { if meta.max_accounting.len() != accounting_map.len() {
@ -336,7 +309,7 @@ where
/// Provide the observer responsible for determining new indexes. /// Provide the observer responsible for determining new indexes.
pub fn with_skip_prob( pub fn with_skip_prob(
observer: &O, observer: &O,
state: &mut CS::State, state: &mut S,
base: CS, base: CS,
skip_non_favored_prob: f64, skip_non_favored_prob: f64,
accounting_map: &'a [u32], accounting_map: &'a [u32],

View File

@ -11,11 +11,11 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
corpus::{Corpus, CorpusId, Testcase}, corpus::{Corpus, CorpusId, Testcase},
feedbacks::MapIndexesMetadata, feedbacks::MapIndexesMetadata,
inputs::UsesInput, inputs::Input,
observers::{CanTrack, ObserversTuple}, observers::{CanTrack, ObserversTuple},
require_index_tracking, require_index_tracking,
schedulers::{LenTimeMulTestcaseScore, RemovableScheduler, Scheduler, TestcaseScore}, schedulers::{LenTimeMulTestcaseScore, RemovableScheduler, Scheduler, TestcaseScore},
state::{HasCorpus, HasRand, UsesState}, state::{HasCorpus, HasRand},
Error, HasMetadata, Error, HasMetadata,
}; };
@ -72,34 +72,28 @@ impl Default for TopRatedsMetadata {
/// ///
/// E.g., it can use all the coverage seen so far to prioritize [`Testcase`]`s` using a [`TestcaseScore`]. /// E.g., it can use all the coverage seen so far to prioritize [`Testcase`]`s` using a [`TestcaseScore`].
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct MinimizerScheduler<CS, F, M, O> { pub struct MinimizerScheduler<CS, F, I, M, O, S> {
base: CS, base: CS,
skip_non_favored_prob: f64, skip_non_favored_prob: f64,
remove_metadata: bool, remove_metadata: bool,
phantom: PhantomData<(F, M, O)>, phantom: PhantomData<(F, I, M, O, S)>,
} }
impl<CS, F, M, O> UsesState for MinimizerScheduler<CS, F, M, O> impl<CS, F, I, M, O, S> RemovableScheduler<I, S> for MinimizerScheduler<CS, F, I, M, O, S>
where where
CS: UsesState, CS: RemovableScheduler<I, S> + Scheduler<I, S>,
{ I: Input,
type State = CS::State; F: TestcaseScore<I, S>,
}
impl<CS, F, M, O> RemovableScheduler for MinimizerScheduler<CS, F, M, O>
where
CS: RemovableScheduler,
F: TestcaseScore<<Self as UsesState>::State>,
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
<Self as UsesState>::State: HasCorpus + HasMetadata + HasRand, S: HasCorpus<Input = I> + HasMetadata + HasRand,
O: CanTrack, O: CanTrack,
{ {
/// Replaces the [`Testcase`] at the given [`CorpusId`] /// Replaces the [`Testcase`] at the given [`CorpusId`]
fn on_replace( fn on_replace(
&mut self, &mut self,
state: &mut <Self as UsesState>::State, state: &mut S,
id: CorpusId, id: CorpusId,
testcase: &Testcase<<<Self as UsesState>::State as UsesInput>::Input>, testcase: &Testcase<I>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.base.on_replace(state, id, testcase)?; self.base.on_replace(state, id, testcase)?;
self.update_score(state, id) self.update_score(state, id)
@ -108,9 +102,9 @@ where
/// Removes an entry from the corpus /// Removes an entry from the corpus
fn on_remove( fn on_remove(
&mut self, &mut self,
state: &mut <Self as UsesState>::State, state: &mut S,
id: CorpusId, id: CorpusId,
testcase: &Option<Testcase<<<Self as UsesState>::State as UsesInput>::Input>>, testcase: &Option<Testcase<I>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.base.on_remove(state, id, testcase)?; self.base.on_remove(state, id, testcase)?;
let mut entries = let mut entries =
@ -194,35 +188,31 @@ where
} }
} }
impl<CS, F, M, O> Scheduler for MinimizerScheduler<CS, F, M, O> impl<CS, F, I, M, O, S> Scheduler<I, S> for MinimizerScheduler<CS, F, I, M, O, S>
where where
CS: Scheduler, CS: Scheduler<I, S>,
F: TestcaseScore<Self::State>, F: TestcaseScore<I, S>,
I: Input,
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
Self::State: HasCorpus + HasMetadata + HasRand, S: HasCorpus<Input = I> + HasMetadata + HasRand,
O: CanTrack, O: CanTrack,
{ {
/// Called when a [`Testcase`] is added to the corpus /// Called when a [`Testcase`] is added to the corpus
fn on_add(&mut self, state: &mut Self::State, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
self.base.on_add(state, id)?; self.base.on_add(state, id)?;
self.update_score(state, id) self.update_score(state, id)
} }
/// An input has been evaluated /// An input has been evaluated
fn on_evaluation<OT>( fn on_evaluation<OT>(&mut self, state: &mut S, input: &I, observers: &OT) -> Result<(), Error>
&mut self,
state: &mut Self::State,
input: &<Self::State as UsesInput>::Input,
observers: &OT,
) -> Result<(), Error>
where where
OT: ObserversTuple<Self::State>, OT: ObserversTuple<S>,
{ {
self.base.on_evaluation(state, input, observers) self.base.on_evaluation(state, input, observers)
} }
/// Gets the next entry /// Gets the next entry
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut S) -> Result<CorpusId, Error> {
self.cull(state)?; self.cull(state)?;
let mut id = self.base.next(state)?; let mut id = self.base.next(state)?;
while { while {
@ -242,7 +232,7 @@ where
/// Set current fuzzed corpus id and `scheduled_count` /// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled( fn set_current_scheduled(
&mut self, &mut self,
_state: &mut Self::State, _state: &mut S,
_next_id: Option<CorpusId>, _next_id: Option<CorpusId>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// We do nothing here, the inner scheduler will take care of it // We do nothing here, the inner scheduler will take care of it
@ -250,22 +240,19 @@ where
} }
} }
impl<CS, F, M, O> MinimizerScheduler<CS, F, M, O> impl<CS, F, I, M, O, S> MinimizerScheduler<CS, F, I, M, O, S>
where where
CS: Scheduler, CS: Scheduler<I, S>,
F: TestcaseScore<<Self as UsesState>::State>, F: TestcaseScore<I, S>,
I: Input,
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
<Self as UsesState>::State: HasCorpus + HasMetadata + HasRand, S: HasCorpus<Input = I> + HasMetadata + HasRand,
O: CanTrack, O: CanTrack,
{ {
/// Update the [`Corpus`] score using the [`MinimizerScheduler`] /// Update the [`Corpus`] score using the [`MinimizerScheduler`]
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
#[allow(clippy::cast_possible_wrap)] #[allow(clippy::cast_possible_wrap)]
pub fn update_score( pub fn update_score(&self, state: &mut S, id: CorpusId) -> Result<(), Error> {
&self,
state: &mut <Self as UsesState>::State,
id: CorpusId,
) -> Result<(), Error> {
// Create a new top rated meta if not existing // Create a new top rated meta if not existing
if state.metadata_map().get::<TopRatedsMetadata>().is_none() { if state.metadata_map().get::<TopRatedsMetadata>().is_none() {
state.add_metadata(TopRatedsMetadata::new()); state.add_metadata(TopRatedsMetadata::new());
@ -339,7 +326,7 @@ where
/// Cull the [`Corpus`] using the [`MinimizerScheduler`] /// Cull the [`Corpus`] using the [`MinimizerScheduler`]
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn cull(&self, state: &<Self as UsesState>::State) -> Result<(), Error> { pub fn cull(&self, state: &S) -> Result<(), Error> {
let Some(top_rated) = state.metadata_map().get::<TopRatedsMetadata>() else { let Some(top_rated) = state.metadata_map().get::<TopRatedsMetadata>() else {
return Ok(()); return Ok(());
}; };
@ -423,14 +410,10 @@ where
} }
/// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`. /// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`.
pub type LenTimeMinimizerScheduler<CS, M, O> = pub type LenTimeMinimizerScheduler<CS, I, M, O, S> =
MinimizerScheduler<CS, LenTimeMulTestcaseScore<<CS as UsesState>::State>, M, O>; MinimizerScheduler<CS, LenTimeMulTestcaseScore<I, S>, I, M, O, S>;
/// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s` /// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`
/// that exercise all the entries registered in the [`MapIndexesMetadata`]. /// that exercise all the entries registered in the [`MapIndexesMetadata`].
pub type IndexesLenTimeMinimizerScheduler<CS, O> = MinimizerScheduler< pub type IndexesLenTimeMinimizerScheduler<CS, I, O, S> =
CS, MinimizerScheduler<CS, LenTimeMulTestcaseScore<I, S>, I, MapIndexesMetadata, O, S>;
LenTimeMulTestcaseScore<<CS as UsesState>::State>,
MapIndexesMetadata,
O,
>;

View File

@ -35,25 +35,25 @@ pub use tuneable::*;
use crate::{ use crate::{
corpus::{Corpus, CorpusId, HasTestcase, SchedulerTestcaseMetadata, Testcase}, corpus::{Corpus, CorpusId, HasTestcase, SchedulerTestcaseMetadata, Testcase},
inputs::UsesInput, inputs::Input,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
random_corpus_id, random_corpus_id,
state::{HasCorpus, HasRand, State, UsesState}, state::{HasCorpus, HasRand, State},
Error, HasMetadata, Error, HasMetadata,
}; };
/// The scheduler also implements `on_remove` and `on_replace` if it implements this stage. /// The scheduler also implements `on_remove` and `on_replace` if it implements this stage.
pub trait RemovableScheduler: Scheduler pub trait RemovableScheduler<I, S>
where where
Self::State: HasCorpus, I: Input,
{ {
/// Removed the given entry from the corpus at the given index /// Removed the given entry from the corpus at the given index
/// When you remove testcases, make sure that that testcase is not currently fuzzed one! /// When you remove testcases, make sure that that testcase is not currently fuzzed one!
fn on_remove( fn on_remove(
&mut self, &mut self,
_state: &mut Self::State, _state: &mut S,
_id: CorpusId, _id: CorpusId,
_testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>, _testcase: &Option<Testcase<I>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
} }
@ -61,21 +61,23 @@ where
/// Replaced the given testcase at the given idx /// Replaced the given testcase at the given idx
fn on_replace( fn on_replace(
&mut self, &mut self,
_state: &mut Self::State, _state: &mut S,
_id: CorpusId, _id: CorpusId,
_prev: &Testcase<<Self::State as UsesInput>::Input>, _prev: &Testcase<I>,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
} }
} }
/// Defines the common metadata operations for the AFL-style schedulers /// Defines the common metadata operations for the AFL-style schedulers
pub trait AflScheduler<C, O, S>: Scheduler pub trait AflScheduler<I, O, S>
where where
Self::State: HasCorpus + HasMetadata + HasTestcase, S: HasCorpus + HasMetadata + HasTestcase,
O: MapObserver, O: MapObserver,
C: AsRef<O>,
{ {
/// The type of [`MapObserver`] that this scheduler will use as reference
type MapObserverRef: AsRef<O>;
/// Return the last hash /// Return the last hash
fn last_hash(&self) -> usize; fn last_hash(&self) -> usize;
@ -83,10 +85,10 @@ where
fn set_last_hash(&mut self, value: usize); fn set_last_hash(&mut self, value: usize);
/// Get the observer map observer name /// Get the observer map observer name
fn map_observer_handle(&self) -> &Handle<C>; fn map_observer_handle(&self) -> &Handle<Self::MapObserverRef>;
/// Called when a [`Testcase`] is added to the corpus /// Called when a [`Testcase`] is added to the corpus
fn on_add_metadata(&self, state: &mut Self::State, id: CorpusId) -> Result<(), Error> { fn on_add_metadata(&self, state: &mut S, id: CorpusId) -> Result<(), Error> {
let current_id = *state.corpus().current(); let current_id = *state.corpus().current();
let mut depth = match current_id { let mut depth = match current_id {
@ -114,12 +116,12 @@ where
/// Called when a [`Testcase`] is evaluated /// Called when a [`Testcase`] is evaluated
fn on_evaluation_metadata<OT>( fn on_evaluation_metadata<OT>(
&mut self, &mut self,
state: &mut Self::State, state: &mut S,
_input: &<Self::State as UsesInput>::Input, _input: &I,
observers: &OT, observers: &OT,
) -> Result<(), Error> ) -> Result<(), Error>
where where
OT: ObserversTuple<Self::State>, OT: ObserversTuple<S>,
{ {
let observer = observers let observer = observers
.get(self.map_observer_handle()) .get(self.map_observer_handle())
@ -140,11 +142,7 @@ where
} }
/// Called when choosing the next [`Testcase`] /// Called when choosing the next [`Testcase`]
fn on_next_metadata( fn on_next_metadata(&mut self, state: &mut S, _next_id: Option<CorpusId>) -> Result<(), Error> {
&mut self,
state: &mut Self::State,
_next_id: Option<CorpusId>,
) -> Result<(), Error> {
let current_id = *state.corpus().current(); let current_id = *state.corpus().current();
if let Some(id) = current_id { if let Some(id) = current_id {
@ -163,45 +161,42 @@ where
} }
/// Trait for Schedulers which track queue cycles /// Trait for Schedulers which track queue cycles
pub trait HasQueueCycles: Scheduler pub trait HasQueueCycles {
where
Self::State: HasCorpus,
{
/// The amount of cycles the scheduler has completed. /// The amount of cycles the scheduler has completed.
fn queue_cycles(&self) -> u64; fn queue_cycles(&self) -> u64;
} }
/// The scheduler define how the fuzzer requests a testcase from the corpus. /// The scheduler define how the fuzzer requests a testcase from the corpus.
/// It has hooks to corpus add/replace/remove to allow complex scheduling algorithms to collect data. /// It has hooks to corpus add/replace/remove to allow complex scheduling algorithms to collect data.
pub trait Scheduler: UsesState pub trait Scheduler<I, S>
where where
Self::State: HasCorpus, S: HasCorpus,
{ {
/// Called when a [`Testcase`] is added to the corpus /// Called when a [`Testcase`] is added to the corpus
fn on_add(&mut self, _state: &mut Self::State, _id: CorpusId) -> Result<(), Error>; fn on_add(&mut self, _state: &mut S, _id: CorpusId) -> Result<(), Error>;
// Add parent_id here if it has no inner // Add parent_id here if it has no inner
/// An input has been evaluated /// An input has been evaluated
fn on_evaluation<OT>( fn on_evaluation<OT>(
&mut self, &mut self,
_state: &mut Self::State, _state: &mut S,
_input: &<Self::State as UsesInput>::Input, _input: &I,
_observers: &OT, _observers: &OT,
) -> Result<(), Error> ) -> Result<(), Error>
where where
OT: ObserversTuple<Self::State>, OT: ObserversTuple<S>,
{ {
Ok(()) Ok(())
} }
/// Gets the next entry /// Gets the next entry
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error>; fn next(&mut self, state: &mut S) -> Result<CorpusId, Error>;
// Increment corpus.current() here if it has no inner // Increment corpus.current() here if it has no inner
/// Set current fuzzed corpus id and `scheduled_count` /// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled( fn set_current_scheduled(
&mut self, &mut self,
state: &mut Self::State, state: &mut S,
next_id: Option<CorpusId>, next_id: Option<CorpusId>,
) -> Result<(), Error> { ) -> Result<(), Error> {
*state.corpus_mut().current_mut() = next_id; *state.corpus_mut().current_mut() = next_id;
@ -215,18 +210,11 @@ pub struct RandScheduler<S> {
phantom: PhantomData<S>, phantom: PhantomData<S>,
} }
impl<S> UsesState for RandScheduler<S> impl<I, S> Scheduler<I, S> for RandScheduler<S>
where
S: State + HasTestcase,
{
type State = S;
}
impl<S> Scheduler for RandScheduler<S>
where where
S: HasCorpus + HasRand + HasTestcase + State, S: HasCorpus + HasRand + HasTestcase + State,
{ {
fn on_add(&mut self, state: &mut Self::State, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
// Set parent id // Set parent id
let current_id = *state.corpus().current(); let current_id = *state.corpus().current();
state state
@ -239,7 +227,7 @@ where
} }
/// Gets the next entry at random /// Gets the next entry at random
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut S) -> Result<CorpusId, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
Err(Error::empty( Err(Error::empty(
"No entries in corpus. This often implies the target is not properly instrumented." "No entries in corpus. This often implies the target is not properly instrumented."
@ -247,7 +235,7 @@ where
)) ))
} else { } else {
let id = random_corpus_id!(state.corpus(), state.rand_mut()); let id = random_corpus_id!(state.corpus(), state.rand_mut());
self.set_current_scheduled(state, Some(id))?; <Self as Scheduler<I, S>>::set_current_scheduled(self, state, Some(id))?;
Ok(id) Ok(id)
} }
} }

View File

@ -11,10 +11,10 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
corpus::{Corpus, CorpusId, HasTestcase, Testcase}, corpus::{Corpus, CorpusId, HasTestcase, Testcase},
inputs::UsesInput, inputs::Input,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
schedulers::{AflScheduler, HasQueueCycles, RemovableScheduler, Scheduler}, schedulers::{AflScheduler, HasQueueCycles, RemovableScheduler, Scheduler},
state::{HasCorpus, State, UsesState}, state::{HasCorpus, State},
Error, HasMetadata, Error, HasMetadata,
}; };
@ -271,33 +271,27 @@ pub enum BaseSchedule {
/// Note that this corpus is merely holding the metadata necessary for the power calculation /// Note that this corpus is merely holding the metadata necessary for the power calculation
/// and here we DON'T actually calculate the power (we do it in the stage) /// and here we DON'T actually calculate the power (we do it in the stage)
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PowerQueueScheduler<C, O, S> { pub struct PowerQueueScheduler<C, I, O, S> {
queue_cycles: u64, queue_cycles: u64,
strat: PowerSchedule, strat: PowerSchedule,
map_observer_handle: Handle<C>, map_observer_handle: Handle<C>,
last_hash: usize, last_hash: usize,
phantom: PhantomData<(O, S)>, phantom: PhantomData<(I, O, S)>,
} }
impl<C, O, S> UsesState for PowerQueueScheduler<C, O, S> impl<C, I, O, S> RemovableScheduler<I, S> for PowerQueueScheduler<C, I, O, S>
where
S: State,
{
type State = S;
}
impl<C, O, S> RemovableScheduler for PowerQueueScheduler<C, O, S>
where where
S: State + HasTestcase + HasMetadata + HasCorpus, S: State + HasTestcase + HasMetadata + HasCorpus,
O: MapObserver, O: MapObserver,
C: AsRef<O>, C: AsRef<O>,
I: Input,
{ {
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata` /// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
fn on_remove( fn on_remove(
&mut self, &mut self,
_state: &mut Self::State, _state: &mut S,
_id: CorpusId, _id: CorpusId,
_prev: &Option<Testcase<<Self::State as UsesInput>::Input>>, _prev: &Option<Testcase<I>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
} }
@ -305,20 +299,22 @@ where
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata` /// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
fn on_replace( fn on_replace(
&mut self, &mut self,
_state: &mut Self::State, _state: &mut S,
_id: CorpusId, _id: CorpusId,
_prev: &Testcase<<Self::State as UsesInput>::Input>, _prev: &Testcase<I>,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
} }
} }
impl<C, O, S> AflScheduler<C, O, S> for PowerQueueScheduler<C, O, S> impl<C, I, O, S> AflScheduler<I, O, S> for PowerQueueScheduler<C, I, O, S>
where where
S: HasCorpus + HasMetadata + HasTestcase + State, S: HasCorpus + HasMetadata + HasTestcase + State,
O: MapObserver, O: MapObserver,
C: AsRef<O>, C: AsRef<O>,
{ {
type MapObserverRef = C;
fn last_hash(&self) -> usize { fn last_hash(&self) -> usize {
self.last_hash self.last_hash
} }
@ -332,7 +328,7 @@ where
} }
} }
impl<C, O, S> HasQueueCycles for PowerQueueScheduler<C, O, S> impl<C, I, O, S> HasQueueCycles for PowerQueueScheduler<C, I, O, S>
where where
S: HasCorpus + HasMetadata + HasTestcase + State, S: HasCorpus + HasMetadata + HasTestcase + State,
O: MapObserver, O: MapObserver,
@ -343,30 +339,25 @@ where
} }
} }
impl<C, O, S> Scheduler for PowerQueueScheduler<C, O, S> impl<C, I, O, S> Scheduler<I, S> for PowerQueueScheduler<C, I, O, S>
where where
S: HasCorpus + HasMetadata + HasTestcase + State, S: HasCorpus + HasMetadata + HasTestcase + State,
O: MapObserver, O: MapObserver,
C: AsRef<O>, C: AsRef<O>,
{ {
/// Called when a [`Testcase`] is added to the corpus /// Called when a [`Testcase`] is added to the corpus
fn on_add(&mut self, state: &mut Self::State, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
self.on_add_metadata(state, id) <Self as AflScheduler<I, O, S>>::on_add_metadata(self, state, id)
} }
fn on_evaluation<OT>( fn on_evaluation<OT>(&mut self, state: &mut S, input: &I, observers: &OT) -> Result<(), Error>
&mut self,
state: &mut Self::State,
input: &<Self::State as UsesInput>::Input,
observers: &OT,
) -> Result<(), Error>
where where
OT: ObserversTuple<Self::State>, OT: ObserversTuple<S>,
{ {
self.on_evaluation_metadata(state, input, observers) self.on_evaluation_metadata(state, input, observers)
} }
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut S) -> Result<CorpusId, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
Err(Error::empty( Err(Error::empty(
"No entries in corpus. This often implies the target is not properly instrumented.", "No entries in corpus. This often implies the target is not properly instrumented.",
@ -394,17 +385,17 @@ where
/// Set current fuzzed corpus id and `scheduled_count` /// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled( fn set_current_scheduled(
&mut self, &mut self,
state: &mut Self::State, state: &mut S,
next_id: Option<CorpusId>, next_id: Option<CorpusId>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.on_next_metadata(state, next_id)?; <Self as AflScheduler<I, O, S>>::on_next_metadata(self, state, next_id)?;
*state.corpus_mut().current_mut() = next_id; *state.corpus_mut().current_mut() = next_id;
Ok(()) Ok(())
} }
} }
impl<C, O, S> PowerQueueScheduler<C, O, S> impl<C, I, O, S> PowerQueueScheduler<C, I, O, S>
where where
S: HasMetadata, S: HasMetadata,
O: MapObserver, O: MapObserver,

View File

@ -10,19 +10,16 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
corpus::{Corpus, CorpusId, HasTestcase, Testcase}, corpus::{Corpus, CorpusId, HasTestcase, Testcase},
inputs::UsesInput, inputs::Input,
schedulers::{RemovableScheduler, Scheduler, TestcaseScore}, schedulers::{RemovableScheduler, Scheduler, TestcaseScore},
state::{HasCorpus, HasRand, State, UsesState}, state::{HasCorpus, HasRand, State},
Error, HasMetadata, Error, HasMetadata,
}; };
/// Conduct reservoir sampling (probabilistic sampling) over all corpus elements. /// Conduct reservoir sampling (probabilistic sampling) over all corpus elements.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ProbabilitySamplingScheduler<F, S> pub struct ProbabilitySamplingScheduler<F, I, S> {
where phantom: PhantomData<(F, I, S)>,
S: UsesInput,
{
phantom: PhantomData<(F, S)>,
} }
/// A state metadata holding a map of probability of corpus elements. /// A state metadata holding a map of probability of corpus elements.
@ -57,10 +54,11 @@ impl Default for ProbabilityMetadata {
} }
} }
impl<F, S> ProbabilitySamplingScheduler<F, S> impl<F, I, S> ProbabilitySamplingScheduler<F, I, S>
where where
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
S: HasCorpus + HasMetadata + HasRand, I: Input,
S: HasCorpus<Input = I> + HasMetadata + HasRand,
{ {
/// Creates a new [`struct@ProbabilitySamplingScheduler`] /// Creates a new [`struct@ProbabilitySamplingScheduler`]
#[must_use] #[must_use]
@ -89,16 +87,17 @@ where
} }
} }
impl<F, S> RemovableScheduler for ProbabilitySamplingScheduler<F, S> impl<I, F, S> RemovableScheduler<I, S> for ProbabilitySamplingScheduler<F, I, S>
where where
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State, I: Input,
S: HasCorpus<Input = I> + HasMetadata + HasRand + HasTestcase + State,
{ {
fn on_remove( fn on_remove(
&mut self, &mut self,
state: &mut Self::State, state: &mut S,
id: CorpusId, id: CorpusId,
_testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>, _testcase: &Option<Testcase<I>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let meta = state let meta = state
.metadata_map_mut() .metadata_map_mut()
@ -112,9 +111,9 @@ where
fn on_replace( fn on_replace(
&mut self, &mut self,
state: &mut Self::State, state: &mut S,
id: CorpusId, id: CorpusId,
_prev: &Testcase<<Self::State as UsesInput>::Input>, _prev: &Testcase<I>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let meta = state let meta = state
.metadata_map_mut() .metadata_map_mut()
@ -128,19 +127,13 @@ where
} }
} }
impl<F, S> UsesState for ProbabilitySamplingScheduler<F, S> impl<I, F, S> Scheduler<I, S> for ProbabilitySamplingScheduler<F, I, S>
where where
S: State + HasTestcase, F: TestcaseScore<I, S>,
I: Input,
S: HasCorpus<Input = I> + HasMetadata + HasRand + HasTestcase + State,
{ {
type State = S; fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
}
impl<F, S> Scheduler for ProbabilitySamplingScheduler<F, S>
where
F: TestcaseScore<S>,
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State,
{
fn on_add(&mut self, state: &mut Self::State, id: CorpusId) -> Result<(), Error> {
let current_id = *state.corpus().current(); let current_id = *state.corpus().current();
state state
.corpus() .corpus()
@ -156,7 +149,7 @@ where
/// Gets the next entry /// Gets the next entry
#[allow(clippy::cast_precision_loss)] #[allow(clippy::cast_precision_loss)]
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut S) -> Result<CorpusId, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
Err(Error::empty(String::from( Err(Error::empty(String::from(
"No entries in corpus. This often implies the target is not properly instrumented.", "No entries in corpus. This often implies the target is not properly instrumented.",
@ -180,10 +173,11 @@ where
} }
} }
impl<F, S> Default for ProbabilitySamplingScheduler<F, S> impl<F, I, S> Default for ProbabilitySamplingScheduler<F, I, S>
where where
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
S: HasCorpus + HasMetadata + HasRand, I: Input,
S: HasCorpus<Input = I> + HasMetadata + HasRand,
{ {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
@ -200,7 +194,7 @@ mod tests {
use crate::{ use crate::{
corpus::{Corpus, InMemoryCorpus, Testcase}, corpus::{Corpus, InMemoryCorpus, Testcase},
feedbacks::ConstFeedback, feedbacks::ConstFeedback,
inputs::{bytes::BytesInput, Input, UsesInput}, inputs::{bytes::BytesInput, Input},
schedulers::{ProbabilitySamplingScheduler, Scheduler, TestcaseScore}, schedulers::{ProbabilitySamplingScheduler, Scheduler, TestcaseScore},
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
Error, HasMetadata, Error, HasMetadata,
@ -216,17 +210,18 @@ mod tests {
phantom: PhantomData<I>, phantom: PhantomData<I>,
} }
impl<S> TestcaseScore<S> for UniformDistribution<S::Input> impl<I, S> TestcaseScore<I, S> for UniformDistribution<I>
where where
S: HasMetadata + HasCorpus, S: HasMetadata + HasCorpus,
I: Input,
{ {
fn compute(_state: &S, _: &mut Testcase<S::Input>) -> Result<f64, Error> { fn compute(_state: &S, _: &mut Testcase<I>) -> Result<f64, Error> {
Ok(FACTOR) Ok(FACTOR)
} }
} }
pub type UniformProbabilitySamplingScheduler<S> = pub type UniformProbabilitySamplingScheduler<I, S> =
ProbabilitySamplingScheduler<UniformDistribution<<S as UsesInput>::Input>, S>; ProbabilitySamplingScheduler<UniformDistribution<I>, I, S>;
#[test] #[test]
fn test_prob_sampling() { fn test_prob_sampling() {
@ -240,7 +235,8 @@ mod tests {
// the first 3 probabilities will be .76, .86, .36 // the first 3 probabilities will be .76, .86, .36
let rand = StdRand::with_seed(2); let rand = StdRand::with_seed(2);
let mut scheduler = UniformProbabilitySamplingScheduler::new(); let mut scheduler: ProbabilitySamplingScheduler<_, BytesInput, _> =
UniformProbabilitySamplingScheduler::new();
let mut feedback = ConstFeedback::new(false); let mut feedback = ConstFeedback::new(false);
let mut objective = ConstFeedback::new(false); let mut objective = ConstFeedback::new(false);

View File

@ -5,33 +5,27 @@ use core::marker::PhantomData;
use crate::{ use crate::{
corpus::{Corpus, CorpusId, HasTestcase}, corpus::{Corpus, CorpusId, HasTestcase},
inputs::Input,
schedulers::{HasQueueCycles, RemovableScheduler, Scheduler}, schedulers::{HasQueueCycles, RemovableScheduler, Scheduler},
state::{HasCorpus, State, UsesState}, state::{HasCorpus, State},
Error, Error,
}; };
/// Walk the corpus in a queue-like fashion /// Walk the corpus in a queue-like fashion
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct QueueScheduler<S> { pub struct QueueScheduler<I, S> {
queue_cycles: u64, queue_cycles: u64,
runs_in_current_cycle: u64, runs_in_current_cycle: u64,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl<S> UsesState for QueueScheduler<S> impl<I, S> RemovableScheduler<I, S> for QueueScheduler<I, S> where I: Input {}
where
S: State,
{
type State = S;
}
impl<S> RemovableScheduler for QueueScheduler<S> where S: HasCorpus + HasTestcase + State {} impl<I, S> Scheduler<I, S> for QueueScheduler<I, S>
impl<S> Scheduler for QueueScheduler<S>
where where
S: HasCorpus + HasTestcase + State, S: HasCorpus + HasTestcase + State,
{ {
fn on_add(&mut self, state: &mut Self::State, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
// Set parent id // Set parent id
let current_id = *state.corpus().current(); let current_id = *state.corpus().current();
state state
@ -44,7 +38,7 @@ where
} }
/// Gets the next entry in the queue /// Gets the next entry in the queue
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut S) -> Result<CorpusId, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
Err(Error::empty( Err(Error::empty(
"No entries in corpus. This often implies the target is not properly instrumented." "No entries in corpus. This often implies the target is not properly instrumented."
@ -69,7 +63,7 @@ where
} }
} }
impl<S> QueueScheduler<S> { impl<I, S> QueueScheduler<I, S> {
/// Creates a new `QueueScheduler` /// Creates a new `QueueScheduler`
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
@ -81,16 +75,13 @@ impl<S> QueueScheduler<S> {
} }
} }
impl<S> Default for QueueScheduler<S> { impl<I, S> Default for QueueScheduler<I, S> {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
} }
impl<S> HasQueueCycles for QueueScheduler<S> impl<I, S> HasQueueCycles for QueueScheduler<I, S> {
where
S: HasCorpus + HasTestcase + State,
{
fn queue_cycles(&self) -> u64 { fn queue_cycles(&self) -> u64 {
self.queue_cycles self.queue_cycles
} }
@ -115,7 +106,7 @@ mod tests {
#[test] #[test]
fn test_queuecorpus() { fn test_queuecorpus() {
let rand = StdRand::with_seed(4); let rand = StdRand::with_seed(4);
let mut scheduler = QueueScheduler::new(); let mut scheduler: QueueScheduler<BytesInput, _> = QueueScheduler::new();
let mut q = let mut q =
OnDiskCorpus::<BytesInput>::new(PathBuf::from("target/.test/fancy/path")).unwrap(); OnDiskCorpus::<BytesInput>::new(PathBuf::from("target/.test/fancy/path")).unwrap();

View File

@ -7,6 +7,7 @@ use libafl_bolts::{HasLen, HasRefCnt};
use crate::{ use crate::{
corpus::{Corpus, SchedulerTestcaseMetadata, Testcase}, corpus::{Corpus, SchedulerTestcaseMetadata, Testcase},
feedbacks::MapIndexesMetadata, feedbacks::MapIndexesMetadata,
inputs::Input,
schedulers::{ schedulers::{
minimizer::{IsFavoredMetadata, TopRatedsMetadata}, minimizer::{IsFavoredMetadata, TopRatedsMetadata},
powersched::{BaseSchedule, SchedulerMetadata}, powersched::{BaseSchedule, SchedulerMetadata},
@ -16,28 +17,29 @@ use crate::{
}; };
/// Compute the favor factor of a [`Testcase`]. Higher is better. /// Compute the favor factor of a [`Testcase`]. Higher is better.
pub trait TestcaseScore<S> pub trait TestcaseScore<I, S>
where where
S: HasMetadata + HasCorpus, S: HasMetadata + HasCorpus,
I: Input,
{ {
/// Computes the favor factor of a [`Testcase`]. Higher is better. /// Computes the favor factor of a [`Testcase`]. Higher is better.
fn compute(state: &S, entry: &mut Testcase<S::Input>) -> Result<f64, Error>; fn compute(state: &S, entry: &mut Testcase<I>) -> Result<f64, Error>;
} }
/// Multiply the testcase size with the execution time. /// Multiply the testcase size with the execution time.
/// This favors small and quick testcases. /// This favors small and quick testcases.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LenTimeMulTestcaseScore<S> { pub struct LenTimeMulTestcaseScore<I, S> {
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl<S> TestcaseScore<S> for LenTimeMulTestcaseScore<S> impl<I, S> TestcaseScore<I, S> for LenTimeMulTestcaseScore<I, S>
where where
S: HasCorpus + HasMetadata, S: HasCorpus<Input = I> + HasMetadata,
S::Input: HasLen, I: HasLen + Input,
{ {
#[allow(clippy::cast_precision_loss, clippy::cast_lossless)] #[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
fn compute(state: &S, entry: &mut Testcase<S::Input>) -> Result<f64, Error> { fn compute(state: &S, entry: &mut Testcase<I>) -> Result<f64, Error> {
// TODO maybe enforce entry.exec_time().is_some() // TODO maybe enforce entry.exec_time().is_some()
Ok(entry.exec_time().map_or(1, |d| d.as_millis()) as f64 Ok(entry.exec_time().map_or(1, |d| d.as_millis()) as f64
* entry.load_len(state.corpus())? as f64) * entry.load_len(state.corpus())? as f64)
@ -56,9 +58,10 @@ pub struct CorpusPowerTestcaseScore<S> {
phantom: PhantomData<S>, phantom: PhantomData<S>,
} }
impl<S> TestcaseScore<S> for CorpusPowerTestcaseScore<S> impl<I, S> TestcaseScore<I, S> for CorpusPowerTestcaseScore<S>
where where
S: HasCorpus + HasMetadata, S: HasCorpus + HasMetadata,
I: Input,
{ {
/// Compute the `power` we assign to each corpus entry /// Compute the `power` we assign to each corpus entry
#[allow( #[allow(
@ -67,7 +70,7 @@ where
clippy::cast_sign_loss, clippy::cast_sign_loss,
clippy::cast_lossless clippy::cast_lossless
)] )]
fn compute(state: &S, entry: &mut Testcase<S::Input>) -> Result<f64, Error> { fn compute(state: &S, entry: &mut Testcase<I>) -> Result<f64, Error> {
let psmeta = state.metadata::<SchedulerMetadata>()?; let psmeta = state.metadata::<SchedulerMetadata>()?;
let fuzz_mu = if let Some(strat) = psmeta.strat() { let fuzz_mu = if let Some(strat) = psmeta.strat() {
@ -277,13 +280,14 @@ pub struct CorpusWeightTestcaseScore<S> {
phantom: PhantomData<S>, phantom: PhantomData<S>,
} }
impl<S> TestcaseScore<S> for CorpusWeightTestcaseScore<S> impl<I, S> TestcaseScore<I, S> for CorpusWeightTestcaseScore<S>
where where
S: HasCorpus + HasMetadata, S: HasCorpus + HasMetadata,
I: Input,
{ {
/// Compute the `weight` used in weighted corpus entry selection algo /// Compute the `weight` used in weighted corpus entry selection algo
#[allow(clippy::cast_precision_loss, clippy::cast_lossless)] #[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
fn compute(state: &S, entry: &mut Testcase<S::Input>) -> Result<f64, Error> { fn compute(state: &S, entry: &mut Testcase<I>) -> Result<f64, Error> {
let mut weight = 1.0; let mut weight = 1.0;
let psmeta = state.metadata::<SchedulerMetadata>()?; let psmeta = state.metadata::<SchedulerMetadata>()?;

View File

@ -11,8 +11,9 @@ use serde::{Deserialize, Serialize};
use super::RemovableScheduler; use super::RemovableScheduler;
use crate::{ use crate::{
corpus::{Corpus, CorpusId, HasTestcase}, corpus::{Corpus, CorpusId, HasTestcase},
inputs::Input,
schedulers::Scheduler, schedulers::Scheduler,
state::{HasCorpus, State, UsesState}, state::{HasCorpus, State},
Error, HasMetadata, Error, HasMetadata,
}; };
@ -30,11 +31,11 @@ impl_serdeany!(TuneableSchedulerMetadata);
/// Walk the corpus in a queue-like fashion /// Walk the corpus in a queue-like fashion
/// With the specific `set_next` method, we can chose the next corpus entry manually /// With the specific `set_next` method, we can chose the next corpus entry manually
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TuneableScheduler<S> { pub struct TuneableScheduler<I, S> {
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl<S> TuneableScheduler<S> impl<I, S> TuneableScheduler<I, S>
where where
S: HasMetadata + HasCorpus, S: HasMetadata + HasCorpus,
{ {
@ -88,23 +89,13 @@ where
} }
} }
impl<S> UsesState for TuneableScheduler<S> impl<I, S> RemovableScheduler<I, S> for TuneableScheduler<I, S> where I: Input {}
where
S: State,
{
type State = S;
}
impl<S> RemovableScheduler for TuneableScheduler<S> where impl<I, S> Scheduler<I, S> for TuneableScheduler<I, S>
S: HasCorpus + HasMetadata + HasTestcase + State
{
}
impl<S> Scheduler for TuneableScheduler<S>
where where
S: HasCorpus + HasMetadata + HasTestcase + State, S: HasCorpus + HasMetadata + HasTestcase + State,
{ {
fn on_add(&mut self, state: &mut Self::State, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
// Set parent id // Set parent id
let current_id = *state.corpus().current(); let current_id = *state.corpus().current();
state state
@ -117,7 +108,7 @@ where
} }
/// Gets the next entry in the queue /// Gets the next entry in the queue
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut S) -> Result<CorpusId, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
return Err(Error::empty( return Err(Error::empty(
"No entries in corpus. This often implies the target is not properly instrumented." "No entries in corpus. This often implies the target is not properly instrumented."

View File

@ -16,7 +16,7 @@ use serde::{Deserialize, Serialize};
use super::powersched::PowerSchedule; use super::powersched::PowerSchedule;
use crate::{ use crate::{
corpus::{Corpus, CorpusId, HasTestcase, Testcase}, corpus::{Corpus, CorpusId, HasTestcase, Testcase},
inputs::UsesInput, inputs::Input,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
random_corpus_id, random_corpus_id,
schedulers::{ schedulers::{
@ -24,7 +24,7 @@ use crate::{
testcase_score::{CorpusWeightTestcaseScore, TestcaseScore}, testcase_score::{CorpusWeightTestcaseScore, TestcaseScore},
AflScheduler, HasQueueCycles, RemovableScheduler, Scheduler, AflScheduler, HasQueueCycles, RemovableScheduler, Scheduler,
}, },
state::{HasCorpus, HasRand, State, UsesState}, state::{HasCorpus, HasRand, State},
Error, HasMetadata, Error, HasMetadata,
}; };
@ -98,22 +98,23 @@ libafl_bolts::impl_serdeany!(WeightedScheduleMetadata);
/// A corpus scheduler using power schedules with weighted queue item selection algo. /// A corpus scheduler using power schedules with weighted queue item selection algo.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct WeightedScheduler<C, F, O, S> { pub struct WeightedScheduler<C, F, I, O, S> {
table_invalidated: bool, table_invalidated: bool,
strat: Option<PowerSchedule>, strat: Option<PowerSchedule>,
map_observer_handle: Handle<C>, map_observer_handle: Handle<C>,
last_hash: usize, last_hash: usize,
queue_cycles: u64, queue_cycles: u64,
phantom: PhantomData<(F, O, S)>, phantom: PhantomData<(F, I, O, S)>,
/// Cycle `PowerSchedule` on completion of every queue cycle. /// Cycle `PowerSchedule` on completion of every queue cycle.
cycle_schedules: bool, cycle_schedules: bool,
} }
impl<C, F, O, S> WeightedScheduler<C, F, O, S> impl<C, F, I, O, S> WeightedScheduler<C, F, I, O, S>
where where
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
I: Input,
O: MapObserver, O: MapObserver,
S: HasCorpus + HasMetadata + HasRand, S: HasCorpus<Input = I> + HasMetadata + HasRand,
C: AsRef<O> + Named, C: AsRef<O> + Named,
{ {
/// Create a new [`WeightedScheduler`] without any power schedule /// Create a new [`WeightedScheduler`] without any power schedule
@ -257,26 +258,20 @@ where
} }
} }
impl<C, F, O, S> UsesState for WeightedScheduler<C, F, O, S> impl<C, F, I, O, S> RemovableScheduler<I, S> for WeightedScheduler<C, F, I, O, S>
where where
S: State, F: TestcaseScore<I, S>,
{
type State = S;
}
impl<C, F, O, S> RemovableScheduler for WeightedScheduler<C, F, O, S>
where
F: TestcaseScore<S>,
O: MapObserver, O: MapObserver,
I: Input,
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State, S: HasCorpus + HasMetadata + HasRand + HasTestcase + State,
C: AsRef<O> + Named, C: AsRef<O> + Named,
{ {
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata` /// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
fn on_remove( fn on_remove(
&mut self, &mut self,
_state: &mut Self::State, _state: &mut S,
_id: CorpusId, _id: CorpusId,
_prev: &Option<Testcase<<Self::State as UsesInput>::Input>>, _prev: &Option<Testcase<I>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.table_invalidated = true; self.table_invalidated = true;
Ok(()) Ok(())
@ -285,22 +280,25 @@ where
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata` /// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
fn on_replace( fn on_replace(
&mut self, &mut self,
_state: &mut Self::State, _state: &mut S,
_id: CorpusId, _id: CorpusId,
_prev: &Testcase<<Self::State as UsesInput>::Input>, _prev: &Testcase<I>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.table_invalidated = true; self.table_invalidated = true;
Ok(()) Ok(())
} }
} }
impl<C, F, O, S> AflScheduler<C, O, S> for WeightedScheduler<C, F, O, S> impl<C, I, F, O, S> AflScheduler<I, O, S> for WeightedScheduler<C, F, I, O, S>
where where
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
I: Input,
O: MapObserver, O: MapObserver,
S: HasCorpus + HasMetadata + HasTestcase + HasRand + State, S: HasCorpus + HasMetadata + HasTestcase + HasRand + State,
C: AsRef<O> + Named, C: AsRef<O> + Named,
{ {
type MapObserverRef = C;
fn last_hash(&self) -> usize { fn last_hash(&self) -> usize {
self.last_hash self.last_hash
} }
@ -314,9 +312,10 @@ where
} }
} }
impl<C, F, O, S> HasQueueCycles for WeightedScheduler<C, F, O, S> impl<C, F, I, O, S> HasQueueCycles for WeightedScheduler<C, F, I, O, S>
where where
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
I: Input,
O: MapObserver, O: MapObserver,
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State, S: HasCorpus + HasMetadata + HasRand + HasTestcase + State,
C: AsRef<O> + Named, C: AsRef<O> + Named,
@ -326,11 +325,12 @@ where
} }
} }
impl<C, F, O, S> Scheduler for WeightedScheduler<C, F, O, S> impl<C, F, I, O, S> Scheduler<I, S> for WeightedScheduler<C, F, I, O, S>
where where
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
I: Input,
O: MapObserver, O: MapObserver,
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State, S: HasCorpus<Input = I> + HasMetadata + HasRand + HasTestcase + State,
C: AsRef<O> + Named, C: AsRef<O> + Named,
{ {
/// Called when a [`Testcase`] is added to the corpus /// Called when a [`Testcase`] is added to the corpus
@ -340,14 +340,9 @@ where
Ok(()) Ok(())
} }
fn on_evaluation<OT>( fn on_evaluation<OT>(&mut self, state: &mut S, input: &I, observers: &OT) -> Result<(), Error>
&mut self,
state: &mut Self::State,
input: &<Self::State as UsesInput>::Input,
observers: &OT,
) -> Result<(), Error>
where where
OT: ObserversTuple<Self::State>, OT: ObserversTuple<S>,
{ {
self.on_evaluation_metadata(state, input, observers) self.on_evaluation_metadata(state, input, observers)
} }
@ -404,7 +399,7 @@ where
/// Set current fuzzed corpus id and `scheduled_count` /// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled( fn set_current_scheduled(
&mut self, &mut self,
state: &mut Self::State, state: &mut S,
next_id: Option<CorpusId>, next_id: Option<CorpusId>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.on_next_metadata(state, next_id)?; self.on_next_metadata(state, next_id)?;
@ -415,4 +410,5 @@ where
} }
/// The standard corpus weight, same as in `AFL++` /// The standard corpus weight, same as in `AFL++`
pub type StdWeightedScheduler<C, O, S> = WeightedScheduler<C, CorpusWeightTestcaseScore<S>, O, S>; pub type StdWeightedScheduler<C, I, O, S> =
WeightedScheduler<C, CorpusWeightTestcaseScore<S>, I, O, S>;

View File

@ -417,9 +417,9 @@ pub static PUSH_STAGE_ADAPTER_NAME: &str = "pushstageadapter";
impl<CS, EM, OT, PS, Z> UsesState for PushStageAdapter<CS, EM, OT, PS, Z> impl<CS, EM, OT, PS, Z> UsesState for PushStageAdapter<CS, EM, OT, PS, Z>
where where
CS: UsesState, Z: UsesState,
{ {
type State = CS::State; type State = Z::State;
} }
impl<CS, EM, OT, PS, Z> Named for PushStageAdapter<CS, EM, OT, PS, Z> { impl<CS, EM, OT, PS, Z> Named for PushStageAdapter<CS, EM, OT, PS, Z> {
@ -431,7 +431,7 @@ impl<CS, EM, OT, PS, Z> Named for PushStageAdapter<CS, EM, OT, PS, Z> {
impl<CS, E, EM, OT, PS, Z> Stage<E, EM, Z> for PushStageAdapter<CS, EM, OT, PS, Z> impl<CS, E, EM, OT, PS, Z> Stage<E, EM, Z> for PushStageAdapter<CS, EM, OT, PS, Z>
where where
CS: Scheduler, CS: Scheduler<Z::Input, Z::State>,
Self::State: HasExecutions Self::State: HasExecutions
+ HasRand + HasRand
+ HasCorpus + HasCorpus
@ -446,7 +446,7 @@ where
+ ProgressReporter<State = Self::State>, + ProgressReporter<State = Self::State>,
OT: ObserversTuple<Self::State>, OT: ObserversTuple<Self::State>,
PS: PushStage<CS, EM, OT, Z>, PS: PushStage<CS, EM, OT, Z>,
Z: ExecutesInput<E, EM, State = Self::State> Z: ExecutesInput<E, EM>
+ ExecutionProcessor + ExecutionProcessor
+ EvaluatorObservers<OT> + EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>, + HasScheduler<Scheduler = CS>,
@ -455,7 +455,7 @@ where
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut CS::State, state: &mut Z::State,
event_mgr: &mut EM, event_mgr: &mut EM,
) -> Result<(), Error> { ) -> Result<(), Error> {
let push_stage = &mut self.push_stage; let push_stage = &mut self.push_stage;

View File

@ -11,6 +11,7 @@ use libafl_bolts::Named;
use crate::{ use crate::{
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
fuzzer::Evaluator, fuzzer::Evaluator,
inputs::Input,
mutators::Mutator, mutators::Mutator,
schedulers::{testcase_score::CorpusPowerTestcaseScore, TestcaseScore}, schedulers::{testcase_score::CorpusPowerTestcaseScore, TestcaseScore},
stages::{mutational::MutatedTransform, MutationalStage, RetryCountRestartHelper, Stage}, stages::{mutational::MutatedTransform, MutationalStage, RetryCountRestartHelper, Stage},
@ -49,9 +50,10 @@ impl<E, F, EM, I, M, Z> MutationalStage<E, EM, I, M, Z> for PowerMutationalStage
where where
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: UsesState<State = Self::State>, EM: UsesState<State = Self::State>,
F: TestcaseScore<Self::State>, F: TestcaseScore<I, Self::State>,
I: Input,
M: Mutator<I, Self::State>, M: Mutator<I, Self::State>,
Self::State: HasCorpus + HasMetadata + HasRand + HasExecutions + HasNamedMetadata, Self::State: HasCorpus<Input = I> + HasMetadata + HasRand + HasExecutions + HasNamedMetadata,
Z: Evaluator<E, EM, State = Self::State>, Z: Evaluator<E, EM, State = Self::State>,
I: MutatedTransform<E::Input, Self::State> + Clone, I: MutatedTransform<E::Input, Self::State> + Clone,
{ {
@ -82,11 +84,11 @@ impl<E, F, EM, I, M, Z> Stage<E, EM, Z> for PowerMutationalStage<E, F, EM, I, M,
where where
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: UsesState<State = Self::State>, EM: UsesState<State = Self::State>,
F: TestcaseScore<Self::State>, F: TestcaseScore<I, Self::State>,
M: Mutator<I, Self::State>, M: Mutator<I, Self::State>,
Self::State: HasCorpus + HasMetadata + HasRand + HasExecutions + HasNamedMetadata, Self::State: HasCorpus<Input = I> + HasMetadata + HasRand + HasExecutions + HasNamedMetadata,
Z: Evaluator<E, EM, State = Self::State>, Z: Evaluator<E, EM, State = Self::State>,
I: MutatedTransform<Self::Input, Self::State> + Clone, I: MutatedTransform<Self::Input, Self::State> + Clone + Input,
{ {
#[inline] #[inline]
#[allow(clippy::let_and_return)] #[allow(clippy::let_and_return)]
@ -111,12 +113,13 @@ where
} }
} }
impl<E, F, EM, M, Z> PowerMutationalStage<E, F, EM, E::Input, M, Z> impl<E, F, EM, I, M, Z> PowerMutationalStage<E, F, EM, I, M, Z>
where where
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: UsesState<State = <Self as UsesState>::State>, EM: UsesState<State = <Self as UsesState>::State>,
F: TestcaseScore<<Self as UsesState>::State>, F: TestcaseScore<I, <Self as UsesState>::State>,
M: Mutator<E::Input, <Self as UsesState>::State>, I: Input,
M: Mutator<I, <Self as UsesState>::State>,
<Self as UsesState>::State: HasCorpus + HasMetadata + HasRand, <Self as UsesState>::State: HasCorpus + HasMetadata + HasRand,
Z: Evaluator<E, EM, State = <Self as UsesState>::State>, Z: Evaluator<E, EM, State = <Self as UsesState>::State>,
{ {

View File

@ -36,16 +36,14 @@ const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15);
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PushStageSharedState<CS, EM, OT, Z> pub struct PushStageSharedState<CS, EM, OT, Z>
where where
CS: Scheduler, CS: Scheduler<Z::Input, Z::State>,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId, EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<Z::State>,
CS::State: HasRand + HasCorpus, Z::State: HasRand + HasCorpus,
Z: ExecutionProcessor<State = CS::State> Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
+ EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>,
{ {
/// The [`crate::state::State`] /// The [`crate::state::State`]
pub state: CS::State, pub state: Z::State,
/// The [`crate::fuzzer::Fuzzer`] instance /// The [`crate::fuzzer::Fuzzer`] instance
pub fuzzer: Z, pub fuzzer: Z,
/// The [`crate::events::EventManager`] /// The [`crate::events::EventManager`]
@ -57,17 +55,15 @@ where
impl<CS, EM, OT, Z> PushStageSharedState<CS, EM, OT, Z> impl<CS, EM, OT, Z> PushStageSharedState<CS, EM, OT, Z>
where where
CS: Scheduler, CS: Scheduler<Z::Input, Z::State>,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId, EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<Z::State>,
CS::State: HasRand + HasCorpus, Z::State: HasRand + HasCorpus,
Z: ExecutionProcessor<State = CS::State> Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
+ EvaluatorObservers<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: CS::State, observers: OT, event_mgr: EM) -> Self { pub fn new(fuzzer: Z, state: Z::State, observers: OT, event_mgr: EM) -> Self {
Self { Self {
state, state,
fuzzer, fuzzer,
@ -82,13 +78,11 @@ where
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PushStageHelper<CS, EM, OT, Z> pub struct PushStageHelper<CS, EM, OT, Z>
where where
CS: Scheduler, CS: Scheduler<Z::Input, Z::State>,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId, EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<Z::State>,
CS::State: HasRand + HasCorpus, Z::State: HasRand + HasCorpus,
Z: ExecutionProcessor<State = CS::State> Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
+ EvaluatorObservers<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.
@ -103,7 +97,7 @@ 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<<CS::State as UsesInput>::Input>, // Todo: Get rid of copy pub current_input: Option<<Z::State as UsesInput>::Input>, // Todo: Get rid of copy
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(CS, EM, OT, Z)>, phantom: PhantomData<(CS, EM, OT, Z)>,
@ -112,13 +106,11 @@ where
impl<CS, EM, OT, Z> PushStageHelper<CS, EM, OT, Z> impl<CS, EM, OT, Z> PushStageHelper<CS, EM, OT, Z>
where where
CS: Scheduler, CS: Scheduler<Z::Input, Z::State>,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId, EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<Z::State>,
CS::State: HasRand + HasCorpus, Z::State: HasRand + HasCorpus,
Z: ExecutionProcessor<State = CS::State> Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
+ EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>,
{ {
/// Create a new [`PushStageHelper`] /// Create a new [`PushStageHelper`]
#[must_use] #[must_use]
@ -181,13 +173,11 @@ where
/// 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<CS, EM, OT, Z>: Iterator
where where
CS: Scheduler, CS: Scheduler<Z::Input, Z::State>,
CS::State: HasRand + HasExecutions + HasMetadata + HasCorpus + HasLastReportTime, Z::State: HasRand + HasExecutions + HasMetadata + HasCorpus + HasLastReportTime,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter, EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId + ProgressReporter,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<Z::State>,
Z: ExecutionProcessor<State = CS::State> Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
+ EvaluatorObservers<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<CS, EM, OT, Z>;
@ -206,7 +196,7 @@ where
fn init( fn init(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut CS::State, _state: &mut Z::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -219,20 +209,20 @@ where
fn pre_exec( fn pre_exec(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut CS::State, _state: &mut Z::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
) -> Option<Result<<CS::State as UsesInput>::Input, Error>>; ) -> Option<Result<<Z::State as UsesInput>::Input, 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 CS::State, _state: &mut Z::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
_input: <CS::State as UsesInput>::Input, _input: <Z::State as UsesInput>::Input,
_exit_kind: ExitKind, _exit_kind: ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
@ -243,7 +233,7 @@ where
fn deinit( fn deinit(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut CS::State, _state: &mut Z::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -251,7 +241,7 @@ where
} }
/// This is the default implementation for `next` for this stage /// This is the default implementation for `next` for this stage
fn next_std(&mut self) -> Option<Result<<CS::State as UsesInput>::Input, Error>> { fn next_std(&mut self) -> Option<Result<<Z::State as UsesInput>::Input, Error>> {
let mut shared_state = { let mut shared_state = {
let shared_state_ref = &mut (*self.push_stage_helper_mut().shared_state).borrow_mut(); let shared_state_ref = &mut (*self.push_stage_helper_mut().shared_state).borrow_mut();
shared_state_ref.take().unwrap() shared_state_ref.take().unwrap()

View File

@ -43,14 +43,12 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct StdMutationalPushStage<CS, EM, M, OT, Z> pub struct StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler, CS: Scheduler<Z::Input, Z::State>,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId, EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
M: Mutator<CS::Input, CS::State>, M: Mutator<Z::Input, Z::State>,
OT: ObserversTuple<CS::State> + Serialize, OT: ObserversTuple<Z::State> + Serialize,
CS::State: HasRand + HasCorpus + Clone + Debug, Z::State: HasRand + HasCorpus + Clone + Debug,
Z: ExecutionProcessor<State = CS::State> Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
+ EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>,
{ {
current_corpus_id: Option<CorpusId>, current_corpus_id: Option<CorpusId>,
testcases_to_do: usize, testcases_to_do: usize,
@ -63,18 +61,16 @@ where
impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z> impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler, CS: Scheduler<Z::Input, Z::State>,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId, EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
M: Mutator<CS::Input, CS::State>, M: Mutator<Z::Input, Z::State>,
OT: ObserversTuple<CS::State> + Serialize, OT: ObserversTuple<Z::State> + Serialize,
CS::State: HasCorpus + HasRand + Clone + Debug, Z::State: HasCorpus + HasRand + Clone + Debug,
Z: ExecutionProcessor<State = CS::State> Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
+ EvaluatorObservers<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 CS::State, _corpus_id: CorpusId) -> Result<usize, Error> { fn iterations(&self, state: &mut Z::State, _corpus_id: CorpusId) -> Result<usize, Error> {
Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS)) Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS))
} }
@ -86,15 +82,12 @@ where
impl<CS, EM, M, OT, Z> PushStage<CS, EM, OT, Z> for StdMutationalPushStage<CS, EM, M, OT, Z> impl<CS, EM, M, OT, Z> PushStage<CS, EM, OT, Z> for StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler, CS: Scheduler<Z::Input, Z::State>,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter, EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId + ProgressReporter,
M: Mutator<CS::Input, CS::State>, M: Mutator<Z::Input, Z::State>,
OT: ObserversTuple<CS::State> + Serialize, OT: ObserversTuple<Z::State> + Serialize,
CS::State: Z::State: HasCorpus + HasRand + HasExecutions + HasLastReportTime + HasMetadata + Clone + Debug,
HasCorpus + HasRand + HasExecutions + HasLastReportTime + HasMetadata + Clone + Debug, Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
Z: ExecutionProcessor<State = CS::State>
+ EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>,
{ {
#[inline] #[inline]
fn push_stage_helper(&self) -> &PushStageHelper<CS, EM, OT, Z> { fn push_stage_helper(&self) -> &PushStageHelper<CS, EM, OT, Z> {
@ -110,7 +103,7 @@ where
fn init( fn init(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut CS::State, state: &mut Z::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -129,10 +122,10 @@ where
fn pre_exec( fn pre_exec(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
state: &mut CS::State, state: &mut Z::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
) -> Option<Result<<CS::State as UsesInput>::Input, Error>> { ) -> Option<Result<<Z::State as UsesInput>::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;
@ -164,10 +157,10 @@ where
fn post_exec( fn post_exec(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut CS::State, state: &mut Z::State,
event_mgr: &mut EM, event_mgr: &mut EM,
observers: &mut OT, observers: &mut OT,
last_input: <CS::State as UsesInput>::Input, last_input: <Z::State as UsesInput>::Input,
exit_kind: ExitKind, exit_kind: ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
// todo: is_interesting, etc. // todo: is_interesting, etc.
@ -186,7 +179,7 @@ where
fn deinit( fn deinit(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut CS::State, _state: &mut Z::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -197,33 +190,28 @@ where
impl<CS, EM, M, OT, Z> Iterator for StdMutationalPushStage<CS, EM, M, OT, Z> impl<CS, EM, M, OT, Z> Iterator for StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler, CS: Scheduler<Z::Input, Z::State>,
EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = CS::State>, EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = Z::State>,
M: Mutator<CS::Input, CS::State>, M: Mutator<Z::Input, Z::State>,
OT: ObserversTuple<CS::State> + Serialize, OT: ObserversTuple<Z::State> + Serialize,
CS::State: Z::State: HasCorpus + HasRand + HasExecutions + HasMetadata + HasLastReportTime + Clone + Debug,
HasCorpus + HasRand + HasExecutions + HasMetadata + HasLastReportTime + Clone + Debug, Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
Z: ExecutionProcessor<State = CS::State>
+ EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>,
{ {
type Item = Result<<CS::State as UsesInput>::Input, Error>; type Item = Result<<Z::State as UsesInput>::Input, Error>;
fn next(&mut self) -> Option<Result<<CS::State as UsesInput>::Input, Error>> { fn next(&mut self) -> Option<Result<<Z::State as UsesInput>::Input, Error>> {
self.next_std() self.next_std()
} }
} }
impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z> impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler, CS: Scheduler<Z::Input, Z::State>,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId, EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
M: Mutator<CS::Input, CS::State>, M: Mutator<Z::Input, Z::State>,
OT: ObserversTuple<CS::State> + Serialize, OT: ObserversTuple<Z::State> + Serialize,
CS::State: HasCorpus + HasRand + Clone + Debug, Z::State: HasCorpus + HasRand + Clone + Debug,
Z: ExecutionProcessor<State = CS::State> Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
+ EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>,
{ {
/// Creates a new default mutational stage /// Creates a new default mutational stage
#[must_use] #[must_use]

View File

@ -57,7 +57,7 @@ where
+ HasFeedback + HasFeedback
+ ExecutesInput<E, EM> + ExecutesInput<E, EM>
+ ExecutionProcessor, + ExecutionProcessor,
Z::Scheduler: RemovableScheduler<State = Self::State>, Z::Scheduler: RemovableScheduler<Self::Input, Self::State>,
{ {
/// The mutator registered for this stage /// The mutator registered for this stage
fn mutator(&self) -> &M; fn mutator(&self) -> &M;
@ -239,7 +239,7 @@ where
impl<E, EM, F, FF, IP, M, Z> Stage<E, EM, Z> for StdTMinMutationalStage<E, EM, F, FF, IP, M, Z> impl<E, EM, F, FF, IP, M, Z> Stage<E, EM, Z> for StdTMinMutationalStage<E, EM, F, FF, IP, M, Z>
where where
Z: HasScheduler + ExecutionProcessor + ExecutesInput<E, EM> + HasFeedback, Z: HasScheduler + ExecutionProcessor + ExecutesInput<E, EM> + HasFeedback,
Z::Scheduler: RemovableScheduler, Z::Scheduler: RemovableScheduler<Self::Input, Self::State>,
E: HasObservers<State = Self::State>, E: HasObservers<State = Self::State>,
<E as UsesObservers>::Observers: Serialize, <E as UsesObservers>::Observers: Serialize,
EM: EventFirer<State = Self::State>, EM: EventFirer<State = Self::State>,
@ -301,7 +301,7 @@ impl<E, EM, F, FF, IP, M, Z> TMinMutationalStage<E, EM, F, IP, M, Z>
for StdTMinMutationalStage<E, EM, F, FF, IP, M, Z> for StdTMinMutationalStage<E, EM, F, FF, IP, M, Z>
where where
Z: HasScheduler + ExecutionProcessor + ExecutesInput<E, EM> + HasFeedback, Z: HasScheduler + ExecutionProcessor + ExecutesInput<E, EM> + HasFeedback,
Z::Scheduler: RemovableScheduler, Z::Scheduler: RemovableScheduler<Self::Input, Self::State>,
E: HasObservers<State = Self::State>, E: HasObservers<State = Self::State>,
<E as UsesObservers>::Observers: Serialize, <E as UsesObservers>::Observers: Serialize,
EM: EventFirer<State = Self::State>, EM: EventFirer<State = Self::State>,

View File

@ -4,46 +4,40 @@ use hashbrown::HashMap;
use libafl::{ use libafl::{
corpus::{Corpus, CorpusId, Testcase}, corpus::{Corpus, CorpusId, Testcase},
feedbacks::MapNoveltiesMetadata, feedbacks::MapNoveltiesMetadata,
inputs::UsesInput, inputs::Input,
schedulers::{RemovableScheduler, Scheduler}, schedulers::{RemovableScheduler, Scheduler},
state::{HasCorpus, State, UsesState}, state::{HasCorpus, State},
Error, HasMetadata, Error, HasMetadata,
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MergeScheduler<S> { pub struct MergeScheduler<I, S> {
mapping: HashMap<usize, CorpusId>, mapping: HashMap<usize, CorpusId>,
all: BTreeSet<CorpusId>, all: BTreeSet<CorpusId>,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl<S> UsesState for MergeScheduler<S> impl<I, S> RemovableScheduler<I, S> for MergeScheduler<I, S>
where
S: State,
{
type State = S;
}
impl<S> RemovableScheduler for MergeScheduler<S>
where where
I: Input,
S: State + HasCorpus, S: State + HasCorpus,
{ {
fn on_remove( fn on_remove(
&mut self, &mut self,
_state: &mut Self::State, _state: &mut S,
id: CorpusId, id: CorpusId,
_testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>, _testcase: &Option<Testcase<I>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.all.remove(&id); self.all.remove(&id);
Ok(()) Ok(())
} }
} }
impl<S> Scheduler for MergeScheduler<S> impl<I, S> Scheduler<I, S> for MergeScheduler<I, S>
where where
S: State + HasCorpus, S: State + HasCorpus,
{ {
fn on_add(&mut self, state: &mut Self::State, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
self.all.insert(id); self.all.insert(id);
let testcase = state.corpus().get(id)?.borrow(); let testcase = state.corpus().get(id)?.borrow();
let meta = testcase.metadata::<MapNoveltiesMetadata>()?; let meta = testcase.metadata::<MapNoveltiesMetadata>()?;
@ -53,12 +47,12 @@ where
Ok(()) Ok(())
} }
fn next(&mut self, _state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, _state: &mut S) -> Result<CorpusId, Error> {
unimplemented!("Not suitable for actual scheduling."); unimplemented!("Not suitable for actual scheduling.");
} }
} }
impl<S> MergeScheduler<S> { impl<I, S> MergeScheduler<I, S> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
mapping: HashMap::default(), mapping: HashMap::default(),