Skip to content

Commit 6d0d4e2

Browse files
authored
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
1 parent d4f4734 commit 6d0d4e2

File tree

1 file changed

+80
-46
lines changed

1 file changed

+80
-46
lines changed

libafl/src/stages/tuneable.rs

Lines changed: 80 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -175,16 +175,14 @@ where
175175
manager: &mut EM,
176176
corpus_idx: CorpusId,
177177
) -> Result<(), Error> {
178-
let metadata: &TuneableMutationalStageMetadata = state.metadata()?;
178+
let fuzz_time = self.seed_fuzz_time(state)?;
179+
let iters = self.fixed_iters(state)?;
179180

180-
let fuzz_time = metadata.fuzz_time;
181-
let iters = metadata.iters;
182-
183-
let (start_time, iters) = if fuzz_time.is_some() {
184-
(Some(current_time()), iters)
185-
} else {
186-
(None, Some(self.iterations(state, corpus_idx)?))
187-
};
181+
if fuzz_time.is_some() && iters.is_some() {
182+
return Err(Error::illegal_state(
183+
"Both fuzz_time and iters specified; failing fast!",
184+
));
185+
}
188186

189187
start_timer!(state);
190188
let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut();
@@ -194,39 +192,42 @@ where
194192
drop(testcase);
195193
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
196194

197-
let mut i = 0_usize;
198-
loop {
199-
if let Some(start_time) = start_time {
200-
if current_time() - start_time >= fuzz_time.unwrap() {
201-
break;
195+
match (fuzz_time, iters) {
196+
(Some(fuzz_time), Some(iters)) => {
197+
// perform n iterations or fuzz for provided time, whichever comes first
198+
let start_time = current_time();
199+
for i in 1..=iters {
200+
if current_time() - start_time >= fuzz_time {
201+
break;
202+
}
203+
204+
self.perform_mutation(fuzzer, executor, state, manager, &input, i)?;
202205
}
203206
}
204-
if let Some(iters) = iters {
205-
if i >= iters as usize {
206-
break;
207+
(Some(fuzz_time), None) => {
208+
// fuzz for provided time
209+
let start_time = current_time();
210+
for i in 1.. {
211+
if current_time() - start_time >= fuzz_time {
212+
break;
213+
}
214+
215+
self.perform_mutation(fuzzer, executor, state, manager, &input, i)?;
207216
}
208-
} else {
209-
i += 1;
210217
}
211-
212-
let mut input = input.clone();
213-
214-
start_timer!(state);
215-
let mutated = self.mutator_mut().mutate(state, &mut input, i as i32)?;
216-
mark_feature_time!(state, PerfFeature::Mutate);
217-
218-
if mutated == MutationResult::Skipped {
219-
continue;
218+
(None, Some(iters)) => {
219+
// perform n iterations
220+
for i in 1..=iters {
221+
self.perform_mutation(fuzzer, executor, state, manager, &input, i)?;
222+
}
223+
}
224+
(None, None) => {
225+
// fall back to random
226+
let iters = self.iterations(state, corpus_idx)?;
227+
for i in 1..=iters {
228+
self.perform_mutation(fuzzer, executor, state, manager, &input, i)?;
229+
}
220230
}
221-
222-
// Time is measured directly the `evaluate_input` function
223-
let (untransformed, post) = input.try_transform_into(state)?;
224-
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, untransformed)?;
225-
226-
start_timer!(state);
227-
self.mutator_mut().post_exec(state, i as i32, corpus_idx)?;
228-
post.post_exec(state, i as i32, corpus_idx)?;
229-
mark_feature_time!(state, PerfFeature::MutatePostExec);
230231
}
231232
Ok(())
232233
}
@@ -246,12 +247,10 @@ where
246247
/// Gets the number of iterations as a random number
247248
#[allow(clippy::cast_possible_truncation)]
248249
fn iterations(&self, state: &mut Z::State, _corpus_idx: CorpusId) -> Result<u64, Error> {
249-
Ok(if let Some(iters) = self.iters(state)? {
250-
iters
251-
} else {
250+
Ok(
252251
// fall back to random
253-
1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS)
254-
})
252+
1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS),
253+
)
255254
}
256255
}
257256

@@ -302,6 +301,7 @@ where
302301
M: Mutator<I, Z::State>,
303302
Z: Evaluator<E, EM>,
304303
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasNamedMetadata + HasMetadata,
304+
I: MutatedTransform<Z::Input, Z::State> + Clone,
305305
{
306306
/// Creates a new default tuneable mutational stage
307307
#[must_use]
@@ -335,20 +335,20 @@ where
335335
set_iters_by_name(state, iters, name)
336336
}
337337

338-
/// Get the set iterations for this [`TuneableMutationalStage`]
339-
pub fn iters<S>(&self, state: &S) -> Result<Option<u64>, Error>
338+
/// Get the set iterations for this [`TuneableMutationalStage`], if any
339+
pub fn fixed_iters<S>(&self, state: &S) -> Result<Option<u64>, Error>
340340
where
341341
S: HasNamedMetadata,
342342
{
343343
get_iters_by_name(state, &self.name)
344344
}
345345

346-
/// Get the set iterations for the std [`TuneableMutationalStage`]
346+
/// Get the set iterations for the std [`TuneableMutationalStage`], if any
347347
pub fn iters_std(state: &Z::State) -> Result<Option<u64>, Error> {
348348
get_iters_by_name(state, STD_TUNEABLE_MUTATIONAL_STAGE_NAME)
349349
}
350350

351-
/// Get the set iterations for the [`TuneableMutationalStage`] with the given name
351+
/// Get the set iterations for the [`TuneableMutationalStage`] with the given name, if any
352352
pub fn iters_by_name<S>(state: &S, name: &str) -> Result<Option<u64>, Error>
353353
where
354354
S: HasNamedMetadata,
@@ -426,6 +426,40 @@ where
426426
{
427427
reset_by_name(state, name)
428428
}
429+
430+
fn perform_mutation(
431+
&mut self,
432+
fuzzer: &mut Z,
433+
executor: &mut E,
434+
state: &mut Z::State,
435+
manager: &mut EM,
436+
input: &I,
437+
stage_idx: u64,
438+
) -> Result<(), Error> {
439+
let mut input = input.clone();
440+
441+
start_timer!(state);
442+
let mutated = self
443+
.mutator_mut()
444+
.mutate(state, &mut input, stage_idx as i32)?;
445+
mark_feature_time!(state, PerfFeature::Mutate);
446+
447+
if mutated == MutationResult::Skipped {
448+
return Ok(());
449+
}
450+
451+
// Time is measured directly the `evaluate_input` function
452+
let (untransformed, post) = input.try_transform_into(state)?;
453+
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, untransformed)?;
454+
455+
start_timer!(state);
456+
self.mutator_mut()
457+
.post_exec(state, stage_idx as i32, corpus_idx)?;
458+
post.post_exec(state, stage_idx as i32, corpus_idx)?;
459+
mark_feature_time!(state, PerfFeature::MutatePostExec);
460+
461+
Ok(())
462+
}
429463
}
430464

431465
impl<E, EM, I, M, Z> TuneableMutationalStage<E, EM, I, M, Z>

0 commit comments

Comments
 (0)