Fix fuzz_level related thing, separate on_replace/on_remove from Scheduler & various fixes (#1119)

* delete HasFuzzedCorpusId

* more

* fmt clp

* aa

* fixing

* delete

* a

* append parent id when Objective

* add HasCorpus inprocss executor

* ecofuzz, delete was_fuzzed, update fuzz_level

* fix

* RemovableScheduler for Tunable, Queue, Weighted

* clp

* no std

* import

* on_execution

* fix

* win

* fmt

* fix

* revert to on_evaluation and propogate in the accounting scheduler

* fix

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
This commit is contained in:
Dongjia "toka" Zhang 2023-03-09 03:43:32 +09:00 committed by GitHub
parent 2ed6583041
commit 4d778dd64d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 445 additions and 303 deletions

View File

@ -19,7 +19,7 @@ use crate::{
corpus::Corpus, corpus::Corpus,
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
schedulers::{LenTimeMulTestcaseScore, Scheduler, TestcaseScore}, schedulers::{LenTimeMulTestcaseScore, RemovableScheduler, Scheduler, TestcaseScore},
state::{HasCorpus, HasMetadata, UsesState}, state::{HasCorpus, HasMetadata, UsesState},
Error, HasScheduler, Error, HasScheduler,
}; };
@ -41,7 +41,7 @@ where
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
CS: Scheduler<State = E::State>, CS: Scheduler<State = E::State> + RemovableScheduler, // schedulers that has on_remove/on_replace only!
EM: UsesState<State = E::State>, EM: UsesState<State = E::State>,
Z: HasScheduler<Scheduler = CS, State = E::State>; Z: HasScheduler<Scheduler = CS, State = E::State>;
} }
@ -100,7 +100,7 @@ where
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
CS: Scheduler<State = E::State>, CS: Scheduler<State = E::State> + RemovableScheduler,
EM: UsesState<State = E::State>, EM: UsesState<State = E::State>,
Z: HasScheduler<Scheduler = CS, State = E::State>, Z: HasScheduler<Scheduler = CS, State = E::State>,
{ {

View File

@ -34,9 +34,7 @@ where
/// Number of executions done at discovery time /// Number of executions done at discovery time
executions: usize, executions: usize,
/// Number of fuzzing iterations of this particular input updated in perform_mutational /// Number of fuzzing iterations of this particular input updated in perform_mutational
fuzz_level: usize, scheduled_count: usize,
/// If it has been fuzzed
fuzzed: bool,
/// Parent [`CorpusId`], if known /// Parent [`CorpusId`], if known
parent_id: Option<CorpusId>, parent_id: Option<CorpusId>,
} }
@ -160,28 +158,16 @@ where
&mut self.executions &mut self.executions
} }
/// Get the `fuzz_level` /// Get the `scheduled_count`
#[inline] #[inline]
pub fn fuzz_level(&self) -> usize { pub fn scheduled_count(&self) -> usize {
self.fuzz_level self.scheduled_count
} }
/// Set the `fuzz_level` /// Set the `scheduled_count`
#[inline] #[inline]
pub fn set_fuzz_level(&mut self, fuzz_level: usize) { pub fn set_scheduled_count(&mut self, scheduled_count: usize) {
self.fuzz_level = fuzz_level; self.scheduled_count = scheduled_count;
}
/// Get if it was fuzzed
#[inline]
pub fn fuzzed(&self) -> bool {
self.fuzzed
}
/// Set if it was fuzzed
#[inline]
pub fn set_fuzzed(&mut self, fuzzed: bool) {
self.fuzzed = fuzzed;
} }
/// Create a new Testcase instance given an input /// Create a new Testcase instance given an input
@ -257,9 +243,8 @@ where
metadata: SerdeAnyMap::new(), metadata: SerdeAnyMap::new(),
exec_time: None, exec_time: None,
cached_len: None, cached_len: None,
fuzz_level: 0, scheduled_count: 0,
executions: 0, executions: 0,
fuzzed: false,
parent_id: None, parent_id: None,
} }
} }
@ -486,13 +471,8 @@ pub mod pybind {
} }
#[getter] #[getter]
fn fuzz_level(&self) -> usize { fn scheduled_count(&self) -> usize {
self.inner.as_ref().fuzz_level() self.inner.as_ref().scheduled_count()
}
#[getter]
fn fuzzed(&self) -> bool {
self.inner.as_ref().fuzzed()
} }
fn metadata(&mut self) -> PyObject { fn metadata(&mut self) -> PyObject {

View File

@ -50,7 +50,7 @@ use crate::{
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::UsesInput, inputs::UsesInput,
observers::{ObserversTuple, UsesObservers}, observers::{ObserversTuple, UsesObservers},
state::{HasClientPerfMonitor, HasFuzzedCorpusId, HasSolutions, UsesState}, state::{HasClientPerfMonitor, HasCorpus, HasSolutions, UsesState},
Error, Error,
}; };
@ -167,7 +167,7 @@ where
H: FnMut(&<S as UsesInput>::Input) -> ExitKind + ?Sized, H: FnMut(&<S as UsesInput>::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>, HB: BorrowMut<H>,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
S: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId, S: HasSolutions + HasClientPerfMonitor + HasCorpus,
{ {
/// Create a new in mem executor. /// Create a new in mem executor.
/// Caution: crash and restart in one of them will lead to odd behavior if multiple are used, /// Caution: crash and restart in one of them will lead to odd behavior if multiple are used,
@ -344,7 +344,7 @@ impl InProcessHandlers {
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId, E::State: HasSolutions + HasClientPerfMonitor + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
#[cfg(unix)] #[cfg(unix)]
@ -545,7 +545,7 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
E: HasObservers, E: HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId, E::State: HasSolutions + HasClientPerfMonitor + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
let observers = executor.observers_mut(); let observers = executor.observers_mut();
@ -561,8 +561,8 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
if interesting { if interesting {
let mut new_testcase = Testcase::new(input.clone()); let mut new_testcase = Testcase::new(input.clone());
new_testcase.set_parent_id_optional(state.fuzzed_corpus_id());
new_testcase.add_metadata(exitkind); new_testcase.add_metadata(exitkind);
new_testcase.set_parent_id_optional(*state.corpus().current());
fuzzer fuzzer
.objective_mut() .objective_mut()
.append_metadata(state, observers, &mut new_testcase) .append_metadata(state, observers, &mut new_testcase)
@ -582,8 +582,6 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
} }
// We will start mutators from scratch after restart. // We will start mutators from scratch after restart.
state.clear_fuzzed_corpus_id();
event_mgr.on_restart(state).unwrap(); event_mgr.on_restart(state).unwrap();
log::info!("Waiting for broker..."); log::info!("Waiting for broker...");
@ -614,7 +612,7 @@ mod unix_signal_handler {
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::UsesInput, inputs::UsesInput,
state::{HasClientPerfMonitor, HasFuzzedCorpusId, HasSolutions}, state::{HasClientPerfMonitor, HasCorpus, HasSolutions},
}; };
pub(crate) type HandlerFuncPtr = pub(crate) type HandlerFuncPtr =
@ -673,7 +671,7 @@ mod unix_signal_handler {
E: HasObservers, E: HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId, E::State: HasSolutions + HasClientPerfMonitor + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
let old_hook = panic::take_hook(); let old_hook = panic::take_hook();
@ -714,7 +712,7 @@ mod unix_signal_handler {
E: HasObservers, E: HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId, E::State: HasSolutions + HasClientPerfMonitor + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
if !data.is_valid() { if !data.is_valid() {
@ -757,7 +755,7 @@ mod unix_signal_handler {
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId, E::State: HasSolutions + HasClientPerfMonitor + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
#[cfg(all(target_os = "android", target_arch = "aarch64"))] #[cfg(all(target_os = "android", target_arch = "aarch64"))]
@ -865,7 +863,7 @@ pub mod windows_asan_handler {
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::UsesInput, inputs::UsesInput,
state::{HasClientPerfMonitor, HasFuzzedCorpusId, HasSolutions}, state::{HasClientPerfMonitor, HasCorpus, HasSolutions},
}; };
/// # Safety /// # Safety
@ -875,7 +873,7 @@ pub mod windows_asan_handler {
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId, E::State: HasSolutions + HasClientPerfMonitor + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
let mut data = &mut GLOBAL_STATE; let mut data = &mut GLOBAL_STATE;
@ -974,7 +972,7 @@ mod windows_exception_handler {
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::UsesInput, inputs::UsesInput,
state::{HasClientPerfMonitor, HasFuzzedCorpusId, HasSolutions}, state::{HasClientPerfMonitor, HasCorpus, HasSolutions},
}; };
pub(crate) type HandlerFuncPtr = pub(crate) type HandlerFuncPtr =
@ -1013,7 +1011,7 @@ mod windows_exception_handler {
E: HasObservers, E: HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId, E::State: HasSolutions + HasClientPerfMonitor + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
let old_hook = panic::take_hook(); let old_hook = panic::take_hook();
@ -1072,7 +1070,7 @@ mod windows_exception_handler {
E: HasObservers, E: HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId, E::State: HasSolutions + HasClientPerfMonitor + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
let data: &mut InProcessExecutorHandlerData = let data: &mut InProcessExecutorHandlerData =
@ -1133,7 +1131,7 @@ mod windows_exception_handler {
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId, E::State: HasSolutions + HasClientPerfMonitor + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
// Have we set a timer_before? // Have we set a timer_before?

View File

@ -14,9 +14,8 @@ use crate::{
executors::ExitKind, executors::ExitKind,
feedbacks::Feedback, feedbacks::Feedback,
generators::NautilusContext, generators::NautilusContext,
inputs::NautilusInput, inputs::{NautilusInput, UsesInput},
observers::ObserversTuple, observers::ObserversTuple,
prelude::UsesInput,
state::{HasClientPerfMonitor, HasMetadata}, state::{HasClientPerfMonitor, HasMetadata},
Error, Error,
}; };

View File

@ -23,10 +23,7 @@ use crate::{
schedulers::Scheduler, schedulers::Scheduler,
stages::StagesTuple, stages::StagesTuple,
start_timer, start_timer,
state::{ state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasSolutions, UsesState},
HasClientPerfMonitor, HasCorpus, HasExecutions, HasFuzzedCorpusId, HasMetadata,
HasSolutions, UsesState,
},
Error, Error,
}; };
@ -330,7 +327,7 @@ where
F: Feedback<CS::State>, F: Feedback<CS::State>,
OF: Feedback<CS::State>, OF: Feedback<CS::State>,
OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned, OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned,
CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions + HasFuzzedCorpusId, CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions,
{ {
/// Evaluate if a set of observation channels has an interesting state /// Evaluate if a set of observation channels has an interesting state
fn process_execution<EM>( fn process_execution<EM>(
@ -387,7 +384,6 @@ where
// Add the input to the main corpus // Add the input to the main corpus
let mut testcase = Testcase::with_executions(input.clone(), *state.executions()); let mut testcase = Testcase::with_executions(input.clone(), *state.executions());
testcase.set_parent_id_optional(state.fuzzed_corpus_id());
self.feedback_mut() self.feedback_mut()
.append_metadata(state, observers, &mut testcase)?; .append_metadata(state, observers, &mut testcase)?;
let idx = state.corpus_mut().add(testcase)?; let idx = state.corpus_mut().add(testcase)?;
@ -421,7 +417,7 @@ where
// The input is a solution, add it to the respective corpus // The input is a solution, add it to the respective corpus
let mut testcase = Testcase::with_executions(input, *state.executions()); let mut testcase = Testcase::with_executions(input, *state.executions());
testcase.set_parent_id_optional(state.fuzzed_corpus_id()); testcase.set_parent_id_optional(*state.corpus().current());
self.objective_mut() self.objective_mut()
.append_metadata(state, observers, &mut testcase)?; .append_metadata(state, observers, &mut testcase)?;
state.solutions_mut().add(testcase)?; state.solutions_mut().add(testcase)?;
@ -447,7 +443,7 @@ where
OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned, OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned,
F: Feedback<CS::State>, F: Feedback<CS::State>,
OF: Feedback<CS::State>, OF: Feedback<CS::State>,
CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions + HasFuzzedCorpusId, CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions,
{ {
/// Process one input, adding to the respective corpora if needed and firing the right events /// Process one input, adding to the respective corpora if needed and firing the right events
#[inline] #[inline]
@ -480,7 +476,7 @@ where
F: Feedback<CS::State>, F: Feedback<CS::State>,
OF: Feedback<CS::State>, OF: Feedback<CS::State>,
OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned, OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned,
CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions + HasFuzzedCorpusId, CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions,
{ {
/// Process one input, adding to the respective corpora if needed and firing the right events /// Process one input, adding to the respective corpora if needed and firing the right events
#[inline] #[inline]
@ -518,7 +514,6 @@ where
// Add the input to the main corpus // Add the input to the main corpus
let mut testcase = Testcase::with_executions(input.clone(), *state.executions()); let mut testcase = Testcase::with_executions(input.clone(), *state.executions());
testcase.set_parent_id_optional(state.fuzzed_corpus_id());
self.feedback_mut() self.feedback_mut()
.append_metadata(state, observers, &mut testcase)?; .append_metadata(state, observers, &mut testcase)?;
let idx = state.corpus_mut().add(testcase)?; let idx = state.corpus_mut().add(testcase)?;
@ -552,7 +547,7 @@ where
EM: ProgressReporter + EventProcessor<E, Self, State = CS::State>, EM: ProgressReporter + EventProcessor<E, Self, State = CS::State>,
F: Feedback<CS::State>, F: Feedback<CS::State>,
OF: Feedback<CS::State>, OF: Feedback<CS::State>,
CS::State: HasClientPerfMonitor + HasExecutions + HasMetadata + HasFuzzedCorpusId, CS::State: HasClientPerfMonitor + HasExecutions + HasMetadata,
ST: StagesTuple<E, EM, CS::State, Self>, ST: StagesTuple<E, EM, CS::State, Self>,
{ {
fn fuzz_one( fn fuzz_one(
@ -577,15 +572,9 @@ where
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
state.introspection_monitor_mut().reset_stage_index(); state.introspection_monitor_mut().reset_stage_index();
// Set the parent id - all new testcases will have this id as parent in the following stages.
state.set_fuzzed_corpus_id(idx);
// Execute all stages // Execute all stages
stages.perform_all(self, executor, state, manager, idx)?; stages.perform_all(self, executor, state, manager, idx)?;
// Reset the parent id
state.clear_fuzzed_corpus_id();
// Init timer for manager // Init timer for manager
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
state.introspection_monitor_mut().start_timer(); state.introspection_monitor_mut().start_timer();

View File

@ -8,9 +8,10 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::{rands::Rand, AsMutSlice, AsSlice, HasLen, HasRefCnt}, bolts::{rands::Rand, AsMutSlice, AsSlice, HasLen, HasRefCnt},
corpus::{Corpus, CorpusId, Testcase}, corpus::{Corpus, CorpusId},
feedbacks::MapIndexesMetadata, feedbacks::MapIndexesMetadata,
inputs::UsesInput, inputs::UsesInput,
observers::ObserversTuple,
schedulers::{ schedulers::{
minimizer::{IsFavoredMetadata, MinimizerScheduler, DEFAULT_SKIP_NON_FAVORED_PROB}, minimizer::{IsFavoredMetadata, MinimizerScheduler, DEFAULT_SKIP_NON_FAVORED_PROB},
LenTimeMulTestcaseScore, Scheduler, LenTimeMulTestcaseScore, Scheduler,
@ -130,22 +131,16 @@ where
self.inner.on_add(state, idx) self.inner.on_add(state, idx)
} }
fn on_replace( fn on_evaluation<OT>(
&mut self, &mut self,
state: &mut Self::State, state: &mut Self::State,
idx: CorpusId, input: &<Self::State as UsesInput>::Input,
testcase: &Testcase<<Self::State as UsesInput>::Input>, observers: &OT,
) -> Result<(), Error> { ) -> Result<(), Error>
self.inner.on_replace(state, idx, testcase) where
} OT: ObserversTuple<Self::State>,
{
fn on_remove( self.inner.on_evaluation(state, input, observers)
&mut self,
state: &mut Self::State,
idx: CorpusId,
testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
) -> Result<(), Error> {
self.inner.on_remove(state, idx, testcase)
} }
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
@ -170,8 +165,21 @@ where
{ {
idx = self.inner.base_mut().next(state)?; idx = self.inner.base_mut().next(state)?;
} }
// Don't add corpus.curret(). The inner scheduler will take care of it
Ok(idx) Ok(idx)
} }
/// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled(
&mut self,
_state: &mut Self::State,
_next_idx: Option<CorpusId>,
) -> Result<(), Error> {
// We do nothing here, the inner scheduler will take care of it
Ok(())
}
} }
impl<'a, CS> CoverageAccountingScheduler<'a, CS> impl<'a, CS> CoverageAccountingScheduler<'a, CS>
@ -271,7 +279,7 @@ where
for (_key, idx) in &top_rated.map { for (_key, idx) in &top_rated.map {
let mut entry = state.corpus().get(*idx)?.borrow_mut(); let mut entry = state.corpus().get(*idx)?.borrow_mut();
if entry.fuzzed() { if entry.scheduled_count() > 0 {
continue; continue;
} }
@ -282,7 +290,7 @@ where
} }
/// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`] /// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`]
/// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`]. /// and has a default probability to skip non-faved Testcases of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
pub fn new(state: &mut CS::State, base: CS, accounting_map: &'a [u32]) -> Self { pub fn new(state: &mut CS::State, base: CS, accounting_map: &'a [u32]) -> Self {
match state.metadata().get::<TopAccountingMetadata>() { match state.metadata().get::<TopAccountingMetadata>() {
Some(meta) => { Some(meta) => {
@ -302,7 +310,7 @@ where
} }
/// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`] /// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`]
/// and has a non-default probability to skip non-faved [`Testcase`]s using (`skip_non_favored_prob`). /// and has a non-default probability to skip non-faved Testcases using (`skip_non_favored_prob`).
pub fn with_skip_prob( pub fn with_skip_prob(
state: &mut CS::State, state: &mut CS::State,
base: CS, base: CS,

View File

@ -47,7 +47,6 @@ pub struct EcoTestcaseMetadata {
last_energy: u64, last_energy: u64,
state: EcoState, state: EcoState,
serial: u64, serial: u64,
was_fuzzed: bool,
computed_score: f64, computed_score: f64,
} }
@ -117,7 +116,6 @@ where
.get_mut::<EcoTestcaseMetadata>() .get_mut::<EcoTestcaseMetadata>()
.ok_or_else(|| Error::key_not_found("EcoTestcaseMetadata not found".to_string()))?; .ok_or_else(|| Error::key_not_found("EcoTestcaseMetadata not found".to_string()))?;
// Set was_fuzzed for the old current // Set was_fuzzed for the old current
meta.was_fuzzed = true;
meta.last_found = count - last_corpus_count; meta.last_found = count - last_corpus_count;
meta.last_energy = meta.mutation_num - last_mutation_num; meta.last_energy = meta.mutation_num - last_mutation_num;
meta.computed_score meta.computed_score
@ -165,29 +163,15 @@ where
fn schedule(state: &mut S) -> Result<CorpusId, Error> { fn schedule(state: &mut S) -> Result<CorpusId, Error> {
let mut selection = None; let mut selection = None;
for id in state.corpus().ids() { for id in state.corpus().ids() {
let was_fuzzed = state let was_fuzzed = state.corpus().get(id)?.borrow().scheduled_count() > 0;
.corpus() if was_fuzzed {
.get(id)?
.borrow()
.metadata()
.get::<EcoTestcaseMetadata>()
.ok_or_else(|| Error::key_not_found("EcoTestcaseMetadata not found".to_string()))?
.was_fuzzed;
if !was_fuzzed {
selection = Some(id); selection = Some(id);
break; break;
} }
} }
for id in state.corpus().ids() { for id in state.corpus().ids() {
let was_fuzzed = state let was_fuzzed = state.corpus().get(id)?.borrow().scheduled_count() > 0;
.corpus()
.get(id)?
.borrow()
.metadata()
.get::<EcoTestcaseMetadata>()
.ok_or_else(|| Error::key_not_found("EcoTestcaseMetadata not found".to_string()))?
.was_fuzzed;
if was_fuzzed { if was_fuzzed {
state state
.metadata_mut() .metadata_mut()
@ -301,10 +285,14 @@ where
// Attach a `SchedulerTestcaseMetaData` to the queue entry. // Attach a `SchedulerTestcaseMetaData` to the queue entry.
depth += 1; depth += 1;
state.corpus().get(idx)?.borrow_mut().add_metadata( {
SchedulerTestcaseMetaData::with_n_fuzz_entry(depth, self.last_hash), let mut testcase = state.corpus().get(idx)?.borrow_mut();
); testcase.add_metadata(SchedulerTestcaseMetaData::with_n_fuzz_entry(
depth,
self.last_hash,
));
testcase.set_parent_id_optional(current_idx);
}
// Add the testcase metadata for this scheduler // Add the testcase metadata for this scheduler
state state
.corpus() .corpus()
@ -324,25 +312,6 @@ where
Ok(()) Ok(())
} }
fn on_replace(
&mut self,
state: &mut S,
idx: CorpusId,
_testcase: &Testcase<S::Input>,
) -> Result<(), Error> {
self.on_add(state, idx)
}
#[allow(clippy::unused_self)]
fn on_remove(
&mut self,
_state: &mut S,
_idx: CorpusId,
_testcase: &Option<Testcase<S::Input>>,
) -> Result<(), Error> {
Ok(())
}
fn on_evaluation<OT>( fn on_evaluation<OT>(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -414,7 +383,7 @@ where
} }
let id = Self::schedule(state)?; let id = Self::schedule(state)?;
*state.corpus_mut().current_mut() = Some(id); self.set_current_scheduled(state, Some(id))?;
let mutation_num = state let mutation_num = state
.corpus() .corpus()
@ -439,6 +408,26 @@ where
Ok(id) Ok(id)
} }
/// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled(
&mut self,
state: &mut Self::State,
next_idx: Option<CorpusId>,
) -> Result<(), Error> {
let current_idx = *state.corpus().current();
if let Some(idx) = current_idx {
let mut testcase = state.corpus().get(idx)?.borrow_mut();
let scheduled_count = testcase.scheduled_count();
// increase scheduled count, this was fuzz_level in afl
testcase.set_scheduled_count(scheduled_count + 1);
}
*state.corpus_mut().current_mut() = next_idx;
Ok(())
}
} }
/// The weight for each corpus entry /// The weight for each corpus entry

View File

@ -13,7 +13,7 @@ use crate::{
feedbacks::MapIndexesMetadata, feedbacks::MapIndexesMetadata,
inputs::UsesInput, inputs::UsesInput,
observers::ObserversTuple, observers::ObserversTuple,
schedulers::{LenTimeMulTestcaseScore, Scheduler, TestcaseScore}, schedulers::{LenTimeMulTestcaseScore, RemovableScheduler, Scheduler, TestcaseScore},
state::{HasCorpus, HasMetadata, HasRand, UsesState}, state::{HasCorpus, HasMetadata, HasRand, UsesState},
Error, Error,
}; };
@ -75,19 +75,13 @@ where
type State = CS::State; type State = CS::State;
} }
impl<CS, F, M> Scheduler for MinimizerScheduler<CS, F, M> impl<CS, F, M> RemovableScheduler for MinimizerScheduler<CS, F, M>
where where
CS: Scheduler, CS: RemovableScheduler,
F: TestcaseScore<CS::State>, F: TestcaseScore<CS::State>,
M: AsSlice<Entry = usize> + SerdeAny + HasRefCnt, M: AsSlice<Entry = usize> + SerdeAny + HasRefCnt,
CS::State: HasCorpus + HasMetadata + HasRand, CS::State: HasCorpus + HasMetadata + HasRand,
{ {
/// Add an entry to the corpus and return its index
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 /// Replaces the testcase at the given idx
fn on_replace( fn on_replace(
&mut self, &mut self,
@ -162,6 +156,20 @@ where
} }
Ok(()) Ok(())
} }
}
impl<CS, F, M> Scheduler for MinimizerScheduler<CS, F, M>
where
CS: Scheduler,
F: TestcaseScore<CS::State>,
M: AsSlice<Entry = usize> + SerdeAny + HasRefCnt,
CS::State: HasCorpus + HasMetadata + HasRand,
{
/// Add an entry to the corpus and return its index
fn on_add(&mut self, state: &mut CS::State, idx: CorpusId) -> Result<(), Error> {
self.base.on_add(state, idx)?;
self.update_score(state, idx)
}
/// An input has been evaluated /// An input has been evaluated
fn on_evaluation<OT>( fn on_evaluation<OT>(
@ -193,6 +201,16 @@ where
} }
Ok(idx) Ok(idx)
} }
/// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled(
&mut self,
_state: &mut Self::State,
_next_idx: Option<CorpusId>,
) -> Result<(), Error> {
// We do nothing here, the inner scheduler will take care of it
Ok(())
}
} }
impl<CS, F, M> MinimizerScheduler<CS, F, M> impl<CS, F, M> MinimizerScheduler<CS, F, M>

View File

@ -42,11 +42,15 @@ use crate::{
Error, Error,
}; };
/// The scheduler define how the fuzzer requests a testcase from the corpus. /// The scheduler also implemnts `on_remove` and `on_replace` if it implements this stage.
/// It has hooks to corpus add/replace/remove to allow complex scheduling algorithms to collect data. pub trait RemovableScheduler: Scheduler {
pub trait Scheduler: UsesState { /// Removed the given entry from the corpus at the given index
/// Added an entry to the corpus at the given index fn on_remove(
fn on_add(&mut self, _state: &mut Self::State, _idx: CorpusId) -> Result<(), Error> { &mut self,
_state: &mut Self::State,
_idx: CorpusId,
_testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
) -> Result<(), Error> {
Ok(()) Ok(())
} }
@ -59,16 +63,14 @@ pub trait Scheduler: UsesState {
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
} }
}
/// Removed the given entry from the corpus at the given index /// The scheduler define how the fuzzer requests a testcase from the corpus.
fn on_remove( /// It has hooks to corpus add/replace/remove to allow complex scheduling algorithms to collect data.
&mut self, pub trait Scheduler: UsesState {
_state: &mut Self::State, /// Added an entry to the corpus at the given index
_idx: CorpusId, fn on_add(&mut self, _state: &mut Self::State, _idx: CorpusId) -> Result<(), Error>;
_testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>, // Add parent_id here if it has no inner
) -> Result<(), Error> {
Ok(())
}
/// An input has been evaluated /// An input has been evaluated
fn on_evaluation<OT>( fn on_evaluation<OT>(
@ -85,6 +87,14 @@ pub trait Scheduler: UsesState {
/// Gets the next entry /// Gets the next entry
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error>; fn next(&mut self, state: &mut Self::State) -> 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,
next_idx: Option<CorpusId>,
) -> Result<(), Error>;
} }
/// Feed the fuzzer simply with a random testcase on request /// Feed the fuzzer simply with a random testcase on request
@ -104,16 +114,38 @@ impl<S> Scheduler for RandScheduler<S>
where where
S: HasCorpus + HasRand, S: HasCorpus + HasRand,
{ {
fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
// Set parent id
let current_idx = *state.corpus().current();
state
.corpus()
.get(idx)?
.borrow_mut()
.set_parent_id_optional(current_idx);
Ok(())
}
/// Gets the next entry at random /// Gets the next entry at random
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
Err(Error::empty("No entries in corpus".to_owned())) Err(Error::empty("No entries in corpus".to_owned()))
} else { } else {
let id = random_corpus_id!(state.corpus(), state.rand_mut()); let id = random_corpus_id!(state.corpus(), state.rand_mut());
*state.corpus_mut().current_mut() = Some(id); self.set_current_scheduled(state, Some(id))?;
Ok(id) Ok(id)
} }
} }
/// Set current fuzzed corpus id and `scheduled_count`. You should call this from `next`
fn set_current_scheduled(
&mut self,
state: &mut Self::State,
next_idx: Option<CorpusId>,
) -> Result<(), Error> {
*state.corpus_mut().current_mut() = next_idx;
Ok(())
}
} }
impl<S> RandScheduler<S> { impl<S> RandScheduler<S> {

View File

@ -12,7 +12,7 @@ use crate::{
corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData, Testcase}, corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData, Testcase},
inputs::UsesInput, inputs::UsesInput,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
schedulers::Scheduler, schedulers::{RemovableScheduler, Scheduler},
state::{HasCorpus, HasMetadata, UsesState}, state::{HasCorpus, HasMetadata, UsesState},
Error, Error,
}; };
@ -178,40 +178,11 @@ where
type State = S; type State = S;
} }
impl<O, S> Scheduler for PowerQueueScheduler<O, S> impl<O, S> RemovableScheduler for PowerQueueScheduler<O, S>
where where
S: HasCorpus + HasMetadata, S: HasCorpus + HasMetadata,
O: MapObserver, O: MapObserver,
{ {
/// Add an entry to the corpus and return its index
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 {
Some(parent_idx) => state
.corpus()
.get(parent_idx)?
.borrow()
.metadata()
.get::<SchedulerTestcaseMetaData>()
.ok_or_else(|| {
Error::key_not_found("SchedulerTestcaseMetaData not found".to_string())
})?
.depth(),
None => 0,
};
// TODO increase perf_score when finding new things like in AFL
// https://github.com/google/AFL/blob/master/afl-fuzz.c#L6547
// Attach a `SchedulerTestcaseMetaData` to the queue entry.
depth += 1;
state.corpus().get(idx)?.borrow_mut().add_metadata(
SchedulerTestcaseMetaData::with_n_fuzz_entry(depth, self.last_hash),
);
Ok(())
}
#[allow(clippy::cast_precision_loss)] #[allow(clippy::cast_precision_loss)]
fn on_replace( fn on_replace(
&mut self, &mut self,
@ -292,6 +263,44 @@ where
Ok(()) Ok(())
} }
}
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(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
let current_idx = *state.corpus().current();
let mut depth = match current_idx {
Some(parent_idx) => state
.corpus()
.get(parent_idx)?
.borrow()
.metadata()
.get::<SchedulerTestcaseMetaData>()
.ok_or_else(|| {
Error::key_not_found("SchedulerTestcaseMetaData not found".to_string())
})?
.depth(),
None => 0,
};
// TODO increase perf_score when finding new things like in AFL
// https://github.com/google/AFL/blob/master/afl-fuzz.c#L6547
// Attach a `SchedulerTestcaseMetaData` to the queue entry.
depth += 1;
let mut testcase = state.corpus().get(idx)?.borrow_mut();
testcase.add_metadata(SchedulerTestcaseMetaData::with_n_fuzz_entry(
depth,
self.last_hash,
));
testcase.set_parent_id_optional(current_idx);
Ok(())
}
fn on_evaluation<OT>( fn on_evaluation<OT>(
&mut self, &mut self,
@ -343,10 +352,27 @@ where
} }
None => state.corpus().first().unwrap(), None => state.corpus().first().unwrap(),
}; };
*state.corpus_mut().current_mut() = Some(id); self.set_current_scheduled(state, Some(id))?;
Ok(id)
}
}
/// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled(
&mut self,
state: &mut Self::State,
next_idx: Option<CorpusId>,
) -> Result<(), Error> {
let current_idx = *state.corpus().current();
if let Some(idx) = current_idx {
let mut testcase = state.corpus().get(idx)?.borrow_mut();
let scheduled_count = testcase.scheduled_count();
// increase scheduled count, this was fuzz_level in afl
testcase.set_scheduled_count(scheduled_count + 1);
// Update the handicap
let mut testcase = state.corpus().get(id)?.borrow_mut();
let tcmeta = testcase let tcmeta = testcase
.metadata_mut() .metadata_mut()
.get_mut::<SchedulerTestcaseMetaData>() .get_mut::<SchedulerTestcaseMetaData>()
@ -359,9 +385,10 @@ where
} else if tcmeta.handicap() > 0 { } else if tcmeta.handicap() > 0 {
tcmeta.set_handicap(tcmeta.handicap() - 1); tcmeta.set_handicap(tcmeta.handicap() - 1);
} }
Ok(id)
} }
*state.corpus_mut().current_mut() = next_idx;
Ok(())
} }
} }

