* Support `MutatedTransform` in `TMinMutationalStage`. * Run `MutatedTransformPost` for the replaced testcase. * Add clone trait bound for `MutatedTransformPost`. * Return an error instead of using unwrap.
This commit is contained in:
parent
f0ee6e0587
commit
c221108916
@ -1,7 +1,7 @@
|
|||||||
//! The [`TMinMutationalStage`] is a stage which will attempt to minimize corpus entries.
|
//! The [`TMinMutationalStage`] is a stage which will attempt to minimize corpus entries.
|
||||||
|
|
||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use core::{fmt::Debug, hash::Hash, marker::PhantomData};
|
use core::{borrow::BorrowMut, fmt::Debug, hash::Hash, marker::PhantomData};
|
||||||
|
|
||||||
use ahash::RandomState;
|
use ahash::RandomState;
|
||||||
use libafl_bolts::{HasLen, Named};
|
use libafl_bolts::{HasLen, Named};
|
||||||
@ -16,7 +16,10 @@ use crate::{
|
|||||||
mutators::{MutationResult, Mutator},
|
mutators::{MutationResult, Mutator},
|
||||||
observers::{MapObserver, ObserversTuple},
|
observers::{MapObserver, ObserversTuple},
|
||||||
schedulers::{RemovableScheduler, Scheduler},
|
schedulers::{RemovableScheduler, Scheduler},
|
||||||
stages::{ExecutionCountRestartHelper, Stage},
|
stages::{
|
||||||
|
mutational::{MutatedTransform, MutatedTransformPost},
|
||||||
|
ExecutionCountRestartHelper, Stage,
|
||||||
|
},
|
||||||
start_timer,
|
start_timer,
|
||||||
state::{
|
state::{
|
||||||
HasCorpus, HasCurrentTestcase, HasExecutions, HasMaxSize, HasMetadata, HasSolutions, State,
|
HasCorpus, HasCurrentTestcase, HasExecutions, HasMaxSize, HasMetadata, HasSolutions, State,
|
||||||
@ -30,7 +33,7 @@ use crate::{monitors::PerfFeature, state::HasClientPerfMonitor};
|
|||||||
/// Mutational stage which minimizes corpus entries.
|
/// Mutational stage which minimizes corpus entries.
|
||||||
///
|
///
|
||||||
/// You must provide at least one mutator that actually reduces size.
|
/// You must provide at least one mutator that actually reduces size.
|
||||||
pub trait TMinMutationalStage<CS, E, EM, F1, F2, M, OT, Z>:
|
pub trait TMinMutationalStage<CS, E, EM, F1, F2, I, IP, M, OT, Z>:
|
||||||
Stage<E, EM, Z> + FeedbackFactory<F2, CS::State, OT>
|
Stage<E, EM, Z> + FeedbackFactory<F2, CS::State, OT>
|
||||||
where
|
where
|
||||||
Self::State: HasCorpus + HasSolutions + HasExecutions + HasMaxSize,
|
Self::State: HasCorpus + HasSolutions + HasExecutions + HasMaxSize,
|
||||||
@ -40,12 +43,14 @@ where
|
|||||||
EM: EventFirer<State = Self::State>,
|
EM: EventFirer<State = Self::State>,
|
||||||
F1: Feedback<Self::State>,
|
F1: Feedback<Self::State>,
|
||||||
F2: Feedback<Self::State>,
|
F2: Feedback<Self::State>,
|
||||||
M: Mutator<Self::Input, Self::State>,
|
M: Mutator<I, Self::State>,
|
||||||
OT: ObserversTuple<CS::State>,
|
OT: ObserversTuple<CS::State>,
|
||||||
Z: ExecutionProcessor<OT, State = Self::State>
|
Z: ExecutionProcessor<OT, State = Self::State>
|
||||||
+ ExecutesInput<E, EM>
|
+ ExecutesInput<E, EM>
|
||||||
+ HasFeedback<Feedback = F1>
|
+ HasFeedback<Feedback = F1>
|
||||||
+ HasScheduler<Scheduler = CS>,
|
+ HasScheduler<Scheduler = CS>,
|
||||||
|
IP: MutatedTransformPost<Self::State> + Clone,
|
||||||
|
I: MutatedTransform<Self::Input, Self::State, Post = IP> + Clone,
|
||||||
{
|
{
|
||||||
/// The mutator registered for this stage
|
/// The mutator registered for this stage
|
||||||
fn mutator(&self) -> &M;
|
fn mutator(&self) -> &M;
|
||||||
@ -77,7 +82,10 @@ where
|
|||||||
- usize::try_from(self.execs_since_progress_start(state)?).unwrap();
|
- usize::try_from(self.execs_since_progress_start(state)?).unwrap();
|
||||||
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
|
let transformed = I::try_transform_from(state.current_testcase_mut()?.borrow_mut(), state)?;
|
||||||
let mut base = state.current_input_cloned()?;
|
let mut base = state.current_input_cloned()?;
|
||||||
|
// potential post operation if base is replaced by a shorter input
|
||||||
|
let mut base_post = None;
|
||||||
let base_hash = RandomState::with_seeds(0, 0, 0, 0).hash_one(&base);
|
let base_hash = RandomState::with_seeds(0, 0, 0, 0).hash_one(&base);
|
||||||
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
||||||
|
|
||||||
@ -93,20 +101,21 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut next_i = i + 1;
|
let mut next_i = i + 1;
|
||||||
let mut input = base.clone();
|
let mut input_transformed = transformed.clone();
|
||||||
|
|
||||||
let before_len = input.len();
|
let before_len = base.len();
|
||||||
|
|
||||||
state.set_max_size(before_len);
|
state.set_max_size(before_len);
|
||||||
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
let mutated = self.mutator_mut().mutate(state, &mut input)?;
|
let mutated = self.mutator_mut().mutate(state, &mut input_transformed)?;
|
||||||
mark_feature_time!(state, PerfFeature::Mutate);
|
mark_feature_time!(state, PerfFeature::Mutate);
|
||||||
|
|
||||||
if mutated == MutationResult::Skipped {
|
if mutated == MutationResult::Skipped {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (input, post) = input_transformed.try_transform_into(state)?;
|
||||||
let corpus_idx = if input.len() < before_len {
|
let corpus_idx = if input.len() < before_len {
|
||||||
// run the input
|
// run the input
|
||||||
let exit_kind = fuzzer.execute_input(state, executor, manager, &input)?;
|
let exit_kind = fuzzer.execute_input(state, executor, manager, &input)?;
|
||||||
@ -134,6 +143,7 @@ where
|
|||||||
if feedback.is_interesting(state, manager, &input, observers, &exit_kind)? {
|
if feedback.is_interesting(state, manager, &input, observers, &exit_kind)? {
|
||||||
// we found a reduced corpus entry! use the smaller base
|
// we found a reduced corpus entry! use the smaller base
|
||||||
base = input;
|
base = input;
|
||||||
|
base_post = Some(post.clone());
|
||||||
|
|
||||||
// do more runs! maybe we can minify further
|
// do more runs! maybe we can minify further
|
||||||
next_i = 0;
|
next_i = 0;
|
||||||
@ -149,6 +159,7 @@ where
|
|||||||
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
self.mutator_mut().post_exec(state, corpus_idx)?;
|
self.mutator_mut().post_exec(state, corpus_idx)?;
|
||||||
|
post.post_exec(state, corpus_idx)?;
|
||||||
mark_feature_time!(state, PerfFeature::MutatePostExec);
|
mark_feature_time!(state, PerfFeature::MutatePostExec);
|
||||||
|
|
||||||
i = next_i;
|
i = next_i;
|
||||||
@ -171,6 +182,11 @@ where
|
|||||||
fuzzer
|
fuzzer
|
||||||
.scheduler_mut()
|
.scheduler_mut()
|
||||||
.on_replace(state, base_corpus_idx, &prev)?;
|
.on_replace(state, base_corpus_idx, &prev)?;
|
||||||
|
// perform the post operation for the new testcase, e.g. to update metadata.
|
||||||
|
// base_post should be updated along with the base (and is no longer None)
|
||||||
|
base_post
|
||||||
|
.ok_or_else(|| Error::empty_optional("Failed to get the MutatedTransformPost"))?
|
||||||
|
.post_exec(state, Some(base_corpus_idx))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.set_max_size(orig_max_size);
|
state.set_max_size(orig_max_size);
|
||||||
@ -184,7 +200,7 @@ where
|
|||||||
|
|
||||||
/// The default corpus entry minimising mutational stage
|
/// The default corpus entry minimising mutational stage
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z> {
|
pub struct StdTMinMutationalStage<CS, E, EM, F1, F2, FF, I, IP, M, OT, Z> {
|
||||||
/// The mutator(s) this stage uses
|
/// The mutator(s) this stage uses
|
||||||
mutator: M,
|
mutator: M,
|
||||||
/// The factory
|
/// The factory
|
||||||
@ -194,22 +210,24 @@ pub struct StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z> {
|
|||||||
/// The progress helper for this stage, keeping track of resumes after timeouts/crashes
|
/// The progress helper for this stage, keeping track of resumes after timeouts/crashes
|
||||||
restart_helper: ExecutionCountRestartHelper,
|
restart_helper: ExecutionCountRestartHelper,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
phantom: PhantomData<(CS, E, EM, F1, F2, OT, Z)>,
|
phantom: PhantomData<(CS, E, EM, F1, F2, I, IP, OT, Z)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, E, EM, F1, F2, FF, M, OT, Z> UsesState
|
impl<CS, E, EM, F1, F2, FF, I, IP, M, OT, Z> UsesState
|
||||||
for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z>
|
for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, I, IP, M, OT, Z>
|
||||||
where
|
where
|
||||||
CS: Scheduler,
|
CS: Scheduler,
|
||||||
M: Mutator<CS::Input, CS::State>,
|
M: Mutator<I, CS::State>,
|
||||||
Z: ExecutionProcessor<OT, State = CS::State>,
|
Z: ExecutionProcessor<OT, State = CS::State>,
|
||||||
CS::State: HasCorpus,
|
CS::State: HasCorpus,
|
||||||
|
IP: MutatedTransformPost<CS::State> + Clone,
|
||||||
|
I: MutatedTransform<CS::Input, CS::State, Post = IP> + Clone,
|
||||||
{
|
{
|
||||||
type State = CS::State;
|
type State = CS::State;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, E, EM, F1, F2, FF, M, OT, Z> Stage<E, EM, Z>
|
impl<CS, E, EM, F1, F2, FF, I, IP, 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, I, IP, M, OT, Z>
|
||||||
where
|
where
|
||||||
CS: Scheduler + RemovableScheduler,
|
CS: Scheduler + RemovableScheduler,
|
||||||
CS::State: HasCorpus + HasSolutions + HasExecutions + HasMaxSize + HasCorpus + HasMetadata,
|
CS::State: HasCorpus + HasSolutions + HasExecutions + HasMaxSize + HasCorpus + HasMetadata,
|
||||||
@ -219,12 +237,14 @@ where
|
|||||||
F1: Feedback<CS::State>,
|
F1: Feedback<CS::State>,
|
||||||
F2: Feedback<CS::State>,
|
F2: Feedback<CS::State>,
|
||||||
FF: FeedbackFactory<F2, CS::State, OT>,
|
FF: FeedbackFactory<F2, CS::State, OT>,
|
||||||
M: Mutator<CS::Input, CS::State>,
|
M: Mutator<I, CS::State>,
|
||||||
OT: ObserversTuple<CS::State>,
|
OT: ObserversTuple<CS::State>,
|
||||||
Z: ExecutionProcessor<OT, State = CS::State>
|
Z: ExecutionProcessor<OT, State = CS::State>
|
||||||
+ ExecutesInput<E, EM>
|
+ ExecutesInput<E, EM>
|
||||||
+ HasFeedback<Feedback = F1>
|
+ HasFeedback<Feedback = F1>
|
||||||
+ HasScheduler<Scheduler = CS>,
|
+ HasScheduler<Scheduler = CS>,
|
||||||
|
IP: MutatedTransformPost<CS::State> + Clone,
|
||||||
|
I: MutatedTransform<CS::Input, CS::State, Post = IP> + Clone,
|
||||||
{
|
{
|
||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -250,8 +270,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, E, EM, F1, F2, FF, M, OT, Z> FeedbackFactory<F2, Z::State, OT>
|
impl<CS, E, EM, F1, F2, FF, I, IP, M, OT, Z> FeedbackFactory<F2, Z::State, OT>
|
||||||
for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z>
|
for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, I, IP, M, OT, Z>
|
||||||
where
|
where
|
||||||
F2: Feedback<Z::State>,
|
F2: Feedback<Z::State>,
|
||||||
FF: FeedbackFactory<F2, Z::State, OT>,
|
FF: FeedbackFactory<F2, Z::State, OT>,
|
||||||
@ -262,8 +282,8 @@ 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, I, IP, M, OT, Z> TMinMutationalStage<CS, E, EM, F1, F2, I, IP, M, OT, Z>
|
||||||
for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z>
|
for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, I, IP, M, OT, Z>
|
||||||
where
|
where
|
||||||
CS: Scheduler + RemovableScheduler,
|
CS: Scheduler + RemovableScheduler,
|
||||||
E: HasObservers<Observers = OT, State = CS::State> + Executor<EM, Z>,
|
E: HasObservers<Observers = OT, State = CS::State> + Executor<EM, Z>,
|
||||||
@ -272,13 +292,15 @@ where
|
|||||||
F2: Feedback<CS::State>,
|
F2: Feedback<CS::State>,
|
||||||
FF: FeedbackFactory<F2, CS::State, OT>,
|
FF: FeedbackFactory<F2, CS::State, OT>,
|
||||||
<CS::State as UsesInput>::Input: HasLen + Hash,
|
<CS::State as UsesInput>::Input: HasLen + Hash,
|
||||||
M: Mutator<CS::Input, CS::State>,
|
M: Mutator<I, CS::State>,
|
||||||
OT: ObserversTuple<CS::State>,
|
OT: ObserversTuple<CS::State>,
|
||||||
CS::State: HasCorpus + HasSolutions + HasExecutions + HasMaxSize + HasMetadata,
|
CS::State: HasCorpus + HasSolutions + HasExecutions + HasMaxSize + HasMetadata,
|
||||||
Z: ExecutionProcessor<OT, State = CS::State>
|
Z: ExecutionProcessor<OT, State = CS::State>
|
||||||
+ ExecutesInput<E, EM>
|
+ ExecutesInput<E, EM>
|
||||||
+ HasFeedback<Feedback = F1>
|
+ HasFeedback<Feedback = F1>
|
||||||
+ HasScheduler<Scheduler = CS>,
|
+ HasScheduler<Scheduler = CS>,
|
||||||
|
IP: MutatedTransformPost<CS::State> + Clone,
|
||||||
|
I: MutatedTransform<CS::Input, CS::State, Post = IP> + Clone,
|
||||||
{
|
{
|
||||||
/// The mutator, added to this stage
|
/// The mutator, added to this stage
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -302,12 +324,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, E, EM, F1, F2, FF, M, OT, Z> StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z>
|
impl<CS, E, EM, F1, F2, FF, I, IP, M, OT, Z>
|
||||||
|
StdTMinMutationalStage<CS, E, EM, F1, F2, FF, I, IP, M, OT, Z>
|
||||||
where
|
where
|
||||||
CS: Scheduler,
|
CS: Scheduler,
|
||||||
M: Mutator<CS::Input, CS::State>,
|
M: Mutator<I, CS::State>,
|
||||||
Z: ExecutionProcessor<OT, State = CS::State>,
|
Z: ExecutionProcessor<OT, State = CS::State>,
|
||||||
CS::State: HasCorpus,
|
CS::State: HasCorpus,
|
||||||
|
IP: MutatedTransformPost<CS::State> + Clone,
|
||||||
|
I: MutatedTransform<CS::Input, CS::State, Post = IP> + Clone,
|
||||||
{
|
{
|
||||||
/// Creates a new minimizing mutational stage that will minimize provided corpus entries
|
/// Creates a new minimizing mutational stage that will minimize provided corpus entries
|
||||||
pub fn new(mutator: M, factory: FF, runs: usize) -> Self {
|
pub fn new(mutator: M, factory: FF, runs: usize) -> Self {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user