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:
parent
ec84c71eae
commit
28786c943a
@ -9,7 +9,7 @@ use libafl::{
|
||||
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback},
|
||||
fuzzer::{Evaluator, Fuzzer, StdFuzzer},
|
||||
inputs::{GeneralizedInput, HasTargetBytes},
|
||||
inputs::{BytesInput, HasTargetBytes},
|
||||
monitors::SimpleMonitor,
|
||||
mutators::{
|
||||
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 buffer = vec![];
|
||||
file.read_to_end(&mut buffer).expect("buffer overflow");
|
||||
let input = GeneralizedInput::new(buffer);
|
||||
let input = BytesInput::new(buffer);
|
||||
initial_inputs.push(input);
|
||||
}
|
||||
}
|
||||
|
||||
// The closure that we want to fuzz
|
||||
let mut harness = |input: &GeneralizedInput| {
|
||||
let mut harness = |input: &BytesInput| {
|
||||
let target_bytes = input.target_bytes();
|
||||
let bytes = target_bytes.as_slice();
|
||||
|
||||
@ -77,12 +77,6 @@ pub fn main() {
|
||||
signals_set(3);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
if input.grimoire_mutated {
|
||||
// println!(">>> {:?}", input.generalized());
|
||||
println!(">>> {:?}", std::str::from_utf8_unchecked(bytes));
|
||||
}
|
||||
}
|
||||
signals_set(1);
|
||||
ExitKind::Ok
|
||||
};
|
||||
@ -158,7 +152,7 @@ pub fn main() {
|
||||
let mut stages = tuple_list!(
|
||||
generalization,
|
||||
StdMutationalStage::new(mutator),
|
||||
StdMutationalStage::new(grimoire_mutator)
|
||||
StdMutationalStage::transforming(grimoire_mutator)
|
||||
);
|
||||
|
||||
for input in initial_inputs {
|
||||
|
@ -31,7 +31,7 @@ use libafl::{
|
||||
feedback_or,
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
||||
fuzzer::{Fuzzer, StdFuzzer},
|
||||
inputs::{BytesInput, GeneralizedInput, HasTargetBytes},
|
||||
inputs::{BytesInput, HasTargetBytes},
|
||||
monitors::SimpleMonitor,
|
||||
mutators::{
|
||||
grimoire::{
|
||||
@ -47,8 +47,8 @@ use libafl::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
|
||||
},
|
||||
stages::{
|
||||
calibrate::CalibrationStage, dump::DumpToDiskStage, power::StdPowerMutationalStage,
|
||||
GeneralizationStage, StdMutationalStage, TracingStage,
|
||||
calibrate::CalibrationStage, power::StdPowerMutationalStage, GeneralizationStage,
|
||||
StdMutationalStage, TracingStage,
|
||||
},
|
||||
state::{HasCorpus, HasMetadata, StdState},
|
||||
Error,
|
||||
@ -148,11 +148,8 @@ pub fn libafl_main() {
|
||||
}
|
||||
}
|
||||
let mut crashes = out_dir.clone();
|
||||
let mut report = out_dir.clone();
|
||||
crashes.push("crashes");
|
||||
report.push("report");
|
||||
out_dir.push("queue");
|
||||
drop(fs::create_dir(&report));
|
||||
|
||||
let in_dir = PathBuf::from(
|
||||
res.get_one::<String>("in")
|
||||
@ -177,10 +174,8 @@ pub fn libafl_main() {
|
||||
);
|
||||
|
||||
if check_if_textual(&in_dir, &tokens) {
|
||||
fuzz_text(
|
||||
out_dir, crashes, &report, &in_dir, tokens, &logfile, timeout,
|
||||
)
|
||||
.expect("An error occurred while fuzzing");
|
||||
fuzz_text(out_dir, crashes, &in_dir, tokens, &logfile, timeout)
|
||||
.expect("An error occurred while fuzzing");
|
||||
} else {
|
||||
fuzz_binary(out_dir, crashes, &in_dir, tokens, &logfile, timeout)
|
||||
.expect("An error occurred while fuzzing");
|
||||
@ -466,7 +461,6 @@ fn fuzz_binary(
|
||||
fn fuzz_text(
|
||||
corpus_dir: PathBuf,
|
||||
objective_dir: PathBuf,
|
||||
report_dir: &Path,
|
||||
seed_dir: &PathBuf,
|
||||
tokenfile: Option<PathBuf>,
|
||||
logfile: &PathBuf,
|
||||
@ -586,7 +580,7 @@ fn fuzz_text(
|
||||
),
|
||||
3,
|
||||
);
|
||||
let grimoire = StdMutationalStage::new(grimoire_mutator);
|
||||
let grimoire = StdMutationalStage::transforming(grimoire_mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
@ -597,7 +591,7 @@ fn fuzz_text(
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
||||
// 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 buf = target.as_slice();
|
||||
libfuzzer_test_one_input(buf);
|
||||
@ -633,23 +627,8 @@ fn fuzz_text(
|
||||
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!
|
||||
let mut stages = tuple_list!(
|
||||
fuzzbench,
|
||||
generalization,
|
||||
calibration,
|
||||
tracing,
|
||||
i2s,
|
||||
power,
|
||||
grimoire
|
||||
);
|
||||
let mut stages = tuple_list!(generalization, calibration, tracing, i2s, power, grimoire);
|
||||
|
||||
// Read tokens
|
||||
if state.metadata().get::<Tokens>().is_none() {
|
||||
|
@ -4,7 +4,6 @@ use libafl::{
|
||||
rands::{Rand, StdRand},
|
||||
tuples::Named,
|
||||
},
|
||||
inputs::UsesInput,
|
||||
mutators::{MutationResult, Mutator},
|
||||
state::HasRand,
|
||||
Error,
|
||||
@ -16,9 +15,9 @@ pub struct LainMutator {
|
||||
inner: lain::mutator::Mutator<StdRand>,
|
||||
}
|
||||
|
||||
impl<S> Mutator<S> for LainMutator
|
||||
impl<S> Mutator<PacketData, S> for LainMutator
|
||||
where
|
||||
S: UsesInput<Input = PacketData> + HasRand,
|
||||
S: HasRand,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
|
@ -5,7 +5,7 @@ use core::{cmp::min, marker::PhantomData};
|
||||
|
||||
use crate::{
|
||||
bolts::rands::Rand,
|
||||
inputs::{bytes::BytesInput, GeneralizedInput, Input},
|
||||
inputs::{bytes::BytesInput, Input},
|
||||
state::HasRand,
|
||||
Error,
|
||||
};
|
||||
@ -33,51 +33,6 @@ where
|
||||
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)]
|
||||
/// Generates random bytes
|
||||
pub struct RandBytesGenerator<S>
|
||||
|
@ -1,18 +1,16 @@
|
||||
//! 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 core::{cell::RefCell, convert::From, hash::Hasher};
|
||||
#[cfg(feature = "std")]
|
||||
use std::{fs::File, io::Read, path::Path};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use ahash::AHasher;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::Error;
|
||||
use crate::{
|
||||
bolts::{ownedref::OwnedSlice, HasLen},
|
||||
inputs::{BytesInput, HasBytesVec, HasTargetBytes, Input},
|
||||
corpus::{Corpus, CorpusId, Testcase},
|
||||
impl_serdeany,
|
||||
inputs::BytesInput,
|
||||
stages::mutational::{MutatedTransform, MutatedTransformPost},
|
||||
state::{HasCorpus, HasMetadata},
|
||||
Error,
|
||||
};
|
||||
|
||||
/// An item of the generalized input
|
||||
@ -24,142 +22,31 @@ pub enum GeneralizedItem {
|
||||
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)]
|
||||
pub struct GeneralizedInput {
|
||||
/// The raw input bytes
|
||||
bytes: Vec<u8>,
|
||||
generalized: Option<Vec<GeneralizedItem>>,
|
||||
/// If was mutated or not by Grimoire
|
||||
pub grimoire_mutated: bool,
|
||||
pub struct GeneralizedInputMetadata {
|
||||
generalized: Vec<GeneralizedItem>,
|
||||
}
|
||||
|
||||
impl Input for GeneralizedInput {
|
||||
/// 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_serdeany!(GeneralizedInputMetadata);
|
||||
|
||||
impl GeneralizedInputMetadata {
|
||||
/// Fill the generalized vector from a slice of option (None -> Gap)
|
||||
pub fn generalized_from_options(&mut self, v: &[Option<u8>]) {
|
||||
let mut res = vec![];
|
||||
#[must_use]
|
||||
pub fn generalized_from_options(v: &[Option<u8>]) -> Self {
|
||||
let mut generalized = vec![];
|
||||
let mut bytes = vec![];
|
||||
if v.first() != Some(&None) {
|
||||
res.push(GeneralizedItem::Gap);
|
||||
generalized.push(GeneralizedItem::Gap);
|
||||
}
|
||||
for e in v {
|
||||
match e {
|
||||
None => {
|
||||
if !bytes.is_empty() {
|
||||
res.push(GeneralizedItem::Bytes(bytes.clone()));
|
||||
generalized.push(GeneralizedItem::Bytes(bytes.clone()));
|
||||
bytes.clear();
|
||||
}
|
||||
res.push(GeneralizedItem::Gap);
|
||||
generalized.push(GeneralizedItem::Gap);
|
||||
}
|
||||
Some(b) => {
|
||||
bytes.push(*b);
|
||||
@ -167,71 +54,93 @@ impl GeneralizedInput {
|
||||
}
|
||||
}
|
||||
if !bytes.is_empty() {
|
||||
res.push(GeneralizedItem::Bytes(bytes));
|
||||
generalized.push(GeneralizedItem::Bytes(bytes));
|
||||
}
|
||||
if res.last() != Some(&GeneralizedItem::Gap) {
|
||||
res.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);
|
||||
if generalized.last() != Some(&GeneralizedItem::Gap) {
|
||||
generalized.push(GeneralizedItem::Gap);
|
||||
}
|
||||
Self { generalized }
|
||||
}
|
||||
|
||||
/// Get the size of the generalized
|
||||
#[must_use]
|
||||
pub fn generalized_len(&self) -> usize {
|
||||
match &self.generalized {
|
||||
None => 0,
|
||||
Some(gen) => {
|
||||
let mut size = 0;
|
||||
for item in gen {
|
||||
match item {
|
||||
GeneralizedItem::Bytes(b) => size += b.len(),
|
||||
GeneralizedItem::Gap => size += 1,
|
||||
}
|
||||
}
|
||||
size
|
||||
let mut size = 0;
|
||||
for item in &self.generalized {
|
||||
match item {
|
||||
GeneralizedItem::Bytes(b) => size += b.len(),
|
||||
GeneralizedItem::Gap => size += 1,
|
||||
}
|
||||
}
|
||||
size
|
||||
}
|
||||
|
||||
/// Convert generalized to bytes
|
||||
#[must_use]
|
||||
pub fn generalized_to_bytes(&self) -> Vec<u8> {
|
||||
match &self.generalized {
|
||||
None => vec![],
|
||||
Some(gen) => {
|
||||
let mut bytes = vec![];
|
||||
for item in gen {
|
||||
if let GeneralizedItem::Bytes(b) = item {
|
||||
bytes.extend_from_slice(b);
|
||||
}
|
||||
}
|
||||
bytes
|
||||
}
|
||||
}
|
||||
self.generalized
|
||||
.iter()
|
||||
.filter_map(|item| match item {
|
||||
GeneralizedItem::Bytes(bytes) => Some(bytes),
|
||||
GeneralizedItem::Gap => None,
|
||||
})
|
||||
.flatten()
|
||||
.copied()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get the generalized input
|
||||
#[must_use]
|
||||
pub fn generalized(&self) -> Option<&[GeneralizedItem]> {
|
||||
self.generalized.as_deref()
|
||||
pub fn generalized(&self) -> &[GeneralizedItem] {
|
||||
&self.generalized
|
||||
}
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ use crate::{
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EncodedRandMutator;
|
||||
|
||||
impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedRandMutator {
|
||||
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedRandMutator {
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
@ -58,7 +58,7 @@ impl EncodedRandMutator {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EncodedIncMutator;
|
||||
|
||||
impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedIncMutator {
|
||||
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedIncMutator {
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
@ -93,7 +93,7 @@ impl EncodedIncMutator {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EncodedDecMutator;
|
||||
|
||||
impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedDecMutator {
|
||||
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedDecMutator {
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
@ -128,7 +128,7 @@ impl EncodedDecMutator {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EncodedAddMutator;
|
||||
|
||||
impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedAddMutator {
|
||||
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedAddMutator {
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
@ -167,7 +167,7 @@ impl EncodedAddMutator {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EncodedDeleteMutator;
|
||||
|
||||
impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedDeleteMutator {
|
||||
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedDeleteMutator {
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
@ -207,9 +207,9 @@ pub struct EncodedInsertCopyMutator {
|
||||
tmp_buf: Vec<u32>,
|
||||
}
|
||||
|
||||
impl<S> Mutator<S> for EncodedInsertCopyMutator
|
||||
impl<S> Mutator<EncodedInput, S> for EncodedInsertCopyMutator
|
||||
where
|
||||
S: UsesInput<Input = EncodedInput> + HasRand + HasMaxSize,
|
||||
S: HasRand + HasMaxSize,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
@ -268,7 +268,7 @@ impl EncodedInsertCopyMutator {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EncodedCopyMutator;
|
||||
|
||||
impl<S: UsesInput<Input = EncodedInput> + HasRand> Mutator<S> for EncodedCopyMutator {
|
||||
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedCopyMutator {
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
@ -308,7 +308,7 @@ impl EncodedCopyMutator {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EncodedCrossoverInsertMutator;
|
||||
|
||||
impl<S> Mutator<S> for EncodedCrossoverInsertMutator
|
||||
impl<S> Mutator<S::Input, S> for EncodedCrossoverInsertMutator
|
||||
where
|
||||
S: UsesInput<Input = EncodedInput> + HasRand + HasCorpus + HasMaxSize,
|
||||
{
|
||||
@ -381,7 +381,7 @@ impl EncodedCrossoverInsertMutator {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EncodedCrossoverReplaceMutator;
|
||||
|
||||
impl<S> Mutator<S> for EncodedCrossoverReplaceMutator
|
||||
impl<S> Mutator<S::Input, S> for EncodedCrossoverReplaceMutator
|
||||
where
|
||||
S: UsesInput<Input = EncodedInput> + HasRand + HasCorpus,
|
||||
{
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
bolts::{rands::Rand, tuples::Named},
|
||||
corpus::Corpus,
|
||||
generators::GramatronGenerator,
|
||||
inputs::{GramatronInput, Terminal, UsesInput},
|
||||
inputs::{GramatronInput, Terminal},
|
||||
mutators::{MutationResult, Mutator},
|
||||
random_corpus_id,
|
||||
state::{HasCorpus, HasMetadata, HasRand},
|
||||
@ -28,9 +28,9 @@ where
|
||||
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
|
||||
S: UsesInput<Input = GramatronInput> + HasRand + HasMetadata,
|
||||
S: HasRand + HasMetadata,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
@ -97,9 +97,9 @@ impl GramatronIdxMapMetadata {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct GramatronSpliceMutator;
|
||||
|
||||
impl<S> Mutator<S> for GramatronSpliceMutator
|
||||
impl<S> Mutator<S::Input, S> for GramatronSpliceMutator
|
||||
where
|
||||
S: UsesInput<Input = GramatronInput> + HasRand + HasCorpus + HasMetadata,
|
||||
S: HasRand + HasCorpus<Input = GramatronInput> + HasMetadata,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
@ -169,9 +169,9 @@ pub struct GramatronRecursionMutator {
|
||||
feature: Vec<Terminal>,
|
||||
}
|
||||
|
||||
impl<S> Mutator<S> for GramatronRecursionMutator
|
||||
impl<S> Mutator<GramatronInput, S> for GramatronRecursionMutator
|
||||
where
|
||||
S: UsesInput<Input = GramatronInput> + HasRand + HasMetadata,
|
||||
S: HasRand + HasMetadata,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
|
@ -7,7 +7,7 @@ use core::cmp::{max, min};
|
||||
use crate::{
|
||||
bolts::{rands::Rand, tuples::Named},
|
||||
corpus::Corpus,
|
||||
inputs::{GeneralizedInput, GeneralizedItem, UsesInput},
|
||||
inputs::{GeneralizedInputMetadata, GeneralizedItem},
|
||||
mutators::{token_mutations::Tokens, MutationResult, Mutator},
|
||||
stages::generalization::GeneralizedIndexesMetadata,
|
||||
state::{HasCorpus, HasMetadata, HasRand},
|
||||
@ -24,7 +24,7 @@ fn extend_with_random_generalized<S>(
|
||||
gap_indices: &mut Vec<usize>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
S: HasMetadata + HasRand + HasCorpus<Input = GeneralizedInput>,
|
||||
S: HasMetadata + HasRand + HasCorpus,
|
||||
{
|
||||
let rand_idx = state.rand_mut().next() as usize;
|
||||
|
||||
@ -40,50 +40,42 @@ where
|
||||
.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) < 50 {
|
||||
let rand1 = 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 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 {
|
||||
let gen = other.generalized().unwrap();
|
||||
for (i, _) in gen
|
||||
.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
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, x)| *x == GeneralizedItem::Gap)
|
||||
{
|
||||
gap_indices.push(i);
|
||||
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(());
|
||||
}
|
||||
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 other = other_testcase.load_input()?;
|
||||
let gen = other.generalized().unwrap();
|
||||
let other = other_testcase
|
||||
.metadata_mut()
|
||||
.get::<GeneralizedInputMetadata>()
|
||||
.unwrap();
|
||||
let gen = other.generalized();
|
||||
|
||||
if items.last() == Some(&GeneralizedItem::Gap) && gen.first() == Some(&GeneralizedItem::Gap) {
|
||||
items.extend_from_slice(&gen[1..]);
|
||||
@ -128,27 +123,22 @@ pub struct GrimoireExtensionMutator {
|
||||
gap_indices: Vec<usize>,
|
||||
}
|
||||
|
||||
impl<S> Mutator<S> for GrimoireExtensionMutator
|
||||
impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireExtensionMutator
|
||||
where
|
||||
S: UsesInput<Input = GeneralizedInput> + HasMetadata + HasRand + HasCorpus,
|
||||
S: HasMetadata + HasRand + HasCorpus,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut GeneralizedInput,
|
||||
generalised_meta: &mut GeneralizedInputMetadata,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if input.generalized().is_none() {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
|
||||
extend_with_random_generalized(
|
||||
state,
|
||||
input.generalized_mut().as_mut().unwrap(),
|
||||
generalised_meta.generalized_mut(),
|
||||
&mut self.gap_indices,
|
||||
)?;
|
||||
|
||||
input.grimoire_mutated = true;
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
}
|
||||
@ -176,29 +166,25 @@ pub struct GrimoireRecursiveReplacementMutator {
|
||||
gap_indices: Vec<usize>,
|
||||
}
|
||||
|
||||
impl<S> Mutator<S> for GrimoireRecursiveReplacementMutator
|
||||
impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireRecursiveReplacementMutator
|
||||
where
|
||||
S: UsesInput<Input = GeneralizedInput> + HasMetadata + HasRand + HasCorpus,
|
||||
S: HasMetadata + HasRand + HasCorpus,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut GeneralizedInput,
|
||||
generalised_meta: &mut GeneralizedInputMetadata,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if input.generalized().is_none() {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
|
||||
let mut mutated = MutationResult::Skipped;
|
||||
|
||||
let depth = *state.rand_mut().choose(&RECURSIVE_REPLACEMENT_DEPTH);
|
||||
for _ in 0..depth {
|
||||
if input.generalized_len() >= MAX_RECURSIVE_REPLACEMENT_LEN {
|
||||
if generalised_meta.generalized_len() >= MAX_RECURSIVE_REPLACEMENT_LEN {
|
||||
break;
|
||||
}
|
||||
|
||||
let gen = input.generalized_mut().as_mut().unwrap();
|
||||
let gen = generalised_meta.generalized_mut();
|
||||
|
||||
for (i, _) in gen
|
||||
.iter()
|
||||
@ -207,6 +193,9 @@ where
|
||||
{
|
||||
self.gap_indices.push(i);
|
||||
}
|
||||
if self.gap_indices.is_empty() {
|
||||
break;
|
||||
}
|
||||
let selected = *state.rand_mut().choose(&self.gap_indices);
|
||||
self.gap_indices.clear();
|
||||
|
||||
@ -219,7 +208,6 @@ where
|
||||
self.scratch.clear();
|
||||
|
||||
mutated = MutationResult::Mutated;
|
||||
input.grimoire_mutated = true;
|
||||
}
|
||||
|
||||
Ok(mutated)
|
||||
@ -247,30 +235,28 @@ impl GrimoireRecursiveReplacementMutator {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct GrimoireStringReplacementMutator {}
|
||||
|
||||
impl<S> Mutator<S> for GrimoireStringReplacementMutator
|
||||
impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireStringReplacementMutator
|
||||
where
|
||||
S: UsesInput<Input = GeneralizedInput> + HasMetadata + HasRand,
|
||||
S: HasMetadata + HasRand + HasCorpus,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut GeneralizedInput,
|
||||
generalised_meta: &mut GeneralizedInputMetadata,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if input.generalized().is_none() {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
|
||||
let tokens_len = {
|
||||
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);
|
||||
}
|
||||
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 mut token_replace = state.rand_mut().below(tokens_len as u64) as usize;
|
||||
if token_find == token_replace {
|
||||
@ -286,7 +272,7 @@ where
|
||||
|
||||
let mut mutated = MutationResult::Skipped;
|
||||
|
||||
let gen = input.generalized_mut().as_mut().unwrap();
|
||||
let gen = generalised_meta.generalized_mut();
|
||||
rand_idx %= gen.len();
|
||||
|
||||
'first: for item in &mut gen[..rand_idx] {
|
||||
@ -330,7 +316,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
input.grimoire_mutated = true;
|
||||
Ok(mutated)
|
||||
}
|
||||
}
|
||||
@ -355,22 +340,17 @@ pub struct GrimoireRandomDeleteMutator {
|
||||
gap_indices: Vec<usize>,
|
||||
}
|
||||
|
||||
impl<S> Mutator<S> for GrimoireRandomDeleteMutator
|
||||
impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireRandomDeleteMutator
|
||||
where
|
||||
S: UsesInput<Input = GeneralizedInput> + HasMetadata + HasRand + HasCorpus,
|
||||
S: HasMetadata + HasRand + HasCorpus,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut GeneralizedInput,
|
||||
generalised_meta: &mut GeneralizedInputMetadata,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if input.generalized().is_none() {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
|
||||
input.grimoire_mutated = true;
|
||||
let gen = input.generalized_mut().as_mut().unwrap();
|
||||
let gen = generalised_meta.generalized_mut();
|
||||
|
||||
for (i, _) in gen
|
||||
.iter()
|
||||
@ -387,12 +367,14 @@ where
|
||||
|
||||
self.gap_indices.clear();
|
||||
|
||||
if min_idx == max_idx {
|
||||
Ok(MutationResult::Skipped)
|
||||
let result = if min_idx == max_idx {
|
||||
MutationResult::Skipped
|
||||
} else {
|
||||
gen.drain(min_idx..max_idx);
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
MutationResult::Mutated
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ pub use nautilus::*;
|
||||
use crate::{
|
||||
bolts::tuples::{HasConstLen, Named},
|
||||
corpus::CorpusId,
|
||||
inputs::UsesInput,
|
||||
Error,
|
||||
};
|
||||
|
||||
@ -45,15 +44,12 @@ pub enum MutationResult {
|
||||
|
||||
/// A mutator takes input, and mutates it.
|
||||
/// Simple as that.
|
||||
pub trait Mutator<S>
|
||||
where
|
||||
S: UsesInput,
|
||||
{
|
||||
pub trait Mutator<I, S> {
|
||||
/// Mutate a given input
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error>;
|
||||
|
||||
@ -69,15 +65,12 @@ where
|
||||
}
|
||||
|
||||
/// A `Tuple` of `Mutators` that can execute multiple `Mutators` in a row.
|
||||
pub trait MutatorsTuple<S>: HasConstLen
|
||||
where
|
||||
S: UsesInput,
|
||||
{
|
||||
pub trait MutatorsTuple<I, S>: HasConstLen {
|
||||
/// Runs the `mutate` function on all `Mutators` in this `Tuple`.
|
||||
fn mutate_all(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error>;
|
||||
|
||||
@ -94,7 +87,7 @@ where
|
||||
&mut self,
|
||||
index: usize,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error>;
|
||||
|
||||
@ -108,14 +101,11 @@ where
|
||||
) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
impl<S> MutatorsTuple<S> for ()
|
||||
where
|
||||
S: UsesInput,
|
||||
{
|
||||
impl<I, S> MutatorsTuple<I, S> for () {
|
||||
fn mutate_all(
|
||||
&mut self,
|
||||
_state: &mut S,
|
||||
_input: &mut S::Input,
|
||||
_input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
Ok(MutationResult::Skipped)
|
||||
@ -134,7 +124,7 @@ where
|
||||
&mut self,
|
||||
_index: usize,
|
||||
_state: &mut S,
|
||||
_input: &mut S::Input,
|
||||
_input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
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
|
||||
Head: Mutator<S> + Named,
|
||||
Tail: MutatorsTuple<S>,
|
||||
S: UsesInput,
|
||||
Head: Mutator<I, S> + Named,
|
||||
Tail: MutatorsTuple<I, S>,
|
||||
{
|
||||
fn mutate_all(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let r = self.0.mutate(state, input, stage_idx)?;
|
||||
@ -185,7 +174,7 @@ where
|
||||
&mut self,
|
||||
index: usize,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if index == 0 {
|
||||
@ -238,7 +227,7 @@ pub mod pybind {
|
||||
}
|
||||
}
|
||||
|
||||
impl Mutator<PythonStdState> for PyObjectMutator {
|
||||
impl Mutator<BytesInput, PythonStdState> for PyObjectMutator {
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut PythonStdState,
|
||||
@ -337,7 +326,7 @@ pub mod pybind {
|
||||
}
|
||||
}
|
||||
|
||||
impl Mutator<PythonStdState> for PythonMutator {
|
||||
impl Mutator<BytesInput, PythonStdState> for PythonMutator {
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut PythonStdState,
|
||||
|
@ -359,21 +359,21 @@ pub enum MOptMode {
|
||||
|
||||
/// This is the main struct of `MOpt`, an `AFL` mutator.
|
||||
/// 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
|
||||
MT: MutatorsTuple<S>,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand + HasMetadata + HasCorpus + HasSolutions,
|
||||
{
|
||||
mode: MOptMode,
|
||||
finds_before: usize,
|
||||
mutations: MT,
|
||||
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
|
||||
MT: MutatorsTuple<S>,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand + HasMetadata + HasCorpus + HasSolutions,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
@ -381,21 +381,21 @@ where
|
||||
f,
|
||||
"StdMOptMutator with {} mutations for Input type {}",
|
||||
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
|
||||
MT: MutatorsTuple<S>,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand + HasMetadata + HasCorpus + HasSolutions,
|
||||
{
|
||||
#[inline]
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
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
|
||||
MT: MutatorsTuple<S>,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand + HasMetadata + HasCorpus + HasSolutions,
|
||||
{
|
||||
/// Create a new [`StdMOptMutator`].
|
||||
@ -548,7 +548,7 @@ where
|
||||
fn core_mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let mut r = MutationResult::Skipped;
|
||||
@ -578,7 +578,7 @@ where
|
||||
fn pilot_mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
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
|
||||
MT: MutatorsTuple<S>,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand + HasMetadata + HasCorpus + HasSolutions,
|
||||
{
|
||||
/// 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
|
||||
MT: MutatorsTuple<S>,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand + HasMetadata + HasCorpus + HasSolutions,
|
||||
{
|
||||
/// 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))
|
||||
}
|
||||
|
||||
/// Get the next mutation to apply
|
||||
#[inline]
|
||||
fn schedule(&self, state: &mut S, _: &S::Input) -> usize {
|
||||
fn schedule(&self, state: &mut S, _: &I) -> usize {
|
||||
state
|
||||
.metadata_mut()
|
||||
.get_mut::<MOpt>()
|
||||
@ -655,7 +655,7 @@ where
|
||||
fn scheduled_mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let mode = self.mode;
|
||||
|
@ -9,7 +9,7 @@ use core::{
|
||||
use crate::{
|
||||
bolts::{rands::Rand, tuples::Named},
|
||||
corpus::Corpus,
|
||||
inputs::{HasBytesVec, UsesInput},
|
||||
inputs::HasBytesVec,
|
||||
mutators::{MutationResult, Mutator},
|
||||
random_corpus_id,
|
||||
state::{HasCorpus, HasMaxSize, HasRand},
|
||||
@ -101,15 +101,15 @@ pub const INTERESTING_32: [i32; 27] = [
|
||||
#[derive(Default, Debug)]
|
||||
pub struct BitFlipMutator;
|
||||
|
||||
impl<S> Mutator<S> for BitFlipMutator
|
||||
impl<I, S> Mutator<I, S> for BitFlipMutator
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut <S as UsesInput>::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if input.bytes().is_empty() {
|
||||
@ -141,15 +141,15 @@ impl BitFlipMutator {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ByteFlipMutator;
|
||||
|
||||
impl<S> Mutator<S> for ByteFlipMutator
|
||||
impl<I, S> Mutator<I, S> for ByteFlipMutator
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if input.bytes().is_empty() {
|
||||
@ -179,15 +179,15 @@ impl ByteFlipMutator {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ByteIncMutator;
|
||||
|
||||
impl<S> Mutator<S> for ByteIncMutator
|
||||
impl<I, S> Mutator<I, S> for ByteIncMutator
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if input.bytes().is_empty() {
|
||||
@ -218,15 +218,15 @@ impl ByteIncMutator {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ByteDecMutator;
|
||||
|
||||
impl<S> Mutator<S> for ByteDecMutator
|
||||
impl<I, S> Mutator<I, S> for ByteDecMutator
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if input.bytes().is_empty() {
|
||||
@ -257,15 +257,15 @@ impl ByteDecMutator {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ByteNegMutator;
|
||||
|
||||
impl<S> Mutator<S> for ByteNegMutator
|
||||
impl<I, S> Mutator<I, S> for ByteNegMutator
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if input.bytes().is_empty() {
|
||||
@ -296,15 +296,15 @@ impl ByteNegMutator {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ByteRandMutator;
|
||||
|
||||
impl<S> Mutator<S> for ByteRandMutator
|
||||
impl<I, S> Mutator<I, S> for ByteRandMutator
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if input.bytes().is_empty() {
|
||||
@ -340,15 +340,15 @@ macro_rules! add_mutator_impl {
|
||||
pub struct $name;
|
||||
|
||||
#[allow(trivial_numeric_casts)]
|
||||
impl<S> Mutator<S> for $name
|
||||
impl<I, S> Mutator<I, S> for $name
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if input.bytes().len() < size_of::<$size>() {
|
||||
@ -406,16 +406,16 @@ macro_rules! interesting_mutator_impl {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct $name;
|
||||
|
||||
impl<S> Mutator<S> for $name
|
||||
impl<I, S> Mutator<I, S> for $name
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
if input.bytes().len() < size_of::<$size>() {
|
||||
@ -459,15 +459,15 @@ interesting_mutator_impl!(DwordInterestingMutator, u32, INTERESTING_32);
|
||||
#[derive(Default, Debug)]
|
||||
pub struct BytesDeleteMutator;
|
||||
|
||||
impl<S> Mutator<S> for BytesDeleteMutator
|
||||
impl<I, S> Mutator<I, S> for BytesDeleteMutator
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let size = input.bytes().len();
|
||||
@ -501,15 +501,15 @@ impl BytesDeleteMutator {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct BytesExpandMutator;
|
||||
|
||||
impl<S> Mutator<S> for BytesExpandMutator
|
||||
impl<I, S> Mutator<I, S> for BytesExpandMutator
|
||||
where
|
||||
S: UsesInput + HasRand + HasMaxSize,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand + HasMaxSize,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let max_size = state.max_size();
|
||||
@ -550,15 +550,15 @@ impl BytesExpandMutator {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct BytesInsertMutator;
|
||||
|
||||
impl<S> Mutator<S> for BytesInsertMutator
|
||||
impl<I, S> Mutator<I, S> for BytesInsertMutator
|
||||
where
|
||||
S: UsesInput + HasRand + HasMaxSize,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand + HasMaxSize,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let max_size = state.max_size();
|
||||
@ -605,15 +605,15 @@ impl BytesInsertMutator {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct BytesRandInsertMutator;
|
||||
|
||||
impl<S> Mutator<S> for BytesRandInsertMutator
|
||||
impl<I, S> Mutator<I, S> for BytesRandInsertMutator
|
||||
where
|
||||
S: UsesInput + HasRand + HasMaxSize,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand + HasMaxSize,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let max_size = state.max_size();
|
||||
@ -657,15 +657,15 @@ impl BytesRandInsertMutator {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct BytesSetMutator;
|
||||
|
||||
impl<S> Mutator<S> for BytesSetMutator
|
||||
impl<I, S> Mutator<I, S> for BytesSetMutator
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let size = input.bytes().len();
|
||||
@ -701,15 +701,15 @@ impl BytesSetMutator {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct BytesRandSetMutator;
|
||||
|
||||
impl<S> Mutator<S> for BytesRandSetMutator
|
||||
impl<I, S> Mutator<I, S> for BytesRandSetMutator
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let size = input.bytes().len();
|
||||
@ -745,15 +745,15 @@ impl BytesRandSetMutator {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct BytesCopyMutator;
|
||||
|
||||
impl<S> Mutator<S> for BytesCopyMutator
|
||||
impl<I, S> Mutator<I, S> for BytesCopyMutator
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let size = input.bytes().len();
|
||||
@ -791,15 +791,15 @@ pub struct BytesInsertCopyMutator {
|
||||
tmp_buf: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<S> Mutator<S> for BytesInsertCopyMutator
|
||||
impl<I, S> Mutator<I, S> for BytesInsertCopyMutator
|
||||
where
|
||||
S: UsesInput + HasRand + HasMaxSize,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand + HasMaxSize,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let max_size = state.max_size();
|
||||
@ -853,15 +853,15 @@ impl BytesInsertCopyMutator {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct BytesSwapMutator;
|
||||
|
||||
impl<S> Mutator<S> for BytesSwapMutator
|
||||
impl<I, S> Mutator<I, S> for BytesSwapMutator
|
||||
where
|
||||
S: UsesInput + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let size = input.bytes().len();
|
||||
@ -899,7 +899,7 @@ impl BytesSwapMutator {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct CrossoverInsertMutator;
|
||||
|
||||
impl<S> Mutator<S> for CrossoverInsertMutator
|
||||
impl<S> Mutator<S::Input, S> for CrossoverInsertMutator
|
||||
where
|
||||
S: HasCorpus + HasRand + HasMaxSize,
|
||||
S::Input: HasBytesVec,
|
||||
@ -974,7 +974,7 @@ impl CrossoverInsertMutator {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct CrossoverReplaceMutator;
|
||||
|
||||
impl<S> Mutator<S> for CrossoverReplaceMutator
|
||||
impl<S> Mutator<S::Input, S> for CrossoverReplaceMutator
|
||||
where
|
||||
S: HasCorpus + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
@ -1056,7 +1056,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SpliceMutator;
|
||||
|
||||
impl<S> Mutator<S> for SpliceMutator
|
||||
impl<S> Mutator<S::Input, S> for SpliceMutator
|
||||
where
|
||||
S: HasCorpus + HasRand,
|
||||
S::Input: HasBytesVec,
|
||||
@ -1178,10 +1178,10 @@ mod tests {
|
||||
state::{HasMetadata, StdState},
|
||||
};
|
||||
|
||||
fn test_mutations<S>() -> impl MutatorsTuple<S>
|
||||
fn test_mutations<I, S>() -> impl MutatorsTuple<I, S>
|
||||
where
|
||||
S: HasRand + HasCorpus + HasMetadata + HasMaxSize,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasRand + HasMetadata + HasMaxSize,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
tuple_list!(
|
||||
BitFlipMutator::new(),
|
||||
|
@ -14,7 +14,6 @@ use crate::{
|
||||
generators::nautilus::NautilusContext,
|
||||
inputs::nautilus::NautilusInput,
|
||||
mutators::{MutationResult, Mutator},
|
||||
prelude::UsesInput,
|
||||
state::{HasCorpus, HasMetadata},
|
||||
Error,
|
||||
};
|
||||
@ -31,10 +30,7 @@ impl Debug for NautilusRandomMutator<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Mutator<S> for NautilusRandomMutator<'_>
|
||||
where
|
||||
S: UsesInput<Input = NautilusInput>,
|
||||
{
|
||||
impl<S> Mutator<NautilusInput, S> for NautilusRandomMutator<'_> {
|
||||
fn mutate(
|
||||
&mut self,
|
||||
_state: &mut S,
|
||||
@ -95,10 +91,7 @@ impl Debug for NautilusRecursionMutator<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Mutator<S> for NautilusRecursionMutator<'_>
|
||||
where
|
||||
S: UsesInput<Input = NautilusInput>,
|
||||
{
|
||||
impl<S> Mutator<NautilusInput, S> for NautilusRecursionMutator<'_> {
|
||||
fn mutate(
|
||||
&mut self,
|
||||
_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
|
||||
S: HasCorpus + HasMetadata + UsesInput<Input = NautilusInput>,
|
||||
S: HasCorpus<Input = NautilusInput> + HasMetadata,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
|
@ -16,9 +16,8 @@ use crate::{
|
||||
AsMutSlice, AsSlice,
|
||||
},
|
||||
corpus::{Corpus, CorpusId},
|
||||
inputs::UsesInput,
|
||||
mutators::{MutationResult, Mutator, MutatorsTuple},
|
||||
state::{HasCorpus, HasMetadata, HasRand, State},
|
||||
state::{HasCorpus, HasMetadata, HasRand},
|
||||
Error,
|
||||
};
|
||||
|
||||
@ -55,10 +54,9 @@ impl LogMutationMetadata {
|
||||
}
|
||||
|
||||
/// A [`Mutator`] that composes multiple mutations into one.
|
||||
pub trait ComposedByMutations<MT, S>
|
||||
pub trait ComposedByMutations<I, MT, S>
|
||||
where
|
||||
MT: MutatorsTuple<S>,
|
||||
S: UsesInput,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
{
|
||||
/// Get the mutations
|
||||
fn mutations(&self) -> &MT;
|
||||
@ -68,23 +66,22 @@ where
|
||||
}
|
||||
|
||||
/// 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
|
||||
MT: MutatorsTuple<S>,
|
||||
S: UsesInput,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
{
|
||||
/// 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
|
||||
fn schedule(&self, state: &mut S, input: &S::Input) -> usize;
|
||||
fn schedule(&self, state: &mut S, input: &I) -> usize;
|
||||
|
||||
/// New default implementation for mutate.
|
||||
/// Implementations must forward mutate() to this method
|
||||
fn scheduled_mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let mut r = MutationResult::Skipped;
|
||||
@ -103,51 +100,51 @@ where
|
||||
}
|
||||
|
||||
/// A [`Mutator`] that schedules one of the embedded mutations on each call.
|
||||
pub struct StdScheduledMutator<MT, S>
|
||||
pub struct StdScheduledMutator<I, MT, S>
|
||||
where
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand,
|
||||
{
|
||||
mutations: MT,
|
||||
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
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"StdScheduledMutator with {} mutations for Input type {}",
|
||||
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
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand,
|
||||
{
|
||||
#[inline]
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
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
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand,
|
||||
{
|
||||
/// Get the mutations
|
||||
#[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
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand,
|
||||
{
|
||||
/// 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))
|
||||
}
|
||||
|
||||
/// 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());
|
||||
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
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand,
|
||||
{
|
||||
/// Create a new [`StdScheduledMutator`] instance specifying mutations
|
||||
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`].
|
||||
pub struct LoggerScheduledMutator<MT, S, SM>
|
||||
pub struct LoggerScheduledMutator<I, MT, S, SM>
|
||||
where
|
||||
MT: MutatorsTuple<S> + NamedTuple,
|
||||
S: UsesInput + HasRand + HasCorpus,
|
||||
SM: ScheduledMutator<MT, S>,
|
||||
MT: MutatorsTuple<I, S> + NamedTuple,
|
||||
S: HasRand + HasCorpus,
|
||||
SM: ScheduledMutator<I, MT, S>,
|
||||
{
|
||||
scheduled: SM,
|
||||
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
|
||||
MT: MutatorsTuple<S> + NamedTuple,
|
||||
S: UsesInput + HasRand + HasCorpus,
|
||||
SM: ScheduledMutator<MT, S>,
|
||||
MT: MutatorsTuple<I, S> + NamedTuple,
|
||||
S: HasRand + HasCorpus,
|
||||
SM: ScheduledMutator<I, MT, S>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"LoggerScheduledMutator with {} mutations for Input type {}",
|
||||
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
|
||||
MT: MutatorsTuple<S> + NamedTuple,
|
||||
S: State + HasRand + HasCorpus,
|
||||
SM: ScheduledMutator<MT, S>,
|
||||
MT: MutatorsTuple<I, S> + NamedTuple,
|
||||
S: HasRand + HasCorpus,
|
||||
SM: ScheduledMutator<I, MT, S>,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut <S as UsesInput>::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
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
|
||||
MT: MutatorsTuple<S> + NamedTuple,
|
||||
S: State + HasRand + HasCorpus,
|
||||
SM: ScheduledMutator<MT, S>,
|
||||
MT: MutatorsTuple<I, S> + NamedTuple,
|
||||
S: HasRand + HasCorpus,
|
||||
SM: ScheduledMutator<I, MT, S>,
|
||||
{
|
||||
#[inline]
|
||||
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
|
||||
MT: MutatorsTuple<S> + NamedTuple,
|
||||
S: State + HasRand + HasCorpus,
|
||||
SM: ScheduledMutator<MT, S>,
|
||||
MT: MutatorsTuple<I, S> + NamedTuple,
|
||||
S: HasRand + HasCorpus,
|
||||
SM: ScheduledMutator<I, MT, S>,
|
||||
{
|
||||
/// 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))
|
||||
}
|
||||
|
||||
/// 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());
|
||||
state
|
||||
.rand_mut()
|
||||
@ -378,7 +375,7 @@ where
|
||||
fn scheduled_mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut <S as UsesInput>::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
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
|
||||
MT: MutatorsTuple<S> + NamedTuple,
|
||||
S: State + HasRand + HasCorpus,
|
||||
SM: ScheduledMutator<MT, S>,
|
||||
MT: MutatorsTuple<I, S> + NamedTuple,
|
||||
S: HasRand + HasCorpus,
|
||||
SM: ScheduledMutator<I, MT, S>,
|
||||
{
|
||||
/// Create a new [`StdScheduledMutator`] instance without mutations and corpus
|
||||
pub fn new(scheduled: SM) -> Self {
|
||||
@ -528,14 +525,16 @@ pub mod pybind {
|
||||
use pyo3::prelude::*;
|
||||
|
||||
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")]
|
||||
#[derive(Debug)]
|
||||
/// Python class for StdHavocMutator
|
||||
pub struct PythonStdHavocMutator {
|
||||
/// Rust wrapped StdHavocMutator object
|
||||
pub inner: StdScheduledMutator<HavocMutationsType, PythonStdState>,
|
||||
pub inner: StdScheduledMutator<BytesInput, HavocMutationsType, PythonStdState>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
|
@ -291,15 +291,15 @@ impl<'it> IntoIterator for &'it Tokens {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TokenInsert;
|
||||
|
||||
impl<S> Mutator<S> for TokenInsert
|
||||
impl<I, S> Mutator<I, S> for TokenInsert
|
||||
where
|
||||
S: UsesInput + HasMetadata + HasRand + HasMaxSize,
|
||||
S::Input: HasBytesVec,
|
||||
S: HasMetadata + HasRand + HasMaxSize,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let max_size = state.max_size();
|
||||
@ -357,15 +357,15 @@ impl TokenInsert {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TokenReplace;
|
||||
|
||||
impl<S> Mutator<S> for TokenReplace
|
||||
impl<I, S> Mutator<I, S> for TokenReplace
|
||||
where
|
||||
S: UsesInput + HasMetadata + HasRand + HasMaxSize,
|
||||
S::Input: HasBytesVec,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let size = input.bytes().len();
|
||||
@ -419,16 +419,16 @@ impl TokenReplace {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct I2SRandReplace;
|
||||
|
||||
impl<S> Mutator<S> for I2SRandReplace
|
||||
impl<I, S> Mutator<I, S> for I2SRandReplace
|
||||
where
|
||||
S: UsesInput + HasMetadata + HasRand + HasMaxSize,
|
||||
S::Input: HasBytesVec,
|
||||
I: HasBytesVec,
|
||||
{
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let size = input.bytes().len();
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
bolts::rands::Rand,
|
||||
impl_serdeany,
|
||||
mutators::{ComposedByMutations, MutationResult, Mutator, MutatorsTuple, ScheduledMutator},
|
||||
state::{HasMetadata, HasRand, State},
|
||||
state::{HasMetadata, HasRand},
|
||||
Error,
|
||||
};
|
||||
|
||||
@ -54,51 +54,51 @@ impl_serdeany!(TuneableScheduledMutatorMetadata);
|
||||
|
||||
/// A [`Mutator`] that schedules one of the embedded mutations on each call.
|
||||
/// The index of the next mutation can be set.
|
||||
pub struct TuneableScheduledMutator<MT, S>
|
||||
pub struct TuneableScheduledMutator<I, MT, S>
|
||||
where
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand,
|
||||
{
|
||||
mutations: MT,
|
||||
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
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"TuneableScheduledMutator with {} mutations for Input type {}",
|
||||
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
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand + HasMetadata,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand + HasMetadata,
|
||||
{
|
||||
#[inline]
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
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
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand,
|
||||
{
|
||||
/// Get the mutations
|
||||
#[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
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand + HasMetadata,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand + HasMetadata,
|
||||
{
|
||||
/// 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) {
|
||||
iters
|
||||
} else {
|
||||
@ -129,7 +129,7 @@ where
|
||||
}
|
||||
|
||||
/// 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());
|
||||
// Assumption: we can not reach this code path without previously adding this metadatum.
|
||||
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
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand + HasMetadata,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand + HasMetadata,
|
||||
{
|
||||
/// Create a new [`TuneableScheduledMutator`] instance specifying mutations
|
||||
pub fn new(state: &mut S, mutations: MT) -> Self {
|
||||
@ -222,7 +222,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_tuning() {
|
||||
let mut state = NopState::new();
|
||||
let mut state: NopState<BytesInput> = NopState::new();
|
||||
let mutators = tuple_list!(
|
||||
BitFlipMutator::new(),
|
||||
ByteDecMutator::new(),
|
||||
|
@ -16,7 +16,7 @@ use crate::{
|
||||
corpus::{Corpus, CorpusId},
|
||||
executors::{Executor, HasObservers},
|
||||
feedbacks::map::MapNoveltiesMetadata,
|
||||
inputs::{GeneralizedInput, GeneralizedItem, HasBytesVec, UsesInput},
|
||||
inputs::{BytesInput, GeneralizedInputMetadata, GeneralizedItem, HasBytesVec, UsesInput},
|
||||
mark_feature_time,
|
||||
observers::{MapObserver, ObserversTuple},
|
||||
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>
|
||||
where
|
||||
EM: UsesState,
|
||||
EM::State: UsesInput<Input = GeneralizedInput>,
|
||||
EM::State: UsesInput<Input = BytesInput>,
|
||||
{
|
||||
type State = EM::State;
|
||||
}
|
||||
@ -79,7 +79,7 @@ where
|
||||
O: MapObserver,
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
E::Observers: ObserversTuple<E::State>,
|
||||
E::State: UsesInput<Input = GeneralizedInput>
|
||||
E::State: UsesInput<Input = BytesInput>
|
||||
+ HasClientPerfMonitor
|
||||
+ HasExecutions
|
||||
+ HasMetadata
|
||||
@ -110,9 +110,8 @@ where
|
||||
state.corpus().get(corpus_idx)?.borrow_mut().load_input()?;
|
||||
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
||||
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);
|
||||
state
|
||||
.metadata_mut()
|
||||
@ -123,6 +122,8 @@ where
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let input = entry.input_mut().as_mut().unwrap();
|
||||
|
||||
let payload: Vec<_> = input.bytes().iter().map(|&x| Some(x)).collect();
|
||||
let original = input.clone();
|
||||
let meta = entry.metadata().get::<MapNoveltiesMetadata>().ok_or_else(|| {
|
||||
@ -324,23 +325,13 @@ where
|
||||
if payload.len() <= MAX_GENERALIZED_LEN {
|
||||
// Save the modified input in the corpus
|
||||
{
|
||||
let mut entry = state.corpus().get(corpus_idx)?.borrow_mut();
|
||||
entry.load_input()?;
|
||||
entry
|
||||
.input_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.generalized_from_options(&payload);
|
||||
entry.store_input()?;
|
||||
let meta = GeneralizedInputMetadata::generalized_from_options(&payload);
|
||||
|
||||
debug_assert!(
|
||||
entry.load_input()?.generalized().unwrap().first()
|
||||
== Some(&GeneralizedItem::Gap)
|
||||
);
|
||||
debug_assert!(
|
||||
entry.load_input()?.generalized().unwrap().last()
|
||||
== Some(&GeneralizedItem::Gap)
|
||||
);
|
||||
debug_assert!(meta.generalized().first() == Some(&GeneralizedItem::Gap));
|
||||
debug_assert!(meta.generalized().last() == Some(&GeneralizedItem::Gap));
|
||||
|
||||
let mut entry = state.corpus().get(corpus_idx)?.borrow_mut();
|
||||
entry.metadata_mut().insert(meta);
|
||||
}
|
||||
|
||||
state
|
||||
@ -360,7 +351,7 @@ where
|
||||
EM: UsesState,
|
||||
O: MapObserver,
|
||||
OT: ObserversTuple<EM::State>,
|
||||
EM::State: UsesInput<Input = GeneralizedInput>
|
||||
EM::State: UsesInput<Input = BytesInput>
|
||||
+ HasClientPerfMonitor
|
||||
+ HasExecutions
|
||||
+ HasMetadata
|
||||
@ -391,7 +382,7 @@ where
|
||||
state: &mut EM::State,
|
||||
manager: &mut EM,
|
||||
novelties: &[usize],
|
||||
input: &GeneralizedInput,
|
||||
input: &BytesInput,
|
||||
) -> Result<bool, Error>
|
||||
where
|
||||
E: Executor<EM, Z> + HasObservers<Observers = OT, State = EM::State>,
|
||||
@ -449,7 +440,7 @@ where
|
||||
if end > payload.len() {
|
||||
end = payload.len();
|
||||
}
|
||||
let mut candidate = GeneralizedInput::new(vec![]);
|
||||
let mut candidate = BytesInput::new(vec![]);
|
||||
candidate
|
||||
.bytes_mut()
|
||||
.extend(payload[..start].iter().flatten());
|
||||
@ -502,7 +493,7 @@ where
|
||||
while end > start {
|
||||
if payload[end] == Some(closing_char) {
|
||||
endings += 1;
|
||||
let mut candidate = GeneralizedInput::new(vec![]);
|
||||
let mut candidate = BytesInput::new(vec![]);
|
||||
candidate
|
||||
.bytes_mut()
|
||||
.extend(payload[..start].iter().flatten());
|
||||
|
@ -7,8 +7,9 @@ use core::marker::PhantomData;
|
||||
use crate::monitors::PerfFeature;
|
||||
use crate::{
|
||||
bolts::rands::Rand,
|
||||
corpus::{Corpus, CorpusId},
|
||||
corpus::{Corpus, CorpusId, Testcase},
|
||||
fuzzer::Evaluator,
|
||||
inputs::Input,
|
||||
mark_feature_time,
|
||||
mutators::Mutator,
|
||||
stages::Stage,
|
||||
@ -19,16 +20,79 @@ use crate::{
|
||||
|
||||
// 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.
|
||||
/// Mutational stages will usually have a range of mutations that are
|
||||
/// 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
|
||||
E: UsesState<State = Self::State>,
|
||||
M: Mutator<Self::State>,
|
||||
M: Mutator<I, Self::State>,
|
||||
EM: UsesState<State = Self::State>,
|
||||
Z: Evaluator<E, EM, State = Self::State>,
|
||||
Self::State: HasClientPerfMonitor + HasCorpus,
|
||||
I: MutatedTransform<Self::Input, Self::State> + Clone,
|
||||
{
|
||||
/// The mutator registered for this stage
|
||||
fn mutator(&self) -> &M;
|
||||
@ -51,25 +115,26 @@ where
|
||||
) -> Result<(), Error> {
|
||||
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 {
|
||||
start_timer!(state);
|
||||
let mut input = state
|
||||
.corpus()
|
||||
.get(corpus_idx)?
|
||||
.borrow_mut()
|
||||
.load_input()?
|
||||
.clone();
|
||||
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
||||
let mut input = input.clone();
|
||||
|
||||
start_timer!(state);
|
||||
self.mutator_mut().mutate(state, &mut input, i as i32)?;
|
||||
mark_feature_time!(state, PerfFeature::Mutate);
|
||||
|
||||
// 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);
|
||||
self.mutator_mut().post_exec(state, i as i32, corpus_idx)?;
|
||||
post.post_exec(state, i as i32, corpus_idx)?;
|
||||
mark_feature_time!(state, PerfFeature::MutatePostExec);
|
||||
}
|
||||
Ok(())
|
||||
@ -82,19 +147,20 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128;
|
||||
|
||||
/// The default mutational stage
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StdMutationalStage<E, EM, M, Z> {
|
||||
pub struct StdMutationalStage<E, EM, I, M, Z> {
|
||||
mutator: M,
|
||||
#[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
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
M: Mutator<Z::State>,
|
||||
M: Mutator<I, Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
|
||||
I: MutatedTransform<Self::Input, Self::State> + Clone,
|
||||
{
|
||||
/// The mutator, added to this stage
|
||||
#[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
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
M: Mutator<Z::State>,
|
||||
M: Mutator<I, Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
|
||||
{
|
||||
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
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
M: Mutator<Z::State>,
|
||||
M: Mutator<I, Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
|
||||
I: MutatedTransform<Self::Input, Self::State> + Clone,
|
||||
{
|
||||
#[inline]
|
||||
#[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
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
M: Mutator<Z::State>,
|
||||
M: Mutator<Z::Input, Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
|
||||
{
|
||||
/// Creates a new default mutational stage
|
||||
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 {
|
||||
mutator,
|
||||
phantom: PhantomData,
|
||||
@ -179,6 +260,7 @@ pub mod pybind {
|
||||
events::pybind::PythonEventManager,
|
||||
executors::pybind::PythonExecutor,
|
||||
fuzzer::pybind::PythonStdFuzzer,
|
||||
inputs::BytesInput,
|
||||
mutators::pybind::PythonMutator,
|
||||
stages::{pybind::PythonStage, StdMutationalStage},
|
||||
};
|
||||
@ -188,8 +270,13 @@ pub mod pybind {
|
||||
/// Python class for StdMutationalStage
|
||||
pub struct PythonStdMutationalStage {
|
||||
/// Rust wrapped StdMutationalStage object
|
||||
pub inner:
|
||||
StdMutationalStage<PythonExecutor, PythonEventManager, PythonMutator, PythonStdFuzzer>,
|
||||
pub inner: StdMutationalStage<
|
||||
PythonExecutor,
|
||||
PythonEventManager,
|
||||
BytesInput,
|
||||
PythonMutator,
|
||||
PythonStdFuzzer,
|
||||
>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
|
@ -13,36 +13,41 @@ use crate::{
|
||||
schedulers::{
|
||||
powersched::SchedulerMetadata, testcase_score::CorpusPowerTestcaseScore, TestcaseScore,
|
||||
},
|
||||
stages::{MutationalStage, Stage},
|
||||
stages::{
|
||||
mutational::{MutatedTransform, MutatedTransformPost},
|
||||
MutationalStage, Stage,
|
||||
},
|
||||
state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState},
|
||||
Error,
|
||||
};
|
||||
|
||||
/// The mutational stage using power schedules
|
||||
#[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,
|
||||
mutator: M,
|
||||
#[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
|
||||
E: UsesState,
|
||||
{
|
||||
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
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
EM: UsesState<State = E::State>,
|
||||
F: TestcaseScore<E::State>,
|
||||
M: Mutator<E::State>,
|
||||
M: Mutator<I, E::State>,
|
||||
O: MapObserver,
|
||||
E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
|
||||
Z: Evaluator<E, EM, State = E::State>,
|
||||
I: MutatedTransform<E::Input, E::State> + Clone,
|
||||
{
|
||||
/// The mutator, added to this stage
|
||||
#[inline]
|
||||
@ -77,17 +82,17 @@ where
|
||||
) -> Result<(), Error> {
|
||||
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 {
|
||||
let mut input = state
|
||||
.corpus()
|
||||
.get(corpus_idx)?
|
||||
.borrow_mut()
|
||||
.load_input()?
|
||||
.clone();
|
||||
let mut input = input.clone();
|
||||
|
||||
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
|
||||
.observers()
|
||||
@ -119,21 +124,23 @@ where
|
||||
}
|
||||
|
||||
self.mutator_mut().post_exec(state, i as i32, corpus_idx)?;
|
||||
post.post_exec(state, i as i32, corpus_idx)?;
|
||||
}
|
||||
|
||||
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
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
EM: UsesState<State = E::State>,
|
||||
F: TestcaseScore<E::State>,
|
||||
M: Mutator<E::State>,
|
||||
M: Mutator<I, E::State>,
|
||||
O: MapObserver,
|
||||
E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
|
||||
Z: Evaluator<E, EM, State = E::State>,
|
||||
I: MutatedTransform<E::Input, E::State> + Clone,
|
||||
{
|
||||
#[inline]
|
||||
#[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
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
EM: UsesState<State = E::State>,
|
||||
F: TestcaseScore<E::State>,
|
||||
M: Mutator<E::State>,
|
||||
M: Mutator<E::Input, E::State>,
|
||||
O: MapObserver,
|
||||
E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
|
||||
Z: Evaluator<E, EM, State = E::State>,
|
||||
{
|
||||
/// Creates a new [`PowerMutationalStage`]
|
||||
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 {
|
||||
map_observer_name: map_observer_name.name().to_string(),
|
||||
mutator,
|
||||
@ -171,5 +194,5 @@ where
|
||||
}
|
||||
|
||||
/// The standard powerscheduling stage
|
||||
pub type StdPowerMutationalStage<E, EM, M, O, Z> =
|
||||
PowerMutationalStage<E, CorpusPowerTestcaseScore<<E as UsesState>::State>, EM, M, O, Z>;
|
||||
pub type StdPowerMutationalStage<E, EM, I, M, O, Z> =
|
||||
PowerMutationalStage<E, CorpusPowerTestcaseScore<<E as UsesState>::State>, EM, I, M, O, Z>;
|
||||
|
@ -41,7 +41,7 @@ pub struct StdMutationalPushStage<CS, EM, M, OT, Z>
|
||||
where
|
||||
CS: Scheduler,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
|
||||
M: Mutator<CS::State>,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
CS::State: HasClientPerfMonitor + HasRand + Clone + Debug,
|
||||
Z: ExecutionProcessor<OT, State = CS::State>
|
||||
@ -63,7 +63,7 @@ impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z>
|
||||
where
|
||||
CS: Scheduler,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
|
||||
M: Mutator<CS::State>,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
CS::State: HasClientPerfMonitor + HasCorpus + HasRand + Clone + Debug,
|
||||
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
|
||||
CS: Scheduler,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter,
|
||||
M: Mutator<CS::State>,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
CS::State:
|
||||
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
|
||||
CS: Scheduler,
|
||||
EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = CS::State>,
|
||||
M: Mutator<CS::State>,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
CS::State:
|
||||
HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug,
|
||||
@ -218,7 +218,7 @@ impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z>
|
||||
where
|
||||
CS: Scheduler,
|
||||
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
|
||||
M: Mutator<CS::State>,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
CS::State: HasClientPerfMonitor + HasCorpus + HasRand + Clone + Debug,
|
||||
Z: ExecutionProcessor<OT, State = CS::State>
|
||||
|
@ -41,7 +41,7 @@ where
|
||||
EM: EventFirer<State = Self::State>,
|
||||
F1: Feedback<Self::State>,
|
||||
F2: Feedback<Self::State>,
|
||||
M: Mutator<Self::State>,
|
||||
M: Mutator<Self::Input, Self::State>,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
Z: ExecutionProcessor<OT, State = Self::State>
|
||||
+ 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>
|
||||
where
|
||||
CS: Scheduler,
|
||||
M: Mutator<CS::State>,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
Z: ExecutionProcessor<OT, State = CS::State>,
|
||||
{
|
||||
type State = CS::State;
|
||||
@ -194,7 +194,7 @@ where
|
||||
F1: Feedback<CS::State>,
|
||||
F2: Feedback<CS::State>,
|
||||
FF: FeedbackFactory<F2, CS::State, OT>,
|
||||
M: Mutator<CS::State>,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
Z: ExecutionProcessor<OT, State = CS::State>
|
||||
+ ExecutesInput<E, EM>
|
||||
@ -241,7 +241,7 @@ where
|
||||
F2: Feedback<CS::State>,
|
||||
FF: FeedbackFactory<F2, CS::State, OT>,
|
||||
<CS::State as UsesInput>::Input: HasLen + Hash,
|
||||
M: Mutator<CS::State>,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
OT: ObserversTuple<CS::State>,
|
||||
CS::State: HasClientPerfMonitor + HasCorpus + HasExecutions + HasMaxSize,
|
||||
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>
|
||||
where
|
||||
CS: Scheduler,
|
||||
M: Mutator<CS::State>,
|
||||
M: Mutator<CS::Input, CS::State>,
|
||||
Z: ExecutionProcessor<OT, State = CS::State>,
|
||||
{
|
||||
/// Creates a new minimising mutational stage that will minimize provided corpus entries
|
||||
|
@ -9,7 +9,10 @@ use crate::{
|
||||
corpus::CorpusId,
|
||||
impl_serdeany,
|
||||
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},
|
||||
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
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TuneableMutationalStage<E, EM, M, Z> {
|
||||
pub struct TuneableMutationalStage<E, EM, I, M, Z> {
|
||||
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
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
M: Mutator<Z::State>,
|
||||
M: Mutator<I, Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
|
||||
I: MutatedTransform<Z::Input, Z::State> + Clone,
|
||||
{
|
||||
/// The mutator, added to this stage
|
||||
#[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
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
M: Mutator<Z::State>,
|
||||
M: Mutator<I, Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
|
||||
I: MutatedTransform<Z::Input, Z::State> + Clone,
|
||||
{
|
||||
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
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
M: Mutator<Z::State>,
|
||||
M: Mutator<I, Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
|
||||
I: MutatedTransform<Z::Input, Z::State> + Clone,
|
||||
{
|
||||
#[inline]
|
||||
#[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
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
M: Mutator<Z::State>,
|
||||
M: Mutator<Z::Input, Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
|
||||
{
|
||||
/// Creates a new default mutational stage
|
||||
#[must_use]
|
||||
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>() {
|
||||
state.add_metadata(TuneableMutationalStageMetadata::default());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user