View File

@ -100,6 +100,13 @@ where
S: HasCorpus + HasMetadata + HasRand, S: HasCorpus + HasMetadata + HasRand,
{ {
fn on_add(&mut 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();
state
.corpus()
.get(idx)?
.borrow_mut()
.set_parent_id_optional(current_idx);
if state.metadata().get::<ProbabilityMetadata>().is_none() { if state.metadata().get::<ProbabilityMetadata>().is_none() {
state.add_metadata(ProbabilityMetadata::new()); state.add_metadata(ProbabilityMetadata::new());
} }
@ -124,10 +131,20 @@ where
break; break;
} }
} }
*state.corpus_mut().current_mut() = Some(ret); self.set_current_scheduled(state, Some(ret))?;
Ok(ret) Ok(ret)
} }
} }
/// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled(
&mut self,
state: &mut Self::State,
next_idx: Option<CorpusId>,
) -> Result<(), Error> {
*state.corpus_mut().current_mut() = next_idx;
Ok(())
}
} }
impl<F, S> Default for ProbabilitySamplingScheduler<F, S> impl<F, S> Default for ProbabilitySamplingScheduler<F, S>

View File

@ -6,7 +6,7 @@ use core::marker::PhantomData;
use crate::{ use crate::{
corpus::{Corpus, CorpusId}, corpus::{Corpus, CorpusId},
inputs::UsesInput, inputs::UsesInput,
schedulers::Scheduler, schedulers::{RemovableScheduler, Scheduler},
state::{HasCorpus, UsesState}, state::{HasCorpus, UsesState},
Error, Error,
}; };
@ -24,10 +24,24 @@ where
type State = S; type State = S;
} }
impl<S> RemovableScheduler for QueueScheduler<S> where S: HasCorpus {}
impl<S> Scheduler for QueueScheduler<S> impl<S> Scheduler for QueueScheduler<S>
where where
S: HasCorpus, S: HasCorpus,
{ {
fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
// Set parent id
let current_idx = *state.corpus().current();
state
.corpus()
.get(idx)?
.borrow_mut()
.set_parent_id_optional(current_idx);
Ok(())
}
/// Gets the next entry in the queue /// Gets the next entry in the queue
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
@ -39,10 +53,20 @@ where
.map(|id| state.corpus().next(id)) .map(|id| state.corpus().next(id))
.flatten() .flatten()
.unwrap_or_else(|| state.corpus().first().unwrap()); .unwrap_or_else(|| state.corpus().first().unwrap());
*state.corpus_mut().current_mut() = Some(id); self.set_current_scheduled(state, Some(id))?;
Ok(id) Ok(id)
} }
} }
/// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled(
&mut self,
state: &mut Self::State,
next_idx: Option<CorpusId>,
) -> Result<(), Error> {
*state.corpus_mut().current_mut() = next_idx;
Ok(())
}
} }
impl<S> QueueScheduler<S> { impl<S> QueueScheduler<S> {

View File

@ -205,7 +205,7 @@ where
} }
} }
PowerSchedule::FAST => { PowerSchedule::FAST => {
if entry.fuzz_level() != 0 { if entry.scheduled_count() != 0 {
let lg = libm::log2(f64::from(psmeta.n_fuzz()[tcmeta.n_fuzz_entry()])); let lg = libm::log2(f64::from(psmeta.n_fuzz()[tcmeta.n_fuzz_entry()]));
match lg { match lg {
@ -244,11 +244,11 @@ where
} }
} }
PowerSchedule::LIN => { PowerSchedule::LIN => {
factor = (entry.fuzz_level() as f64) factor = (entry.scheduled_count() as f64)
/ f64::from(psmeta.n_fuzz()[tcmeta.n_fuzz_entry()] + 1); / f64::from(psmeta.n_fuzz()[tcmeta.n_fuzz_entry()] + 1);
} }
PowerSchedule::QUAD => { PowerSchedule::QUAD => {
factor = ((entry.fuzz_level() * entry.fuzz_level()) as f64) factor = ((entry.scheduled_count() * entry.scheduled_count()) as f64)
/ f64::from(psmeta.n_fuzz()[tcmeta.n_fuzz_entry()] + 1); / f64::from(psmeta.n_fuzz()[tcmeta.n_fuzz_entry()] + 1);
} }
} }
@ -310,7 +310,7 @@ where
// This means that this testcase has never gone through the calibration stage before1, // This means that this testcase has never gone through the calibration stage before1,
// In this case we'll just return the default weight // In this case we'll just return the default weight
// This methoud is called in corpus's on_add() method. Fuzz_level is zero at that time. // This methoud is called in corpus's on_add() method. Fuzz_level is zero at that time.
if entry.fuzz_level() == 0 || psmeta.cycles() == 0 { if entry.scheduled_count() == 0 || psmeta.cycles() == 0 {
return Ok(weight); return Ok(weight);
} }
@ -362,7 +362,7 @@ where
} }
// was it fuzzed before? // was it fuzzed before?
if entry.fuzz_level() == 0 { if entry.scheduled_count() == 0 {
weight *= 2.0; weight *= 2.0;
} }

