No Uses* (again) (#2537)
* ihatethislanguageihatethislanguageihatethislanguageihatethislanguage
* 1
* a
* fuck
* FMTFMTFMTFMTFMTFMT
* 👍
* afasdfadsfs
* lol
* aa
* a bit more
This commit is contained in:
parent
e370e2f852
commit
93fdbb604c
@ -15,7 +15,7 @@ use libafl::{
|
||||
inputs::UsesInput,
|
||||
mutators::Tokens,
|
||||
observers::MapObserver,
|
||||
schedulers::{minimizer::IsFavoredMetadata, HasQueueCycles, Scheduler},
|
||||
schedulers::{minimizer::IsFavoredMetadata, HasQueueCycles},
|
||||
stages::{calibrate::UnstableEntriesMetadata, Stage},
|
||||
state::{HasCorpus, HasExecutions, HasImported, HasStartTime, Stoppable, UsesState},
|
||||
Error, HasMetadata, HasNamedMetadata, HasScheduler, SerdeAny,
|
||||
@ -240,7 +240,7 @@ where
|
||||
+ HasTestcase,
|
||||
O: MapObserver,
|
||||
C: AsRef<O> + Named,
|
||||
<Z as HasScheduler>::Scheduler: Scheduler + HasQueueCycles,
|
||||
<Z as HasScheduler>::Scheduler: HasQueueCycles,
|
||||
{
|
||||
fn perform(
|
||||
&mut self,
|
||||
|
@ -2,45 +2,39 @@ use std::marker::PhantomData;
|
||||
|
||||
use libafl::{
|
||||
corpus::{Corpus, CorpusId, HasTestcase, SchedulerTestcaseMetadata, Testcase},
|
||||
inputs::UsesInput,
|
||||
inputs::{Input, UsesInput},
|
||||
observers::{CanTrack, ObserversTuple},
|
||||
schedulers::{
|
||||
HasQueueCycles, MinimizerScheduler, RemovableScheduler, Scheduler, TestcaseScore,
|
||||
},
|
||||
state::{HasCorpus, HasRand, State, UsesState},
|
||||
state::{HasCorpus, HasRand, State},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
use libafl_bolts::{serdeany::SerdeAny, AsIter, HasRefCnt};
|
||||
|
||||
pub enum SupportedSchedulers<S, Q, CS, F, M, O> {
|
||||
Queue(Q, PhantomData<(S, Q, CS, F, M, O)>),
|
||||
pub enum SupportedSchedulers<CS, F, I, M, O, S, Q> {
|
||||
Queue(Q, PhantomData<(CS, F, I, M, O, S, Q)>),
|
||||
Weighted(
|
||||
MinimizerScheduler<CS, F, M, O>,
|
||||
PhantomData<(S, Q, CS, F, M, O)>,
|
||||
MinimizerScheduler<CS, F, I, M, O, S>,
|
||||
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
|
||||
S: State + HasRand + HasCorpus + HasMetadata + HasTestcase,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
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>,
|
||||
CS: Scheduler<I, S> + RemovableScheduler<I, S>,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
|
||||
O: CanTrack,
|
||||
F: TestcaseScore<S>,
|
||||
Q: Scheduler<I, S> + RemovableScheduler<I, S>,
|
||||
S: UsesInput + HasTestcase + HasMetadata + HasCorpus<Input = I> + HasRand + State,
|
||||
{
|
||||
fn on_remove(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
state: &mut S,
|
||||
id: CorpusId,
|
||||
testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
||||
testcase: &Option<Testcase<I>>,
|
||||
) -> Result<(), Error> {
|
||||
match self {
|
||||
Self::Queue(queue, _) => queue.on_remove(state, id, testcase),
|
||||
@ -48,12 +42,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn on_replace(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
id: CorpusId,
|
||||
prev: &Testcase<<Self::State as UsesInput>::Input>,
|
||||
) -> Result<(), Error> {
|
||||
fn on_replace(&mut self, state: &mut S, id: CorpusId, prev: &Testcase<I>) -> Result<(), Error> {
|
||||
match self {
|
||||
Self::Queue(queue, _) => queue.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
|
||||
S: UsesInput + HasTestcase + HasMetadata + HasCorpus + HasRand + State,
|
||||
Q: Scheduler<State = S>,
|
||||
CS: Scheduler<State = S>,
|
||||
CS: Scheduler<I, S>,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
|
||||
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 {
|
||||
// We need to manually set the depth
|
||||
// since we want to avoid implementing `AflScheduler` for `QueueScheduler`
|
||||
@ -94,20 +84,15 @@ where
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
Self::Queue(queue, _) => queue.next(state),
|
||||
Self::Weighted(weighted, _) => weighted.next(state),
|
||||
}
|
||||
}
|
||||
fn on_evaluation<OTB>(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
input: &<Self::State as UsesInput>::Input,
|
||||
observers: &OTB,
|
||||
) -> Result<(), Error>
|
||||
fn on_evaluation<OTB>(&mut self, state: &mut S, input: &I, observers: &OTB) -> Result<(), Error>
|
||||
where
|
||||
OTB: ObserversTuple<Self::State>,
|
||||
OTB: ObserversTuple<S>,
|
||||
{
|
||||
match self {
|
||||
Self::Queue(queue, _) => queue.on_evaluation(state, input, observers),
|
||||
@ -117,7 +102,7 @@ where
|
||||
|
||||
fn set_current_scheduled(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
state: &mut S,
|
||||
next_id: Option<CorpusId>,
|
||||
) -> Result<(), Error> {
|
||||
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
|
||||
S: UsesInput + HasTestcase + HasMetadata + HasCorpus + HasRand + State,
|
||||
Q: Scheduler<State = S> + HasQueueCycles,
|
||||
CS: Scheduler<State = S> + HasQueueCycles,
|
||||
O: CanTrack,
|
||||
CS: Scheduler<I, S> + HasQueueCycles,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
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 {
|
||||
match self {
|
||||
|
@ -22,7 +22,7 @@ pub struct PacketLenMetadata {
|
||||
|
||||
pub struct PacketLenTestcaseScore {}
|
||||
|
||||
impl<S> TestcaseScore<S> for PacketLenTestcaseScore
|
||||
impl<S> TestcaseScore<PacketData, S> for PacketLenTestcaseScore
|
||||
where
|
||||
S: HasCorpus<Input = PacketData> + HasMetadata,
|
||||
{
|
||||
@ -34,8 +34,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub type PacketLenMinimizerScheduler<CS, O> =
|
||||
MinimizerScheduler<CS, PacketLenTestcaseScore, MapIndexesMetadata, O>;
|
||||
pub type PacketLenMinimizerScheduler<CS, O, S> =
|
||||
MinimizerScheduler<CS, PacketLenTestcaseScore, PacketData, MapIndexesMetadata, O, S>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
||||
pub struct PacketLenFeedback {
|
||||
|
@ -17,6 +17,7 @@ use crate::{
|
||||
corpus::Corpus,
|
||||
events::{Event, EventFirer, LogSeverity},
|
||||
executors::{Executor, HasObservers},
|
||||
inputs::UsesInput,
|
||||
monitors::{AggregatorOps, UserStats, UserStatsValue},
|
||||
observers::{MapObserver, ObserversTuple},
|
||||
schedulers::{LenTimeMulTestcaseScore, RemovableScheduler, Scheduler, TestcaseScore},
|
||||
@ -41,7 +42,7 @@ where
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
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>,
|
||||
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.
|
||||
pub type StdCorpusMinimizer<C, E, O, T> =
|
||||
MapCorpusMinimizer<C, E, O, T, LenTimeMulTestcaseScore<<E as UsesState>::State>>;
|
||||
pub type StdCorpusMinimizer<C, E, O, T> = MapCorpusMinimizer<
|
||||
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>
|
||||
where
|
||||
E: UsesState,
|
||||
E::State: HasCorpus + HasMetadata,
|
||||
TS: TestcaseScore<E::State>,
|
||||
TS: TestcaseScore<E::Input, E::State>,
|
||||
C: Named,
|
||||
{
|
||||
/// Constructs a new `MapCorpusMinimizer` from a provided observer. This observer will be used
|
||||
@ -83,7 +89,7 @@ where
|
||||
C: AsRef<O>,
|
||||
E::State: HasMetadata + HasCorpus + HasExecutions,
|
||||
T: Copy + Hash + Eq,
|
||||
TS: TestcaseScore<E::State>,
|
||||
TS: TestcaseScore<E::Input, E::State>,
|
||||
{
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn minimize<CS, EM, Z>(
|
||||
@ -95,7 +101,7 @@ where
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
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>,
|
||||
Z: HasScheduler<Scheduler = CS, State = E::State>,
|
||||
{
|
||||
|
@ -560,7 +560,7 @@ mod tests {
|
||||
let mut mgr = NopEventManager::new();
|
||||
let mut state =
|
||||
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(
|
||||
&mut harness,
|
||||
|
@ -6,6 +6,8 @@ use core::{fmt::Debug, marker::PhantomData, time::Duration};
|
||||
use libafl_bolts::current_time;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
#[cfg(feature = "introspection")]
|
||||
use crate::monitors::PerfFeature;
|
||||
use crate::{
|
||||
corpus::{Corpus, CorpusId, HasCurrentCorpusId, HasTestcase, Testcase},
|
||||
events::{Event, EventConfig, EventFirer, EventProcessor, ProgressReporter},
|
||||
@ -23,8 +25,6 @@ use crate::{
|
||||
},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
#[cfg(feature = "introspection")]
|
||||
use crate::{monitors::PerfFeature, state::HasClientPerfMonitor};
|
||||
|
||||
/// Send a monitor update all 15 (or more) seconds
|
||||
const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15);
|
||||
@ -35,7 +35,7 @@ where
|
||||
Self::State: HasCorpus,
|
||||
{
|
||||
/// The [`Scheduler`] for this fuzzer
|
||||
type Scheduler: Scheduler<State = Self::State>;
|
||||
type Scheduler: Scheduler<Self::Input, Self::State>;
|
||||
|
||||
/// The scheduler
|
||||
fn scheduler(&self) -> &Self::Scheduler;
|
||||
@ -303,24 +303,24 @@ pub enum ExecuteInputResult {
|
||||
|
||||
/// Your default fuzzer instance, for everyday use.
|
||||
#[derive(Debug)]
|
||||
pub struct StdFuzzer<CS, F, OF> {
|
||||
pub struct StdFuzzer<CS, F, OF, S> {
|
||||
scheduler: CS,
|
||||
feedback: F,
|
||||
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
|
||||
CS: Scheduler,
|
||||
CS::State: HasCorpus,
|
||||
S: State,
|
||||
{
|
||||
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
|
||||
CS: Scheduler,
|
||||
CS::State: HasCorpus,
|
||||
S: State + HasCorpus,
|
||||
CS: Scheduler<S::Input, S>,
|
||||
{
|
||||
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
|
||||
CS: Scheduler,
|
||||
F: Feedback<Self::State>,
|
||||
OF: Feedback<Self::State>,
|
||||
CS::State: HasCorpus,
|
||||
S: State,
|
||||
F: Feedback<S>,
|
||||
OF: Feedback<S>,
|
||||
{
|
||||
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
|
||||
CS: Scheduler,
|
||||
F: Feedback<Self::State>,
|
||||
OF: Feedback<Self::State>,
|
||||
CS::State: HasCorpus,
|
||||
S: State,
|
||||
F: Feedback<S>,
|
||||
OF: Feedback<S>,
|
||||
{
|
||||
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
|
||||
CS: Scheduler,
|
||||
F: Feedback<Self::State>,
|
||||
OF: Feedback<Self::State>,
|
||||
CS::State: HasCorpus
|
||||
CS: Scheduler<S::Input, S>,
|
||||
F: Feedback<S>,
|
||||
OF: Feedback<S>,
|
||||
S: HasCorpus
|
||||
+ HasSolutions
|
||||
+ HasExecutions
|
||||
+ HasCorpus
|
||||
+ HasCurrentTestcase<<Self::State as UsesInput>::Input>
|
||||
+ HasCurrentCorpusId,
|
||||
+ HasCurrentTestcase<S::Input>
|
||||
+ HasCurrentCorpusId
|
||||
+ State,
|
||||
{
|
||||
fn check_results<EM, OT>(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
input: &<Self::State as UsesInput>::Input,
|
||||
input: &S::Input,
|
||||
observers: &OT,
|
||||
exit_kind: &ExitKind,
|
||||
) -> 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
|
||||
CS: Scheduler,
|
||||
OT: ObserversTuple<Self::State> + Serialize + DeserializeOwned,
|
||||
F: Feedback<Self::State>,
|
||||
OF: Feedback<Self::State>,
|
||||
CS::State: HasCorpus + HasSolutions + HasExecutions,
|
||||
CS: Scheduler<S::Input, S>,
|
||||
OT: ObserversTuple<S> + Serialize + DeserializeOwned,
|
||||
F: Feedback<S>,
|
||||
OF: Feedback<S>,
|
||||
S: HasCorpus + HasSolutions + HasExecutions + State,
|
||||
{
|
||||
/// Process one input, adding to the respective corpora if needed and firing the right events
|
||||
#[inline]
|
||||
fn evaluate_input_with_observers<E, EM>(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
state: &mut S,
|
||||
executor: &mut E,
|
||||
manager: &mut EM,
|
||||
input: <Self::State as UsesInput>::Input,
|
||||
input: S::Input,
|
||||
send_events: bool,
|
||||
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error>
|
||||
where
|
||||
E: Executor<EM, Self> + HasObservers<Observers = OT, State = Self::State>,
|
||||
EM: EventFirer<State = Self::State>,
|
||||
E: Executor<EM, Self> + HasObservers<Observers = OT, State = S>,
|
||||
EM: EventFirer<State = S>,
|
||||
{
|
||||
let exit_kind = self.execute_input(state, executor, manager, &input)?;
|
||||
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
|
||||
CS: Scheduler,
|
||||
E: HasObservers<State = Self::State, Observers = OT> + Executor<EM, Self>,
|
||||
EM: EventFirer<State = Self::State>,
|
||||
F: Feedback<Self::State>,
|
||||
OF: Feedback<Self::State>,
|
||||
OT: ObserversTuple<Self::State> + Serialize + DeserializeOwned,
|
||||
CS::State: HasCorpus + HasSolutions + HasExecutions + HasLastFoundTime,
|
||||
CS: Scheduler<S::Input, S>,
|
||||
E: HasObservers<State = S, Observers = OT> + Executor<EM, Self>,
|
||||
EM: EventFirer<State = S>,
|
||||
F: Feedback<S>,
|
||||
OF: Feedback<S>,
|
||||
OT: ObserversTuple<S> + Serialize + DeserializeOwned,
|
||||
S: HasCorpus + HasSolutions + HasExecutions + HasLastFoundTime + State,
|
||||
{
|
||||
/// Process one input, adding to the respective corpora if needed and firing the right events
|
||||
#[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
|
||||
CS: Scheduler,
|
||||
E: UsesState<State = Self::State>,
|
||||
EM: ProgressReporter + EventProcessor<E, Self, State = Self::State>,
|
||||
F: Feedback<Self::State>,
|
||||
OF: Feedback<Self::State>,
|
||||
CS::State: HasExecutions
|
||||
CS: Scheduler<S::Input, S>,
|
||||
E: UsesState<State = S>,
|
||||
EM: ProgressReporter + EventProcessor<E, Self, State = S>,
|
||||
F: Feedback<S>,
|
||||
OF: Feedback<S>,
|
||||
S: HasExecutions
|
||||
+ HasMetadata
|
||||
+ HasCorpus
|
||||
+ HasTestcase
|
||||
+ HasLastReportTime
|
||||
+ HasCurrentCorpusId
|
||||
+ HasCurrentStageId,
|
||||
ST: StagesTuple<E, EM, Self::State, Self>,
|
||||
+ HasCurrentStageId
|
||||
+ State,
|
||||
ST: StagesTuple<E, EM, S, Self>,
|
||||
{
|
||||
fn fuzz_one(
|
||||
&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
|
||||
CS: Scheduler,
|
||||
CS: Scheduler<S::Input, S>,
|
||||
F: 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.
|
||||
pub fn new(scheduler: CS, feedback: F, objective: OF) -> Self {
|
||||
@ -847,6 +847,7 @@ where
|
||||
scheduler,
|
||||
feedback,
|
||||
objective,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -896,22 +897,22 @@ where
|
||||
) -> 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
|
||||
CS: Scheduler,
|
||||
CS: Scheduler<S::Input, S>,
|
||||
F: Feedback<<Self as UsesState>::State>,
|
||||
OF: Feedback<<Self as UsesState>::State>,
|
||||
E: Executor<EM, Self> + HasObservers<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
|
||||
fn execute_input(
|
||||
&mut self,
|
||||
state: &mut <Self as UsesState>::State,
|
||||
state: &mut S,
|
||||
executor: &mut E,
|
||||
event_mgr: &mut EM,
|
||||
input: &<<Self as UsesState>::State as UsesInput>::Input,
|
||||
input: &S::Input,
|
||||
) -> Result<ExitKind, Error> {
|
||||
start_timer!(state);
|
||||
executor.observers_mut().pre_exec_all(state, input)?;
|
||||
|
@ -13,13 +13,13 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
corpus::{Corpus, CorpusId},
|
||||
feedbacks::MapIndexesMetadata,
|
||||
inputs::UsesInput,
|
||||
inputs::Input,
|
||||
observers::{CanTrack, ObserversTuple},
|
||||
schedulers::{
|
||||
minimizer::{IsFavoredMetadata, MinimizerScheduler, DEFAULT_SKIP_NON_FAVORED_PROB},
|
||||
LenTimeMulTestcaseScore, Scheduler,
|
||||
},
|
||||
state::{HasCorpus, HasRand, UsesState},
|
||||
state::{HasCorpus, HasRand},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
|
||||
@ -105,55 +105,32 @@ impl TopAccountingMetadata {
|
||||
|
||||
/// A minimizer scheduler using coverage accounting
|
||||
#[derive(Debug)]
|
||||
pub struct CoverageAccountingScheduler<'a, CS, O>
|
||||
where
|
||||
CS: UsesState,
|
||||
CS::State: Debug,
|
||||
{
|
||||
pub struct CoverageAccountingScheduler<'a, CS, I, O, S> {
|
||||
accounting_map: &'a [u32],
|
||||
skip_non_favored_prob: f64,
|
||||
inner: MinimizerScheduler<
|
||||
CS,
|
||||
LenTimeMulTestcaseScore<<CS as UsesState>::State>,
|
||||
MapIndexesMetadata,
|
||||
O,
|
||||
>,
|
||||
inner: MinimizerScheduler<CS, LenTimeMulTestcaseScore<I, S>, I, MapIndexesMetadata, O, S>,
|
||||
}
|
||||
|
||||
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
|
||||
CS: UsesState,
|
||||
CS::State: Debug,
|
||||
{
|
||||
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,
|
||||
CS: Scheduler<I, S>,
|
||||
S: HasCorpus<Input = I> + HasMetadata + HasRand + Debug,
|
||||
I: HasLen + Input,
|
||||
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.inner.on_add(state, id)
|
||||
}
|
||||
|
||||
fn on_evaluation<OT>(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
input: &<Self::State as UsesInput>::Input,
|
||||
observers: &OT,
|
||||
) -> Result<(), Error>
|
||||
fn on_evaluation<OT>(&mut self, state: &mut S, input: &I, observers: &OT) -> Result<(), Error>
|
||||
where
|
||||
OT: ObserversTuple<Self::State>,
|
||||
OT: ObserversTuple<S>,
|
||||
{
|
||||
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
|
||||
.metadata_map()
|
||||
.get::<TopAccountingMetadata>()
|
||||
@ -184,7 +161,7 @@ where
|
||||
/// Set current fuzzed corpus id and `scheduled_count`
|
||||
fn set_current_scheduled(
|
||||
&mut self,
|
||||
_state: &mut Self::State,
|
||||
_state: &mut S,
|
||||
_next_id: Option<CorpusId>,
|
||||
) -> Result<(), Error> {
|
||||
// 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
|
||||
CS: Scheduler,
|
||||
CS::State: HasCorpus + HasMetadata + HasRand + Debug,
|
||||
<CS::State as UsesInput>::Input: HasLen,
|
||||
CS: Scheduler<I, S>,
|
||||
S: HasCorpus<Input = I> + HasMetadata + HasRand + Debug,
|
||||
I: HasLen + Input,
|
||||
O: CanTrack,
|
||||
{
|
||||
/// Update the `Corpus` score
|
||||
#[allow(clippy::unused_self)]
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
pub fn update_accounting_score(
|
||||
&self,
|
||||
state: &mut CS::State,
|
||||
id: CorpusId,
|
||||
) -> Result<(), Error> {
|
||||
pub fn update_accounting_score(&self, state: &mut S, id: CorpusId) -> Result<(), Error> {
|
||||
let mut indexes = vec![];
|
||||
let mut new_favoreds = vec![];
|
||||
{
|
||||
@ -291,7 +264,7 @@ where
|
||||
|
||||
/// Cull the `Corpus`
|
||||
#[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 {
|
||||
return Ok(());
|
||||
};
|
||||
@ -312,7 +285,7 @@ where
|
||||
/// and has a default probability to skip non-faved Testcases of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
|
||||
///
|
||||
/// 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>() {
|
||||
Some(meta) => {
|
||||
if meta.max_accounting.len() != accounting_map.len() {
|
||||
@ -336,7 +309,7 @@ where
|
||||
/// Provide the observer responsible for determining new indexes.
|
||||
pub fn with_skip_prob(
|
||||
observer: &O,
|
||||
state: &mut CS::State,
|
||||
state: &mut S,
|
||||
base: CS,
|
||||
skip_non_favored_prob: f64,
|
||||
accounting_map: &'a [u32],
|
||||
|
@ -11,11 +11,11 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
corpus::{Corpus, CorpusId, Testcase},
|
||||
feedbacks::MapIndexesMetadata,
|
||||
inputs::UsesInput,
|
||||
inputs::Input,
|
||||
observers::{CanTrack, ObserversTuple},
|
||||
require_index_tracking,
|
||||
schedulers::{LenTimeMulTestcaseScore, RemovableScheduler, Scheduler, TestcaseScore},
|
||||
state::{HasCorpus, HasRand, UsesState},
|
||||
state::{HasCorpus, HasRand},
|
||||
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`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MinimizerScheduler<CS, F, M, O> {
|
||||
pub struct MinimizerScheduler<CS, F, I, M, O, S> {
|
||||
base: CS,
|
||||
skip_non_favored_prob: f64,
|
||||
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
|
||||
CS: UsesState,
|
||||
{
|
||||
type State = CS::State;
|
||||
}
|
||||
|
||||
impl<CS, F, M, O> RemovableScheduler for MinimizerScheduler<CS, F, M, O>
|
||||
where
|
||||
CS: RemovableScheduler,
|
||||
F: TestcaseScore<<Self as UsesState>::State>,
|
||||
CS: RemovableScheduler<I, S> + Scheduler<I, S>,
|
||||
I: Input,
|
||||
F: TestcaseScore<I, S>,
|
||||
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
|
||||
<Self as UsesState>::State: HasCorpus + HasMetadata + HasRand,
|
||||
S: HasCorpus<Input = I> + HasMetadata + HasRand,
|
||||
O: CanTrack,
|
||||
{
|
||||
/// Replaces the [`Testcase`] at the given [`CorpusId`]
|
||||
fn on_replace(
|
||||
&mut self,
|
||||
state: &mut <Self as UsesState>::State,
|
||||
state: &mut S,
|
||||
id: CorpusId,
|
||||
testcase: &Testcase<<<Self as UsesState>::State as UsesInput>::Input>,
|
||||
testcase: &Testcase<I>,
|
||||
) -> Result<(), Error> {
|
||||
self.base.on_replace(state, id, testcase)?;
|
||||
self.update_score(state, id)
|
||||
@ -108,9 +102,9 @@ where
|
||||
/// Removes an entry from the corpus
|
||||
fn on_remove(
|
||||
&mut self,
|
||||
state: &mut <Self as UsesState>::State,
|
||||
state: &mut S,
|
||||
id: CorpusId,
|
||||
testcase: &Option<Testcase<<<Self as UsesState>::State as UsesInput>::Input>>,
|
||||
testcase: &Option<Testcase<I>>,
|
||||
) -> Result<(), Error> {
|
||||
self.base.on_remove(state, id, testcase)?;
|
||||
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
|
||||
CS: Scheduler,
|
||||
F: TestcaseScore<Self::State>,
|
||||
CS: Scheduler<I, S>,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
|
||||
Self::State: HasCorpus + HasMetadata + HasRand,
|
||||
S: HasCorpus<Input = I> + HasMetadata + HasRand,
|
||||
O: CanTrack,
|
||||
{
|
||||
/// 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.update_score(state, id)
|
||||
}
|
||||
|
||||
/// An input has been evaluated
|
||||
fn on_evaluation<OT>(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
input: &<Self::State as UsesInput>::Input,
|
||||
observers: &OT,
|
||||
) -> Result<(), Error>
|
||||
fn on_evaluation<OT>(&mut self, state: &mut S, input: &I, observers: &OT) -> Result<(), Error>
|
||||
where
|
||||
OT: ObserversTuple<Self::State>,
|
||||
OT: ObserversTuple<S>,
|
||||
{
|
||||
self.base.on_evaluation(state, input, observers)
|
||||
}
|
||||
|
||||
/// 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)?;
|
||||
let mut id = self.base.next(state)?;
|
||||
while {
|
||||
@ -242,7 +232,7 @@ where
|
||||
/// Set current fuzzed corpus id and `scheduled_count`
|
||||
fn set_current_scheduled(
|
||||
&mut self,
|
||||
_state: &mut Self::State,
|
||||
_state: &mut S,
|
||||
_next_id: Option<CorpusId>,
|
||||
) -> Result<(), Error> {
|
||||
// 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
|
||||
CS: Scheduler,
|
||||
F: TestcaseScore<<Self as UsesState>::State>,
|
||||
CS: Scheduler<I, S>,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
|
||||
<Self as UsesState>::State: HasCorpus + HasMetadata + HasRand,
|
||||
S: HasCorpus<Input = I> + HasMetadata + HasRand,
|
||||
O: CanTrack,
|
||||
{
|
||||
/// Update the [`Corpus`] score using the [`MinimizerScheduler`]
|
||||
#[allow(clippy::unused_self)]
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
pub fn update_score(
|
||||
&self,
|
||||
state: &mut <Self as UsesState>::State,
|
||||
id: CorpusId,
|
||||
) -> Result<(), Error> {
|
||||
pub fn update_score(&self, state: &mut S, id: CorpusId) -> Result<(), Error> {
|
||||
// Create a new top rated meta if not existing
|
||||
if state.metadata_map().get::<TopRatedsMetadata>().is_none() {
|
||||
state.add_metadata(TopRatedsMetadata::new());
|
||||
@ -339,7 +326,7 @@ where
|
||||
|
||||
/// Cull the [`Corpus`] using the [`MinimizerScheduler`]
|
||||
#[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 {
|
||||
return Ok(());
|
||||
};
|
||||
@ -423,14 +410,10 @@ where
|
||||
}
|
||||
|
||||
/// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`.
|
||||
pub type LenTimeMinimizerScheduler<CS, M, O> =
|
||||
MinimizerScheduler<CS, LenTimeMulTestcaseScore<<CS as UsesState>::State>, M, O>;
|
||||
pub type LenTimeMinimizerScheduler<CS, I, M, O, S> =
|
||||
MinimizerScheduler<CS, LenTimeMulTestcaseScore<I, S>, I, M, O, S>;
|
||||
|
||||
/// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`
|
||||
/// that exercise all the entries registered in the [`MapIndexesMetadata`].
|
||||
pub type IndexesLenTimeMinimizerScheduler<CS, O> = MinimizerScheduler<
|
||||
CS,
|
||||
LenTimeMulTestcaseScore<<CS as UsesState>::State>,
|
||||
MapIndexesMetadata,
|
||||
O,
|
||||
>;
|
||||
pub type IndexesLenTimeMinimizerScheduler<CS, I, O, S> =
|
||||
MinimizerScheduler<CS, LenTimeMulTestcaseScore<I, S>, I, MapIndexesMetadata, O, S>;
|
||||
|
@ -35,25 +35,25 @@ pub use tuneable::*;
|
||||
|
||||
use crate::{
|
||||
corpus::{Corpus, CorpusId, HasTestcase, SchedulerTestcaseMetadata, Testcase},
|
||||
inputs::UsesInput,
|
||||
inputs::Input,
|
||||
observers::{MapObserver, ObserversTuple},
|
||||
random_corpus_id,
|
||||
state::{HasCorpus, HasRand, State, UsesState},
|
||||
state::{HasCorpus, HasRand, State},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
|
||||
/// The scheduler also implements `on_remove` and `on_replace` if it implements this stage.
|
||||
pub trait RemovableScheduler: Scheduler
|
||||
pub trait RemovableScheduler<I, S>
|
||||
where
|
||||
Self::State: HasCorpus,
|
||||
I: Input,
|
||||
{
|
||||
/// 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!
|
||||
fn on_remove(
|
||||
&mut self,
|
||||
_state: &mut Self::State,
|
||||
_state: &mut S,
|
||||
_id: CorpusId,
|
||||
_testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
||||
_testcase: &Option<Testcase<I>>,
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
@ -61,21 +61,23 @@ where
|
||||
/// Replaced the given testcase at the given idx
|
||||
fn on_replace(
|
||||
&mut self,
|
||||
_state: &mut Self::State,
|
||||
_state: &mut S,
|
||||
_id: CorpusId,
|
||||
_prev: &Testcase<<Self::State as UsesInput>::Input>,
|
||||
_prev: &Testcase<I>,
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines the common metadata operations for the AFL-style schedulers
|
||||
pub trait AflScheduler<C, O, S>: Scheduler
|
||||
pub trait AflScheduler<I, O, S>
|
||||
where
|
||||
Self::State: HasCorpus + HasMetadata + HasTestcase,
|
||||
S: HasCorpus + HasMetadata + HasTestcase,
|
||||
O: MapObserver,
|
||||
C: AsRef<O>,
|
||||
{
|
||||
/// The type of [`MapObserver`] that this scheduler will use as reference
|
||||
type MapObserverRef: AsRef<O>;
|
||||
|
||||
/// Return the last hash
|
||||
fn last_hash(&self) -> usize;
|
||||
|
||||
@ -83,10 +85,10 @@ where
|
||||
fn set_last_hash(&mut self, value: usize);
|
||||
|
||||
/// 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
|
||||
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 mut depth = match current_id {
|
||||
@ -114,12 +116,12 @@ where
|
||||
/// Called when a [`Testcase`] is evaluated
|
||||
fn on_evaluation_metadata<OT>(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
_input: &<Self::State as UsesInput>::Input,
|
||||
state: &mut S,
|
||||
_input: &I,
|
||||
observers: &OT,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
OT: ObserversTuple<Self::State>,
|
||||
OT: ObserversTuple<S>,
|
||||
{
|
||||
let observer = observers
|
||||
.get(self.map_observer_handle())
|
||||
@ -140,11 +142,7 @@ where
|
||||
}
|
||||
|
||||
/// Called when choosing the next [`Testcase`]
|
||||
fn on_next_metadata(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
_next_id: Option<CorpusId>,
|
||||
) -> Result<(), Error> {
|
||||
fn on_next_metadata(&mut self, state: &mut S, _next_id: Option<CorpusId>) -> Result<(), Error> {
|
||||
let current_id = *state.corpus().current();
|
||||
|
||||
if let Some(id) = current_id {
|
||||
@ -163,45 +161,42 @@ where
|
||||
}
|
||||
|
||||
/// Trait for Schedulers which track queue cycles
|
||||
pub trait HasQueueCycles: Scheduler
|
||||
where
|
||||
Self::State: HasCorpus,
|
||||
{
|
||||
pub trait HasQueueCycles {
|
||||
/// The amount of cycles the scheduler has completed.
|
||||
fn queue_cycles(&self) -> u64;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
pub trait Scheduler: UsesState
|
||||
pub trait Scheduler<I, S>
|
||||
where
|
||||
Self::State: HasCorpus,
|
||||
S: HasCorpus,
|
||||
{
|
||||
/// 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
|
||||
|
||||
/// An input has been evaluated
|
||||
fn on_evaluation<OT>(
|
||||
&mut self,
|
||||
_state: &mut Self::State,
|
||||
_input: &<Self::State as UsesInput>::Input,
|
||||
_state: &mut S,
|
||||
_input: &I,
|
||||
_observers: &OT,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
OT: ObserversTuple<Self::State>,
|
||||
OT: ObserversTuple<S>,
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
||||
/// Set current fuzzed corpus id and `scheduled_count`
|
||||
fn set_current_scheduled(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
state: &mut S,
|
||||
next_id: Option<CorpusId>,
|
||||
) -> Result<(), Error> {
|
||||
*state.corpus_mut().current_mut() = next_id;
|
||||
@ -215,18 +210,11 @@ pub struct RandScheduler<S> {
|
||||
phantom: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<S> UsesState for RandScheduler<S>
|
||||
where
|
||||
S: State + HasTestcase,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<S> Scheduler for RandScheduler<S>
|
||||
impl<I, S> Scheduler<I, S> for RandScheduler<S>
|
||||
where
|
||||
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
|
||||
let current_id = *state.corpus().current();
|
||||
state
|
||||
@ -239,7 +227,7 @@ where
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
Err(Error::empty(
|
||||
"No entries in corpus. This often implies the target is not properly instrumented."
|
||||
@ -247,7 +235,7 @@ where
|
||||
))
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,10 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
corpus::{Corpus, CorpusId, HasTestcase, Testcase},
|
||||
inputs::UsesInput,
|
||||
inputs::Input,
|
||||
observers::{MapObserver, ObserversTuple},
|
||||
schedulers::{AflScheduler, HasQueueCycles, RemovableScheduler, Scheduler},
|
||||
state::{HasCorpus, State, UsesState},
|
||||
state::{HasCorpus, State},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
|
||||
@ -271,33 +271,27 @@ pub enum BaseSchedule {
|
||||
/// 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)
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PowerQueueScheduler<C, O, S> {
|
||||
pub struct PowerQueueScheduler<C, I, O, S> {
|
||||
queue_cycles: u64,
|
||||
strat: PowerSchedule,
|
||||
map_observer_handle: Handle<C>,
|
||||
last_hash: usize,
|
||||
phantom: PhantomData<(O, S)>,
|
||||
phantom: PhantomData<(I, O, S)>,
|
||||
}
|
||||
|
||||
impl<C, O, S> UsesState for PowerQueueScheduler<C, O, S>
|
||||
where
|
||||
S: State,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<C, O, S> RemovableScheduler for PowerQueueScheduler<C, O, S>
|
||||
impl<C, I, O, S> RemovableScheduler<I, S> for PowerQueueScheduler<C, I, O, S>
|
||||
where
|
||||
S: State + HasTestcase + HasMetadata + HasCorpus,
|
||||
O: MapObserver,
|
||||
C: AsRef<O>,
|
||||
I: Input,
|
||||
{
|
||||
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
|
||||
fn on_remove(
|
||||
&mut self,
|
||||
_state: &mut Self::State,
|
||||
_state: &mut S,
|
||||
_id: CorpusId,
|
||||
_prev: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
||||
_prev: &Option<Testcase<I>>,
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
@ -305,20 +299,22 @@ where
|
||||
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
|
||||
fn on_replace(
|
||||
&mut self,
|
||||
_state: &mut Self::State,
|
||||
_state: &mut S,
|
||||
_id: CorpusId,
|
||||
_prev: &Testcase<<Self::State as UsesInput>::Input>,
|
||||
_prev: &Testcase<I>,
|
||||
) -> Result<(), Error> {
|
||||
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
|
||||
S: HasCorpus + HasMetadata + HasTestcase + State,
|
||||
O: MapObserver,
|
||||
C: AsRef<O>,
|
||||
{
|
||||
type MapObserverRef = C;
|
||||
|
||||
fn last_hash(&self) -> usize {
|
||||
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
|
||||
S: HasCorpus + HasMetadata + HasTestcase + State,
|
||||
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
|
||||
S: HasCorpus + HasMetadata + HasTestcase + State,
|
||||
O: MapObserver,
|
||||
C: AsRef<O>,
|
||||
{
|
||||
/// Called when a [`Testcase`] is added to the corpus
|
||||
fn on_add(&mut self, state: &mut Self::State, id: CorpusId) -> Result<(), Error> {
|
||||
self.on_add_metadata(state, id)
|
||||
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
|
||||
<Self as AflScheduler<I, O, S>>::on_add_metadata(self, state, id)
|
||||
}
|
||||
|
||||
fn on_evaluation<OT>(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
input: &<Self::State as UsesInput>::Input,
|
||||
observers: &OT,
|
||||
) -> Result<(), Error>
|
||||
fn on_evaluation<OT>(&mut self, state: &mut S, input: &I, observers: &OT) -> Result<(), Error>
|
||||
where
|
||||
OT: ObserversTuple<Self::State>,
|
||||
OT: ObserversTuple<S>,
|
||||
{
|
||||
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 {
|
||||
Err(Error::empty(
|
||||
"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`
|
||||
fn set_current_scheduled(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
state: &mut S,
|
||||
next_id: Option<CorpusId>,
|
||||
) -> 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;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, O, S> PowerQueueScheduler<C, O, S>
|
||||
impl<C, I, O, S> PowerQueueScheduler<C, I, O, S>
|
||||
where
|
||||
S: HasMetadata,
|
||||
O: MapObserver,
|
||||
|
@ -10,19 +10,16 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
corpus::{Corpus, CorpusId, HasTestcase, Testcase},
|
||||
inputs::UsesInput,
|
||||
inputs::Input,
|
||||
schedulers::{RemovableScheduler, Scheduler, TestcaseScore},
|
||||
state::{HasCorpus, HasRand, State, UsesState},
|
||||
state::{HasCorpus, HasRand, State},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
|
||||
/// Conduct reservoir sampling (probabilistic sampling) over all corpus elements.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ProbabilitySamplingScheduler<F, S>
|
||||
where
|
||||
S: UsesInput,
|
||||
{
|
||||
phantom: PhantomData<(F, S)>,
|
||||
pub struct ProbabilitySamplingScheduler<F, I, S> {
|
||||
phantom: PhantomData<(F, I, S)>,
|
||||
}
|
||||
|
||||
/// 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
|
||||
F: TestcaseScore<S>,
|
||||
S: HasCorpus + HasMetadata + HasRand,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
S: HasCorpus<Input = I> + HasMetadata + HasRand,
|
||||
{
|
||||
/// Creates a new [`struct@ProbabilitySamplingScheduler`]
|
||||
#[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
|
||||
F: TestcaseScore<S>,
|
||||
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
S: HasCorpus<Input = I> + HasMetadata + HasRand + HasTestcase + State,
|
||||
{
|
||||
fn on_remove(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
state: &mut S,
|
||||
id: CorpusId,
|
||||
_testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
||||
_testcase: &Option<Testcase<I>>,
|
||||
) -> Result<(), Error> {
|
||||
let meta = state
|
||||
.metadata_map_mut()
|
||||
@ -112,9 +111,9 @@ where
|
||||
|
||||
fn on_replace(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
state: &mut S,
|
||||
id: CorpusId,
|
||||
_prev: &Testcase<<Self::State as UsesInput>::Input>,
|
||||
_prev: &Testcase<I>,
|
||||
) -> Result<(), Error> {
|
||||
let meta = state
|
||||
.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
|
||||
S: State + HasTestcase,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
S: HasCorpus<Input = I> + HasMetadata + HasRand + HasTestcase + State,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
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> {
|
||||
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
|
||||
let current_id = *state.corpus().current();
|
||||
state
|
||||
.corpus()
|
||||
@ -156,7 +149,7 @@ where
|
||||
|
||||
/// Gets the next entry
|
||||
#[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 {
|
||||
Err(Error::empty(String::from(
|
||||
"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
|
||||
F: TestcaseScore<S>,
|
||||
S: HasCorpus + HasMetadata + HasRand,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
S: HasCorpus<Input = I> + HasMetadata + HasRand,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
@ -200,7 +194,7 @@ mod tests {
|
||||
use crate::{
|
||||
corpus::{Corpus, InMemoryCorpus, Testcase},
|
||||
feedbacks::ConstFeedback,
|
||||
inputs::{bytes::BytesInput, Input, UsesInput},
|
||||
inputs::{bytes::BytesInput, Input},
|
||||
schedulers::{ProbabilitySamplingScheduler, Scheduler, TestcaseScore},
|
||||
state::{HasCorpus, StdState},
|
||||
Error, HasMetadata,
|
||||
@ -216,17 +210,18 @@ mod tests {
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<S> TestcaseScore<S> for UniformDistribution<S::Input>
|
||||
impl<I, S> TestcaseScore<I, S> for UniformDistribution<I>
|
||||
where
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
pub type UniformProbabilitySamplingScheduler<S> =
|
||||
ProbabilitySamplingScheduler<UniformDistribution<<S as UsesInput>::Input>, S>;
|
||||
pub type UniformProbabilitySamplingScheduler<I, S> =
|
||||
ProbabilitySamplingScheduler<UniformDistribution<I>, I, S>;
|
||||
|
||||
#[test]
|
||||
fn test_prob_sampling() {
|
||||
@ -240,7 +235,8 @@ mod tests {
|
||||
// the first 3 probabilities will be .76, .86, .36
|
||||
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 objective = ConstFeedback::new(false);
|
||||
|
@ -5,33 +5,27 @@ use core::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
corpus::{Corpus, CorpusId, HasTestcase},
|
||||
inputs::Input,
|
||||
schedulers::{HasQueueCycles, RemovableScheduler, Scheduler},
|
||||
state::{HasCorpus, State, UsesState},
|
||||
state::{HasCorpus, State},
|
||||
Error,
|
||||
};
|
||||
|
||||
/// Walk the corpus in a queue-like fashion
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct QueueScheduler<S> {
|
||||
pub struct QueueScheduler<I, S> {
|
||||
queue_cycles: u64,
|
||||
runs_in_current_cycle: u64,
|
||||
phantom: PhantomData<S>,
|
||||
phantom: PhantomData<(I, S)>,
|
||||
}
|
||||
|
||||
impl<S> UsesState for QueueScheduler<S>
|
||||
where
|
||||
S: State,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
impl<I, S> RemovableScheduler<I, S> for QueueScheduler<I, S> where I: Input {}
|
||||
|
||||
impl<S> RemovableScheduler for QueueScheduler<S> where S: HasCorpus + HasTestcase + State {}
|
||||
|
||||
impl<S> Scheduler for QueueScheduler<S>
|
||||
impl<I, S> Scheduler<I, S> for QueueScheduler<I, S>
|
||||
where
|
||||
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
|
||||
let current_id = *state.corpus().current();
|
||||
state
|
||||
@ -44,7 +38,7 @@ where
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
Err(Error::empty(
|
||||
"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`
|
||||
#[must_use]
|
||||
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 {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> HasQueueCycles for QueueScheduler<S>
|
||||
where
|
||||
S: HasCorpus + HasTestcase + State,
|
||||
{
|
||||
impl<I, S> HasQueueCycles for QueueScheduler<I, S> {
|
||||
fn queue_cycles(&self) -> u64 {
|
||||
self.queue_cycles
|
||||
}
|
||||
@ -115,7 +106,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_queuecorpus() {
|
||||
let rand = StdRand::with_seed(4);
|
||||
let mut scheduler = QueueScheduler::new();
|
||||
let mut scheduler: QueueScheduler<BytesInput, _> = QueueScheduler::new();
|
||||
|
||||
let mut q =
|
||||
OnDiskCorpus::<BytesInput>::new(PathBuf::from("target/.test/fancy/path")).unwrap();
|
||||
|
@ -7,6 +7,7 @@ use libafl_bolts::{HasLen, HasRefCnt};
|
||||
use crate::{
|
||||
corpus::{Corpus, SchedulerTestcaseMetadata, Testcase},
|
||||
feedbacks::MapIndexesMetadata,
|
||||
inputs::Input,
|
||||
schedulers::{
|
||||
minimizer::{IsFavoredMetadata, TopRatedsMetadata},
|
||||
powersched::{BaseSchedule, SchedulerMetadata},
|
||||
@ -16,28 +17,29 @@ use crate::{
|
||||
};
|
||||
|
||||
/// Compute the favor factor of a [`Testcase`]. Higher is better.
|
||||
pub trait TestcaseScore<S>
|
||||
pub trait TestcaseScore<I, S>
|
||||
where
|
||||
S: HasMetadata + HasCorpus,
|
||||
I: Input,
|
||||
{
|
||||
/// 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.
|
||||
/// This favors small and quick testcases.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LenTimeMulTestcaseScore<S> {
|
||||
phantom: PhantomData<S>,
|
||||
pub struct LenTimeMulTestcaseScore<I, S> {
|
||||
phantom: PhantomData<(I, S)>,
|
||||
}
|
||||
|
||||
impl<S> TestcaseScore<S> for LenTimeMulTestcaseScore<S>
|
||||
impl<I, S> TestcaseScore<I, S> for LenTimeMulTestcaseScore<I, S>
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
S::Input: HasLen,
|
||||
S: HasCorpus<Input = I> + HasMetadata,
|
||||
I: HasLen + Input,
|
||||
{
|
||||
#[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()
|
||||
Ok(entry.exec_time().map_or(1, |d| d.as_millis()) as f64
|
||||
* entry.load_len(state.corpus())? as f64)
|
||||
@ -56,9 +58,10 @@ pub struct CorpusPowerTestcaseScore<S> {
|
||||
phantom: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<S> TestcaseScore<S> for CorpusPowerTestcaseScore<S>
|
||||
impl<I, S> TestcaseScore<I, S> for CorpusPowerTestcaseScore<S>
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
I: Input,
|
||||
{
|
||||
/// Compute the `power` we assign to each corpus entry
|
||||
#[allow(
|
||||
@ -67,7 +70,7 @@ where
|
||||
clippy::cast_sign_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 psmeta = state.metadata::<SchedulerMetadata>()?;
|
||||
|
||||
let fuzz_mu = if let Some(strat) = psmeta.strat() {
|
||||
@ -277,13 +280,14 @@ pub struct CorpusWeightTestcaseScore<S> {
|
||||
phantom: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<S> TestcaseScore<S> for CorpusWeightTestcaseScore<S>
|
||||
impl<I, S> TestcaseScore<I, S> for CorpusWeightTestcaseScore<S>
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
I: Input,
|
||||
{
|
||||
/// Compute the `weight` used in weighted corpus entry selection algo
|
||||
#[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 psmeta = state.metadata::<SchedulerMetadata>()?;
|
||||
|
||||
|
@ -11,8 +11,9 @@ use serde::{Deserialize, Serialize};
|
||||
use super::RemovableScheduler;
|
||||
use crate::{
|
||||
corpus::{Corpus, CorpusId, HasTestcase},
|
||||
inputs::Input,
|
||||
schedulers::Scheduler,
|
||||
state::{HasCorpus, State, UsesState},
|
||||
state::{HasCorpus, State},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
|
||||
@ -30,11 +31,11 @@ impl_serdeany!(TuneableSchedulerMetadata);
|
||||
/// Walk the corpus in a queue-like fashion
|
||||
/// With the specific `set_next` method, we can chose the next corpus entry manually
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TuneableScheduler<S> {
|
||||
phantom: PhantomData<S>,
|
||||
pub struct TuneableScheduler<I, S> {
|
||||
phantom: PhantomData<(I, S)>,
|
||||
}
|
||||
|
||||
impl<S> TuneableScheduler<S>
|
||||
impl<I, S> TuneableScheduler<I, S>
|
||||
where
|
||||
S: HasMetadata + HasCorpus,
|
||||
{
|
||||
@ -88,23 +89,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> UsesState for TuneableScheduler<S>
|
||||
where
|
||||
S: State,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
impl<I, S> RemovableScheduler<I, S> for TuneableScheduler<I, S> where I: Input {}
|
||||
|
||||
impl<S> RemovableScheduler for TuneableScheduler<S> where
|
||||
S: HasCorpus + HasMetadata + HasTestcase + State
|
||||
{
|
||||
}
|
||||
|
||||
impl<S> Scheduler for TuneableScheduler<S>
|
||||
impl<I, S> Scheduler<I, S> for TuneableScheduler<I, S>
|
||||
where
|
||||
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
|
||||
let current_id = *state.corpus().current();
|
||||
state
|
||||
@ -117,7 +108,7 @@ where
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
return Err(Error::empty(
|
||||
"No entries in corpus. This often implies the target is not properly instrumented."
|
||||
|
@ -16,7 +16,7 @@ use serde::{Deserialize, Serialize};
|
||||
use super::powersched::PowerSchedule;
|
||||
use crate::{
|
||||
corpus::{Corpus, CorpusId, HasTestcase, Testcase},
|
||||
inputs::UsesInput,
|
||||
inputs::Input,
|
||||
observers::{MapObserver, ObserversTuple},
|
||||
random_corpus_id,
|
||||
schedulers::{
|
||||
@ -24,7 +24,7 @@ use crate::{
|
||||
testcase_score::{CorpusWeightTestcaseScore, TestcaseScore},
|
||||
AflScheduler, HasQueueCycles, RemovableScheduler, Scheduler,
|
||||
},
|
||||
state::{HasCorpus, HasRand, State, UsesState},
|
||||
state::{HasCorpus, HasRand, State},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
|
||||
@ -98,22 +98,23 @@ libafl_bolts::impl_serdeany!(WeightedScheduleMetadata);
|
||||
|
||||
/// A corpus scheduler using power schedules with weighted queue item selection algo.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WeightedScheduler<C, F, O, S> {
|
||||
pub struct WeightedScheduler<C, F, I, O, S> {
|
||||
table_invalidated: bool,
|
||||
strat: Option<PowerSchedule>,
|
||||
map_observer_handle: Handle<C>,
|
||||
last_hash: usize,
|
||||
queue_cycles: u64,
|
||||
phantom: PhantomData<(F, O, S)>,
|
||||
phantom: PhantomData<(F, I, O, S)>,
|
||||
/// Cycle `PowerSchedule` on completion of every queue cycle.
|
||||
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
|
||||
F: TestcaseScore<S>,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
O: MapObserver,
|
||||
S: HasCorpus + HasMetadata + HasRand,
|
||||
S: HasCorpus<Input = I> + HasMetadata + HasRand,
|
||||
C: AsRef<O> + Named,
|
||||
{
|
||||
/// 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
|
||||
S: State,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<C, F, O, S> RemovableScheduler for WeightedScheduler<C, F, O, S>
|
||||
where
|
||||
F: TestcaseScore<S>,
|
||||
F: TestcaseScore<I, S>,
|
||||
O: MapObserver,
|
||||
I: Input,
|
||||
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State,
|
||||
C: AsRef<O> + Named,
|
||||
{
|
||||
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
|
||||
fn on_remove(
|
||||
&mut self,
|
||||
_state: &mut Self::State,
|
||||
_state: &mut S,
|
||||
_id: CorpusId,
|
||||
_prev: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
||||
_prev: &Option<Testcase<I>>,
|
||||
) -> Result<(), Error> {
|
||||
self.table_invalidated = true;
|
||||
Ok(())
|
||||
@ -285,22 +280,25 @@ where
|
||||
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
|
||||
fn on_replace(
|
||||
&mut self,
|
||||
_state: &mut Self::State,
|
||||
_state: &mut S,
|
||||
_id: CorpusId,
|
||||
_prev: &Testcase<<Self::State as UsesInput>::Input>,
|
||||
_prev: &Testcase<I>,
|
||||
) -> Result<(), Error> {
|
||||
self.table_invalidated = true;
|
||||
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
|
||||
F: TestcaseScore<S>,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
O: MapObserver,
|
||||
S: HasCorpus + HasMetadata + HasTestcase + HasRand + State,
|
||||
C: AsRef<O> + Named,
|
||||
{
|
||||
type MapObserverRef = C;
|
||||
|
||||
fn last_hash(&self) -> usize {
|
||||
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
|
||||
F: TestcaseScore<S>,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
O: MapObserver,
|
||||
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State,
|
||||
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
|
||||
F: TestcaseScore<S>,
|
||||
F: TestcaseScore<I, S>,
|
||||
I: Input,
|
||||
O: MapObserver,
|
||||
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State,
|
||||
S: HasCorpus<Input = I> + HasMetadata + HasRand + HasTestcase + State,
|
||||
C: AsRef<O> + Named,
|
||||
{
|
||||
/// Called when a [`Testcase`] is added to the corpus
|
||||
@ -340,14 +340,9 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_evaluation<OT>(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
input: &<Self::State as UsesInput>::Input,
|
||||
observers: &OT,
|
||||
) -> Result<(), Error>
|
||||
fn on_evaluation<OT>(&mut self, state: &mut S, input: &I, observers: &OT) -> Result<(), Error>
|
||||
where
|
||||
OT: ObserversTuple<Self::State>,
|
||||
OT: ObserversTuple<S>,
|
||||
{
|
||||
self.on_evaluation_metadata(state, input, observers)
|
||||
}
|
||||
@ -404,7 +399,7 @@ where
|
||||
/// Set current fuzzed corpus id and `scheduled_count`
|
||||
fn set_current_scheduled(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
state: &mut S,
|
||||
next_id: Option<CorpusId>,
|
||||
) -> Result<(), Error> {
|
||||
self.on_next_metadata(state, next_id)?;
|
||||
@ -415,4 +410,5 @@ where
|
||||
}
|
||||
|
||||
/// 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>;
|
||||
|
@ -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>
|
||||
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> {
|
||||
@ -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>
|
||||
where
|
||||
CS: Scheduler,
|
||||
CS: Scheduler<Z::Input, Z::State>,
|
||||
Self::State: HasExecutions
|
||||
+ HasRand
|
||||
+ HasCorpus
|
||||
@ -446,7 +446,7 @@ where
|
||||
+ ProgressReporter<State = Self::State>,
|
||||
OT: ObserversTuple<Self::State>,
|
||||
PS: PushStage<CS, EM, OT, Z>,
|
||||
Z: ExecutesInput<E, EM, State = Self::State>
|
||||
Z: ExecutesInput<E, EM>
|
||||
+ ExecutionProcessor
|
||||
+ EvaluatorObservers<OT>
|
||||
+ HasScheduler<Scheduler = CS>,
|
||||
@ -455,7 +455,7 @@ where
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
executor: &mut E,
|
||||
state: &mut CS::State,
|
||||
state: &mut Z::State,
|
||||
event_mgr: &mut EM,
|
||||
) -> Result<(), Error> {
|
||||
let push_stage = &mut self.push_stage;
|
||||
|
@ -11,6 +11,7 @@ use libafl_bolts::Named;
|
||||
use crate::{
|
||||
executors::{Executor, HasObservers},
|
||||
fuzzer::Evaluator,
|
||||
inputs::Input,
|
||||
mutators::Mutator,
|
||||
schedulers::{testcase_score::CorpusPowerTestcaseScore, TestcaseScore},
|
||||
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
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
EM: UsesState<State = Self::State>,
|
||||
F: TestcaseScore<Self::State>,
|
||||
F: TestcaseScore<I, Self::State>,
|
||||
I: Input,
|
||||
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>,
|
||||
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
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
EM: UsesState<State = Self::State>,
|
||||
F: TestcaseScore<Self::State>,
|
||||
F: TestcaseScore<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>,
|
||||
I: MutatedTransform<Self::Input, Self::State> + Clone,
|
||||
I: MutatedTransform<Self::Input, Self::State> + Clone + Input,
|
||||
{
|
||||
#[inline]
|
||||
#[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
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
EM: UsesState<State = <Self as UsesState>::State>,
|
||||
F: TestcaseScore<<Self as UsesState>::State>,
|
||||
M: Mutator<E::Input, <Self as UsesState>::State>,
|
||||
F: TestcaseScore<I, <Self as UsesState>::State>,
|
||||
I: Input,
|
||||
M: Mutator<I, <Self as UsesState>::State>,
|
||||
<Self as UsesState>::State: HasCorpus + HasMetadata + HasRand,
|
||||
Z: Evaluator<E, EM, State = <Self as UsesState>::State>,
|
||||
{
|
||||
|
@ -36,16 +36,14 @@ const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15);
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PushStageSharedState<CS, EM, OT, Z>
|
||||
where
|
||||
CS: Scheduler,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
CS::State: HasRand + HasCorpus,
|
||||
Z: ExecutionProcessor<State = CS::State>
|
||||
+ EvaluatorObservers<OT>
|
||||
+ HasScheduler<Scheduler = CS>,
|
||||
CS: Scheduler<Z::Input, Z::State>,
|
||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
||||
OT: ObserversTuple<Z::State>,
|
||||
Z::State: HasRand + HasCorpus,
|
||||
Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
|
||||
{
|
||||
/// The [`crate::state::State`]
|
||||
pub state: CS::State,
|
||||
pub state: Z::State,
|
||||
/// The [`crate::fuzzer::Fuzzer`] instance
|
||||
pub fuzzer: Z,
|
||||
/// The [`crate::events::EventManager`]
|
||||
@ -57,17 +55,15 @@ where
|
||||
|
||||
impl<CS, EM, OT, Z> PushStageSharedState<CS, EM, OT, Z>
|
||||
where
|
||||
CS: Scheduler,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
CS::State: HasRand + HasCorpus,
|
||||
Z: ExecutionProcessor<State = CS::State>
|
||||
+ EvaluatorObservers<OT>
|
||||
+ HasScheduler<Scheduler = CS>,
|
||||
CS: Scheduler<Z::Input, Z::State>,
|
||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
||||
OT: ObserversTuple<Z::State>,
|
||||
Z::State: HasRand + HasCorpus,
|
||||
Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
|
||||
{
|
||||
/// Create a new `PushStageSharedState` that can be used by all [`PushStage`]s
|
||||
#[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 {
|
||||
state,
|
||||
fuzzer,
|
||||
@ -82,13 +78,11 @@ where
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PushStageHelper<CS, EM, OT, Z>
|
||||
where
|
||||
CS: Scheduler,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
CS::State: HasRand + HasCorpus,
|
||||
Z: ExecutionProcessor<State = CS::State>
|
||||
+ EvaluatorObservers<OT>
|
||||
+ HasScheduler<Scheduler = CS>,
|
||||
CS: Scheduler<Z::Input, Z::State>,
|
||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
||||
OT: ObserversTuple<Z::State>,
|
||||
Z::State: HasRand + HasCorpus,
|
||||
Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
|
||||
{
|
||||
/// If this stage has already been initalized.
|
||||
/// This gets reset to `false` after one iteration of the stage is done.
|
||||
@ -103,7 +97,7 @@ where
|
||||
pub current_corpus_id: Option<CorpusId>,
|
||||
|
||||
/// 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)]
|
||||
phantom: PhantomData<(CS, EM, OT, Z)>,
|
||||
@ -112,13 +106,11 @@ where
|
||||
|
||||
impl<CS, EM, OT, Z> PushStageHelper<CS, EM, OT, Z>
|
||||
where
|
||||
CS: Scheduler,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
CS::State: HasRand + HasCorpus,
|
||||
Z: ExecutionProcessor<State = CS::State>
|
||||
+ EvaluatorObservers<OT>
|
||||
+ HasScheduler<Scheduler = CS>,
|
||||
CS: Scheduler<Z::Input, Z::State>,
|
||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
||||
OT: ObserversTuple<Z::State>,
|
||||
Z::State: HasRand + HasCorpus,
|
||||
Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
|
||||
{
|
||||
/// Create a new [`PushStageHelper`]
|
||||
#[must_use]
|
||||
@ -181,13 +173,11 @@ where
|
||||
/// After it has finished once, we will call it agan for the next fuzzer round.
|
||||
pub trait PushStage<CS, EM, OT, Z>: Iterator
|
||||
where
|
||||
CS: Scheduler,
|
||||
CS::State: HasRand + HasExecutions + HasMetadata + HasCorpus + HasLastReportTime,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
Z: ExecutionProcessor<State = CS::State>
|
||||
+ EvaluatorObservers<OT>
|
||||
+ HasScheduler<Scheduler = CS>,
|
||||
CS: Scheduler<Z::Input, Z::State>,
|
||||
Z::State: HasRand + HasExecutions + HasMetadata + HasCorpus + HasLastReportTime,
|
||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId + ProgressReporter,
|
||||
OT: ObserversTuple<Z::State>,
|
||||
Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
|
||||
{
|
||||
/// Gets the [`PushStageHelper`]
|
||||
fn push_stage_helper(&self) -> &PushStageHelper<CS, EM, OT, Z>;
|
||||
@ -206,7 +196,7 @@ where
|
||||
fn init(
|
||||
&mut self,
|
||||
_fuzzer: &mut Z,
|
||||
_state: &mut CS::State,
|
||||
_state: &mut Z::State,
|
||||
_event_mgr: &mut EM,
|
||||
_observers: &mut OT,
|
||||
) -> Result<(), Error> {
|
||||
@ -219,20 +209,20 @@ where
|
||||
fn pre_exec(
|
||||
&mut self,
|
||||
_fuzzer: &mut Z,
|
||||
_state: &mut CS::State,
|
||||
_state: &mut Z::State,
|
||||
_event_mgr: &mut EM,
|
||||
_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.
|
||||
#[inline]
|
||||
fn post_exec(
|
||||
&mut self,
|
||||
_fuzzer: &mut Z,
|
||||
_state: &mut CS::State,
|
||||
_state: &mut Z::State,
|
||||
_event_mgr: &mut EM,
|
||||
_observers: &mut OT,
|
||||
_input: <CS::State as UsesInput>::Input,
|
||||
_input: <Z::State as UsesInput>::Input,
|
||||
_exit_kind: ExitKind,
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
@ -243,7 +233,7 @@ where
|
||||
fn deinit(
|
||||
&mut self,
|
||||
_fuzzer: &mut Z,
|
||||
_state: &mut CS::State,
|
||||
_state: &mut Z::State,
|
||||
_event_mgr: &mut EM,
|
||||
_observers: &mut OT,
|
||||
) -> Result<(), Error> {
|
||||
@ -251,7 +241,7 @@ where
|
||||
}
|
||||
|
||||
/// 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 shared_state_ref = &mut (*self.push_stage_helper_mut().shared_state).borrow_mut();
|
||||
shared_state_ref.take().unwrap()
|
||||
|
@ -43,14 +43,12 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128;
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StdMutationalPushStage<CS, EM, M, OT, Z>
|
||||
where
|
||||
CS: Scheduler,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
OT: ObserversTuple<CS::State> + Serialize,
|
||||
CS::State: HasRand + HasCorpus + Clone + Debug,
|
||||
Z: ExecutionProcessor<State = CS::State>
|
||||
+ EvaluatorObservers<OT>
|
||||
+ HasScheduler<Scheduler = CS>,
|
||||
CS: Scheduler<Z::Input, Z::State>,
|
||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
||||
M: Mutator<Z::Input, Z::State>,
|
||||
OT: ObserversTuple<Z::State> + Serialize,
|
||||
Z::State: HasRand + HasCorpus + Clone + Debug,
|
||||
Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
|
||||
{
|
||||
current_corpus_id: Option<CorpusId>,
|
||||
testcases_to_do: usize,
|
||||
@ -63,18 +61,16 @@ where
|
||||
|
||||
impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z>
|
||||
where
|
||||
CS: Scheduler,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
OT: ObserversTuple<CS::State> + Serialize,
|
||||
CS::State: HasCorpus + HasRand + Clone + Debug,
|
||||
Z: ExecutionProcessor<State = CS::State>
|
||||
+ EvaluatorObservers<OT>
|
||||
+ HasScheduler<Scheduler = CS>,
|
||||
CS: Scheduler<Z::Input, Z::State>,
|
||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
||||
M: Mutator<Z::Input, Z::State>,
|
||||
OT: ObserversTuple<Z::State> + Serialize,
|
||||
Z::State: HasCorpus + HasRand + Clone + Debug,
|
||||
Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
|
||||
{
|
||||
/// 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
|
||||
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))
|
||||
}
|
||||
|
||||
@ -86,15 +82,12 @@ where
|
||||
|
||||
impl<CS, EM, M, OT, Z> PushStage<CS, EM, OT, Z> for StdMutationalPushStage<CS, EM, M, OT, Z>
|
||||
where
|
||||
CS: Scheduler,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
OT: ObserversTuple<CS::State> + Serialize,
|
||||
CS::State:
|
||||
HasCorpus + HasRand + HasExecutions + HasLastReportTime + HasMetadata + Clone + Debug,
|
||||
Z: ExecutionProcessor<State = CS::State>
|
||||
+ EvaluatorObservers<OT>
|
||||
+ HasScheduler<Scheduler = CS>,
|
||||
CS: Scheduler<Z::Input, Z::State>,
|
||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId + ProgressReporter,
|
||||
M: Mutator<Z::Input, Z::State>,
|
||||
OT: ObserversTuple<Z::State> + Serialize,
|
||||
Z::State: HasCorpus + HasRand + HasExecutions + HasLastReportTime + HasMetadata + Clone + Debug,
|
||||
Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
|
||||
{
|
||||
#[inline]
|
||||
fn push_stage_helper(&self) -> &PushStageHelper<CS, EM, OT, Z> {
|
||||
@ -110,7 +103,7 @@ where
|
||||
fn init(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
state: &mut CS::State,
|
||||
state: &mut Z::State,
|
||||
_event_mgr: &mut EM,
|
||||
_observers: &mut OT,
|
||||
) -> Result<(), Error> {
|
||||
@ -129,10 +122,10 @@ where
|
||||
fn pre_exec(
|
||||
&mut self,
|
||||
_fuzzer: &mut Z,
|
||||
state: &mut CS::State,
|
||||
state: &mut Z::State,
|
||||
_event_mgr: &mut EM,
|
||||
_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 {
|
||||
// finished with this cicle.
|
||||
return None;
|
||||
@ -164,10 +157,10 @@ where
|
||||
fn post_exec(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
state: &mut CS::State,
|
||||
state: &mut Z::State,
|
||||
event_mgr: &mut EM,
|
||||
observers: &mut OT,
|
||||
last_input: <CS::State as UsesInput>::Input,
|
||||
last_input: <Z::State as UsesInput>::Input,
|
||||
exit_kind: ExitKind,
|
||||
) -> Result<(), Error> {
|
||||
// todo: is_interesting, etc.
|
||||
@ -186,7 +179,7 @@ where
|
||||
fn deinit(
|
||||
&mut self,
|
||||
_fuzzer: &mut Z,
|
||||
_state: &mut CS::State,
|
||||
_state: &mut Z::State,
|
||||
_event_mgr: &mut EM,
|
||||
_observers: &mut OT,
|
||||
) -> Result<(), Error> {
|
||||
@ -197,33 +190,28 @@ where
|
||||
|
||||
impl<CS, EM, M, OT, Z> Iterator for StdMutationalPushStage<CS, EM, M, OT, Z>
|
||||
where
|
||||
CS: Scheduler,
|
||||
EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = CS::State>,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
OT: ObserversTuple<CS::State> + Serialize,
|
||||
CS::State:
|
||||
HasCorpus + HasRand + HasExecutions + HasMetadata + HasLastReportTime + Clone + Debug,
|
||||
Z: ExecutionProcessor<State = CS::State>
|
||||
+ EvaluatorObservers<OT>
|
||||
+ HasScheduler<Scheduler = CS>,
|
||||
CS: Scheduler<Z::Input, Z::State>,
|
||||
EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = Z::State>,
|
||||
M: Mutator<Z::Input, Z::State>,
|
||||
OT: ObserversTuple<Z::State> + Serialize,
|
||||
Z::State: HasCorpus + HasRand + HasExecutions + HasMetadata + HasLastReportTime + Clone + Debug,
|
||||
Z: ExecutionProcessor + 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()
|
||||
}
|
||||
}
|
||||
|
||||
impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z>
|
||||
where
|
||||
CS: Scheduler,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
OT: ObserversTuple<CS::State> + Serialize,
|
||||
CS::State: HasCorpus + HasRand + Clone + Debug,
|
||||
Z: ExecutionProcessor<State = CS::State>
|
||||
+ EvaluatorObservers<OT>
|
||||
+ HasScheduler<Scheduler = CS>,
|
||||
CS: Scheduler<Z::Input, Z::State>,
|
||||
EM: EventFirer<State = Z::State> + EventRestarter + HasEventManagerId,
|
||||
M: Mutator<Z::Input, Z::State>,
|
||||
OT: ObserversTuple<Z::State> + Serialize,
|
||||
Z::State: HasCorpus + HasRand + Clone + Debug,
|
||||
Z: ExecutionProcessor + EvaluatorObservers<OT> + HasScheduler<Scheduler = CS>,
|
||||
{
|
||||
/// Creates a new default mutational stage
|
||||
#[must_use]
|
||||
|
@ -57,7 +57,7 @@ where
|
||||
+ HasFeedback
|
||||
+ ExecutesInput<E, EM>
|
||||
+ ExecutionProcessor,
|
||||
Z::Scheduler: RemovableScheduler<State = Self::State>,
|
||||
Z::Scheduler: RemovableScheduler<Self::Input, Self::State>,
|
||||
{
|
||||
/// The mutator registered for this stage
|
||||
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>
|
||||
where
|
||||
Z: HasScheduler + ExecutionProcessor + ExecutesInput<E, EM> + HasFeedback,
|
||||
Z::Scheduler: RemovableScheduler,
|
||||
Z::Scheduler: RemovableScheduler<Self::Input, Self::State>,
|
||||
E: HasObservers<State = Self::State>,
|
||||
<E as UsesObservers>::Observers: Serialize,
|
||||
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>
|
||||
where
|
||||
Z: HasScheduler + ExecutionProcessor + ExecutesInput<E, EM> + HasFeedback,
|
||||
Z::Scheduler: RemovableScheduler,
|
||||
Z::Scheduler: RemovableScheduler<Self::Input, Self::State>,
|
||||
E: HasObservers<State = Self::State>,
|
||||
<E as UsesObservers>::Observers: Serialize,
|
||||
EM: EventFirer<State = Self::State>,
|
||||
|
@ -4,46 +4,40 @@ use hashbrown::HashMap;
|
||||
use libafl::{
|
||||
corpus::{Corpus, CorpusId, Testcase},
|
||||
feedbacks::MapNoveltiesMetadata,
|
||||
inputs::UsesInput,
|
||||
inputs::Input,
|
||||
schedulers::{RemovableScheduler, Scheduler},
|
||||
state::{HasCorpus, State, UsesState},
|
||||
state::{HasCorpus, State},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MergeScheduler<S> {
|
||||
pub struct MergeScheduler<I, S> {
|
||||
mapping: HashMap<usize, CorpusId>,
|
||||
all: BTreeSet<CorpusId>,
|
||||
phantom: PhantomData<S>,
|
||||
phantom: PhantomData<(I, S)>,
|
||||
}
|
||||
|
||||
impl<S> UsesState for MergeScheduler<S>
|
||||
where
|
||||
S: State,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<S> RemovableScheduler for MergeScheduler<S>
|
||||
impl<I, S> RemovableScheduler<I, S> for MergeScheduler<I, S>
|
||||
where
|
||||
I: Input,
|
||||
S: State + HasCorpus,
|
||||
{
|
||||
fn on_remove(
|
||||
&mut self,
|
||||
_state: &mut Self::State,
|
||||
_state: &mut S,
|
||||
id: CorpusId,
|
||||
_testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
||||
_testcase: &Option<Testcase<I>>,
|
||||
) -> Result<(), Error> {
|
||||
self.all.remove(&id);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Scheduler for MergeScheduler<S>
|
||||
impl<I, S> Scheduler<I, S> for MergeScheduler<I, S>
|
||||
where
|
||||
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);
|
||||
let testcase = state.corpus().get(id)?.borrow();
|
||||
let meta = testcase.metadata::<MapNoveltiesMetadata>()?;
|
||||
@ -53,12 +47,12 @@ where
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> MergeScheduler<S> {
|
||||
impl<I, S> MergeScheduler<I, S> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
mapping: HashMap::default(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user