Metadata + infinite loop fix for TuneableMutationalStage (#1514)

* update tuneable: consistently access metadata + force 'choice'

* oops, loop in the wrong place

* clarify API some; allow for least of set configuration
This commit is contained in:
Addison Crump 2023-09-16 16:54:40 +02:00 committed by GitHub
parent d4f47340a3
commit 6d0d4e287a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -175,16 +175,14 @@ where
manager: &mut EM, manager: &mut EM,
corpus_idx: CorpusId, corpus_idx: CorpusId,
) -> Result<(), Error> { ) -> Result<(), Error> {
let metadata: &TuneableMutationalStageMetadata = state.metadata()?; let fuzz_time = self.seed_fuzz_time(state)?;
let iters = self.fixed_iters(state)?;
let fuzz_time = metadata.fuzz_time; if fuzz_time.is_some() && iters.is_some() {
let iters = metadata.iters; return Err(Error::illegal_state(
"Both fuzz_time and iters specified; failing fast!",
let (start_time, iters) = if fuzz_time.is_some() { ));
(Some(current_time()), iters) }
} else {
(None, Some(self.iterations(state, corpus_idx)?))
};
start_timer!(state); start_timer!(state);
let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut(); let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut();
@ -194,39 +192,42 @@ where
drop(testcase); drop(testcase);
mark_feature_time!(state, PerfFeature::GetInputFromCorpus); mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
let mut i = 0_usize; match (fuzz_time, iters) {
loop { (Some(fuzz_time), Some(iters)) => {
if let Some(start_time) = start_time { // perform n iterations or fuzz for provided time, whichever comes first
if current_time() - start_time >= fuzz_time.unwrap() { let start_time = current_time();
break; for i in 1..=iters {
if current_time() - start_time >= fuzz_time {
break;
}
self.perform_mutation(fuzzer, executor, state, manager, &input, i)?;
} }
} }
if let Some(iters) = iters { (Some(fuzz_time), None) => {
if i >= iters as usize { // fuzz for provided time
break; let start_time = current_time();
for i in 1.. {
if current_time() - start_time >= fuzz_time {
break;
}
self.perform_mutation(fuzzer, executor, state, manager, &input, i)?;
} }
} else {
i += 1;
} }
(None, Some(iters)) => {
let mut input = input.clone(); // perform n iterations
for i in 1..=iters {
start_timer!(state); self.perform_mutation(fuzzer, executor, state, manager, &input, i)?;
let mutated = self.mutator_mut().mutate(state, &mut input, i as i32)?; }
mark_feature_time!(state, PerfFeature::Mutate); }
(None, None) => {
if mutated == MutationResult::Skipped { // fall back to random
continue; let iters = self.iterations(state, corpus_idx)?;
for i in 1..=iters {
self.perform_mutation(fuzzer, executor, state, manager, &input, i)?;
}
} }
// Time is measured directly the `evaluate_input` function
let (untransformed, post) = input.try_transform_into(state)?;
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, untransformed)?;
start_timer!(state);
self.mutator_mut().post_exec(state, i as i32, corpus_idx)?;
post.post_exec(state, i as i32, corpus_idx)?;
mark_feature_time!(state, PerfFeature::MutatePostExec);
} }
Ok(()) Ok(())
} }
@ -246,12 +247,10 @@ where
/// Gets the number of iterations as a random number /// Gets the number of iterations as a random number
#[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_possible_truncation)]
fn iterations(&self, state: &mut Z::State, _corpus_idx: CorpusId) -> Result<u64, Error> { fn iterations(&self, state: &mut Z::State, _corpus_idx: CorpusId) -> Result<u64, Error> {
Ok(if let Some(iters) = self.iters(state)? { Ok(
iters
} else {
// fall back to random // fall back to random
1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) 1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS),
}) )
} }
} }
@ -302,6 +301,7 @@ where
M: Mutator<I, Z::State>, M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasNamedMetadata + HasMetadata, Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasNamedMetadata + HasMetadata,
I: MutatedTransform<Z::Input, Z::State> + Clone,
{ {
/// Creates a new default tuneable mutational stage /// Creates a new default tuneable mutational stage
#[must_use] #[must_use]
@ -335,20 +335,20 @@ where
set_iters_by_name(state, iters, name) set_iters_by_name(state, iters, name)
} }
/// Get the set iterations for this [`TuneableMutationalStage`] /// Get the set iterations for this [`TuneableMutationalStage`], if any
pub fn iters<S>(&self, state: &S) -> Result<Option<u64>, Error> pub fn fixed_iters<S>(&self, state: &S) -> Result<Option<u64>, Error>
where where
S: HasNamedMetadata, S: HasNamedMetadata,
{ {
get_iters_by_name(state, &self.name) get_iters_by_name(state, &self.name)
} }
/// Get the set iterations for the std [`TuneableMutationalStage`] /// Get the set iterations for the std [`TuneableMutationalStage`], if any
pub fn iters_std(state: &Z::State) -> Result<Option<u64>, Error> { pub fn iters_std(state: &Z::State) -> Result<Option<u64>, Error> {
get_iters_by_name(state, STD_TUNEABLE_MUTATIONAL_STAGE_NAME) get_iters_by_name(state, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
} }
/// Get the set iterations for the [`TuneableMutationalStage`] with the given name /// Get the set iterations for the [`TuneableMutationalStage`] with the given name, if any
pub fn iters_by_name<S>(state: &S, name: &str) -> Result<Option<u64>, Error> pub fn iters_by_name<S>(state: &S, name: &str) -> Result<Option<u64>, Error>
where where
S: HasNamedMetadata, S: HasNamedMetadata,
@ -426,6 +426,40 @@ where
{ {
reset_by_name(state, name) reset_by_name(state, name)
} }
fn perform_mutation(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut Z::State,
manager: &mut EM,
input: &I,
stage_idx: u64,
) -> Result<(), Error> {
let mut input = input.clone();
start_timer!(state);
let mutated = self
.mutator_mut()
.mutate(state, &mut input, stage_idx as i32)?;
mark_feature_time!(state, PerfFeature::Mutate);
if mutated == MutationResult::Skipped {
return Ok(());
}
// Time is measured directly the `evaluate_input` function
let (untransformed, post) = input.try_transform_into(state)?;
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, untransformed)?;
start_timer!(state);
self.mutator_mut()
.post_exec(state, stage_idx as i32, corpus_idx)?;
post.post_exec(state, stage_idx as i32, corpus_idx)?;
mark_feature_time!(state, PerfFeature::MutatePostExec);
Ok(())
}
} }
impl<E, EM, I, M, Z> TuneableMutationalStage<E, EM, I, M, Z> impl<E, EM, I, M, Z> TuneableMutationalStage<E, EM, I, M, Z>