View File

@ -7,6 +7,7 @@ use core::marker::PhantomData;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::RemovableScheduler;
use crate::{ use crate::{
corpus::{Corpus, CorpusId}, corpus::{Corpus, CorpusId},
impl_serdeany, impl_serdeany,
@ -88,10 +89,24 @@ where
type State = S; type State = S;
} }
impl<S> RemovableScheduler for TuneableScheduler<S> where S: HasCorpus + HasMetadata {}
impl<S> Scheduler for TuneableScheduler<S> impl<S> Scheduler for TuneableScheduler<S>
where where
S: HasCorpus + HasMetadata, S: HasCorpus + HasMetadata,
{ {
fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
// Set parent id
let current_idx = *state.corpus().current();
state
.corpus()
.get(idx)?
.borrow_mut()
.set_parent_id_optional(current_idx);
Ok(())
}
/// Gets the next entry in the queue /// Gets the next entry in the queue
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
@ -105,7 +120,17 @@ where
} else { } else {
state.corpus().first().unwrap() state.corpus().first().unwrap()
}; };
*state.corpus_mut().current_mut() = Some(id); self.set_current_scheduled(state, Some(id))?;
Ok(id) Ok(id)
} }
/// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled(
&mut self,
state: &mut Self::State,
next_idx: Option<CorpusId>,
) -> Result<(), Error> {
*state.corpus_mut().current_mut() = next_idx;
Ok(())
}
} }

