Grimoire fixes (#993)

* fixup grimoire/generalisation, remove GeneralizedInput in favour of metadata

* additional cleanup

* transformable inputs to solve the grimoire problem

* explicit use of 'transforming' to keep typing compatible with normal usage

* clippy fix

* fixes for nautilus, python

* explicit inlining for reflexive impl

* fix for tutorial

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
This commit is contained in:
Addison Crump 2023-01-13 01:07:21 +01:00 committed by GitHub
parent ec84c71eae
commit 28786c943a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 608 additions and 687 deletions

View File

@ -9,7 +9,7 @@ use libafl::{
executors::{inprocess::InProcessExecutor, ExitKind}, executors::{inprocess::InProcessExecutor, ExitKind},
feedbacks::{CrashFeedback, MaxMapFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Evaluator, Fuzzer, StdFuzzer}, fuzzer::{Evaluator, Fuzzer, StdFuzzer},
inputs::{GeneralizedInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{ mutators::{
havoc_mutations, scheduled::StdScheduledMutator, GrimoireExtensionMutator, havoc_mutations, scheduled::StdScheduledMutator, GrimoireExtensionMutator,
@ -59,13 +59,13 @@ pub fn main() {
let mut file = fs::File::open(path).expect("no file found"); let mut file = fs::File::open(path).expect("no file found");
let mut buffer = vec![]; let mut buffer = vec![];
file.read_to_end(&mut buffer).expect("buffer overflow"); file.read_to_end(&mut buffer).expect("buffer overflow");
let input = GeneralizedInput::new(buffer); let input = BytesInput::new(buffer);
initial_inputs.push(input); initial_inputs.push(input);
} }
} }
// The closure that we want to fuzz // The closure that we want to fuzz
let mut harness = |input: &GeneralizedInput| { let mut harness = |input: &BytesInput| {
let target_bytes = input.target_bytes(); let target_bytes = input.target_bytes();
let bytes = target_bytes.as_slice(); let bytes = target_bytes.as_slice();
@ -77,12 +77,6 @@ pub fn main() {
signals_set(3); signals_set(3);
} }
unsafe {
if input.grimoire_mutated {
// println!(">>> {:?}", input.generalized());
println!(">>> {:?}", std::str::from_utf8_unchecked(bytes));
}
}
signals_set(1); signals_set(1);
ExitKind::Ok ExitKind::Ok
}; };
@ -158,7 +152,7 @@ pub fn main() {
let mut stages = tuple_list!( let mut stages = tuple_list!(
generalization, generalization,
StdMutationalStage::new(mutator), StdMutationalStage::new(mutator),
StdMutationalStage::new(grimoire_mutator) StdMutationalStage::transforming(grimoire_mutator)
); );
for input in initial_inputs { for input in initial_inputs {

View File

@ -31,7 +31,7 @@ use libafl::{
feedback_or, feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
inputs::{BytesInput, GeneralizedInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{ mutators::{
grimoire::{ grimoire::{
@ -47,8 +47,8 @@ use libafl::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
}, },
stages::{ stages::{
calibrate::CalibrationStage, dump::DumpToDiskStage, power::StdPowerMutationalStage, calibrate::CalibrationStage, power::StdPowerMutationalStage, GeneralizationStage,
GeneralizationStage, StdMutationalStage, TracingStage, StdMutationalStage, TracingStage,
}, },
state::{HasCorpus, HasMetadata, StdState}, state::{HasCorpus, HasMetadata, StdState},
Error, Error,
@ -148,11 +148,8 @@ pub fn libafl_main() {
} }
} }
let mut crashes = out_dir.clone(); let mut crashes = out_dir.clone();
let mut report = out_dir.clone();
crashes.push("crashes"); crashes.push("crashes");
report.push("report");
out_dir.push("queue"); out_dir.push("queue");
drop(fs::create_dir(&report));
let in_dir = PathBuf::from( let in_dir = PathBuf::from(
res.get_one::<String>("in") res.get_one::<String>("in")
@ -177,10 +174,8 @@ pub fn libafl_main() {
); );
if check_if_textual(&in_dir, &tokens) { if check_if_textual(&in_dir, &tokens) {
fuzz_text( fuzz_text(out_dir, crashes, &in_dir, tokens, &logfile, timeout)
out_dir, crashes, &report, &in_dir, tokens, &logfile, timeout, .expect("An error occurred while fuzzing");
)
.expect("An error occurred while fuzzing");
} else { } else {
fuzz_binary(out_dir, crashes, &in_dir, tokens, &logfile, timeout) fuzz_binary(out_dir, crashes, &in_dir, tokens, &logfile, timeout)
.expect("An error occurred while fuzzing"); .expect("An error occurred while fuzzing");
@ -466,7 +461,6 @@ fn fuzz_binary(
fn fuzz_text( fn fuzz_text(
corpus_dir: PathBuf, corpus_dir: PathBuf,
objective_dir: PathBuf, objective_dir: PathBuf,
report_dir: &Path,
seed_dir: &PathBuf, seed_dir: &PathBuf,
tokenfile: Option<PathBuf>, tokenfile: Option<PathBuf>,
logfile: &PathBuf, logfile: &PathBuf,
@ -586,7 +580,7 @@ fn fuzz_text(
), ),
3, 3,
); );
let grimoire = StdMutationalStage::new(grimoire_mutator); let grimoire = StdMutationalStage::transforming(grimoire_mutator);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
@ -597,7 +591,7 @@ fn fuzz_text(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
// The wrapped harness function, calling out to the LLVM-style harness // The wrapped harness function, calling out to the LLVM-style harness
let mut harness = |input: &GeneralizedInput| { let mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
@ -633,23 +627,8 @@ fn fuzz_text(
timeout * 10, timeout * 10,
)); ));
let fuzzbench = DumpToDiskStage::new(
|input: &GeneralizedInput| input.target_bytes().into(),
&report_dir.join("queue"),
&report_dir.join("crashes"),
)
.unwrap();
// The order of the stages matter! // The order of the stages matter!
let mut stages = tuple_list!( let mut stages = tuple_list!(generalization, calibration, tracing, i2s, power, grimoire);
fuzzbench,
generalization,
calibration,
tracing,
i2s,
power,
grimoire
);
// Read tokens // Read tokens
if state.metadata().get::<Tokens>().is_none() { if state.metadata().get::<Tokens>().is_none() {

View File

@ -4,7 +4,6 @@ use libafl::{
rands::{Rand, StdRand}, rands::{Rand, StdRand},
tuples::Named, tuples::Named,
}, },
inputs::UsesInput,
mutators::{MutationResult, Mutator}, mutators::{MutationResult, Mutator},
state::HasRand, state::HasRand,
Error, Error,
@ -16,9 +15,9 @@ pub struct LainMutator {
inner: lain::mutator::Mutator<StdRand>, inner: lain::mutator::Mutator<StdRand>,
} }
impl<S> Mutator<S> for LainMutator impl<S> Mutator<PacketData, S> for LainMutator
where where
S: UsesInput<Input = PacketData> + HasRand, S: HasRand,
{ {
fn mutate( fn mutate(
&mut self, &mut self,

View File

@ -5,7 +5,7 @@ use core::{cmp::min, marker::PhantomData};
use crate::{ use crate::{
bolts::rands::Rand, bolts::rands::Rand,
inputs::{bytes::BytesInput, GeneralizedInput, Input}, inputs::{bytes::BytesInput, Input},
state::HasRand, state::HasRand,
Error, Error,
}; };
@ -33,51 +33,6 @@ where
fn generate_dummy(&self, state: &mut S) -> I; fn generate_dummy(&self, state: &mut S) -> I;
} }
/// A Generator that produces [`GeneralizedInput`]s from a wrapped [`BytesInput`] generator
#[derive(Clone, Debug)]
pub struct GeneralizedInputBytesGenerator<G, S> {
bytes_generator: G,
phantom: PhantomData<S>,
}
impl<G, S> GeneralizedInputBytesGenerator<G, S>
where
S: HasRand,
G: Generator<BytesInput, S>,
{
/// Creates a new [`GeneralizedInputBytesGenerator`] by wrapping a bytes generator.
pub fn new(bytes_generator: G) -> Self {
Self {
bytes_generator,
phantom: PhantomData,
}
}
}
impl<G, S> From<G> for GeneralizedInputBytesGenerator<G, S>
where
S: HasRand,
G: Generator<BytesInput, S>,
{
fn from(bytes_generator: G) -> Self {
Self::new(bytes_generator)
}
}
impl<G, S> Generator<GeneralizedInput, S> for GeneralizedInputBytesGenerator<G, S>
where
S: HasRand,
G: Generator<BytesInput, S>,
{
fn generate(&mut self, state: &mut S) -> Result<GeneralizedInput, Error> {
Ok(self.bytes_generator.generate(state)?.into())
}
fn generate_dummy(&self, state: &mut S) -> GeneralizedInput {
self.bytes_generator.generate_dummy(state).into()
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
/// Generates random bytes /// Generates random bytes
pub struct RandBytesGenerator<S> pub struct RandBytesGenerator<S>

View File

@ -1,18 +1,16 @@
//! The `GeneralizedInput` is an input that ca be generalized to represent a rule, used by Grimoire //! The `GeneralizedInput` is an input that ca be generalized to represent a rule, used by Grimoire
use alloc::{borrow::ToOwned, rc::Rc, string::String, vec::Vec}; use alloc::vec::Vec;
use core::{cell::RefCell, convert::From, hash::Hasher};
#[cfg(feature = "std")]
use std::{fs::File, io::Read, path::Path};
use ahash::AHasher;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use crate::Error;
use crate::{ use crate::{
bolts::{ownedref::OwnedSlice, HasLen}, corpus::{Corpus, CorpusId, Testcase},
inputs::{BytesInput, HasBytesVec, HasTargetBytes, Input}, impl_serdeany,
inputs::BytesInput,
stages::mutational::{MutatedTransform, MutatedTransformPost},
state::{HasCorpus, HasMetadata},
Error,
}; };
/// An item of the generalized input /// An item of the generalized input
@ -24,142 +22,31 @@ pub enum GeneralizedItem {
Gap, Gap,
} }
/// A bytes input with a generalized version mainly used for Grimoire /// Metadata regarding the generalised content of an input
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, Hash)] #[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct GeneralizedInput { pub struct GeneralizedInputMetadata {
/// The raw input bytes generalized: Vec<GeneralizedItem>,
bytes: Vec<u8>,
generalized: Option<Vec<GeneralizedItem>>,
/// If was mutated or not by Grimoire
pub grimoire_mutated: bool,
} }
impl Input for GeneralizedInput { impl_serdeany!(GeneralizedInputMetadata);
/// Generate a name for this input
fn generate_name(&self, _idx: usize) -> String {
let mut hasher = AHasher::new_with_keys(0, 0);
// TODO add generalized
hasher.write(self.bytes());
format!("{:016x}", hasher.finish())
}
/// Load from a plain file of bytes
#[cfg(feature = "std")]
fn from_file<P>(path: P) -> Result<Self, Error>
where
P: AsRef<Path>,
{
let mut file = File::open(path)?;
let mut bytes: Vec<u8> = vec![];
file.read_to_end(&mut bytes)?;
Ok(Self {
bytes,
generalized: None,
grimoire_mutated: false,
})
}
/// An hook executed before being added to the corpus
fn wrapped_as_testcase(&mut self) {
// remove generalized for inputs generated with bit-level mutations
// and fix bytes for the ones generated by grimoire
if self.grimoire_mutated {
self.bytes = self.generalized_to_bytes();
} else {
self.generalized = None;
}
// restore to allow bit-level mutations
self.grimoire_mutated = false;
}
}
/// Rc Ref-cell from Input
impl From<GeneralizedInput> for Rc<RefCell<GeneralizedInput>> {
fn from(input: GeneralizedInput) -> Self {
Rc::new(RefCell::new(input))
}
}
impl HasBytesVec for GeneralizedInput {
#[inline]
fn bytes(&self) -> &[u8] {
&self.bytes
}
#[inline]
fn bytes_mut(&mut self) -> &mut Vec<u8> {
&mut self.bytes
}
}
impl HasTargetBytes for GeneralizedInput {
#[inline]
fn target_bytes(&self) -> OwnedSlice<u8> {
if self.grimoire_mutated {
OwnedSlice::from(self.generalized_to_bytes())
} else {
OwnedSlice::from(&self.bytes)
}
}
}
impl HasLen for GeneralizedInput {
#[inline]
fn len(&self) -> usize {
self.bytes.len()
}
}
impl From<Vec<u8>> for GeneralizedInput {
fn from(bytes: Vec<u8>) -> Self {
Self::new(bytes)
}
}
impl From<&[u8]> for GeneralizedInput {
fn from(bytes: &[u8]) -> Self {
Self::new(bytes.to_owned())
}
}
impl From<BytesInput> for GeneralizedInput {
fn from(bytes_input: BytesInput) -> Self {
Self::new(bytes_input.bytes)
}
}
impl From<&BytesInput> for GeneralizedInput {
fn from(bytes_input: &BytesInput) -> Self {
bytes_input.bytes().into()
}
}
impl GeneralizedInput {
/// Creates a new bytes input using the given bytes
#[must_use]
pub fn new(bytes: Vec<u8>) -> Self {
Self {
bytes,
generalized: None,
grimoire_mutated: false,
}
}
impl GeneralizedInputMetadata {
/// Fill the generalized vector from a slice of option (None -> Gap) /// Fill the generalized vector from a slice of option (None -> Gap)
pub fn generalized_from_options(&mut self, v: &[Option<u8>]) { #[must_use]
let mut res = vec![]; pub fn generalized_from_options(v: &[Option<u8>]) -> Self {
let mut generalized = vec![];
let mut bytes = vec![]; let mut bytes = vec![];
if v.first() != Some(&None) { if v.first() != Some(&None) {
res.push(GeneralizedItem::Gap); generalized.push(GeneralizedItem::Gap);
} }
for e in v { for e in v {
match e { match e {
None => { None => {
if !bytes.is_empty() { if !bytes.is_empty() {
res.push(GeneralizedItem::Bytes(bytes.clone())); generalized.push(GeneralizedItem::Bytes(bytes.clone()));
bytes.clear(); bytes.clear();
} }
res.push(GeneralizedItem::Gap); generalized.push(GeneralizedItem::Gap);
} }
Some(b) => { Some(b) => {
bytes.push(*b); bytes.push(*b);
@ -167,71 +54,93 @@ impl GeneralizedInput {
} }
} }
if !bytes.is_empty() { if !bytes.is_empty() {
res.push(GeneralizedItem::Bytes(bytes)); generalized.push(GeneralizedItem::Bytes(bytes));
} }
if res.last() != Some(&GeneralizedItem::Gap) { if generalized.last() != Some(&GeneralizedItem::Gap) {
res.push(GeneralizedItem::Gap); generalized.push(GeneralizedItem::Gap);
}
self.generalized = Some(res);
}
/// Extend the generalized input
pub fn generalized_extend(&mut self, other: &[GeneralizedItem]) {
let gen = self.generalized.get_or_insert_with(Vec::new);
if gen.last().is_some()
&& other.first().is_some()
&& *gen.last().unwrap() == GeneralizedItem::Gap
&& *other.first().unwrap() == GeneralizedItem::Gap
{
gen.extend_from_slice(&other[1..]);
} else {
gen.extend_from_slice(other);
} }
Self { generalized }
} }
/// Get the size of the generalized /// Get the size of the generalized
#[must_use] #[must_use]
pub fn generalized_len(&self) -> usize { pub fn generalized_len(&self) -> usize {
match &self.generalized { let mut size = 0;
None => 0, for item in &self.generalized {
Some(gen) => { match item {
let mut size = 0; GeneralizedItem::Bytes(b) => size += b.len(),
for item in gen { GeneralizedItem::Gap => size += 1,
match item {
GeneralizedItem::Bytes(b) => size += b.len(),
GeneralizedItem::Gap => size += 1,
}
}
size
} }
} }
size
} }
/// Convert generalized to bytes /// Convert generalized to bytes
#[must_use] #[must_use]
pub fn generalized_to_bytes(&self) -> Vec<u8> { pub fn generalized_to_bytes(&self) -> Vec<u8> {
match &self.generalized { self.generalized
None => vec![], .iter()
Some(gen) => { .filter_map(|item| match item {
let mut bytes = vec![]; GeneralizedItem::Bytes(bytes) => Some(bytes),
for item in gen { GeneralizedItem::Gap => None,
if let GeneralizedItem::Bytes(b) = item { })
bytes.extend_from_slice(b); .flatten()
} .copied()
} .collect()
bytes
}
}
} }
/// Get the generalized input /// Get the generalized input
#[must_use] #[must_use]
pub fn generalized(&self) -> Option<&[GeneralizedItem]> { pub fn generalized(&self) -> &[GeneralizedItem] {
self.generalized.as_deref() &self.generalized
} }
/// Get the generalized input (mutable) /// Get the generalized input (mutable)
pub fn generalized_mut(&mut self) -> &mut Option<Vec<GeneralizedItem>> { pub fn generalized_mut(&mut self) -> &mut Vec<GeneralizedItem> {
&mut self.generalized &mut self.generalized
} }
} }
impl<S> MutatedTransform<BytesInput, S> for GeneralizedInputMetadata
where
S: HasCorpus,
{
type Post = Self;
fn try_transform_from(
base: &Testcase<BytesInput>,
_state: &S,
corpus_idx: CorpusId,
) -> Result<Self, Error> {
base.metadata()
.get::<GeneralizedInputMetadata>()
.ok_or_else(|| {
Error::key_not_found(format!(
"Couldn't find the GeneralizedInputMetadata for corpus entry {corpus_idx}",
))
})
.cloned()
}
fn try_transform_into(self, _state: &S) -> Result<(BytesInput, Self::Post), Error> {
Ok((BytesInput::from(self.generalized_to_bytes()), self))
}
}
impl<S> MutatedTransformPost<S> for GeneralizedInputMetadata
where
S: HasCorpus,
{
fn post_exec(
self,
state: &mut S,
_stage_idx: i32,
corpus_idx: Option<CorpusId>,
) -> Result<(), Error> {
if let Some(corpus_idx) = corpus_idx {
let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut();
testcase.metadata_mut().insert(self);
}
Ok(())
}
}

View File

@ -23,7 +23,7 @@ use crate::{
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedRandMutator; pub struct EncodedRandMutator;
impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedRandMutator { impl<S: HasRand> Mutator<EncodedInput, S> for EncodedRandMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -58,7 +58,7 @@ impl EncodedRandMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedIncMutator; pub struct EncodedIncMutator;
impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedIncMutator { impl<S: HasRand> Mutator<EncodedInput, S> for EncodedIncMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -93,7 +93,7 @@ impl EncodedIncMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedDecMutator; pub struct EncodedDecMutator;
impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedDecMutator { impl<S: HasRand> Mutator<EncodedInput, S> for EncodedDecMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -128,7 +128,7 @@ impl EncodedDecMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedAddMutator; pub struct EncodedAddMutator;
impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedAddMutator { impl<S: HasRand> Mutator<EncodedInput, S> for EncodedAddMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -167,7 +167,7 @@ impl EncodedAddMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedDeleteMutator; pub struct EncodedDeleteMutator;
impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedDeleteMutator { impl<S: HasRand> Mutator<EncodedInput, S> for EncodedDeleteMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -207,9 +207,9 @@ pub struct EncodedInsertCopyMutator {
tmp_buf: Vec<u32>, tmp_buf: Vec<u32>,
} }
impl<S> Mutator<S> for EncodedInsertCopyMutator impl<S> Mutator<EncodedInput, S> for EncodedInsertCopyMutator
where where
S: UsesInput<Input = EncodedInput> + HasRand + HasMaxSize, S: HasRand + HasMaxSize,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -268,7 +268,7 @@ impl EncodedInsertCopyMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedCopyMutator; pub struct EncodedCopyMutator;
impl<S: UsesInput<Input = EncodedInput> + HasRand> Mutator<S> for EncodedCopyMutator { impl<S: HasRand> Mutator<EncodedInput, S> for EncodedCopyMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -308,7 +308,7 @@ impl EncodedCopyMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedCrossoverInsertMutator; pub struct EncodedCrossoverInsertMutator;
impl<S> Mutator<S> for EncodedCrossoverInsertMutator impl<S> Mutator<S::Input, S> for EncodedCrossoverInsertMutator
where where
S: UsesInput<Input = EncodedInput> + HasRand + HasCorpus + HasMaxSize, S: UsesInput<Input = EncodedInput> + HasRand + HasCorpus + HasMaxSize,
{ {
@ -381,7 +381,7 @@ impl EncodedCrossoverInsertMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedCrossoverReplaceMutator; pub struct EncodedCrossoverReplaceMutator;
impl<S> Mutator<S> for EncodedCrossoverReplaceMutator impl<S> Mutator<S::Input, S> for EncodedCrossoverReplaceMutator
where where
S: UsesInput<Input = EncodedInput> + HasRand + HasCorpus, S: UsesInput<Input = EncodedInput> + HasRand + HasCorpus,
{ {

View File

@ -10,7 +10,7 @@ use crate::{
bolts::{rands::Rand, tuples::Named}, bolts::{rands::Rand, tuples::Named},
corpus::Corpus, corpus::Corpus,
generators::GramatronGenerator, generators::GramatronGenerator,
inputs::{GramatronInput, Terminal, UsesInput}, inputs::{GramatronInput, Terminal},
mutators::{MutationResult, Mutator}, mutators::{MutationResult, Mutator},
random_corpus_id, random_corpus_id,
state::{HasCorpus, HasMetadata, HasRand}, state::{HasCorpus, HasMetadata, HasRand},
@ -28,9 +28,9 @@ where
generator: &'a GramatronGenerator<'a, S>, generator: &'a GramatronGenerator<'a, S>,
} }
impl<'a, S> Mutator<S> for GramatronRandomMutator<'a, S> impl<'a, S> Mutator<GramatronInput, S> for GramatronRandomMutator<'a, S>
where where
S: UsesInput<Input = GramatronInput> + HasRand + HasMetadata, S: HasRand + HasMetadata,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -97,9 +97,9 @@ impl GramatronIdxMapMetadata {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct GramatronSpliceMutator; pub struct GramatronSpliceMutator;
impl<S> Mutator<S> for GramatronSpliceMutator impl<S> Mutator<S::Input, S> for GramatronSpliceMutator
where where
S: UsesInput<Input = GramatronInput> + HasRand + HasCorpus + HasMetadata, S: HasRand + HasCorpus<Input = GramatronInput> + HasMetadata,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -169,9 +169,9 @@ pub struct GramatronRecursionMutator {
feature: Vec<Terminal>, feature: Vec<Terminal>,
} }
impl<S> Mutator<S> for GramatronRecursionMutator impl<S> Mutator<GramatronInput, S> for GramatronRecursionMutator
where where
S: UsesInput<Input = GramatronInput> + HasRand + HasMetadata, S: HasRand + HasMetadata,
{ {
fn mutate( fn mutate(
&mut self, &mut self,

View File

@ -7,7 +7,7 @@ use core::cmp::{max, min};
use crate::{ use crate::{
bolts::{rands::Rand, tuples::Named}, bolts::{rands::Rand, tuples::Named},
corpus::Corpus, corpus::Corpus,
inputs::{GeneralizedInput, GeneralizedItem, UsesInput}, inputs::{GeneralizedInputMetadata, GeneralizedItem},
mutators::{token_mutations::Tokens, MutationResult, Mutator}, mutators::{token_mutations::Tokens, MutationResult, Mutator},
stages::generalization::GeneralizedIndexesMetadata, stages::generalization::GeneralizedIndexesMetadata,
state::{HasCorpus, HasMetadata, HasRand}, state::{HasCorpus, HasMetadata, HasRand},
@ -24,7 +24,7 @@ fn extend_with_random_generalized<S>(
gap_indices: &mut Vec<usize>, gap_indices: &mut Vec<usize>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
S: HasMetadata + HasRand + HasCorpus<Input = GeneralizedInput>, S: HasMetadata + HasRand + HasCorpus,
{ {
let rand_idx = state.rand_mut().next() as usize; let rand_idx = state.rand_mut().next() as usize;
@ -40,50 +40,42 @@ where
.unwrap() .unwrap()
}; };
/*if state
.corpus()
.get(idx)?
.borrow_mut()
.load_input()?
.generalized()
.is_none()
{
return Ok(true);
}*/
if state.rand_mut().below(100) > CHOOSE_SUBINPUT_PROB { if state.rand_mut().below(100) > CHOOSE_SUBINPUT_PROB {
if state.rand_mut().below(100) < 50 { if state.rand_mut().below(100) < 50 {
let rand1 = state.rand_mut().next() as usize; let rand1 = state.rand_mut().next() as usize;
let rand2 = state.rand_mut().next() as usize; let rand2 = state.rand_mut().next() as usize;
let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
let other = other_testcase.load_input()?; if let Some(other) = other_testcase
.metadata_mut()
.get::<GeneralizedInputMetadata>()
{
if other.generalized_len() > 0 {
let gen = other.generalized();
if other.generalized_len() > 0 { for (i, _) in gen
let gen = other.generalized().unwrap(); .iter()
.enumerate()
.filter(|&(_, x)| *x == GeneralizedItem::Gap)
{
gap_indices.push(i);
}
let min_idx = gap_indices[rand1 % gap_indices.len()];
let max_idx = gap_indices[rand2 % gap_indices.len()];
let (mut min_idx, max_idx) = (min(min_idx, max_idx), max(min_idx, max_idx));
for (i, _) in gen gap_indices.clear();
.iter()
.enumerate() if items.last() == Some(&GeneralizedItem::Gap) {
.filter(|&(_, x)| *x == GeneralizedItem::Gap) min_idx += 1;
{ }
gap_indices.push(i); items.extend_from_slice(&gen[min_idx..=max_idx]);
debug_assert!(items.first() == Some(&GeneralizedItem::Gap));
debug_assert!(items.last() == Some(&GeneralizedItem::Gap));
return Ok(());
} }
let min_idx = gap_indices[rand1 % gap_indices.len()];
let max_idx = gap_indices[rand2 % gap_indices.len()];
let (mut min_idx, max_idx) = (min(min_idx, max_idx), max(min_idx, max_idx));
gap_indices.clear();
if items.last() == Some(&GeneralizedItem::Gap) {
min_idx += 1;
}
items.extend_from_slice(&gen[min_idx..=max_idx]);
debug_assert!(items.first() == Some(&GeneralizedItem::Gap));
debug_assert!(items.last() == Some(&GeneralizedItem::Gap));
return Ok(());
} }
} }
@ -107,8 +99,11 @@ where
} }
let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
let other = other_testcase.load_input()?; let other = other_testcase
let gen = other.generalized().unwrap(); .metadata_mut()
.get::<GeneralizedInputMetadata>()
.unwrap();
let gen = other.generalized();
if items.last() == Some(&GeneralizedItem::Gap) && gen.first() == Some(&GeneralizedItem::Gap) { if items.last() == Some(&GeneralizedItem::Gap) && gen.first() == Some(&GeneralizedItem::Gap) {
items.extend_from_slice(&gen[1..]); items.extend_from_slice(&gen[1..]);
@ -128,27 +123,22 @@ pub struct GrimoireExtensionMutator {
gap_indices: Vec<usize>, gap_indices: Vec<usize>,
} }
impl<S> Mutator<S> for GrimoireExtensionMutator impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireExtensionMutator
where where
S: UsesInput<Input = GeneralizedInput> + HasMetadata + HasRand + HasCorpus, S: HasMetadata + HasRand + HasCorpus,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut GeneralizedInput, generalised_meta: &mut GeneralizedInputMetadata,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.generalized().is_none() {
return Ok(MutationResult::Skipped);
}
extend_with_random_generalized( extend_with_random_generalized(
state, state,
input.generalized_mut().as_mut().unwrap(), generalised_meta.generalized_mut(),
&mut self.gap_indices, &mut self.gap_indices,
)?; )?;
input.grimoire_mutated = true;
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
} }
@ -176,29 +166,25 @@ pub struct GrimoireRecursiveReplacementMutator {
gap_indices: Vec<usize>, gap_indices: Vec<usize>,
} }
impl<S> Mutator<S> for GrimoireRecursiveReplacementMutator impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireRecursiveReplacementMutator
where where
S: UsesInput<Input = GeneralizedInput> + HasMetadata + HasRand + HasCorpus, S: HasMetadata + HasRand + HasCorpus,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut GeneralizedInput, generalised_meta: &mut GeneralizedInputMetadata,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.generalized().is_none() {
return Ok(MutationResult::Skipped);
}
let mut mutated = MutationResult::Skipped; let mut mutated = MutationResult::Skipped;
let depth = *state.rand_mut().choose(&RECURSIVE_REPLACEMENT_DEPTH); let depth = *state.rand_mut().choose(&RECURSIVE_REPLACEMENT_DEPTH);
for _ in 0..depth { for _ in 0..depth {
if input.generalized_len() >= MAX_RECURSIVE_REPLACEMENT_LEN { if generalised_meta.generalized_len() >= MAX_RECURSIVE_REPLACEMENT_LEN {
break; break;
} }
let gen = input.generalized_mut().as_mut().unwrap(); let gen = generalised_meta.generalized_mut();
for (i, _) in gen for (i, _) in gen
.iter() .iter()
@ -207,6 +193,9 @@ where
{ {
self.gap_indices.push(i); self.gap_indices.push(i);
} }
if self.gap_indices.is_empty() {
break;
}
let selected = *state.rand_mut().choose(&self.gap_indices); let selected = *state.rand_mut().choose(&self.gap_indices);
self.gap_indices.clear(); self.gap_indices.clear();
@ -219,7 +208,6 @@ where
self.scratch.clear(); self.scratch.clear();
mutated = MutationResult::Mutated; mutated = MutationResult::Mutated;
input.grimoire_mutated = true;
} }
Ok(mutated) Ok(mutated)
@ -247,30 +235,28 @@ impl GrimoireRecursiveReplacementMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct GrimoireStringReplacementMutator {} pub struct GrimoireStringReplacementMutator {}
impl<S> Mutator<S> for GrimoireStringReplacementMutator impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireStringReplacementMutator
where where
S: UsesInput<Input = GeneralizedInput> + HasMetadata + HasRand, S: HasMetadata + HasRand + HasCorpus,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut GeneralizedInput, generalised_meta: &mut GeneralizedInputMetadata,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.generalized().is_none() {
return Ok(MutationResult::Skipped);
}
let tokens_len = { let tokens_len = {
let meta = state.metadata().get::<Tokens>(); let meta = state.metadata().get::<Tokens>();
if meta.is_none() { if let Some(tokens) = meta {
if tokens.is_empty() {
return Ok(MutationResult::Skipped);
}
tokens.tokens().len()
} else {
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
if meta.unwrap().tokens().is_empty() {
return Ok(MutationResult::Skipped);
}
meta.unwrap().tokens().len()
}; };
let token_find = state.rand_mut().below(tokens_len as u64) as usize; let token_find = state.rand_mut().below(tokens_len as u64) as usize;
let mut token_replace = state.rand_mut().below(tokens_len as u64) as usize; let mut token_replace = state.rand_mut().below(tokens_len as u64) as usize;
if token_find == token_replace { if token_find == token_replace {
@ -286,7 +272,7 @@ where
let mut mutated = MutationResult::Skipped; let mut mutated = MutationResult::Skipped;
let gen = input.generalized_mut().as_mut().unwrap(); let gen = generalised_meta.generalized_mut();
rand_idx %= gen.len(); rand_idx %= gen.len();
'first: for item in &mut gen[..rand_idx] { 'first: for item in &mut gen[..rand_idx] {
@ -330,7 +316,6 @@ where
} }
} }
input.grimoire_mutated = true;
Ok(mutated) Ok(mutated)
} }
} }
@ -355,22 +340,17 @@ pub struct GrimoireRandomDeleteMutator {
gap_indices: Vec<usize>, gap_indices: Vec<usize>,
} }
impl<S> Mutator<S> for GrimoireRandomDeleteMutator impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireRandomDeleteMutator
where where
S: UsesInput<Input = GeneralizedInput> + HasMetadata + HasRand + HasCorpus, S: HasMetadata + HasRand + HasCorpus,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut GeneralizedInput, generalised_meta: &mut GeneralizedInputMetadata,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.generalized().is_none() { let gen = generalised_meta.generalized_mut();
return Ok(MutationResult::Skipped);
}
input.grimoire_mutated = true;
let gen = input.generalized_mut().as_mut().unwrap();
for (i, _) in gen for (i, _) in gen
.iter() .iter()
@ -387,12 +367,14 @@ where
self.gap_indices.clear(); self.gap_indices.clear();
if min_idx == max_idx { let result = if min_idx == max_idx {
Ok(MutationResult::Skipped) MutationResult::Skipped
} else { } else {
gen.drain(min_idx..max_idx); gen.drain(min_idx..max_idx);
Ok(MutationResult::Mutated) MutationResult::Mutated
} };
Ok(result)
} }
} }

View File

@ -25,7 +25,6 @@ pub use nautilus::*;
use crate::{ use crate::{
bolts::tuples::{HasConstLen, Named}, bolts::tuples::{HasConstLen, Named},
corpus::CorpusId, corpus::CorpusId,
inputs::UsesInput,
Error, Error,
}; };
@ -45,15 +44,12 @@ pub enum MutationResult {
/// A mutator takes input, and mutates it. /// A mutator takes input, and mutates it.
/// Simple as that. /// Simple as that.
pub trait Mutator<S> pub trait Mutator<I, S> {
where
S: UsesInput,
{
/// Mutate a given input /// Mutate a given input
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error>; ) -> Result<MutationResult, Error>;
@ -69,15 +65,12 @@ where
} }
/// A `Tuple` of `Mutators` that can execute multiple `Mutators` in a row. /// A `Tuple` of `Mutators` that can execute multiple `Mutators` in a row.
pub trait MutatorsTuple<S>: HasConstLen pub trait MutatorsTuple<I, S>: HasConstLen {
where
S: UsesInput,
{
/// Runs the `mutate` function on all `Mutators` in this `Tuple`. /// Runs the `mutate` function on all `Mutators` in this `Tuple`.
fn mutate_all( fn mutate_all(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error>; ) -> Result<MutationResult, Error>;
@ -94,7 +87,7 @@ where
&mut self, &mut self,
index: usize, index: usize,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error>; ) -> Result<MutationResult, Error>;
@ -108,14 +101,11 @@ where
) -> Result<(), Error>; ) -> Result<(), Error>;
} }
impl<S> MutatorsTuple<S> for () impl<I, S> MutatorsTuple<I, S> for () {
where
S: UsesInput,
{
fn mutate_all( fn mutate_all(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_input: &mut S::Input, _input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
Ok(MutationResult::Skipped) Ok(MutationResult::Skipped)
@ -134,7 +124,7 @@ where
&mut self, &mut self,
_index: usize, _index: usize,
_state: &mut S, _state: &mut S,
_input: &mut S::Input, _input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
Ok(MutationResult::Skipped) Ok(MutationResult::Skipped)
@ -151,16 +141,15 @@ where
} }
} }
impl<Head, Tail, S> MutatorsTuple<S> for (Head, Tail) impl<Head, Tail, I, S> MutatorsTuple<I, S> for (Head, Tail)
where where
Head: Mutator<S> + Named, Head: Mutator<I, S> + Named,
Tail: MutatorsTuple<S>, Tail: MutatorsTuple<I, S>,
S: UsesInput,
{ {
fn mutate_all( fn mutate_all(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let r = self.0.mutate(state, input, stage_idx)?; let r = self.0.mutate(state, input, stage_idx)?;
@ -185,7 +174,7 @@ where
&mut self, &mut self,
index: usize, index: usize,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if index == 0 { if index == 0 {
@ -238,7 +227,7 @@ pub mod pybind {
} }
} }
impl Mutator<PythonStdState> for PyObjectMutator { impl Mutator<BytesInput, PythonStdState> for PyObjectMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut PythonStdState, state: &mut PythonStdState,
@ -337,7 +326,7 @@ pub mod pybind {
} }
} }
impl Mutator<PythonStdState> for PythonMutator { impl Mutator<BytesInput, PythonStdState> for PythonMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut PythonStdState, state: &mut PythonStdState,

View File

@ -359,21 +359,21 @@ pub enum MOptMode {
/// This is the main struct of `MOpt`, an `AFL` mutator. /// This is the main struct of `MOpt`, an `AFL` mutator.
/// See the original `MOpt` implementation in <https://github.com/puppet-meteor/MOpt-AFL> /// See the original `MOpt` implementation in <https://github.com/puppet-meteor/MOpt-AFL>
pub struct StdMOptMutator<MT, S> pub struct StdMOptMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: HasRand + HasMetadata + HasCorpus + HasSolutions, S: HasRand + HasMetadata + HasCorpus + HasSolutions,
{ {
mode: MOptMode, mode: MOptMode,
finds_before: usize, finds_before: usize,
mutations: MT, mutations: MT,
max_stack_pow: u64, max_stack_pow: u64,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl<MT, S> Debug for StdMOptMutator<MT, S> impl<I, MT, S> Debug for StdMOptMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: HasRand + HasMetadata + HasCorpus + HasSolutions, S: HasRand + HasMetadata + HasCorpus + HasSolutions,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -381,21 +381,21 @@ where
f, f,
"StdMOptMutator with {} mutations for Input type {}", "StdMOptMutator with {} mutations for Input type {}",
self.mutations.len(), self.mutations.len(),
core::any::type_name::<S::Input>() core::any::type_name::<I>()
) )
} }
} }
impl<MT, S> Mutator<S> for StdMOptMutator<MT, S> impl<I, MT, S> Mutator<I, S> for StdMOptMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: HasRand + HasMetadata + HasCorpus + HasSolutions, S: HasRand + HasMetadata + HasCorpus + HasSolutions,
{ {
#[inline] #[inline]
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
self.finds_before = state.corpus().count() + state.solutions().count(); self.finds_before = state.corpus().count() + state.solutions().count();
@ -521,9 +521,9 @@ where
} }
} }
impl<MT, S> StdMOptMutator<MT, S> impl<I, MT, S> StdMOptMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: HasRand + HasMetadata + HasCorpus + HasSolutions, S: HasRand + HasMetadata + HasCorpus + HasSolutions,
{ {
/// Create a new [`StdMOptMutator`]. /// Create a new [`StdMOptMutator`].
@ -548,7 +548,7 @@ where
fn core_mutate( fn core_mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let mut r = MutationResult::Skipped; let mut r = MutationResult::Skipped;
@ -578,7 +578,7 @@ where
fn pilot_mutate( fn pilot_mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let mut r = MutationResult::Skipped; let mut r = MutationResult::Skipped;
@ -613,9 +613,9 @@ where
} }
} }
impl<MT, S> ComposedByMutations<MT, S> for StdMOptMutator<MT, S> impl<I, MT, S> ComposedByMutations<I, MT, S> for StdMOptMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: HasRand + HasMetadata + HasCorpus + HasSolutions, S: HasRand + HasMetadata + HasCorpus + HasSolutions,
{ {
/// Get the mutations /// Get the mutations
@ -631,19 +631,19 @@ where
} }
} }
impl<MT, S> ScheduledMutator<MT, S> for StdMOptMutator<MT, S> impl<I, MT, S> ScheduledMutator<I, MT, S> for StdMOptMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: HasRand + HasMetadata + HasCorpus + HasSolutions, S: HasRand + HasMetadata + HasCorpus + HasSolutions,
{ {
/// Compute the number of iterations used to apply stacked mutations /// Compute the number of iterations used to apply stacked mutations
fn iterations(&self, state: &mut S, _: &S::Input) -> u64 { fn iterations(&self, state: &mut S, _: &I) -> u64 {
1 << (1 + state.rand_mut().below(self.max_stack_pow)) 1 << (1 + state.rand_mut().below(self.max_stack_pow))
} }
/// Get the next mutation to apply /// Get the next mutation to apply
#[inline] #[inline]
fn schedule(&self, state: &mut S, _: &S::Input) -> usize { fn schedule(&self, state: &mut S, _: &I) -> usize {
state state
.metadata_mut() .metadata_mut()
.get_mut::<MOpt>() .get_mut::<MOpt>()
@ -655,7 +655,7 @@ where
fn scheduled_mutate( fn scheduled_mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let mode = self.mode; let mode = self.mode;

View File

@ -9,7 +9,7 @@ use core::{
use crate::{ use crate::{
bolts::{rands::Rand, tuples::Named}, bolts::{rands::Rand, tuples::Named},
corpus::Corpus, corpus::Corpus,
inputs::{HasBytesVec, UsesInput}, inputs::HasBytesVec,
mutators::{MutationResult, Mutator}, mutators::{MutationResult, Mutator},
random_corpus_id, random_corpus_id,
state::{HasCorpus, HasMaxSize, HasRand}, state::{HasCorpus, HasMaxSize, HasRand},
@ -101,15 +101,15 @@ pub const INTERESTING_32: [i32; 27] = [
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BitFlipMutator; pub struct BitFlipMutator;
impl<S> Mutator<S> for BitFlipMutator impl<I, S> Mutator<I, S> for BitFlipMutator
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut <S as UsesInput>::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -141,15 +141,15 @@ impl BitFlipMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ByteFlipMutator; pub struct ByteFlipMutator;
impl<S> Mutator<S> for ByteFlipMutator impl<I, S> Mutator<I, S> for ByteFlipMutator
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -179,15 +179,15 @@ impl ByteFlipMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ByteIncMutator; pub struct ByteIncMutator;
impl<S> Mutator<S> for ByteIncMutator impl<I, S> Mutator<I, S> for ByteIncMutator
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -218,15 +218,15 @@ impl ByteIncMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ByteDecMutator; pub struct ByteDecMutator;
impl<S> Mutator<S> for ByteDecMutator impl<I, S> Mutator<I, S> for ByteDecMutator
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -257,15 +257,15 @@ impl ByteDecMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ByteNegMutator; pub struct ByteNegMutator;
impl<S> Mutator<S> for ByteNegMutator impl<I, S> Mutator<I, S> for ByteNegMutator
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -296,15 +296,15 @@ impl ByteNegMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ByteRandMutator; pub struct ByteRandMutator;
impl<S> Mutator<S> for ByteRandMutator impl<I, S> Mutator<I, S> for ByteRandMutator
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -340,15 +340,15 @@ macro_rules! add_mutator_impl {
pub struct $name; pub struct $name;
#[allow(trivial_numeric_casts)] #[allow(trivial_numeric_casts)]
impl<S> Mutator<S> for $name impl<I, S> Mutator<I, S> for $name
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().len() < size_of::<$size>() { if input.bytes().len() < size_of::<$size>() {
@ -406,16 +406,16 @@ macro_rules! interesting_mutator_impl {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct $name; pub struct $name;
impl<S> Mutator<S> for $name impl<I, S> Mutator<I, S> for $name
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().len() < size_of::<$size>() { if input.bytes().len() < size_of::<$size>() {
@ -459,15 +459,15 @@ interesting_mutator_impl!(DwordInterestingMutator, u32, INTERESTING_32);
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesDeleteMutator; pub struct BytesDeleteMutator;
impl<S> Mutator<S> for BytesDeleteMutator impl<I, S> Mutator<I, S> for BytesDeleteMutator
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -501,15 +501,15 @@ impl BytesDeleteMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesExpandMutator; pub struct BytesExpandMutator;
impl<S> Mutator<S> for BytesExpandMutator impl<I, S> Mutator<I, S> for BytesExpandMutator
where where
S: UsesInput + HasRand + HasMaxSize, S: HasRand + HasMaxSize,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -550,15 +550,15 @@ impl BytesExpandMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesInsertMutator; pub struct BytesInsertMutator;
impl<S> Mutator<S> for BytesInsertMutator impl<I, S> Mutator<I, S> for BytesInsertMutator
where where
S: UsesInput + HasRand + HasMaxSize, S: HasRand + HasMaxSize,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -605,15 +605,15 @@ impl BytesInsertMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesRandInsertMutator; pub struct BytesRandInsertMutator;
impl<S> Mutator<S> for BytesRandInsertMutator impl<I, S> Mutator<I, S> for BytesRandInsertMutator
where where
S: UsesInput + HasRand + HasMaxSize, S: HasRand + HasMaxSize,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -657,15 +657,15 @@ impl BytesRandInsertMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesSetMutator; pub struct BytesSetMutator;
impl<S> Mutator<S> for BytesSetMutator impl<I, S> Mutator<I, S> for BytesSetMutator
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -701,15 +701,15 @@ impl BytesSetMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesRandSetMutator; pub struct BytesRandSetMutator;
impl<S> Mutator<S> for BytesRandSetMutator impl<I, S> Mutator<I, S> for BytesRandSetMutator
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -745,15 +745,15 @@ impl BytesRandSetMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesCopyMutator; pub struct BytesCopyMutator;
impl<S> Mutator<S> for BytesCopyMutator impl<I, S> Mutator<I, S> for BytesCopyMutator
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -791,15 +791,15 @@ pub struct BytesInsertCopyMutator {
tmp_buf: Vec<u8>, tmp_buf: Vec<u8>,
} }
impl<S> Mutator<S> for BytesInsertCopyMutator impl<I, S> Mutator<I, S> for BytesInsertCopyMutator
where where
S: UsesInput + HasRand + HasMaxSize, S: HasRand + HasMaxSize,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -853,15 +853,15 @@ impl BytesInsertCopyMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct BytesSwapMutator; pub struct BytesSwapMutator;
impl<S> Mutator<S> for BytesSwapMutator impl<I, S> Mutator<I, S> for BytesSwapMutator
where where
S: UsesInput + HasRand, S: HasRand,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -899,7 +899,7 @@ impl BytesSwapMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct CrossoverInsertMutator; pub struct CrossoverInsertMutator;
impl<S> Mutator<S> for CrossoverInsertMutator impl<S> Mutator<S::Input, S> for CrossoverInsertMutator
where where
S: HasCorpus + HasRand + HasMaxSize, S: HasCorpus + HasRand + HasMaxSize,
S::Input: HasBytesVec, S::Input: HasBytesVec,
@ -974,7 +974,7 @@ impl CrossoverInsertMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct CrossoverReplaceMutator; pub struct CrossoverReplaceMutator;
impl<S> Mutator<S> for CrossoverReplaceMutator impl<S> Mutator<S::Input, S> for CrossoverReplaceMutator
where where
S: HasCorpus + HasRand, S: HasCorpus + HasRand,
S::Input: HasBytesVec, S::Input: HasBytesVec,
@ -1056,7 +1056,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct SpliceMutator; pub struct SpliceMutator;
impl<S> Mutator<S> for SpliceMutator impl<S> Mutator<S::Input, S> for SpliceMutator
where where
S: HasCorpus + HasRand, S: HasCorpus + HasRand,
S::Input: HasBytesVec, S::Input: HasBytesVec,
@ -1178,10 +1178,10 @@ mod tests {
state::{HasMetadata, StdState}, state::{HasMetadata, StdState},
}; };
fn test_mutations<S>() -> impl MutatorsTuple<S> fn test_mutations<I, S>() -> impl MutatorsTuple<I, S>
where where
S: HasRand + HasCorpus + HasMetadata + HasMaxSize, S: HasRand + HasMetadata + HasMaxSize,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
tuple_list!( tuple_list!(
BitFlipMutator::new(), BitFlipMutator::new(),

View File

@ -14,7 +14,6 @@ use crate::{
generators::nautilus::NautilusContext, generators::nautilus::NautilusContext,
inputs::nautilus::NautilusInput, inputs::nautilus::NautilusInput,
mutators::{MutationResult, Mutator}, mutators::{MutationResult, Mutator},
prelude::UsesInput,
state::{HasCorpus, HasMetadata}, state::{HasCorpus, HasMetadata},
Error, Error,
}; };
@ -31,10 +30,7 @@ impl Debug for NautilusRandomMutator<'_> {
} }
} }
impl<S> Mutator<S> for NautilusRandomMutator<'_> impl<S> Mutator<NautilusInput, S> for NautilusRandomMutator<'_> {
where
S: UsesInput<Input = NautilusInput>,
{
fn mutate( fn mutate(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
@ -95,10 +91,7 @@ impl Debug for NautilusRecursionMutator<'_> {
} }
} }
impl<S> Mutator<S> for NautilusRecursionMutator<'_> impl<S> Mutator<NautilusInput, S> for NautilusRecursionMutator<'_> {
where
S: UsesInput<Input = NautilusInput>,
{
fn mutate( fn mutate(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
@ -161,9 +154,9 @@ impl Debug for NautilusSpliceMutator<'_> {
} }
} }
impl<S> Mutator<S> for NautilusSpliceMutator<'_> impl<S> Mutator<NautilusInput, S> for NautilusSpliceMutator<'_>
where where
S: HasCorpus + HasMetadata + UsesInput<Input = NautilusInput>, S: HasCorpus<Input = NautilusInput> + HasMetadata,
{ {
fn mutate( fn mutate(
&mut self, &mut self,

View File

@ -16,9 +16,8 @@ use crate::{
AsMutSlice, AsSlice, AsMutSlice, AsSlice,
}, },
corpus::{Corpus, CorpusId}, corpus::{Corpus, CorpusId},
inputs::UsesInput,
mutators::{MutationResult, Mutator, MutatorsTuple}, mutators::{MutationResult, Mutator, MutatorsTuple},
state::{HasCorpus, HasMetadata, HasRand, State}, state::{HasCorpus, HasMetadata, HasRand},
Error, Error,
}; };
@ -55,10 +54,9 @@ impl LogMutationMetadata {
} }
/// A [`Mutator`] that composes multiple mutations into one. /// A [`Mutator`] that composes multiple mutations into one.
pub trait ComposedByMutations<MT, S> pub trait ComposedByMutations<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: UsesInput,
{ {
/// Get the mutations /// Get the mutations
fn mutations(&self) -> &MT; fn mutations(&self) -> &MT;
@ -68,23 +66,22 @@ where
} }
/// A [`Mutator`] scheduling multiple [`Mutator`]s for an input. /// A [`Mutator`] scheduling multiple [`Mutator`]s for an input.
pub trait ScheduledMutator<MT, S>: ComposedByMutations<MT, S> + Mutator<S> pub trait ScheduledMutator<I, MT, S>: ComposedByMutations<I, MT, S> + Mutator<I, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: UsesInput,
{ {
/// Compute the number of iterations used to apply stacked mutations /// Compute the number of iterations used to apply stacked mutations
fn iterations(&self, state: &mut S, input: &S::Input) -> u64; fn iterations(&self, state: &mut S, input: &I) -> u64;
/// Get the next mutation to apply /// Get the next mutation to apply
fn schedule(&self, state: &mut S, input: &S::Input) -> usize; fn schedule(&self, state: &mut S, input: &I) -> usize;
/// New default implementation for mutate. /// New default implementation for mutate.
/// Implementations must forward mutate() to this method /// Implementations must forward mutate() to this method
fn scheduled_mutate( fn scheduled_mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let mut r = MutationResult::Skipped; let mut r = MutationResult::Skipped;
@ -103,51 +100,51 @@ where
} }
/// A [`Mutator`] that schedules one of the embedded mutations on each call. /// A [`Mutator`] that schedules one of the embedded mutations on each call.
pub struct StdScheduledMutator<MT, S> pub struct StdScheduledMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: State + HasRand, S: HasRand,
{ {
mutations: MT, mutations: MT,
max_stack_pow: u64, max_stack_pow: u64,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl<MT, S> Debug for StdScheduledMutator<MT, S> impl<I, MT, S> Debug for StdScheduledMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: State + HasRand, S: HasRand,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"StdScheduledMutator with {} mutations for Input type {}", "StdScheduledMutator with {} mutations for Input type {}",
self.mutations.len(), self.mutations.len(),
core::any::type_name::<S::Input>() core::any::type_name::<I>()
) )
} }
} }
impl<MT, S> Mutator<S> for StdScheduledMutator<MT, S> impl<I, MT, S> Mutator<I, S> for StdScheduledMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: State + HasRand, S: HasRand,
{ {
#[inline] #[inline]
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
self.scheduled_mutate(state, input, stage_idx) self.scheduled_mutate(state, input, stage_idx)
} }
} }
impl<MT, S> ComposedByMutations<MT, S> for StdScheduledMutator<MT, S> impl<I, MT, S> ComposedByMutations<I, MT, S> for StdScheduledMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: State + HasRand, S: HasRand,
{ {
/// Get the mutations /// Get the mutations
#[inline] #[inline]
@ -162,27 +159,27 @@ where
} }
} }
impl<MT, S> ScheduledMutator<MT, S> for StdScheduledMutator<MT, S> impl<I, MT, S> ScheduledMutator<I, MT, S> for StdScheduledMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: State + HasRand, S: HasRand,
{ {
/// Compute the number of iterations used to apply stacked mutations /// Compute the number of iterations used to apply stacked mutations
fn iterations(&self, state: &mut S, _: &S::Input) -> u64 { fn iterations(&self, state: &mut S, _: &I) -> u64 {
1 << (1 + state.rand_mut().below(self.max_stack_pow)) 1 << (1 + state.rand_mut().below(self.max_stack_pow))
} }
/// Get the next mutation to apply /// Get the next mutation to apply
fn schedule(&self, state: &mut S, _: &S::Input) -> usize { fn schedule(&self, state: &mut S, _: &I) -> usize {
debug_assert!(!self.mutations().is_empty()); debug_assert!(!self.mutations().is_empty());
state.rand_mut().below(self.mutations().len() as u64) as usize state.rand_mut().below(self.mutations().len() as u64) as usize
} }
} }
impl<MT, S> StdScheduledMutator<MT, S> impl<I, MT, S> StdScheduledMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: State + HasRand, S: HasRand,
{ {
/// Create a new [`StdScheduledMutator`] instance specifying mutations /// Create a new [`StdScheduledMutator`] instance specifying mutations
pub fn new(mutations: MT) -> Self { pub fn new(mutations: MT) -> Self {
@ -275,43 +272,43 @@ pub fn tokens_mutations() -> tuple_list_type!(TokenInsert, TokenReplace) {
} }
/// A logging [`Mutator`] that wraps around a [`StdScheduledMutator`]. /// A logging [`Mutator`] that wraps around a [`StdScheduledMutator`].
pub struct LoggerScheduledMutator<MT, S, SM> pub struct LoggerScheduledMutator<I, MT, S, SM>
where where
MT: MutatorsTuple<S> + NamedTuple, MT: MutatorsTuple<I, S> + NamedTuple,
S: UsesInput + HasRand + HasCorpus, S: HasRand + HasCorpus,
SM: ScheduledMutator<MT, S>, SM: ScheduledMutator<I, MT, S>,
{ {
scheduled: SM, scheduled: SM,
mutation_log: Vec<usize>, mutation_log: Vec<usize>,
phantom: PhantomData<(MT, S)>, phantom: PhantomData<(I, MT, S)>,
} }
impl<MT, S, SM> Debug for LoggerScheduledMutator<MT, S, SM> impl<I, MT, S, SM> Debug for LoggerScheduledMutator<I, MT, S, SM>
where where
MT: MutatorsTuple<S> + NamedTuple, MT: MutatorsTuple<I, S> + NamedTuple,
S: UsesInput + HasRand + HasCorpus, S: HasRand + HasCorpus,
SM: ScheduledMutator<MT, S>, SM: ScheduledMutator<I, MT, S>,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"LoggerScheduledMutator with {} mutations for Input type {}", "LoggerScheduledMutator with {} mutations for Input type {}",
self.scheduled.mutations().len(), self.scheduled.mutations().len(),
core::any::type_name::<<S as UsesInput>::Input>() core::any::type_name::<I>()
) )
} }
} }
impl<MT, S, SM> Mutator<S> for LoggerScheduledMutator<MT, S, SM> impl<I, MT, S, SM> Mutator<I, S> for LoggerScheduledMutator<I, MT, S, SM>
where where
MT: MutatorsTuple<S> + NamedTuple, MT: MutatorsTuple<I, S> + NamedTuple,
S: State + HasRand + HasCorpus, S: HasRand + HasCorpus,
SM: ScheduledMutator<MT, S>, SM: ScheduledMutator<I, MT, S>,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut <S as UsesInput>::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
self.scheduled_mutate(state, input, stage_idx) self.scheduled_mutate(state, input, stage_idx)
@ -339,11 +336,11 @@ where
} }
} }
impl<MT, S, SM> ComposedByMutations<MT, S> for LoggerScheduledMutator<MT, S, SM> impl<I, MT, S, SM> ComposedByMutations<I, MT, S> for LoggerScheduledMutator<I, MT, S, SM>
where where
MT: MutatorsTuple<S> + NamedTuple, MT: MutatorsTuple<I, S> + NamedTuple,
S: State + HasRand + HasCorpus, S: HasRand + HasCorpus,
SM: ScheduledMutator<MT, S>, SM: ScheduledMutator<I, MT, S>,
{ {
#[inline] #[inline]
fn mutations(&self) -> &MT { fn mutations(&self) -> &MT {
@ -356,19 +353,19 @@ where
} }
} }
impl<MT, S, SM> ScheduledMutator<MT, S> for LoggerScheduledMutator<MT, S, SM> impl<I, MT, S, SM> ScheduledMutator<I, MT, S> for LoggerScheduledMutator<I, MT, S, SM>
where where
MT: MutatorsTuple<S> + NamedTuple, MT: MutatorsTuple<I, S> + NamedTuple,
S: State + HasRand + HasCorpus, S: HasRand + HasCorpus,
SM: ScheduledMutator<MT, S>, SM: ScheduledMutator<I, MT, S>,
{ {
/// Compute the number of iterations used to apply stacked mutations /// Compute the number of iterations used to apply stacked mutations
fn iterations(&self, state: &mut S, _: &<S as UsesInput>::Input) -> u64 { fn iterations(&self, state: &mut S, _: &I) -> u64 {
1 << (1 + state.rand_mut().below(6)) 1 << (1 + state.rand_mut().below(6))
} }
/// Get the next mutation to apply /// Get the next mutation to apply
fn schedule(&self, state: &mut S, _: &<S as UsesInput>::Input) -> usize { fn schedule(&self, state: &mut S, _: &I) -> usize {
debug_assert!(!self.scheduled.mutations().is_empty()); debug_assert!(!self.scheduled.mutations().is_empty());
state state
.rand_mut() .rand_mut()
@ -378,7 +375,7 @@ where
fn scheduled_mutate( fn scheduled_mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut <S as UsesInput>::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let mut r = MutationResult::Skipped; let mut r = MutationResult::Skipped;
@ -398,11 +395,11 @@ where
} }
} }
impl<MT, S, SM> LoggerScheduledMutator<MT, S, SM> impl<I, MT, S, SM> LoggerScheduledMutator<I, MT, S, SM>
where where
MT: MutatorsTuple<S> + NamedTuple, MT: MutatorsTuple<I, S> + NamedTuple,
S: State + HasRand + HasCorpus, S: HasRand + HasCorpus,
SM: ScheduledMutator<MT, S>, SM: ScheduledMutator<I, MT, S>,
{ {
/// Create a new [`StdScheduledMutator`] instance without mutations and corpus /// Create a new [`StdScheduledMutator`] instance without mutations and corpus
pub fn new(scheduled: SM) -> Self { pub fn new(scheduled: SM) -> Self {
@ -528,14 +525,16 @@ pub mod pybind {
use pyo3::prelude::*; use pyo3::prelude::*;
use super::{havoc_mutations, Debug, HavocMutationsType, StdScheduledMutator}; use super::{havoc_mutations, Debug, HavocMutationsType, StdScheduledMutator};
use crate::{mutators::pybind::PythonMutator, state::pybind::PythonStdState}; use crate::{
inputs::BytesInput, mutators::pybind::PythonMutator, state::pybind::PythonStdState,
};
#[pyclass(unsendable, name = "StdHavocMutator")] #[pyclass(unsendable, name = "StdHavocMutator")]
#[derive(Debug)] #[derive(Debug)]
/// Python class for StdHavocMutator /// Python class for StdHavocMutator
pub struct PythonStdHavocMutator { pub struct PythonStdHavocMutator {
/// Rust wrapped StdHavocMutator object /// Rust wrapped StdHavocMutator object
pub inner: StdScheduledMutator<HavocMutationsType, PythonStdState>, pub inner: StdScheduledMutator<BytesInput, HavocMutationsType, PythonStdState>,
} }
#[pymethods] #[pymethods]

View File

@ -291,15 +291,15 @@ impl<'it> IntoIterator for &'it Tokens {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct TokenInsert; pub struct TokenInsert;
impl<S> Mutator<S> for TokenInsert impl<I, S> Mutator<I, S> for TokenInsert
where where
S: UsesInput + HasMetadata + HasRand + HasMaxSize, S: HasMetadata + HasRand + HasMaxSize,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -357,15 +357,15 @@ impl TokenInsert {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct TokenReplace; pub struct TokenReplace;
impl<S> Mutator<S> for TokenReplace impl<I, S> Mutator<I, S> for TokenReplace
where where
S: UsesInput + HasMetadata + HasRand + HasMaxSize, S: UsesInput + HasMetadata + HasRand + HasMaxSize,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -419,16 +419,16 @@ impl TokenReplace {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct I2SRandReplace; pub struct I2SRandReplace;
impl<S> Mutator<S> for I2SRandReplace impl<I, S> Mutator<I, S> for I2SRandReplace
where where
S: UsesInput + HasMetadata + HasRand + HasMaxSize, S: UsesInput + HasMetadata + HasRand + HasMaxSize,
S::Input: HasBytesVec, I: HasBytesVec,
{ {
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();

View File

@ -15,7 +15,7 @@ use crate::{
bolts::rands::Rand, bolts::rands::Rand,
impl_serdeany, impl_serdeany,
mutators::{ComposedByMutations, MutationResult, Mutator, MutatorsTuple, ScheduledMutator}, mutators::{ComposedByMutations, MutationResult, Mutator, MutatorsTuple, ScheduledMutator},
state::{HasMetadata, HasRand, State}, state::{HasMetadata, HasRand},
Error, Error,
}; };
@ -54,51 +54,51 @@ impl_serdeany!(TuneableScheduledMutatorMetadata);
/// A [`Mutator`] that schedules one of the embedded mutations on each call. /// A [`Mutator`] that schedules one of the embedded mutations on each call.
/// The index of the next mutation can be set. /// The index of the next mutation can be set.
pub struct TuneableScheduledMutator<MT, S> pub struct TuneableScheduledMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: State + HasRand, S: HasRand,
{ {
mutations: MT, mutations: MT,
max_stack_pow: u64, max_stack_pow: u64,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl<MT, S> Debug for TuneableScheduledMutator<MT, S> impl<I, MT, S> Debug for TuneableScheduledMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: State + HasRand, S: HasRand,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"TuneableScheduledMutator with {} mutations for Input type {}", "TuneableScheduledMutator with {} mutations for Input type {}",
self.mutations.len(), self.mutations.len(),
core::any::type_name::<S::Input>() core::any::type_name::<I>()
) )
} }
} }
impl<MT, S> Mutator<S> for TuneableScheduledMutator<MT, S> impl<I, MT, S> Mutator<I, S> for TuneableScheduledMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: State + HasRand + HasMetadata, S: HasRand + HasMetadata,
{ {
#[inline] #[inline]
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut S::Input, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
self.scheduled_mutate(state, input, stage_idx) self.scheduled_mutate(state, input, stage_idx)
} }
} }
impl<MT, S> ComposedByMutations<MT, S> for TuneableScheduledMutator<MT, S> impl<I, MT, S> ComposedByMutations<I, MT, S> for TuneableScheduledMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: State + HasRand, S: HasRand,
{ {
/// Get the mutations /// Get the mutations
#[inline] #[inline]
@ -113,13 +113,13 @@ where
} }
} }
impl<MT, S> ScheduledMutator<MT, S> for TuneableScheduledMutator<MT, S> impl<I, MT, S> ScheduledMutator<I, MT, S> for TuneableScheduledMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: State + HasRand + HasMetadata, S: HasRand + HasMetadata,
{ {
/// Compute the number of iterations used to apply stacked mutations /// Compute the number of iterations used to apply stacked mutations
fn iterations(&self, state: &mut S, _: &S::Input) -> u64 { fn iterations(&self, state: &mut S, _: &I) -> u64 {
if let Some(iters) = Self::get_iters(state) { if let Some(iters) = Self::get_iters(state) {
iters iters
} else { } else {
@ -129,7 +129,7 @@ where
} }
/// Get the next mutation to apply /// Get the next mutation to apply
fn schedule(&self, state: &mut S, _: &S::Input) -> usize { fn schedule(&self, state: &mut S, _: &I) -> usize {
debug_assert!(!self.mutations().is_empty()); debug_assert!(!self.mutations().is_empty());
// Assumption: we can not reach this code path without previously adding this metadatum. // Assumption: we can not reach this code path without previously adding this metadatum.
let metadata = TuneableScheduledMutatorMetadata::get_mut(state).unwrap(); let metadata = TuneableScheduledMutatorMetadata::get_mut(state).unwrap();
@ -152,10 +152,10 @@ where
} }
} }
impl<MT, S> TuneableScheduledMutator<MT, S> impl<I, MT, S> TuneableScheduledMutator<I, MT, S>
where where
MT: MutatorsTuple<S>, MT: MutatorsTuple<I, S>,
S: State + HasRand + HasMetadata, S: HasRand + HasMetadata,
{ {
/// Create a new [`TuneableScheduledMutator`] instance specifying mutations /// Create a new [`TuneableScheduledMutator`] instance specifying mutations
pub fn new(state: &mut S, mutations: MT) -> Self { pub fn new(state: &mut S, mutations: MT) -> Self {
@ -222,7 +222,7 @@ mod test {
#[test] #[test]
fn test_tuning() { fn test_tuning() {
let mut state = NopState::new(); let mut state: NopState<BytesInput> = NopState::new();
let mutators = tuple_list!( let mutators = tuple_list!(
BitFlipMutator::new(), BitFlipMutator::new(),
ByteDecMutator::new(), ByteDecMutator::new(),

View File

@ -16,7 +16,7 @@ use crate::{
corpus::{Corpus, CorpusId}, corpus::{Corpus, CorpusId},
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
feedbacks::map::MapNoveltiesMetadata, feedbacks::map::MapNoveltiesMetadata,
inputs::{GeneralizedInput, GeneralizedItem, HasBytesVec, UsesInput}, inputs::{BytesInput, GeneralizedInputMetadata, GeneralizedItem, HasBytesVec, UsesInput},
mark_feature_time, mark_feature_time,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
stages::Stage, stages::Stage,
@ -69,7 +69,7 @@ pub struct GeneralizationStage<EM, O, OT, Z> {
impl<EM, O, OT, Z> UsesState for GeneralizationStage<EM, O, OT, Z> impl<EM, O, OT, Z> UsesState for GeneralizationStage<EM, O, OT, Z>
where where
EM: UsesState, EM: UsesState,
EM::State: UsesInput<Input = GeneralizedInput>, EM::State: UsesInput<Input = BytesInput>,
{ {
type State = EM::State; type State = EM::State;
} }
@ -79,7 +79,7 @@ where
O: MapObserver, O: MapObserver,
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
E::Observers: ObserversTuple<E::State>, E::Observers: ObserversTuple<E::State>,
E::State: UsesInput<Input = GeneralizedInput> E::State: UsesInput<Input = BytesInput>
+ HasClientPerfMonitor + HasClientPerfMonitor
+ HasExecutions + HasExecutions
+ HasMetadata + HasMetadata
@ -110,9 +110,8 @@ where
state.corpus().get(corpus_idx)?.borrow_mut().load_input()?; state.corpus().get(corpus_idx)?.borrow_mut().load_input()?;
mark_feature_time!(state, PerfFeature::GetInputFromCorpus); mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
let mut entry = state.corpus().get(corpus_idx)?.borrow_mut(); let mut entry = state.corpus().get(corpus_idx)?.borrow_mut();
let input = entry.input_mut().as_mut().unwrap();
if input.generalized().is_some() { if entry.metadata().contains::<GeneralizedInputMetadata>() {
drop(entry); drop(entry);
state state
.metadata_mut() .metadata_mut()
@ -123,6 +122,8 @@ where
return Ok(()); return Ok(());
} }
let input = entry.input_mut().as_mut().unwrap();
let payload: Vec<_> = input.bytes().iter().map(|&x| Some(x)).collect(); let payload: Vec<_> = input.bytes().iter().map(|&x| Some(x)).collect();
let original = input.clone(); let original = input.clone();
let meta = entry.metadata().get::<MapNoveltiesMetadata>().ok_or_else(|| { let meta = entry.metadata().get::<MapNoveltiesMetadata>().ok_or_else(|| {
@ -324,23 +325,13 @@ where
if payload.len() <= MAX_GENERALIZED_LEN { if payload.len() <= MAX_GENERALIZED_LEN {
// Save the modified input in the corpus // Save the modified input in the corpus
{ {
let mut entry = state.corpus().get(corpus_idx)?.borrow_mut(); let meta = GeneralizedInputMetadata::generalized_from_options(&payload);
entry.load_input()?;
entry
.input_mut()
.as_mut()
.unwrap()
.generalized_from_options(&payload);
entry.store_input()?;
debug_assert!( debug_assert!(meta.generalized().first() == Some(&GeneralizedItem::Gap));
entry.load_input()?.generalized().unwrap().first() debug_assert!(meta.generalized().last() == Some(&GeneralizedItem::Gap));
== Some(&GeneralizedItem::Gap)
); let mut entry = state.corpus().get(corpus_idx)?.borrow_mut();
debug_assert!( entry.metadata_mut().insert(meta);
entry.load_input()?.generalized().unwrap().last()
== Some(&GeneralizedItem::Gap)
);
} }
state state
@ -360,7 +351,7 @@ where
EM: UsesState, EM: UsesState,
O: MapObserver, O: MapObserver,
OT: ObserversTuple<EM::State>, OT: ObserversTuple<EM::State>,
EM::State: UsesInput<Input = GeneralizedInput> EM::State: UsesInput<Input = BytesInput>
+ HasClientPerfMonitor + HasClientPerfMonitor
+ HasExecutions + HasExecutions
+ HasMetadata + HasMetadata
@ -391,7 +382,7 @@ where
state: &mut EM::State, state: &mut EM::State,
manager: &mut EM, manager: &mut EM,
novelties: &[usize], novelties: &[usize],
input: &GeneralizedInput, input: &BytesInput,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
E: Executor<EM, Z> + HasObservers<Observers = OT, State = EM::State>, E: Executor<EM, Z> + HasObservers<Observers = OT, State = EM::State>,
@ -449,7 +440,7 @@ where
if end > payload.len() { if end > payload.len() {
end = payload.len(); end = payload.len();
} }
let mut candidate = GeneralizedInput::new(vec![]); let mut candidate = BytesInput::new(vec![]);
candidate candidate
.bytes_mut() .bytes_mut()
.extend(payload[..start].iter().flatten()); .extend(payload[..start].iter().flatten());
@ -502,7 +493,7 @@ where
while end > start { while end > start {
if payload[end] == Some(closing_char) { if payload[end] == Some(closing_char) {
endings += 1; endings += 1;
let mut candidate = GeneralizedInput::new(vec![]); let mut candidate = BytesInput::new(vec![]);
candidate candidate
.bytes_mut() .bytes_mut()
.extend(payload[..start].iter().flatten()); .extend(payload[..start].iter().flatten());

View File

@ -7,8 +7,9 @@ use core::marker::PhantomData;
use crate::monitors::PerfFeature; use crate::monitors::PerfFeature;
use crate::{ use crate::{
bolts::rands::Rand, bolts::rands::Rand,
corpus::{Corpus, CorpusId}, corpus::{Corpus, CorpusId, Testcase},
fuzzer::Evaluator, fuzzer::Evaluator,
inputs::Input,
mark_feature_time, mark_feature_time,
mutators::Mutator, mutators::Mutator,
stages::Stage, stages::Stage,
@ -19,16 +20,79 @@ use crate::{
// TODO multi mutators stage // TODO multi mutators stage
/// Action performed after the un-transformed input is executed (e.g., updating metadata)
#[allow(unused_variables)]
pub trait MutatedTransformPost<S>: Sized {
/// Perform any post-execution steps necessary for the transformed input (e.g., updating metadata)
#[inline]
fn post_exec(
self,
state: &mut S,
stage_idx: i32,
corpus_idx: Option<CorpusId>,
) -> Result<(), Error> {
Ok(())
}
}
impl<S> MutatedTransformPost<S> for () {}
/// A type which may both be transformed from and into a given input type, used to perform
/// mutations over inputs which are not necessarily performable on the underlying type
///
/// This trait is implemented such that all testcases inherently transform to their inputs, should
/// the input be cloneable.
pub trait MutatedTransform<I, S>: Sized
where
I: Input,
{
/// Type indicating actions to be taken after the post-transformation input is executed
type Post: MutatedTransformPost<S>;
/// Transform the provided testcase into this type
fn try_transform_from(
base: &Testcase<I>,
state: &S,
corpus_idx: CorpusId,
) -> Result<Self, Error>;
/// Transform this instance back into the original input type
fn try_transform_into(self, state: &S) -> Result<(I, Self::Post), Error>;
}
// reflexive definition
impl<I, S> MutatedTransform<I, S> for I
where
I: Input + Clone,
{
type Post = ();
#[inline]
fn try_transform_from(
base: &Testcase<I>,
_state: &S,
_corpus_idx: CorpusId,
) -> Result<Self, Error> {
Ok(base.input().as_ref().unwrap().clone())
}
#[inline]
fn try_transform_into(self, _state: &S) -> Result<(I, Self::Post), Error> {
Ok((self, ()))
}
}
/// A Mutational stage is the stage in a fuzzing run that mutates inputs. /// A Mutational stage is the stage in a fuzzing run that mutates inputs.
/// Mutational stages will usually have a range of mutations that are /// Mutational stages will usually have a range of mutations that are
/// being applied to the input one by one, between executions. /// being applied to the input one by one, between executions.
pub trait MutationalStage<E, EM, M, Z>: Stage<E, EM, Z> pub trait MutationalStage<E, EM, I, M, Z>: Stage<E, EM, Z>
where where
E: UsesState<State = Self::State>, E: UsesState<State = Self::State>,
M: Mutator<Self::State>, M: Mutator<I, Self::State>,
EM: UsesState<State = Self::State>, EM: UsesState<State = Self::State>,
Z: Evaluator<E, EM, State = Self::State>, Z: Evaluator<E, EM, State = Self::State>,
Self::State: HasClientPerfMonitor + HasCorpus, Self::State: HasClientPerfMonitor + HasCorpus,
I: MutatedTransform<Self::Input, Self::State> + Clone,
{ {
/// The mutator registered for this stage /// The mutator registered for this stage
fn mutator(&self) -> &M; fn mutator(&self) -> &M;
@ -51,25 +115,26 @@ where
) -> Result<(), Error> { ) -> Result<(), Error> {
let num = self.iterations(state, corpus_idx)?; let num = self.iterations(state, corpus_idx)?;
start_timer!(state);
let testcase = state.corpus().get(corpus_idx)?.borrow();
let input = I::try_transform_from(&testcase, state, corpus_idx)?;
drop(testcase);
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
for i in 0..num { for i in 0..num {
start_timer!(state); let mut input = input.clone();
let mut input = state
.corpus()
.get(corpus_idx)?
.borrow_mut()
.load_input()?
.clone();
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
start_timer!(state); start_timer!(state);
self.mutator_mut().mutate(state, &mut input, i as i32)?; self.mutator_mut().mutate(state, &mut input, i as i32)?;
mark_feature_time!(state, PerfFeature::Mutate); mark_feature_time!(state, PerfFeature::Mutate);
// Time is measured directly the `evaluate_input` function // Time is measured directly the `evaluate_input` function
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, input)?; let (untransformed, post) = input.try_transform_into(state)?;
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, untransformed)?;
start_timer!(state); start_timer!(state);
self.mutator_mut().post_exec(state, i as i32, corpus_idx)?; 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); mark_feature_time!(state, PerfFeature::MutatePostExec);
} }
Ok(()) Ok(())
@ -82,19 +147,20 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128;
/// The default mutational stage /// The default mutational stage
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct StdMutationalStage<E, EM, M, Z> { pub struct StdMutationalStage<E, EM, I, M, Z> {
mutator: M, mutator: M,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, Z)>, phantom: PhantomData<(E, EM, I, Z)>,
} }
impl<E, EM, M, Z> MutationalStage<E, EM, M, Z> for StdMutationalStage<E, EM, M, Z> impl<E, EM, I, M, Z> MutationalStage<E, EM, I, M, Z> for StdMutationalStage<E, EM, I, M, Z>
where where
E: UsesState<State = Z::State>, E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>, EM: UsesState<State = Z::State>,
M: Mutator<Z::State>, M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand, Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
I: MutatedTransform<Self::Input, Self::State> + Clone,
{ {
/// The mutator, added to this stage /// The mutator, added to this stage
#[inline] #[inline]
@ -114,24 +180,25 @@ where
} }
} }
impl<E, EM, M, Z> UsesState for StdMutationalStage<E, EM, M, Z> impl<E, EM, I, M, Z> UsesState for StdMutationalStage<E, EM, I, M, Z>
where where
E: UsesState<State = Z::State>, E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>, EM: UsesState<State = Z::State>,
M: Mutator<Z::State>, M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand, Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
{ {
type State = Z::State; type State = Z::State;
} }
impl<E, EM, M, Z> Stage<E, EM, Z> for StdMutationalStage<E, EM, M, Z> impl<E, EM, I, M, Z> Stage<E, EM, Z> for StdMutationalStage<E, EM, I, M, Z>
where where
E: UsesState<State = Z::State>, E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>, EM: UsesState<State = Z::State>,
M: Mutator<Z::State>, M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand, Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
I: MutatedTransform<Self::Input, Self::State> + Clone,
{ {
#[inline] #[inline]
#[allow(clippy::let_and_return)] #[allow(clippy::let_and_return)]
@ -152,16 +219,30 @@ where
} }
} }
impl<E, EM, M, Z> StdMutationalStage<E, EM, M, Z> impl<E, EM, M, Z> StdMutationalStage<E, EM, Z::Input, M, Z>
where where
E: UsesState<State = Z::State>, E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>, EM: UsesState<State = Z::State>,
M: Mutator<Z::State>, M: Mutator<Z::Input, Z::State>,
Z: Evaluator<E, EM>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand, Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
{ {
/// Creates a new default mutational stage /// Creates a new default mutational stage
pub fn new(mutator: M) -> Self { pub fn new(mutator: M) -> Self {
Self::transforming(mutator)
}
}
impl<E, EM, I, M, Z> StdMutationalStage<E, EM, I, M, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
{
/// Creates a new transforming mutational stage
pub fn transforming(mutator: M) -> Self {
Self { Self {
mutator, mutator,
phantom: PhantomData, phantom: PhantomData,
@ -179,6 +260,7 @@ pub mod pybind {
events::pybind::PythonEventManager, events::pybind::PythonEventManager,
executors::pybind::PythonExecutor, executors::pybind::PythonExecutor,
fuzzer::pybind::PythonStdFuzzer, fuzzer::pybind::PythonStdFuzzer,
inputs::BytesInput,
mutators::pybind::PythonMutator, mutators::pybind::PythonMutator,
stages::{pybind::PythonStage, StdMutationalStage}, stages::{pybind::PythonStage, StdMutationalStage},
}; };
@ -188,8 +270,13 @@ pub mod pybind {
/// Python class for StdMutationalStage /// Python class for StdMutationalStage
pub struct PythonStdMutationalStage { pub struct PythonStdMutationalStage {
/// Rust wrapped StdMutationalStage object /// Rust wrapped StdMutationalStage object
pub inner: pub inner: StdMutationalStage<
StdMutationalStage<PythonExecutor, PythonEventManager, PythonMutator, PythonStdFuzzer>, PythonExecutor,
PythonEventManager,
BytesInput,
PythonMutator,
PythonStdFuzzer,
>,
} }
#[pymethods] #[pymethods]

View File

@ -13,36 +13,41 @@ use crate::{
schedulers::{ schedulers::{
powersched::SchedulerMetadata, testcase_score::CorpusPowerTestcaseScore, TestcaseScore, powersched::SchedulerMetadata, testcase_score::CorpusPowerTestcaseScore, TestcaseScore,
}, },
stages::{MutationalStage, Stage}, stages::{
mutational::{MutatedTransform, MutatedTransformPost},
MutationalStage, Stage,
},
state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState}, state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState},
Error, Error,
}; };
/// The mutational stage using power schedules /// The mutational stage using power schedules
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PowerMutationalStage<E, F, EM, M, O, Z> { pub struct PowerMutationalStage<E, F, EM, I, M, O, Z> {
map_observer_name: String, map_observer_name: String,
mutator: M, mutator: M,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(E, F, EM, O, Z)>, phantom: PhantomData<(E, F, EM, I, O, Z)>,
} }
impl<E, F, EM, M, O, Z> UsesState for PowerMutationalStage<E, F, EM, M, O, Z> impl<E, F, EM, I, M, O, Z> UsesState for PowerMutationalStage<E, F, EM, I, M, O, Z>
where where
E: UsesState, E: UsesState,
{ {
type State = E::State; type State = E::State;
} }
impl<E, F, EM, M, O, Z> MutationalStage<E, EM, M, Z> for PowerMutationalStage<E, F, EM, M, O, Z> impl<E, F, EM, I, M, O, Z> MutationalStage<E, EM, I, M, Z>
for PowerMutationalStage<E, F, EM, I, M, O, Z>
where where
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: UsesState<State = E::State>, EM: UsesState<State = E::State>,
F: TestcaseScore<E::State>, F: TestcaseScore<E::State>,
M: Mutator<E::State>, M: Mutator<I, E::State>,
O: MapObserver, O: MapObserver,
E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
Z: Evaluator<E, EM, State = E::State>, Z: Evaluator<E, EM, State = E::State>,
I: MutatedTransform<E::Input, E::State> + Clone,
{ {
/// The mutator, added to this stage /// The mutator, added to this stage
#[inline] #[inline]
@ -77,17 +82,17 @@ where
) -> Result<(), Error> { ) -> Result<(), Error> {
let num = self.iterations(state, corpus_idx)?; let num = self.iterations(state, corpus_idx)?;
let testcase = state.corpus().get(corpus_idx)?.borrow();
let input = I::try_transform_from(&testcase, state, corpus_idx)?;
drop(testcase);
for i in 0..num { for i in 0..num {
let mut input = state let mut input = input.clone();
.corpus()
.get(corpus_idx)?
.borrow_mut()
.load_input()?
.clone();
self.mutator_mut().mutate(state, &mut input, i as i32)?; self.mutator_mut().mutate(state, &mut input, i as i32)?;
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, input)?; let (untransformed, post) = input.try_transform_into(state)?;
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, untransformed)?;
let observer = executor let observer = executor
.observers() .observers()
@ -119,21 +124,23 @@ where
} }
self.mutator_mut().post_exec(state, i as i32, corpus_idx)?; self.mutator_mut().post_exec(state, i as i32, corpus_idx)?;
post.post_exec(state, i as i32, corpus_idx)?;
} }
Ok(()) Ok(())
} }
} }
impl<E, F, EM, M, O, Z> Stage<E, EM, Z> for PowerMutationalStage<E, F, EM, M, O, Z> impl<E, F, EM, I, M, O, Z> Stage<E, EM, Z> for PowerMutationalStage<E, F, EM, I, M, O, Z>
where where
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: UsesState<State = E::State>, EM: UsesState<State = E::State>,
F: TestcaseScore<E::State>, F: TestcaseScore<E::State>,
M: Mutator<E::State>, M: Mutator<I, E::State>,
O: MapObserver, O: MapObserver,
E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
Z: Evaluator<E, EM, State = E::State>, Z: Evaluator<E, EM, State = E::State>,
I: MutatedTransform<E::Input, E::State> + Clone,
{ {
#[inline] #[inline]
#[allow(clippy::let_and_return)] #[allow(clippy::let_and_return)]
@ -150,18 +157,34 @@ where
} }
} }
impl<E, F, EM, M, O, Z> PowerMutationalStage<E, F, EM, M, O, Z> impl<E, F, EM, M, O, Z> PowerMutationalStage<E, F, EM, E::Input, M, O, Z>
where where
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: UsesState<State = E::State>, EM: UsesState<State = E::State>,
F: TestcaseScore<E::State>, F: TestcaseScore<E::State>,
M: Mutator<E::State>, M: Mutator<E::Input, E::State>,
O: MapObserver, O: MapObserver,
E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
Z: Evaluator<E, EM, State = E::State>, Z: Evaluator<E, EM, State = E::State>,
{ {
/// Creates a new [`PowerMutationalStage`] /// Creates a new [`PowerMutationalStage`]
pub fn new(mutator: M, map_observer_name: &O) -> Self { pub fn new(mutator: M, map_observer_name: &O) -> Self {
Self::transforming(mutator, map_observer_name)
}
}
impl<E, F, EM, I, M, O, Z> PowerMutationalStage<E, F, EM, I, M, O, 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 {
Self { Self {
map_observer_name: map_observer_name.name().to_string(), map_observer_name: map_observer_name.name().to_string(),
mutator, mutator,
@ -171,5 +194,5 @@ where
} }
/// The standard powerscheduling stage /// The standard powerscheduling stage
pub type StdPowerMutationalStage<E, EM, M, O, Z> = pub type StdPowerMutationalStage<E, EM, I, M, O, Z> =
PowerMutationalStage<E, CorpusPowerTestcaseScore<<E as UsesState>::State>, EM, M, O, Z>; PowerMutationalStage<E, CorpusPowerTestcaseScore<<E as UsesState>::State>, EM, I, M, O, Z>;

View File

@ -41,7 +41,7 @@ pub struct StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler, CS: Scheduler,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
M: Mutator<CS::State>, M: Mutator<CS::Input, CS::State>,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<CS::State>,
CS::State: HasClientPerfMonitor + HasRand + Clone + Debug, CS::State: HasClientPerfMonitor + HasRand + Clone + Debug,
Z: ExecutionProcessor<OT, State = CS::State> Z: ExecutionProcessor<OT, State = CS::State>
@ -63,7 +63,7 @@ impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler, CS: Scheduler,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
M: Mutator<CS::State>, M: Mutator<CS::Input, CS::State>,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<CS::State>,
CS::State: HasClientPerfMonitor + HasCorpus + HasRand + Clone + Debug, CS::State: HasClientPerfMonitor + HasCorpus + HasRand + Clone + Debug,
Z: ExecutionProcessor<OT, State = CS::State> Z: ExecutionProcessor<OT, State = CS::State>
@ -86,7 +86,7 @@ impl<CS, EM, M, OT, Z> PushStage<CS, EM, OT, Z> for StdMutationalPushStage<CS, E
where where
CS: Scheduler, CS: Scheduler,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter,
M: Mutator<CS::State>, M: Mutator<CS::Input, CS::State>,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<CS::State>,
CS::State: CS::State:
HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug, HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug,
@ -199,7 +199,7 @@ impl<CS, EM, M, OT, Z> Iterator for StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler, CS: Scheduler,
EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = CS::State>, EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = CS::State>,
M: Mutator<CS::State>, M: Mutator<CS::Input, CS::State>,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<CS::State>,
CS::State: CS::State:
HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug, HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug,
@ -218,7 +218,7 @@ impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler, CS: Scheduler,
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
M: Mutator<CS::State>, M: Mutator<CS::Input, CS::State>,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<CS::State>,
CS::State: HasClientPerfMonitor + HasCorpus + HasRand + Clone + Debug, CS::State: HasClientPerfMonitor + HasCorpus + HasRand + Clone + Debug,
Z: ExecutionProcessor<OT, State = CS::State> Z: ExecutionProcessor<OT, State = CS::State>

View File

@ -41,7 +41,7 @@ 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::State>, M: Mutator<Self::Input, 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>
@ -177,7 +177,7 @@ impl<CS, E, EM, F1, F2, FF, M, OT, Z> UsesState
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,
M: Mutator<CS::State>, M: Mutator<CS::Input, CS::State>,
Z: ExecutionProcessor<OT, State = CS::State>, Z: ExecutionProcessor<OT, State = CS::State>,
{ {
type State = CS::State; type State = CS::State;
@ -194,7 +194,7 @@ 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::State>, M: Mutator<CS::Input, 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>
@ -241,7 +241,7 @@ 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::State>, M: Mutator<CS::Input, CS::State>,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<CS::State>,
CS::State: HasClientPerfMonitor + HasCorpus + HasExecutions + HasMaxSize, CS::State: HasClientPerfMonitor + HasCorpus + HasExecutions + HasMaxSize,
Z: ExecutionProcessor<OT, State = CS::State> Z: ExecutionProcessor<OT, State = CS::State>
@ -270,7 +270,7 @@ 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, M, OT, Z> StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z>
where where
CS: Scheduler, CS: Scheduler,
M: Mutator<CS::State>, M: Mutator<CS::Input, CS::State>,
Z: ExecutionProcessor<OT, State = CS::State>, Z: ExecutionProcessor<OT, State = CS::State>,
{ {
/// Creates a new minimising mutational stage that will minimize provided corpus entries /// Creates a new minimising mutational stage that will minimize provided corpus entries

View File

@ -9,7 +9,10 @@ use crate::{
corpus::CorpusId, corpus::CorpusId,
impl_serdeany, impl_serdeany,
mutators::Mutator, mutators::Mutator,
stages::{mutational::DEFAULT_MUTATIONAL_MAX_ITERATIONS, MutationalStage, Stage}, stages::{
mutational::{MutatedTransform, DEFAULT_MUTATIONAL_MAX_ITERATIONS},
MutationalStage, Stage,
},
state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState}, state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState},
Error, Evaluator, Error, Evaluator,
}; };
@ -52,18 +55,19 @@ pub fn reset<S: HasMetadata>(state: &mut S) -> Result<(), Error> {
/// A [`crate::stages::MutationalStage`] where the mutator iteration can be tuned at runtime /// A [`crate::stages::MutationalStage`] where the mutator iteration can be tuned at runtime
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct TuneableMutationalStage<E, EM, M, Z> { pub struct TuneableMutationalStage<E, EM, I, M, Z> {
mutator: M, mutator: M,
phantom: PhantomData<(E, EM, Z)>, phantom: PhantomData<(E, EM, I, Z)>,
} }
impl<E, EM, M, Z> MutationalStage<E, EM, M, Z> for TuneableMutationalStage<E, EM, M, Z> impl<E, EM, I, M, Z> MutationalStage<E, EM, I, M, Z> for TuneableMutationalStage<E, EM, I, M, Z>
where where
E: UsesState<State = Z::State>, E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>, EM: UsesState<State = Z::State>,
M: Mutator<Z::State>, M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
I: MutatedTransform<Z::Input, Z::State> + Clone,
{ {
/// The mutator, added to this stage /// The mutator, added to this stage
#[inline] #[inline]
@ -89,24 +93,26 @@ where
} }
} }
impl<E, EM, M, Z> UsesState for TuneableMutationalStage<E, EM, M, Z> impl<E, EM, I, M, Z> UsesState for TuneableMutationalStage<E, EM, I, M, Z>
where where
E: UsesState<State = Z::State>, E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>, EM: UsesState<State = Z::State>,
M: Mutator<Z::State>, M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand, Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
I: MutatedTransform<Z::Input, Z::State> + Clone,
{ {
type State = Z::State; type State = Z::State;
} }
impl<E, EM, M, Z> Stage<E, EM, Z> for TuneableMutationalStage<E, EM, M, Z> impl<E, EM, I, M, Z> Stage<E, EM, Z> for TuneableMutationalStage<E, EM, I, M, Z>
where where
E: UsesState<State = Z::State>, E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>, EM: UsesState<State = Z::State>,
M: Mutator<Z::State>, M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
I: MutatedTransform<Z::Input, Z::State> + Clone,
{ {
#[inline] #[inline]
#[allow(clippy::let_and_return)] #[allow(clippy::let_and_return)]
@ -127,17 +133,32 @@ where
} }
} }
impl<E, EM, M, Z> TuneableMutationalStage<E, EM, M, Z> impl<E, EM, M, Z> TuneableMutationalStage<E, EM, Z::Input, M, Z>
where where
E: UsesState<State = Z::State>, E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>, EM: UsesState<State = Z::State>,
M: Mutator<Z::State>, M: Mutator<Z::Input, Z::State>,
Z: Evaluator<E, EM>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
{ {
/// Creates a new default mutational stage /// Creates a new default mutational stage
#[must_use] #[must_use]
pub fn new(state: &mut Z::State, mutator: M) -> Self { pub fn new(state: &mut Z::State, mutator: M) -> Self {
Self::transforming(state, mutator)
}
}
impl<E, EM, I, M, Z> TuneableMutationalStage<E, EM, I, M, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
M: Mutator<I, Z::State>,
Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
{
/// Creates a new tranforming mutational stage
#[must_use]
pub fn transforming(state: &mut Z::State, mutator: M) -> Self {
if !state.has_metadata::<TuneableMutationalStageMetadata>() { if !state.has_metadata::<TuneableMutationalStageMetadata>() {
state.add_metadata(TuneableMutationalStageMetadata::default()); state.add_metadata(TuneableMutationalStageMetadata::default());
} }