on_evaluation Scheduler method (#1106)
* add on evaluation hook in schedulers * on_evaluation for WeightedScheduler * fix PowerQueueScheduler * fix fuzzers * upd qemu * tests * upd
This commit is contained in:
parent
59bf118a5a
commit
dc800f0814
@ -304,11 +304,12 @@ fn fuzz(
|
||||
5,
|
||||
)?;
|
||||
|
||||
let power = StdPowerMutationalStage::new(mutator, &edges_observer);
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::EXPLORE),
|
||||
));
|
||||
|
||||
|
@ -292,11 +292,12 @@ fn fuzz(
|
||||
5,
|
||||
)?;
|
||||
|
||||
let power = StdPowerMutationalStage::new(mutator, &edges_observer);
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
PowerSchedule::FAST,
|
||||
));
|
||||
|
||||
|
@ -294,11 +294,12 @@ fn fuzz(
|
||||
5,
|
||||
)?;
|
||||
|
||||
let power = StdPowerMutationalStage::new(mutator, &edges_observer);
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::EXPLORE),
|
||||
));
|
||||
|
||||
|
@ -304,11 +304,12 @@ fn fuzz(
|
||||
5,
|
||||
)?;
|
||||
|
||||
let power = StdPowerMutationalStage::new(mutator, &edges_observer);
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
PowerSchedule::FAST,
|
||||
));
|
||||
|
||||
|
@ -365,11 +365,12 @@ fn fuzz_binary(
|
||||
5,
|
||||
)?;
|
||||
|
||||
let power = StdPowerMutationalStage::new(mutator, &edges_observer);
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::EXPLORE),
|
||||
));
|
||||
|
||||
@ -568,7 +569,7 @@ fn fuzz_text(
|
||||
5,
|
||||
)?;
|
||||
|
||||
let power = StdPowerMutationalStage::new(mutator, &edges_observer);
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
let grimoire_mutator = StdScheduledMutator::with_max_stack_pow(
|
||||
tuple_list!(
|
||||
@ -586,6 +587,7 @@ fn fuzz_text(
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::EXPLORE),
|
||||
));
|
||||
|
||||
|
@ -142,13 +142,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
|
||||
let power = StdPowerMutationalStage::new(mutator, &edges_observer);
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
let mut stages = tuple_list!(calibration, power);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::FAST),
|
||||
));
|
||||
|
||||
|
@ -141,13 +141,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
|
||||
let power = StdPowerMutationalStage::new(mutator, &edges_observer);
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
let mut stages = tuple_list!(calibration, power);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::FAST),
|
||||
));
|
||||
|
||||
|
@ -107,13 +107,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
|
||||
let power = StdPowerMutationalStage::new(mutator, &edges_observer);
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
let mut stages = tuple_list!(calibration, power);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::FAST),
|
||||
));
|
||||
|
||||
|
@ -127,13 +127,16 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
// Setup a lain mutator with a mutational stage
|
||||
let mutator = LainMutator::new();
|
||||
|
||||
let power = StdPowerMutationalStage::new(mutator, &edges_observer);
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
let mut stages = tuple_list!(calibration, power);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler =
|
||||
PacketLenMinimizerScheduler::new(PowerQueueScheduler::new(&mut state, PowerSchedule::FAST));
|
||||
let scheduler = PacketLenMinimizerScheduler::new(PowerQueueScheduler::new(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
PowerSchedule::FAST,
|
||||
));
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -300,6 +300,18 @@ impl SchedulerTestcaseMetaData {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new [`struct@SchedulerTestcaseMetaData`] given `n_fuzz_entry`
|
||||
#[must_use]
|
||||
pub fn with_n_fuzz_entry(depth: u64, n_fuzz_entry: usize) -> Self {
|
||||
Self {
|
||||
bitmap_size: 0,
|
||||
handicap: 0,
|
||||
depth,
|
||||
n_fuzz_entry,
|
||||
cycle_and_time: (Duration::default(), 0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the bitmap size
|
||||
#[inline]
|
||||
#[must_use]
|
||||
|
@ -460,6 +460,9 @@ where
|
||||
{
|
||||
let exit_kind = self.execute_input(state, executor, manager, &input)?;
|
||||
let observers = executor.observers();
|
||||
|
||||
self.scheduler.on_evaluation(state, &input, observers)?;
|
||||
|
||||
self.process_execution(state, manager, input, observers, &exit_kind, send_events)
|
||||
}
|
||||
}
|
||||
|
@ -125,13 +125,13 @@ where
|
||||
CS::State: HasCorpus + HasMetadata + HasRand + Debug,
|
||||
<CS::State as UsesInput>::Input: HasLen,
|
||||
{
|
||||
fn on_add(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
|
||||
fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
|
||||
self.update_accounting_score(state, idx)?;
|
||||
self.inner.on_add(state, idx)
|
||||
}
|
||||
|
||||
fn on_replace(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
idx: CorpusId,
|
||||
testcase: &Testcase<<Self::State as UsesInput>::Input>,
|
||||
@ -140,7 +140,7 @@ where
|
||||
}
|
||||
|
||||
fn on_remove(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
idx: CorpusId,
|
||||
testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
||||
@ -148,7 +148,7 @@ where
|
||||
self.inner.on_remove(state, idx, testcase)
|
||||
}
|
||||
|
||||
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||
if state
|
||||
.metadata()
|
||||
.get::<TopAccountingMetadata>()
|
||||
@ -158,7 +158,7 @@ where
|
||||
} else {
|
||||
self.inner.cull(state)?;
|
||||
}
|
||||
let mut idx = self.inner.base().next(state)?;
|
||||
let mut idx = self.inner.base_mut().next(state)?;
|
||||
while {
|
||||
let has = !state
|
||||
.corpus()
|
||||
@ -168,7 +168,7 @@ where
|
||||
has
|
||||
} && state.rand_mut().below(100) < self.skip_non_favored_prob
|
||||
{
|
||||
idx = self.inner.base().next(state)?;
|
||||
idx = self.inner.base_mut().next(state)?;
|
||||
}
|
||||
Ok(idx)
|
||||
}
|
||||
|
@ -82,14 +82,14 @@ where
|
||||
CS::State: HasCorpus + HasMetadata + HasRand,
|
||||
{
|
||||
/// Add an entry to the corpus and return its index
|
||||
fn on_add(&self, state: &mut CS::State, idx: CorpusId) -> Result<(), Error> {
|
||||
fn on_add(&mut self, state: &mut CS::State, idx: CorpusId) -> Result<(), Error> {
|
||||
self.base.on_add(state, idx)?;
|
||||
self.update_score(state, idx)
|
||||
}
|
||||
|
||||
/// Replaces the testcase at the given idx
|
||||
fn on_replace(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut CS::State,
|
||||
idx: CorpusId,
|
||||
testcase: &Testcase<<CS::State as UsesInput>::Input>,
|
||||
@ -100,7 +100,7 @@ where
|
||||
|
||||
/// Removes an entry from the corpus, returning M if M was present.
|
||||
fn on_remove(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut CS::State,
|
||||
idx: CorpusId,
|
||||
testcase: &Option<Testcase<<CS::State as UsesInput>::Input>>,
|
||||
@ -163,7 +163,7 @@ where
|
||||
}
|
||||
|
||||
/// Gets the next entry
|
||||
fn next(&self, state: &mut CS::State) -> Result<CorpusId, Error> {
|
||||
fn next(&mut self, state: &mut CS::State) -> Result<CorpusId, Error> {
|
||||
self.cull(state)?;
|
||||
let mut idx = self.base.next(state)?;
|
||||
while {
|
||||
@ -295,6 +295,11 @@ where
|
||||
&self.base
|
||||
}
|
||||
|
||||
/// Get a reference to the base scheduler (mut)
|
||||
pub fn base_mut(&mut self) -> &mut CS {
|
||||
&mut self.base
|
||||
}
|
||||
|
||||
/// Creates a new [`MinimizerScheduler`] that wraps a `base` [`Scheduler`]
|
||||
/// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
|
||||
pub fn new(base: CS) -> Self {
|
||||
|
@ -33,6 +33,7 @@ use crate::{
|
||||
bolts::rands::Rand,
|
||||
corpus::{Corpus, CorpusId, Testcase},
|
||||
inputs::UsesInput,
|
||||
observers::ObserversTuple,
|
||||
random_corpus_id,
|
||||
state::{HasCorpus, HasRand, UsesState},
|
||||
Error,
|
||||
@ -42,13 +43,13 @@ use crate::{
|
||||
/// It has hooks to corpus add/replace/remove to allow complex scheduling algorithms to collect data.
|
||||
pub trait Scheduler: UsesState {
|
||||
/// Added an entry to the corpus at the given index
|
||||
fn on_add(&self, _state: &mut Self::State, _idx: CorpusId) -> Result<(), Error> {
|
||||
fn on_add(&mut self, _state: &mut Self::State, _idx: CorpusId) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Replaced the given testcase at the given idx
|
||||
fn on_replace(
|
||||
&self,
|
||||
&mut self,
|
||||
_state: &mut Self::State,
|
||||
_idx: CorpusId,
|
||||
_prev: &Testcase<<Self::State as UsesInput>::Input>,
|
||||
@ -58,7 +59,7 @@ pub trait Scheduler: UsesState {
|
||||
|
||||
/// Removed the given entry from the corpus at the given index
|
||||
fn on_remove(
|
||||
&self,
|
||||
&mut self,
|
||||
_state: &mut Self::State,
|
||||
_idx: CorpusId,
|
||||
_testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
||||
@ -66,8 +67,21 @@ pub trait Scheduler: UsesState {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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>
|
||||
where
|
||||
OT: ObserversTuple<Self::State>,
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets the next entry
|
||||
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error>;
|
||||
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error>;
|
||||
}
|
||||
|
||||
/// Feed the fuzzer simply with a random testcase on request
|
||||
@ -88,7 +102,7 @@ where
|
||||
S: HasCorpus + HasRand,
|
||||
{
|
||||
/// Gets the next entry at random
|
||||
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||
if state.corpus().count() == 0 {
|
||||
Err(Error::empty("No entries in corpus".to_owned()))
|
||||
} else {
|
||||
|
@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData, Testcase},
|
||||
inputs::UsesInput,
|
||||
observers::{MapObserver, ObserversTuple},
|
||||
schedulers::Scheduler,
|
||||
state::{HasCorpus, HasMetadata, UsesState},
|
||||
Error,
|
||||
@ -163,24 +164,27 @@ pub enum PowerSchedule {
|
||||
|
||||
/// A corpus scheduler using power schedules
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PowerQueueScheduler<S> {
|
||||
pub struct PowerQueueScheduler<O, S> {
|
||||
strat: PowerSchedule,
|
||||
phantom: PhantomData<S>,
|
||||
map_observer_name: String,
|
||||
last_hash: usize,
|
||||
phantom: PhantomData<(O, S)>,
|
||||
}
|
||||
|
||||
impl<S> UsesState for PowerQueueScheduler<S>
|
||||
impl<O, S> UsesState for PowerQueueScheduler<O, S>
|
||||
where
|
||||
S: UsesInput,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<S> Scheduler for PowerQueueScheduler<S>
|
||||
impl<O, S> Scheduler for PowerQueueScheduler<O, S>
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
O: MapObserver,
|
||||
{
|
||||
/// Add an entry to the corpus and return its index
|
||||
fn on_add(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
|
||||
fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
|
||||
let current_idx = *state.corpus().current();
|
||||
|
||||
let mut depth = match current_idx {
|
||||
@ -199,17 +203,15 @@ where
|
||||
|
||||
// Attach a `SchedulerTestcaseMetaData` to the queue entry.
|
||||
depth += 1;
|
||||
state
|
||||
.corpus()
|
||||
.get(idx)?
|
||||
.borrow_mut()
|
||||
.add_metadata(SchedulerTestcaseMetaData::new(depth));
|
||||
state.corpus().get(idx)?.borrow_mut().add_metadata(
|
||||
SchedulerTestcaseMetaData::with_n_fuzz_entry(depth, self.last_hash),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
fn on_replace(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
idx: CorpusId,
|
||||
prev: &Testcase<<Self::State as UsesInput>::Input>,
|
||||
@ -251,7 +253,7 @@ where
|
||||
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
fn on_remove(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
_idx: CorpusId,
|
||||
prev: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
||||
@ -288,7 +290,36 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||
fn on_evaluation<OT>(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
_input: &<Self::State as UsesInput>::Input,
|
||||
observers: &OT,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
OT: ObserversTuple<Self::State>,
|
||||
{
|
||||
let observer = observers
|
||||
.match_name::<O>(&self.map_observer_name)
|
||||
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?;
|
||||
|
||||
let mut hash = observer.hash() as usize;
|
||||
|
||||
let psmeta = state
|
||||
.metadata_mut()
|
||||
.get_mut::<SchedulerMetadata>()
|
||||
.ok_or_else(|| Error::key_not_found("SchedulerMetadata not found".to_string()))?;
|
||||
|
||||
hash %= psmeta.n_fuzz().len();
|
||||
// Update the path frequency
|
||||
psmeta.n_fuzz_mut()[hash] = psmeta.n_fuzz()[hash].saturating_add(1);
|
||||
|
||||
self.last_hash = hash;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||
if state.corpus().count() == 0 {
|
||||
Err(Error::empty(String::from("No entries in corpus")))
|
||||
} else {
|
||||
@ -331,18 +362,21 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> PowerQueueScheduler<S>
|
||||
impl<O, S> PowerQueueScheduler<O, S>
|
||||
where
|
||||
S: HasMetadata,
|
||||
O: MapObserver,
|
||||
{
|
||||
/// Create a new [`PowerQueueScheduler`]
|
||||
#[must_use]
|
||||
pub fn new(state: &mut S, strat: PowerSchedule) -> Self {
|
||||
pub fn new(state: &mut S, map_observer: &O, strat: PowerSchedule) -> Self {
|
||||
if !state.has_metadata::<SchedulerMetadata>() {
|
||||
state.add_metadata::<SchedulerMetadata>(SchedulerMetadata::new(Some(strat)));
|
||||
}
|
||||
PowerQueueScheduler {
|
||||
strat,
|
||||
map_observer_name: map_observer.name().to_string(),
|
||||
last_hash: 0,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ where
|
||||
F: TestcaseScore<S>,
|
||||
S: HasCorpus + HasMetadata + HasRand,
|
||||
{
|
||||
fn on_add(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
|
||||
fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
|
||||
if state.metadata().get::<ProbabilityMetadata>().is_none() {
|
||||
state.add_metadata(ProbabilityMetadata::new());
|
||||
}
|
||||
@ -108,7 +108,7 @@ where
|
||||
|
||||
/// Gets the next entry
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||
if state.corpus().count() == 0 {
|
||||
Err(Error::empty(String::from("No entries in corpus")))
|
||||
} else {
|
||||
@ -182,7 +182,7 @@ mod tests {
|
||||
// the first 3 probabilities will be .69, .86, .44
|
||||
let rand = StdRand::with_seed(12);
|
||||
|
||||
let scheduler = UniformProbabilitySamplingScheduler::new();
|
||||
let mut scheduler = UniformProbabilitySamplingScheduler::new();
|
||||
|
||||
let mut feedback = ConstFeedback::new(false);
|
||||
let mut objective = ConstFeedback::new(false);
|
||||
|
@ -29,7 +29,7 @@ where
|
||||
S: HasCorpus,
|
||||
{
|
||||
/// Gets the next entry in the queue
|
||||
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||
if state.corpus().count() == 0 {
|
||||
Err(Error::empty("No entries in corpus".to_owned()))
|
||||
} else {
|
||||
@ -79,7 +79,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_queuecorpus() {
|
||||
let rand = StdRand::with_seed(4);
|
||||
let scheduler = QueueScheduler::new();
|
||||
let mut scheduler = QueueScheduler::new();
|
||||
|
||||
let mut q =
|
||||
OnDiskCorpus::<BytesInput>::new(PathBuf::from("target/.test/fancy/path")).unwrap();
|
||||
|
@ -93,7 +93,7 @@ where
|
||||
S: HasCorpus + HasMetadata,
|
||||
{
|
||||
/// Gets the next entry in the queue
|
||||
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||
if state.corpus().count() == 0 {
|
||||
return Err(Error::empty("No entries in corpus".to_owned()));
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use crate::{
|
||||
bolts::rands::Rand,
|
||||
corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData, Testcase},
|
||||
inputs::UsesInput,
|
||||
observers::{MapObserver, ObserversTuple},
|
||||
random_corpus_id,
|
||||
schedulers::{
|
||||
powersched::{PowerSchedule, SchedulerMetadata},
|
||||
@ -88,25 +89,28 @@ crate::impl_serdeany!(WeightedScheduleMetadata);
|
||||
|
||||
/// A corpus scheduler using power schedules with weighted queue item selection algo.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WeightedScheduler<F, S> {
|
||||
pub struct WeightedScheduler<F, O, S> {
|
||||
strat: Option<PowerSchedule>,
|
||||
phantom: PhantomData<(F, S)>,
|
||||
map_observer_name: String,
|
||||
last_hash: usize,
|
||||
phantom: PhantomData<(F, O, S)>,
|
||||
}
|
||||
|
||||
impl<F, S> WeightedScheduler<F, S>
|
||||
impl<F, O, S> WeightedScheduler<F, O, S>
|
||||
where
|
||||
F: TestcaseScore<S>,
|
||||
O: MapObserver,
|
||||
S: HasCorpus + HasMetadata + HasRand,
|
||||
{
|
||||
/// Create a new [`WeightedScheduler`] without any power schedule
|
||||
#[must_use]
|
||||
pub fn new(state: &mut S) -> Self {
|
||||
Self::with_schedule(state, None)
|
||||
pub fn new(state: &mut S, map_observer: &O) -> Self {
|
||||
Self::with_schedule(state, map_observer, None)
|
||||
}
|
||||
|
||||
/// Create a new [`WeightedScheduler`]
|
||||
#[must_use]
|
||||
pub fn with_schedule(state: &mut S, strat: Option<PowerSchedule>) -> Self {
|
||||
pub fn with_schedule(state: &mut S, map_observer: &O, strat: Option<PowerSchedule>) -> Self {
|
||||
if !state.has_metadata::<SchedulerMetadata>() {
|
||||
state.add_metadata(SchedulerMetadata::new(strat));
|
||||
}
|
||||
@ -116,6 +120,8 @@ where
|
||||
}
|
||||
Self {
|
||||
strat,
|
||||
map_observer_name: map_observer.name().to_string(),
|
||||
last_hash: 0,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -216,20 +222,21 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, S> UsesState for WeightedScheduler<F, S>
|
||||
impl<F, O, S> UsesState for WeightedScheduler<F, O, S>
|
||||
where
|
||||
S: UsesInput,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<F, S> Scheduler for WeightedScheduler<F, S>
|
||||
impl<F, O, S> Scheduler for WeightedScheduler<F, O, S>
|
||||
where
|
||||
F: TestcaseScore<S>,
|
||||
O: MapObserver,
|
||||
S: HasCorpus + HasMetadata + HasRand,
|
||||
{
|
||||
/// Add an entry to the corpus and return its index
|
||||
fn on_add(&self, state: &mut S, idx: CorpusId) -> Result<(), Error> {
|
||||
fn on_add(&mut self, state: &mut S, idx: CorpusId) -> Result<(), Error> {
|
||||
let current_idx = *state.corpus().current();
|
||||
|
||||
let mut depth = match current_idx {
|
||||
@ -248,11 +255,9 @@ where
|
||||
|
||||
// Attach a `SchedulerTestcaseMetaData` to the queue entry.
|
||||
depth += 1;
|
||||
state
|
||||
.corpus()
|
||||
.get(idx)?
|
||||
.borrow_mut()
|
||||
.add_metadata(SchedulerTestcaseMetaData::new(depth));
|
||||
state.corpus().get(idx)?.borrow_mut().add_metadata(
|
||||
SchedulerTestcaseMetaData::with_n_fuzz_entry(depth, self.last_hash),
|
||||
);
|
||||
|
||||
// Recreate the alias table
|
||||
self.create_alias_table(state)?;
|
||||
@ -260,7 +265,7 @@ where
|
||||
}
|
||||
|
||||
fn on_replace(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
idx: CorpusId,
|
||||
_testcase: &Testcase<S::Input>,
|
||||
@ -270,7 +275,7 @@ where
|
||||
}
|
||||
|
||||
fn on_remove(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
_idx: CorpusId,
|
||||
_testcase: &Option<Testcase<S::Input>>,
|
||||
@ -280,8 +285,37 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_evaluation<OT>(
|
||||
&mut self,
|
||||
state: &mut Self::State,
|
||||
_input: &<Self::State as UsesInput>::Input,
|
||||
observers: &OT,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
OT: ObserversTuple<Self::State>,
|
||||
{
|
||||
let observer = observers
|
||||
.match_name::<O>(&self.map_observer_name)
|
||||
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?;
|
||||
|
||||
let mut hash = observer.hash() as usize;
|
||||
|
||||
let psmeta = state
|
||||
.metadata_mut()
|
||||
.get_mut::<SchedulerMetadata>()
|
||||
.ok_or_else(|| Error::key_not_found("SchedulerMetadata not found".to_string()))?;
|
||||
|
||||
hash %= psmeta.n_fuzz().len();
|
||||
// Update the path frequency
|
||||
psmeta.n_fuzz_mut()[hash] = psmeta.n_fuzz()[hash].saturating_add(1);
|
||||
|
||||
self.last_hash = hash;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::similar_names, clippy::cast_precision_loss)]
|
||||
fn next(&self, state: &mut S) -> Result<CorpusId, Error> {
|
||||
fn next(&mut self, state: &mut S) -> Result<CorpusId, Error> {
|
||||
let corpus_counts = state.corpus().count();
|
||||
if corpus_counts == 0 {
|
||||
Err(Error::empty(String::from("No entries in corpus")))
|
||||
@ -345,4 +379,4 @@ where
|
||||
}
|
||||
|
||||
/// The standard corpus weight, same as aflpp
|
||||
pub type StdWeightedScheduler<S> = WeightedScheduler<CorpusWeightTestcaseScore<S>, S>;
|
||||
pub type StdWeightedScheduler<O, S> = WeightedScheduler<CorpusWeightTestcaseScore<S>, O, S>;
|
||||
|
@ -1,50 +1,39 @@
|
||||
//! The power schedules. This stage should be invoked after the calibration stage.
|
||||
|
||||
use alloc::string::{String, ToString};
|
||||
use core::{fmt::Debug, marker::PhantomData};
|
||||
|
||||
use crate::{
|
||||
bolts::tuples::MatchName,
|
||||
corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData},
|
||||
corpus::{Corpus, CorpusId},
|
||||
executors::{Executor, HasObservers},
|
||||
fuzzer::Evaluator,
|
||||
mutators::Mutator,
|
||||
observers::MapObserver,
|
||||
schedulers::{
|
||||
powersched::SchedulerMetadata, testcase_score::CorpusPowerTestcaseScore, TestcaseScore,
|
||||
},
|
||||
stages::{
|
||||
mutational::{MutatedTransform, MutatedTransformPost},
|
||||
MutationalStage, Stage,
|
||||
},
|
||||
schedulers::{testcase_score::CorpusPowerTestcaseScore, TestcaseScore},
|
||||
stages::{mutational::MutatedTransform, MutationalStage, Stage},
|
||||
state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState},
|
||||
Error,
|
||||
};
|
||||
|
||||
/// The mutational stage using power schedules
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PowerMutationalStage<E, F, EM, I, M, O, Z> {
|
||||
map_observer_name: String,
|
||||
pub struct PowerMutationalStage<E, F, EM, I, M, Z> {
|
||||
mutator: M,
|
||||
#[allow(clippy::type_complexity)]
|
||||
phantom: PhantomData<(E, F, EM, I, O, Z)>,
|
||||
phantom: PhantomData<(E, F, EM, I, Z)>,
|
||||
}
|
||||
|
||||
impl<E, F, EM, I, M, O, Z> UsesState for PowerMutationalStage<E, F, EM, I, M, O, Z>
|
||||
impl<E, F, EM, I, M, Z> UsesState for PowerMutationalStage<E, F, EM, I, M, Z>
|
||||
where
|
||||
E: UsesState,
|
||||
{
|
||||
type State = E::State;
|
||||
}
|
||||
|
||||
impl<E, F, EM, I, M, O, Z> MutationalStage<E, EM, I, M, Z>
|
||||
for PowerMutationalStage<E, F, EM, I, M, O, Z>
|
||||
impl<E, F, EM, I, M, Z> MutationalStage<E, EM, I, M, Z> for PowerMutationalStage<E, F, EM, I, M, Z>
|
||||
where
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
EM: UsesState<State = E::State>,
|
||||
F: TestcaseScore<E::State>,
|
||||
M: Mutator<I, E::State>,
|
||||
O: MapObserver,
|
||||
E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
|
||||
Z: Evaluator<E, EM, State = E::State>,
|
||||
I: MutatedTransform<E::Input, E::State> + Clone,
|
||||
@ -70,74 +59,14 @@ where
|
||||
|
||||
Ok(score)
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
fn perform_mutational(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
executor: &mut E,
|
||||
state: &mut E::State,
|
||||
manager: &mut EM,
|
||||
corpus_idx: CorpusId,
|
||||
) -> Result<(), Error> {
|
||||
let num = self.iterations(state, corpus_idx)?;
|
||||
|
||||
let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut();
|
||||
let Ok(input) = I::try_transform_from(&mut testcase, state, corpus_idx) else { return Ok(()); };
|
||||
drop(testcase);
|
||||
|
||||
for i in 0..num {
|
||||
let mut input = input.clone();
|
||||
|
||||
self.mutator_mut().mutate(state, &mut input, i as i32)?;
|
||||
|
||||
let (untransformed, post) = input.try_transform_into(state)?;
|
||||
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, untransformed)?;
|
||||
|
||||
let observer = executor
|
||||
.observers()
|
||||
.match_name::<O>(&self.map_observer_name)
|
||||
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?;
|
||||
|
||||
let mut hash = observer.hash() as usize;
|
||||
|
||||
let psmeta = state
|
||||
.metadata_mut()
|
||||
.get_mut::<SchedulerMetadata>()
|
||||
.ok_or_else(|| Error::key_not_found("SchedulerMetadata not found".to_string()))?;
|
||||
|
||||
hash %= psmeta.n_fuzz().len();
|
||||
// Update the path frequency
|
||||
psmeta.n_fuzz_mut()[hash] = psmeta.n_fuzz()[hash].saturating_add(1);
|
||||
|
||||
if let Some(idx) = corpus_idx {
|
||||
state
|
||||
.corpus()
|
||||
.get(idx)?
|
||||
.borrow_mut()
|
||||
.metadata_mut()
|
||||
.get_mut::<SchedulerTestcaseMetaData>()
|
||||
.ok_or_else(|| {
|
||||
Error::key_not_found("SchedulerTestcaseMetaData not found".to_string())
|
||||
})?
|
||||
.set_n_fuzz_entry(hash);
|
||||
}
|
||||
|
||||
self.mutator_mut().post_exec(state, i as i32, corpus_idx)?;
|
||||
post.post_exec(state, i as i32, corpus_idx)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, F, EM, I, M, O, Z> Stage<E, EM, Z> for PowerMutationalStage<E, F, EM, I, M, O, Z>
|
||||
impl<E, F, EM, I, M, Z> Stage<E, EM, Z> for PowerMutationalStage<E, F, EM, I, M, Z>
|
||||
where
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
EM: UsesState<State = E::State>,
|
||||
F: TestcaseScore<E::State>,
|
||||
M: Mutator<I, E::State>,
|
||||
O: MapObserver,
|
||||
E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
|
||||
Z: Evaluator<E, EM, State = E::State>,
|
||||
I: MutatedTransform<E::Input, E::State> + Clone,
|
||||
@ -157,36 +86,33 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, F, EM, M, O, Z> PowerMutationalStage<E, F, EM, E::Input, M, O, Z>
|
||||
impl<E, F, EM, M, Z> PowerMutationalStage<E, F, EM, E::Input, M, Z>
|
||||
where
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
EM: UsesState<State = E::State>,
|
||||
F: TestcaseScore<E::State>,
|
||||
M: Mutator<E::Input, E::State>,
|
||||
O: MapObserver,
|
||||
E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
|
||||
Z: Evaluator<E, EM, State = E::State>,
|
||||
{
|
||||
/// Creates a new [`PowerMutationalStage`]
|
||||
pub fn new(mutator: M, map_observer_name: &O) -> Self {
|
||||
Self::transforming(mutator, map_observer_name)
|
||||
pub fn new(mutator: M) -> Self {
|
||||
Self::transforming(mutator)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, F, EM, I, M, O, Z> PowerMutationalStage<E, F, EM, I, M, O, Z>
|
||||
impl<E, F, EM, I, M, Z> PowerMutationalStage<E, F, EM, I, M, Z>
|
||||
where
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
EM: UsesState<State = E::State>,
|
||||
F: TestcaseScore<E::State>,
|
||||
M: Mutator<I, E::State>,
|
||||
O: MapObserver,
|
||||
E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
|
||||
Z: Evaluator<E, EM, State = E::State>,
|
||||
{
|
||||
/// Creates a new transforming [`PowerMutationalStage`]
|
||||
pub fn transforming(mutator: M, map_observer_name: &O) -> Self {
|
||||
pub fn transforming(mutator: M) -> Self {
|
||||
Self {
|
||||
map_observer_name: map_observer_name.name().to_string(),
|
||||
mutator,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
@ -194,5 +120,5 @@ where
|
||||
}
|
||||
|
||||
/// The standard powerscheduling stage
|
||||
pub type StdPowerMutationalStage<E, EM, I, M, O, Z> =
|
||||
PowerMutationalStage<E, CorpusPowerTestcaseScore<<E as UsesState>::State>, EM, I, M, O, Z>;
|
||||
pub type StdPowerMutationalStage<E, EM, I, M, Z> =
|
||||
PowerMutationalStage<E, CorpusPowerTestcaseScore<<E as UsesState>::State>, EM, I, M, Z>;
|
||||
|
@ -116,7 +116,7 @@ where
|
||||
self.current_corpus_idx = Some(if let Some(corpus_idx) = self.current_corpus_idx {
|
||||
corpus_idx
|
||||
} else {
|
||||
fuzzer.scheduler().next(state)?
|
||||
fuzzer.scheduler_mut().next(state)?
|
||||
});
|
||||
|
||||
self.testcases_to_do = self.iterations(state, self.current_corpus_idx.unwrap())?;
|
||||
|
@ -8,7 +8,7 @@ use which::which;
|
||||
|
||||
const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
|
||||
const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
|
||||
const QEMU_REVISION: &str = "f6a2e732e8e225ebb8d1a9399561af7330af31b3";
|
||||
const QEMU_REVISION: &str = "0dc52ed6f3915f727aaec8648706760f278f0571";
|
||||
|
||||
fn build_dep_check(tools: &[&str]) {
|
||||
for tool in tools {
|
||||
@ -249,7 +249,6 @@ pub fn build(
|
||||
.arg("--disable-vhost-vdpa")
|
||||
.arg("--disable-virglrenderer")
|
||||
.arg("--disable-virtfs")
|
||||
.arg("--disable-virtiofsd")
|
||||
.arg("--disable-vmnet")
|
||||
.arg("--disable-vnc")
|
||||
.arg("--disable-vnc-jpeg")
|
||||
|
Loading…
x
Reference in New Issue
Block a user