View File

@ -9,14 +9,14 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::rands::Rand, bolts::rands::Rand,
corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData, Testcase}, corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData},
inputs::UsesInput, inputs::UsesInput,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
random_corpus_id, random_corpus_id,
schedulers::{ schedulers::{
powersched::{PowerSchedule, SchedulerMetadata}, powersched::{PowerSchedule, SchedulerMetadata},
testcase_score::{CorpusWeightTestcaseScore, TestcaseScore}, testcase_score::{CorpusWeightTestcaseScore, TestcaseScore},
Scheduler, RemovableScheduler, Scheduler,
}, },
state::{HasCorpus, HasMetadata, HasRand, UsesState}, state::{HasCorpus, HasMetadata, HasRand, UsesState},
Error, Error,
@ -229,6 +229,94 @@ where
type State = S; type State = S;
} }
impl<F, O, S> RemovableScheduler for WeightedScheduler<F, O, S>
where
F: TestcaseScore<S>,
O: MapObserver,
S: HasCorpus + HasMetadata + HasRand,
{
#[allow(clippy::cast_precision_loss)]
fn on_remove(
&mut self,
state: &mut Self::State,
_idx: CorpusId,
prev: &Option<crate::corpus::Testcase<<Self::State as UsesInput>::Input>>,
) -> Result<(), Error> {
let prev = prev.as_ref().ok_or_else(|| {
Error::illegal_argument(
"Power schedulers must be aware of the removed corpus entry for reweighting.",
)
})?;
let prev_meta = prev
.metadata()
.get::<SchedulerTestcaseMetaData>()
.ok_or_else(|| {
Error::key_not_found("SchedulerTestcaseMetaData not found".to_string())
})?;
// Use these to adjust `SchedulerMetadata`
let (prev_total_time, prev_cycles) = prev_meta.cycle_and_time();
let prev_bitmap_size = prev_meta.bitmap_size();
let prev_bitmap_size_log = libm::log2(prev_bitmap_size as f64);
let psmeta = state
.metadata_mut()
.get_mut::<SchedulerMetadata>()
.ok_or_else(|| Error::key_not_found("SchedulerMetadata not found".to_string()))?;
psmeta.set_exec_time(psmeta.exec_time() - prev_total_time);
psmeta.set_cycles(psmeta.cycles() - (prev_cycles as u64));
psmeta.set_bitmap_size(psmeta.bitmap_size() - prev_bitmap_size);
psmeta.set_bitmap_size_log(psmeta.bitmap_size_log() - prev_bitmap_size_log);
psmeta.set_bitmap_entries(psmeta.bitmap_entries() - 1);
Ok(())
}
#[allow(clippy::cast_precision_loss)]
fn on_replace(
&mut self,
state: &mut Self::State,
idx: CorpusId,
prev: &crate::corpus::Testcase<<Self::State as UsesInput>::Input>,
) -> Result<(), Error> {
let prev_meta = prev
.metadata()
.get::<SchedulerTestcaseMetaData>()
.ok_or_else(|| {
Error::key_not_found("SchedulerTestcaseMetaData not found".to_string())
})?;
// Next depth is + 1
let prev_depth = prev_meta.depth() + 1;
// Use these to adjust `SchedulerMetadata`
let (prev_total_time, prev_cycles) = prev_meta.cycle_and_time();
let prev_bitmap_size = prev_meta.bitmap_size();
let prev_bitmap_size_log = libm::log2(prev_bitmap_size as f64);
let psmeta = state
.metadata_mut()
.get_mut::<SchedulerMetadata>()
.ok_or_else(|| Error::key_not_found("SchedulerMetadata not found".to_string()))?;
// We won't add new one because it'll get added when it gets executed in calirbation next time.
psmeta.set_exec_time(psmeta.exec_time() - prev_total_time);
psmeta.set_cycles(psmeta.cycles() - (prev_cycles as u64));
psmeta.set_bitmap_size(psmeta.bitmap_size() - prev_bitmap_size);
psmeta.set_bitmap_size_log(psmeta.bitmap_size_log() - prev_bitmap_size_log);
psmeta.set_bitmap_entries(psmeta.bitmap_entries() - 1);
state
.corpus()
.get(idx)?
.borrow_mut()
.add_metadata(SchedulerTestcaseMetaData::new(prev_depth));
Ok(())
}
}
impl<F, O, S> Scheduler for WeightedScheduler<F, O, S> impl<F, O, S> Scheduler for WeightedScheduler<F, O, S>
where where
F: TestcaseScore<S>, F: TestcaseScore<S>,
@ -255,9 +343,14 @@ where
// Attach a `SchedulerTestcaseMetaData` to the queue entry. // Attach a `SchedulerTestcaseMetaData` to the queue entry.
depth += 1; depth += 1;
state.corpus().get(idx)?.borrow_mut().add_metadata( {
SchedulerTestcaseMetaData::with_n_fuzz_entry(depth, self.last_hash), let mut testcase = state.corpus().get(idx)?.borrow_mut();
); testcase.add_metadata(SchedulerTestcaseMetaData::with_n_fuzz_entry(
depth,
self.last_hash,
));
testcase.set_parent_id_optional(current_idx);
}
// TODO increase perf_score when finding new things like in AFL // TODO increase perf_score when finding new things like in AFL
// https://github.com/google/AFL/blob/master/afl-fuzz.c#L6547 // https://github.com/google/AFL/blob/master/afl-fuzz.c#L6547
@ -267,27 +360,6 @@ where
Ok(()) Ok(())
} }
fn on_replace(
&mut self,
state: &mut S,
idx: CorpusId,
_testcase: &Testcase<S::Input>,
) -> Result<(), Error> {
// Recreate the alias table
self.on_add(state, idx)
}
fn on_remove(
&mut self,
state: &mut S,
_idx: CorpusId,
_testcase: &Option<Testcase<S::Input>>,
) -> Result<(), Error> {
// Recreate the alias table
self.create_alias_table(state)?;
Ok(())
}
fn on_evaluation<OT>( fn on_evaluation<OT>(
&mut self, &mut self,
state: &mut Self::State, state: &mut Self::State,
@ -360,10 +432,27 @@ where
})?; })?;
psmeta.set_queue_cycles(psmeta.queue_cycles() + 1); psmeta.set_queue_cycles(psmeta.queue_cycles() + 1);
} }
*state.corpus_mut().current_mut() = Some(idx);
// Update the handicap self.set_current_scheduled(state, Some(idx))?;
Ok(idx)
}
}
/// Set current fuzzed corpus id and `scheduled_count`
fn set_current_scheduled(
&mut self,
state: &mut Self::State,
next_idx: Option<CorpusId>,
) -> Result<(), Error> {
let current_idx = *state.corpus().current();
if let Some(idx) = current_idx {
let mut testcase = state.corpus().get(idx)?.borrow_mut(); let mut testcase = state.corpus().get(idx)?.borrow_mut();
let scheduled_count = testcase.scheduled_count();
// increase scheduled count, this was fuzz_level in afl
testcase.set_scheduled_count(scheduled_count + 1);
let tcmeta = testcase let tcmeta = testcase
.metadata_mut() .metadata_mut()
.get_mut::<SchedulerTestcaseMetaData>() .get_mut::<SchedulerTestcaseMetaData>()
@ -376,8 +465,10 @@ where
} else if tcmeta.handicap() > 0 { } else if tcmeta.handicap() > 0 {
tcmeta.set_handicap(tcmeta.handicap() - 1); tcmeta.set_handicap(tcmeta.handicap() - 1);
} }
Ok(idx)
} }
*state.corpus_mut().current_mut() = next_idx;
Ok(())
} }
} }

View File

@ -106,7 +106,9 @@ where
// Run this stage only once for each corpus entry and only if we haven't already inspected it // Run this stage only once for each corpus entry and only if we haven't already inspected it
{ {
let corpus = state.corpus().get(corpus_idx)?.borrow(); let corpus = state.corpus().get(corpus_idx)?.borrow();
if corpus.fuzz_level() > 0 { // println!("calibration; corpus.scheduled_count() : {}", corpus.scheduled_count());
if corpus.scheduled_count() > 0 {
return Ok(()); return Ok(());
} }
} }
@ -269,10 +271,10 @@ where
psmeta.set_bitmap_entries(psmeta.bitmap_entries() + 1); psmeta.set_bitmap_entries(psmeta.bitmap_entries() + 1);
let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut(); let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut();
let fuzz_level = testcase.fuzz_level(); let scheduled_count = testcase.scheduled_count();
testcase.set_exec_time(total_time / (iter as u32)); testcase.set_exec_time(total_time / (iter as u32));
testcase.set_fuzz_level(fuzz_level + 1); testcase.set_scheduled_count(scheduled_count + 1);
// log::trace!("time: {:#?}", testcase.exec_time()); // log::trace!("time: {:#?}", testcase.exec_time());
let data = testcase let data = testcase

View File

@ -21,9 +21,7 @@ use crate::{
observers::ObserversTuple, observers::ObserversTuple,
schedulers::Scheduler, schedulers::Scheduler,
start_timer, start_timer,
state::{ state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasRand},
HasClientPerfMonitor, HasCorpus, HasExecutions, HasFuzzedCorpusId, HasMetadata, HasRand,
},
Error, EvaluatorObservers, ExecutionProcessor, HasScheduler, Error, EvaluatorObservers, ExecutionProcessor, HasScheduler,
}; };
@ -90,14 +88,8 @@ where
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter,
M: Mutator<CS::Input, CS::State>, M: Mutator<CS::Input, CS::State>,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<CS::State>,
CS::State: HasFuzzedCorpusId CS::State:
+ HasClientPerfMonitor HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug,
+ HasCorpus
+ HasRand
+ HasExecutions
+ HasMetadata
+ Clone
+ Debug,
Z: ExecutionProcessor<OT, State = CS::State> Z: ExecutionProcessor<OT, State = CS::State>
+ EvaluatorObservers<OT> + EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>, + HasScheduler<Scheduler = CS>,
@ -144,8 +136,6 @@ where
return None; return None;
} }
let idx = self.current_corpus_idx.unwrap();
state.set_fuzzed_corpus_id(idx);
start_timer!(state); start_timer!(state);
let mut input = state let mut input = state
.corpus() .corpus()
@ -188,7 +178,6 @@ where
.post_exec(state, self.stage_idx, self.current_corpus_idx)?; .post_exec(state, self.stage_idx, self.current_corpus_idx)?;
mark_feature_time!(state, PerfFeature::MutatePostExec); mark_feature_time!(state, PerfFeature::MutatePostExec);
self.testcases_done += 1; self.testcases_done += 1;
state.clear_fuzzed_corpus_id();
Ok(()) Ok(())
} }
@ -212,14 +201,8 @@ where
EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = CS::State>, EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = CS::State>,
M: Mutator<CS::Input, CS::State>, M: Mutator<CS::Input, CS::State>,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<CS::State>,
CS::State: HasClientPerfMonitor CS::State:
+ HasCorpus HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug,
+ HasRand
+ HasExecutions
+ HasMetadata
+ Clone
+ Debug
+ HasFuzzedCorpusId,
Z: ExecutionProcessor<OT, State = CS::State> Z: ExecutionProcessor<OT, State = CS::State>
+ EvaluatorObservers<OT> + EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>, + HasScheduler<Scheduler = CS>,

View File

@ -21,7 +21,7 @@ use crate::{
mark_feature_time, mark_feature_time,
mutators::Mutator, mutators::Mutator,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
schedulers::Scheduler, schedulers::{RemovableScheduler, Scheduler},
stages::Stage, stages::Stage,
start_timer, start_timer,
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMaxSize, HasSolutions, UsesState}, state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMaxSize, HasSolutions, UsesState},
@ -36,7 +36,7 @@ pub trait TMinMutationalStage<CS, E, EM, F1, F2, M, OT, Z>:
where where
Self::State: HasCorpus + HasSolutions + HasExecutions + HasMaxSize + HasClientPerfMonitor, Self::State: HasCorpus + HasSolutions + HasExecutions + HasMaxSize + HasClientPerfMonitor,
<Self::State as UsesInput>::Input: HasLen + Hash, <Self::State as UsesInput>::Input: HasLen + Hash,
CS: Scheduler<State = Self::State>, CS: Scheduler<State = Self::State> + RemovableScheduler,
E: Executor<EM, Z> + HasObservers<Observers = OT, State = Self::State>, E: Executor<EM, Z> + HasObservers<Observers = OT, State = Self::State>,
EM: EventFirer<State = Self::State>, EM: EventFirer<State = Self::State>,
F1: Feedback<Self::State>, F1: Feedback<Self::State>,
@ -204,7 +204,7 @@ where
impl<CS, E, EM, F1, F2, FF, M, OT, Z> Stage<E, EM, Z> impl<CS, E, EM, F1, F2, FF, M, OT, Z> Stage<E, EM, Z>
for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z> for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z>
where where
CS: Scheduler, CS: Scheduler + RemovableScheduler,
CS::State: HasCorpus + HasSolutions + HasExecutions + HasMaxSize + HasClientPerfMonitor, CS::State: HasCorpus + HasSolutions + HasExecutions + HasMaxSize + HasClientPerfMonitor,
<CS::State as UsesInput>::Input: HasLen + Hash, <CS::State as UsesInput>::Input: HasLen + Hash,
E: Executor<EM, Z> + HasObservers<Observers = OT, State = CS::State>, E: Executor<EM, Z> + HasObservers<Observers = OT, State = CS::State>,
@ -252,7 +252,7 @@ where
impl<CS, E, EM, F1, F2, FF, M, OT, Z> TMinMutationalStage<CS, E, EM, F1, F2, M, OT, Z> impl<CS, E, EM, F1, F2, FF, M, OT, Z> TMinMutationalStage<CS, E, EM, F1, F2, M, OT, Z>
for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z> for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z>
where where
CS: Scheduler, CS: Scheduler + RemovableScheduler,
E: HasObservers<Observers = OT, State = CS::State> + Executor<EM, Z>, E: HasObservers<Observers = OT, State = CS::State> + Executor<EM, Z>,
EM: EventFirer<State = CS::State>, EM: EventFirer<State = CS::State>,
F1: Feedback<CS::State>, F1: Feedback<CS::State>,

View File

@ -60,21 +60,6 @@ pub trait HasCorpus: UsesInput {
fn corpus_mut(&mut self) -> &mut Self::Corpus; fn corpus_mut(&mut self) -> &mut Self::Corpus;
} }
/// Trait for a state that has information about which [`CorpusId`]
/// is currently being fuzzed.
/// When a new interesting input was found, this value becomes the `parent_id`.
pub trait HasFuzzedCorpusId {
/// The currently fuzzed [`CorpusId`], if known.
/// If a new interesting testcase was found, this should usually become the `parent_id`.
fn fuzzed_corpus_id(&self) -> Option<CorpusId>;
/// Sets the currently fuzzed [`CorpusId`].
fn set_fuzzed_corpus_id(&mut self, corpus_id: CorpusId);
/// Resets the currently fuzzed [`CorpusId`].
fn clear_fuzzed_corpus_id(&mut self);
}
/// Interact with the maximum size /// Interact with the maximum size
pub trait HasMaxSize { pub trait HasMaxSize {
/// The maximum size hint for items and mutations returned /// The maximum size hint for items and mutations returned
@ -207,8 +192,6 @@ pub struct StdState<I, C, R, SC> {
named_metadata: NamedSerdeAnyMap, named_metadata: NamedSerdeAnyMap,
/// MaxSize testcase size for mutators that appreciate it /// MaxSize testcase size for mutators that appreciate it
max_size: usize, max_size: usize,
/// The [`CorpusId`] of the testcase we're currently fuzzing.
fuzzed_corpus_id: Option<CorpusId>,
/// Performance statistics for this fuzzer /// Performance statistics for this fuzzer
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
introspection_monitor: ClientPerfMonitor, introspection_monitor: ClientPerfMonitor,
@ -274,20 +257,6 @@ where
} }
} }
impl<I, C, R, SC> HasFuzzedCorpusId for StdState<I, C, R, SC> {
fn fuzzed_corpus_id(&self) -> Option<CorpusId> {
self.fuzzed_corpus_id
}
fn set_fuzzed_corpus_id(&mut self, fuzzed_corpus_id: CorpusId) {
self.fuzzed_corpus_id = Some(fuzzed_corpus_id);
}
fn clear_fuzzed_corpus_id(&mut self) {
self.fuzzed_corpus_id = None;
}
}
impl<I, C, R, SC> HasSolutions for StdState<I, C, R, SC> impl<I, C, R, SC> HasSolutions for StdState<I, C, R, SC>
where where
I: Input, I: Input,
@ -725,7 +694,6 @@ where
corpus, corpus,
solutions, solutions,
max_size: DEFAULT_MAX_SIZE, max_size: DEFAULT_MAX_SIZE,
fuzzed_corpus_id: None,
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
introspection_monitor: ClientPerfMonitor::new(), introspection_monitor: ClientPerfMonitor::new(),
#[cfg(feature = "std")] #[cfg(feature = "std")]

View File

@ -8,7 +8,7 @@ use frida_gum::{
#[cfg(windows)] #[cfg(windows)]
use libafl::{ use libafl::{
executors::inprocess::{HasInProcessHandlers, InProcessHandlers}, executors::inprocess::{HasInProcessHandlers, InProcessHandlers},
state::{HasClientPerfMonitor, HasFuzzedCorpusId, HasSolutions}, state::{HasClientPerfMonitor, HasCorpus, HasSolutions},
}; };
use libafl::{ use libafl::{
executors::{Executor, ExitKind, HasObservers, InProcessExecutor}, executors::{Executor, ExitKind, HasObservers, InProcessExecutor},
@ -200,7 +200,7 @@ impl<'a, 'b, 'c, H, OT, RT, S> HasInProcessHandlers
for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where where
H: FnMut(&S::Input) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
S: UsesInput + HasClientPerfMonitor + HasSolutions + HasFuzzedCorpusId, S: UsesInput + HasClientPerfMonitor + HasSolutions + HasCorpus,
S::Input: HasTargetBytes, S::Input: HasTargetBytes,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
RT: FridaRuntimeTuple, RT: FridaRuntimeTuple,

View File

@ -13,10 +13,7 @@ use libafl::{
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::UsesInput, inputs::UsesInput,
observers::{ObserversTuple, UsesObservers}, observers::{ObserversTuple, UsesObservers},
state::{ state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions, State, UsesState},
HasClientPerfMonitor, HasCorpus, HasExecutions, HasFuzzedCorpusId, HasSolutions, State,
UsesState,
},
Error, Error,
}; };
@ -67,12 +64,7 @@ where
where where
EM: EventFirer<State = S> + EventRestarter<State = S>, EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<S>, OF: Feedback<S>,
S: State S: State + HasExecutions + HasCorpus + HasSolutions + HasClientPerfMonitor,
+ HasExecutions
+ HasCorpus
+ HasSolutions
+ HasClientPerfMonitor
+ HasFuzzedCorpusId,
Z: HasObjective<Objective = OF, State = S>, Z: HasObjective<Objective = OF, State = S>,
{ {
Ok(Self { Ok(Self {

View File

@ -4,7 +4,7 @@ use libafl::{
events::{EventFirer, EventRestarter}, events::{EventFirer, EventRestarter},
executors::{inprocess::windows_asan_handler::asan_death_handler, Executor, HasObservers}, executors::{inprocess::windows_asan_handler::asan_death_handler, Executor, HasObservers},
feedbacks::Feedback, feedbacks::Feedback,
state::{HasClientPerfMonitor, HasFuzzedCorpusId, HasSolutions}, state::{HasClientPerfMonitor, HasCorpus, HasSolutions},
HasObjective, HasObjective,
}; };
@ -32,7 +32,7 @@ where
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId, E::State: HasSolutions + HasClientPerfMonitor + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
__sanitizer_set_death_callback(asan_death_handler::<E, EM, OF, Z>); __sanitizer_set_death_callback(asan_death_handler::<E, EM, OF, Z>);