unfinished generic magics
This commit is contained in:
parent
31d94925d0
commit
8b22a06ec9
225
libafl/src/corpus/minset.rs
Normal file
225
libafl/src/corpus/minset.rs
Normal file
@ -0,0 +1,225 @@
|
||||
use alloc::{borrow::ToOwned, vec::Vec};
|
||||
use core::{cell::RefCell, iter::Iterator, marker::PhantomData};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus, corpus::HasTestcaseVec, corpus::Testcase, inputs::{HasLen, Input}, utils::Rand, Error,
|
||||
};
|
||||
|
||||
pub trait FavFactor: Serialize + serde::de::DeserializeOwned + 'static
|
||||
{
|
||||
fn compute<I>(testcase: &Testcase<I>) -> Result<u64, Error>
|
||||
where
|
||||
I: Input;
|
||||
}
|
||||
|
||||
pub struct LenTimeMulFavFactor {}
|
||||
|
||||
// TODO time as Duration and put len into Testcase
|
||||
impl FavFactor for LenTimeMulFavFactor {
|
||||
fn compute<I>(entry: &Testcase<I>) -> Result<u64, Error>
|
||||
where
|
||||
I: Input + HasLen
|
||||
{
|
||||
entry.exec_time() * entry.load_input().len()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CorpusMinimizer {
|
||||
fn update_score<C, I, R>(corpus: &mut C, idx: usize) -> Result<(), Error>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand;
|
||||
|
||||
fn cull<C, I, R>(corpus: &mut C) -> Result<(), Error>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand;
|
||||
}
|
||||
|
||||
pub struct FavCorpusMinimizer<F>
|
||||
where
|
||||
F: FavFactor
|
||||
{
|
||||
phantom: PhantomData<F>
|
||||
}
|
||||
|
||||
impl<F> CorpusMinimizer for FavCorpusMinimizer<F>
|
||||
where
|
||||
F: FavFactor
|
||||
{
|
||||
fn update_score<C, I, R>(corpus: &mut C, idx: usize) -> Result<(), Error>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
fn cull<C, I, R>(corpus: &mut C) -> Result<(), Error>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct NoveltiesMeta {
|
||||
novelties: Vec<usize>,
|
||||
}
|
||||
// impl Iterator<Item = usize>
|
||||
|
||||
/// A Queue-like corpus, wrapping an existing Corpus instance
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(bound = "I: serde::de::DeserializeOwned")]
|
||||
pub struct MinSetCorpus<C, F, I, IT, R, T>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
F: FavFactor,
|
||||
I: Input,
|
||||
IT: Iterator<Item = T>,
|
||||
R: Rand,
|
||||
{
|
||||
corpus: C,
|
||||
pos: usize,
|
||||
// TODO rebase minset on remove()
|
||||
minset: HashSet<usize>,
|
||||
top_rated: HashMap<T, usize>,
|
||||
phantom: PhantomData<(F, I, IT, R)>,
|
||||
}
|
||||
|
||||
impl<C, I, R> HasTestcaseVec<I> for MinSetCorpus<C, I, R>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
#[inline]
|
||||
fn entries(&self) -> &[RefCell<Testcase<I>>] {
|
||||
self.corpus.entries()
|
||||
}
|
||||
#[inline]
|
||||
fn entries_mut(&mut self) -> &mut Vec<RefCell<Testcase<I>>> {
|
||||
self.corpus.entries_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, I, R> Corpus<I, R> for MinSetCorpus<C, I, R>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
/// Returns the number of elements
|
||||
#[inline]
|
||||
fn count(&self) -> usize {
|
||||
self.corpus.count()
|
||||
}
|
||||
|
||||
// TODO change add to return Result
|
||||
#[inline]
|
||||
fn add(&mut self, entry: Testcase<I>) -> usize {
|
||||
let idx = self.corpus.add(entry);
|
||||
self.update_score(idx).unwrap();
|
||||
idx
|
||||
}
|
||||
|
||||
/// Removes an entry from the corpus, returning it if it was present.
|
||||
#[inline]
|
||||
fn remove(&mut self, entry: &Testcase<I>) -> Option<Testcase<I>> {
|
||||
self.corpus.remove(entry)
|
||||
}
|
||||
|
||||
/// Gets a random entry
|
||||
#[inline]
|
||||
fn random_entry(&self, rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), Error> {
|
||||
self.corpus.random_entry(rand)
|
||||
}
|
||||
|
||||
/// Returns the testacase we currently use
|
||||
#[inline]
|
||||
fn current_testcase(&self) -> (&RefCell<Testcase<I>>, usize) {
|
||||
(self.get(self.pos - 1), self.pos - 1)
|
||||
}
|
||||
|
||||
/// Gets the next entry
|
||||
#[inline]
|
||||
fn next(&mut self, _rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), Error> {
|
||||
self.cull();
|
||||
self.pos += 1;
|
||||
if self.corpus.count() == 0 {
|
||||
return Err(Error::Empty("Corpus".to_owned()));
|
||||
}
|
||||
if self.pos > self.corpus.count() {
|
||||
// TODO: Always loop or return informational error?
|
||||
self.pos = 1;
|
||||
self.cycles += 1;
|
||||
}
|
||||
Ok((&self.corpus.entries()[self.pos - 1], self.pos - 1))
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, I, R> MinSetCorpus<C, I, R>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
pub fn new(corpus: C) -> Self {
|
||||
Self {
|
||||
corpus: corpus,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn corpus(&self) -> &C {
|
||||
&self.corpus
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn corpus_mut(&mut self) -> &mut C {
|
||||
&mut self.corpus
|
||||
}
|
||||
|
||||
// TODO move this functions and top rated to another struct
|
||||
// create something like MinSetCorpus<.., FavMinimizer<LenTimeMulFavFactor>>
|
||||
|
||||
pub fn update_score(&mut self, idx: usize) -> Result<(), Error> {
|
||||
let factor = F::compute(self.entries()[idx].borrow())?;
|
||||
for elem in entry.get::<IT>() {
|
||||
if let val = self.top_rated.get_mut(elem) {
|
||||
if factor > F::compute(self.entries()[val].borrow())? {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
let _ = self.top_rated.insert(elem, idx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cull(&mut self) {
|
||||
let mut acc = HashSet::new();
|
||||
self.minset.clear();
|
||||
|
||||
for key in self.top_rated.keys() {
|
||||
if !acc.contains(key) {
|
||||
let idx = self.top_rated.get(key).unwrap();
|
||||
let entry = self.entries()[idx].borrow();
|
||||
for elem in entry.get::<IT>() {
|
||||
acc.insert(elem);
|
||||
}
|
||||
|
||||
self.minset.insert(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
103
libafl/src/corpus/mod old.rs
Normal file
103
libafl/src/corpus/mod old.rs
Normal file
@ -0,0 +1,103 @@
|
||||
//! Corpuses contain the testcases, either in mem, on disk, or somewhere else.
|
||||
//! They will hand out the next fuzz target, potentially doing basic scheduling.
|
||||
|
||||
pub mod testcase;
|
||||
pub use testcase::Testcase;
|
||||
|
||||
pub mod inmemory;
|
||||
pub use inmemory::InMemoryCorpus;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub mod ondisk;
|
||||
#[cfg(feature = "std")]
|
||||
pub use ondisk::OnDiskCorpus;
|
||||
|
||||
pub mod queue;
|
||||
pub use queue::QueueCorpus;
|
||||
|
||||
use alloc::{borrow::ToOwned, vec::Vec};
|
||||
use core::{cell::RefCell, ptr};
|
||||
|
||||
use crate::{inputs::Input, utils::Rand, Error};
|
||||
|
||||
/// A way to obtain the containing testcase entries
|
||||
pub trait HasTestcaseVec<I>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
/// Get the entries vector field
|
||||
fn entries(&self) -> &[RefCell<Testcase<I>>];
|
||||
|
||||
/// Get the entries vector field (mutable)
|
||||
fn entries_mut(&mut self) -> &mut Vec<RefCell<Testcase<I>>>;
|
||||
}
|
||||
|
||||
/// Corpus with all current testcases
|
||||
pub trait Corpus<I, R>: HasTestcaseVec<I> + serde::Serialize + serde::de::DeserializeOwned
|
||||
where
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
/// Returns the number of elements
|
||||
#[inline]
|
||||
fn count(&self) -> usize {
|
||||
self.entries().len()
|
||||
}
|
||||
|
||||
// TODO implement a was_fuzzed counter
|
||||
|
||||
/// Add an entry to the corpus and return its index
|
||||
#[inline]
|
||||
fn add(&mut self, testcase: Testcase<I>) -> usize {
|
||||
self.entries_mut().push(RefCell::new(testcase));
|
||||
self.entries().len() - 1
|
||||
}
|
||||
|
||||
/// Replaces the testcase at the given idx
|
||||
fn replace(&mut self, idx: usize, testcase: Testcase<I>) -> Result<(), Error> {
|
||||
if self.entries_mut().len() < idx {
|
||||
return Err(Error::KeyNotFound(format!("Index {} out of bounds", idx)));
|
||||
}
|
||||
self.entries_mut()[idx] = RefCell::new(testcase);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get by id
|
||||
#[inline]
|
||||
fn get(&self, idx: usize) -> &RefCell<Testcase<I>> {
|
||||
&self.entries()[idx]
|
||||
}
|
||||
|
||||
/// Removes an entry from the corpus, returning it if it was present.
|
||||
#[inline]
|
||||
fn remove(&mut self, entry: &Testcase<I>) -> Option<Testcase<I>> {
|
||||
match self
|
||||
.entries()
|
||||
.iter()
|
||||
.position(|x| ptr::eq(x.as_ptr(), entry))
|
||||
{
|
||||
Some(i) => Some(self.entries_mut().remove(i).into_inner()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a random entry
|
||||
#[inline]
|
||||
fn random_entry(&self, rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), Error> {
|
||||
if self.count() == 0 {
|
||||
Err(Error::Empty("No entries in corpus".to_owned()))
|
||||
} else {
|
||||
let len = { self.entries().len() };
|
||||
let id = rand.below(len as u64) as usize;
|
||||
Ok((self.get(id), id))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: IntoIter
|
||||
/// Gets the next entry
|
||||
fn next(&mut self, rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), Error>;
|
||||
|
||||
/// Returns the testacase we currently use
|
||||
fn current_testcase(&self) -> (&RefCell<Testcase<I>>, usize);
|
||||
}
|
||||
|
@ -1,102 +1,204 @@
|
||||
//! Corpuses contain the testcases, either in mem, on disk, or somewhere else.
|
||||
//! They will hand out the next fuzz target, potentially doing basic scheduling.
|
||||
|
||||
pub mod testcase;
|
||||
pub use testcase::Testcase;
|
||||
|
||||
pub mod inmemory;
|
||||
pub use inmemory::InMemoryCorpus;
|
||||
use alloc::{vec::Vec};
|
||||
use core::{cell::RefCell};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub mod ondisk;
|
||||
#[cfg(feature = "std")]
|
||||
pub use ondisk::OnDiskCorpus;
|
||||
|
||||
pub mod queue;
|
||||
pub use queue::QueueCorpus;
|
||||
|
||||
use alloc::{borrow::ToOwned, vec::Vec};
|
||||
use core::{cell::RefCell, ptr};
|
||||
|
||||
use crate::{inputs::Input, utils::Rand, Error};
|
||||
|
||||
/// A way to obtain the containing testcase entries
|
||||
pub trait HasTestcaseVec<I>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
/// Get the entries vector field
|
||||
fn entries(&self) -> &[RefCell<Testcase<I>>];
|
||||
|
||||
/// Get the entries vector field (mutable)
|
||||
fn entries_mut(&mut self) -> &mut Vec<RefCell<Testcase<I>>>;
|
||||
}
|
||||
use crate::{
|
||||
inputs::Input,
|
||||
state::{HasCorpus, HasRand},
|
||||
utils::Rand,
|
||||
Error,
|
||||
};
|
||||
|
||||
/// Corpus with all current testcases
|
||||
pub trait Corpus<I, R>: HasTestcaseVec<I> + serde::Serialize + serde::de::DeserializeOwned
|
||||
pub trait Corpus<I>: serde::Serialize + serde::de::DeserializeOwned
|
||||
where
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
/// Returns the number of elements
|
||||
#[inline]
|
||||
fn count(&self) -> usize {
|
||||
self.entries().len()
|
||||
}
|
||||
|
||||
// TODO implement a was_fuzzed counter
|
||||
fn count(&self) -> usize;
|
||||
|
||||
/// Add an entry to the corpus and return its index
|
||||
#[inline]
|
||||
fn add(&mut self, testcase: Testcase<I>) -> usize {
|
||||
self.entries_mut().push(RefCell::new(testcase));
|
||||
self.entries().len() - 1
|
||||
}
|
||||
fn add(&mut self, testcase: Testcase<I>) -> Result<usize, Error>;
|
||||
|
||||
/// Replaces the testcase at the given idx
|
||||
fn replace(&mut self, idx: usize, testcase: Testcase<I>) -> Result<(), Error> {
|
||||
if self.entries_mut().len() < idx {
|
||||
return Err(Error::KeyNotFound(format!("Index {} out of bounds", idx)));
|
||||
}
|
||||
self.entries_mut()[idx] = RefCell::new(testcase);
|
||||
fn replace(&mut self, idx: usize, testcase: Testcase<I>) -> Result<(), Error>;
|
||||
|
||||
/// Removes an entry from the corpus, returning it if it was present.
|
||||
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<I>>, Error>;
|
||||
|
||||
/// Get by id
|
||||
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error>;
|
||||
}
|
||||
|
||||
pub trait CorpusScheduler {
|
||||
|
||||
/// Add an entry to the corpus and return its index
|
||||
fn on_add<C, I, R, S>(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error>
|
||||
where
|
||||
S: HasCorpus<C, I> + HasRand<R>,
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get by id
|
||||
#[inline]
|
||||
fn get(&self, idx: usize) -> &RefCell<Testcase<I>> {
|
||||
&self.entries()[idx]
|
||||
/// Replaces the testcase at the given idx
|
||||
fn on_replace<C, I, R, S>(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error>
|
||||
where
|
||||
S: HasCorpus<C, I> + HasRand<R>,
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes an entry from the corpus, returning it if it was present.
|
||||
#[inline]
|
||||
fn remove(&mut self, entry: &Testcase<I>) -> Option<Testcase<I>> {
|
||||
match self
|
||||
.entries()
|
||||
.iter()
|
||||
.position(|x| ptr::eq(x.as_ptr(), entry))
|
||||
fn on_remove<C, I, R, S>(&self, state: &mut S, idx: usize, testcase: &Option<Testcase<I>>) -> Result<(), Error>
|
||||
where
|
||||
S: HasCorpus<C, I> + HasRand<R>,
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand
|
||||
{
|
||||
Some(i) => Some(self.entries_mut().remove(i).into_inner()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a random entry
|
||||
#[inline]
|
||||
fn random_entry(&self, rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), Error> {
|
||||
if self.count() == 0 {
|
||||
Err(Error::Empty("No entries in corpus".to_owned()))
|
||||
} else {
|
||||
let len = { self.entries().len() };
|
||||
let id = rand.below(len as u64) as usize;
|
||||
Ok((self.get(id), id))
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: IntoIter
|
||||
/// Gets the next entry
|
||||
fn next(&mut self, rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), Error>;
|
||||
fn next<C, I, R, S>(&self, state: &mut S) -> Result<usize, Error>
|
||||
where
|
||||
S: HasCorpus<C, I> + HasRand<R>,
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand;
|
||||
|
||||
/// Returns the testacase we currently use
|
||||
fn current_testcase(&self) -> (&RefCell<Testcase<I>>, usize);
|
||||
}
|
||||
|
||||
pub struct RandCorpusScheduler {}
|
||||
|
||||
impl CorpusScheduler for RandCorpusScheduler {
|
||||
/// Gets the next entry at random
|
||||
fn next<C, I, R, S>(state: &mut S) -> Result<usize, Error>
|
||||
where
|
||||
S: HasCorpus<C, I> + HasRand<R>,
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand
|
||||
{
|
||||
if state.corpus().count() == 0 {
|
||||
Err(Error::Empty("No entries in corpus".to_owned()))
|
||||
} else {
|
||||
let len = state.corpus().count();
|
||||
let id = state.rand_mut().below(len as u64) as usize;
|
||||
Ok(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InMemoryCorpus<I>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
entries: Vec<RefCell<Testcase<I>>>,
|
||||
}
|
||||
|
||||
impl<I, SC> Corpus<I> for InMemoryCorpus<I>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
|
||||
/// Returns the number of elements
|
||||
#[inline]
|
||||
fn count(&self) -> usize {
|
||||
self.entries.len()
|
||||
}
|
||||
|
||||
/// Add an entry to the corpus and return its index
|
||||
#[inline]
|
||||
fn add(&mut self, testcase: Testcase<I>) -> Result<usize, Error> {
|
||||
self.entries.push(RefCell::new(testcase));
|
||||
Ok(self.entries.len() - 1)
|
||||
}
|
||||
|
||||
/// Replaces the testcase at the given idx
|
||||
#[inline]
|
||||
fn replace(&mut self, idx: usize, testcase: Testcase<I>) -> Result<(), Error> {
|
||||
if idx >= self.entries.len() {
|
||||
return Err(Error::KeyNotFound(format!("Index {} out of bounds", idx)));
|
||||
}
|
||||
self.entries[idx] = RefCell::new(testcase);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes an entry from the corpus, returning it if it was present.
|
||||
#[inline]
|
||||
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<I>>, Error> {
|
||||
if idx >= self.entries.len() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(self.entries.remove(idx).into_inner()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get by id
|
||||
#[inline]
|
||||
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error> {
|
||||
Ok(&self.entries[idx])
|
||||
}
|
||||
|
||||
/*/// Add an entry to the corpus and return its index
|
||||
#[inline]
|
||||
fn add<R, S>(state: &mut S, testcase: Testcase<I>) -> Result<usize, Error>
|
||||
where
|
||||
S: HasCorpus<Self, I> + HasRand<R>,
|
||||
R: Rand
|
||||
{
|
||||
state.corpus_mut().entries.push(RefCell::new(testcase));
|
||||
let idx = state.corpus().entries.len() - 1;
|
||||
// Scheduler hook
|
||||
SC::on_add(state, idx, state.corpus().entries[idx].borrow())?;
|
||||
Ok(idx)
|
||||
}
|
||||
|
||||
/// Replaces the testcase at the given idx
|
||||
#[inline]
|
||||
fn replace<R, S>(state: &mut S, idx: usize, testcase: Testcase<I>) -> Result<(), Error>
|
||||
where
|
||||
S: HasCorpus<Self, I> + HasRand<R>,
|
||||
R: Rand
|
||||
{
|
||||
if state.corpus().entries.len() < idx {
|
||||
return Err(Error::KeyNotFound(format!("Index {} out of bounds", idx)));
|
||||
}
|
||||
state.corpus_mut().entries[idx] = RefCell::new(testcase);
|
||||
// Scheduler hook
|
||||
SC::on_replace(state, idx, state.corpus().entries[idx])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes an entry from the corpus, returning it if it was present.
|
||||
#[inline]
|
||||
fn remove<R, S>(state: &mut S, idx: usize) -> Result<Option<Testcase<I>>, Error>
|
||||
where
|
||||
S: HasCorpus<Self, I> + HasRand<R>,
|
||||
R: Rand
|
||||
{
|
||||
let testcase = match state.corpus_mut()
|
||||
.entries
|
||||
.iter()
|
||||
.position(|x| ptr::eq(x.as_ptr(), entry))
|
||||
{
|
||||
Some(i) => Some(state.corpus_mut().entries.remove(i).into_inner()),
|
||||
None => None,
|
||||
};
|
||||
// Scheduler hook
|
||||
SC::on_remove(state, idx, &testcase)?;
|
||||
Ok(testcase)
|
||||
}*/
|
||||
}
|
||||
|
@ -148,13 +148,6 @@ where
|
||||
self.0.discard_metadata(input)?;
|
||||
self.1.discard_metadata_all(input)
|
||||
}
|
||||
|
||||
/*
|
||||
fn restore_state_from_all(&mut self, restore_from: &Self) -> Result<(), Error> {
|
||||
self.0.restore_from(restore_from.0)?;
|
||||
self.1.restore_state_from_all(restore_from.1)?;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/// Is a crash feedback
|
||||
|
142
libafl/src/fuzzer.rs
Normal file
142
libafl/src/fuzzer.rs
Normal file
@ -0,0 +1,142 @@
|
||||
use core::{marker::PhantomData};
|
||||
|
||||
use crate::{
|
||||
corpus::{CorpusScheduler},
|
||||
events::{Event, EventManager},
|
||||
executors::{Executor},
|
||||
inputs::Input,
|
||||
stages::StagesTuple,
|
||||
utils::{current_milliseconds, current_time},
|
||||
Error
|
||||
};
|
||||
|
||||
/// Holds a set of stages
|
||||
pub trait HasStages<ST>
|
||||
where
|
||||
ST: StagesTuple,
|
||||
{
|
||||
fn stages(&self) -> &ST;
|
||||
|
||||
fn stages_mut(&mut self) -> &mut ST;
|
||||
}
|
||||
|
||||
/// Holds a set of stages
|
||||
pub trait HasCorpusScheduler<CS>
|
||||
where
|
||||
CS: CorpusScheduler,
|
||||
{
|
||||
fn scheduler(&self) -> &CS;
|
||||
|
||||
fn scheduler_mut(&mut self) -> &mut CS;
|
||||
}
|
||||
|
||||
/// The main fuzzer trait.
|
||||
pub trait Fuzzer<CS, ST, I>: HasCorpusScheduler<CS> + HasStages<ST>
|
||||
where
|
||||
CS: CorpusScheduler,
|
||||
ST: StagesTuple<I>,
|
||||
I: Input
|
||||
{
|
||||
fn fuzz_one<E, EM, S>(
|
||||
&mut self,
|
||||
executor: &mut E,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
) -> Result<usize, Error>
|
||||
where
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I>,
|
||||
{
|
||||
let idx = self.scheduler().next(state)?;
|
||||
|
||||
self.stages()
|
||||
.perform_all(executor, state, manager, idx)?;
|
||||
|
||||
manager.process(state, executor)?;
|
||||
Ok(idx)
|
||||
}
|
||||
|
||||
fn fuzz_loop<E, EM, S>(
|
||||
&mut self,
|
||||
executor: &mut E,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
) -> Result<usize, Error>
|
||||
where
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I>,
|
||||
{
|
||||
let mut last = current_milliseconds();
|
||||
loop {
|
||||
self.fuzz_one(executor, state, manager)?;
|
||||
let cur = current_milliseconds();
|
||||
if cur - last > 60 * 100 {
|
||||
last = cur;
|
||||
manager.fire(
|
||||
state,
|
||||
Event::UpdateStats {
|
||||
executions: state.executions(),
|
||||
time: current_time(),
|
||||
phantom: PhantomData,
|
||||
},
|
||||
)?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Your default fuzzer instance, for everyday use.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StdFuzzer<CS, ST, I>
|
||||
where
|
||||
CS: CorpusScheduler,
|
||||
ST: StagesTuple<I>,
|
||||
I: Input
|
||||
{
|
||||
scheduler: CS,
|
||||
stages: ST,
|
||||
}
|
||||
|
||||
impl<CS, ST, I> HasStages<ST> for StdFuzzer<CS, ST, I>
|
||||
where
|
||||
CS: CorpusScheduler,
|
||||
ST: StagesTuple<I>,
|
||||
I: Input
|
||||
{
|
||||
fn stages(&self) -> &ST {
|
||||
&self.stages
|
||||
}
|
||||
|
||||
fn stages_mut(&mut self) -> &mut ST {
|
||||
&mut self.stages
|
||||
}
|
||||
}
|
||||
|
||||
impl<CS, ST, I> HasCorpusScheduler<CS> for StdFuzzer<CS, ST, I>
|
||||
where
|
||||
CS: CorpusScheduler,
|
||||
ST: StagesTuple<I>,
|
||||
I: Input
|
||||
{
|
||||
fn scheduler(&self) -> &CS {
|
||||
&self.scheduler
|
||||
}
|
||||
|
||||
fn scheduler_mut(&mut self) -> &mut CS {
|
||||
&mut self.scheduler
|
||||
}
|
||||
}
|
||||
|
||||
impl<CS, ST, I> StdFuzzer<CS, ST, I>
|
||||
where
|
||||
CS: CorpusScheduler,
|
||||
ST: StagesTuple<I>,
|
||||
I: Input
|
||||
{
|
||||
pub fn new(scheduler: CS, stages: ST) -> Self {
|
||||
Self {
|
||||
scheduler: scheduler,
|
||||
stages: stages,
|
||||
}
|
||||
}
|
||||
}
|
@ -25,144 +25,15 @@ pub mod state;
|
||||
pub mod stats;
|
||||
pub mod utils;
|
||||
|
||||
pub mod fuzzer;
|
||||
pub use fuzzer::*;
|
||||
|
||||
use alloc::string::String;
|
||||
use core::{fmt, marker::PhantomData};
|
||||
use corpus::Corpus;
|
||||
use events::{Event, EventManager};
|
||||
use executors::{Executor, HasObservers};
|
||||
use feedbacks::FeedbacksTuple;
|
||||
use inputs::Input;
|
||||
use observers::ObserversTuple;
|
||||
use stages::StagesTuple;
|
||||
use state::{HasCorpus, State};
|
||||
use utils::{current_milliseconds, current_time, Rand};
|
||||
use core::{fmt};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::{env::VarError, io, num::ParseIntError, string::FromUtf8Error};
|
||||
|
||||
/// The main fuzzer trait.
|
||||
pub trait Fuzzer<C, E, EM, FT, ST, I, OC, OFT, OT, R>
|
||||
where
|
||||
ST: StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R>,
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
fn stages(&self) -> &ST;
|
||||
|
||||
fn stages_mut(&mut self) -> &mut ST;
|
||||
|
||||
fn fuzz_one(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
executor: &mut E,
|
||||
state: &mut State<C, FT, I, OC, OFT, R>,
|
||||
manager: &mut EM,
|
||||
) -> Result<usize, Error> {
|
||||
let (_, idx) = state.corpus_mut().next(rand)?;
|
||||
|
||||
self.stages_mut()
|
||||
.perform_all(rand, executor, state, manager, idx)?;
|
||||
|
||||
manager.process(state, executor)?;
|
||||
Ok(idx)
|
||||
}
|
||||
|
||||
fn fuzz_loop(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
executor: &mut E,
|
||||
state: &mut State<C, FT, I, OC, OFT, R>,
|
||||
manager: &mut EM,
|
||||
) -> Result<(), Error> {
|
||||
let mut last = current_milliseconds();
|
||||
loop {
|
||||
self.fuzz_one(rand, executor, state, manager)?;
|
||||
let cur = current_milliseconds();
|
||||
if cur - last > 60 * 100 {
|
||||
last = cur;
|
||||
manager.fire(
|
||||
state,
|
||||
Event::UpdateStats {
|
||||
executions: state.executions(),
|
||||
time: current_time(),
|
||||
phantom: PhantomData,
|
||||
},
|
||||
)?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Your default fuzzer instance, for everyday use.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StdFuzzer<C, E, EM, FT, ST, I, OC, OFT, OT, R>
|
||||
where
|
||||
ST: StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R>,
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
stages: ST,
|
||||
phantom: PhantomData<(EM, E, OC, OFT, OT, FT, C, I, R)>,
|
||||
}
|
||||
|
||||
impl<C, E, EM, FT, ST, I, OC, OFT, OT, R> Fuzzer<C, E, EM, FT, ST, I, OC, OFT, OT, R>
|
||||
for StdFuzzer<C, E, EM, FT, ST, I, OC, OFT, OT, R>
|
||||
where
|
||||
ST: StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R>,
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
fn stages(&self) -> &ST {
|
||||
&self.stages
|
||||
}
|
||||
|
||||
fn stages_mut(&mut self) -> &mut ST {
|
||||
&mut self.stages
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, E, EM, FT, ST, I, OC, OFT, OT, R> StdFuzzer<C, E, EM, FT, ST, I, OC, OFT, OT, R>
|
||||
where
|
||||
ST: StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R>,
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
pub fn new(stages: ST) -> Self {
|
||||
Self {
|
||||
stages: stages,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Main error struct for AFL
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
|
@ -8,10 +8,7 @@ pub mod token_mutations;
|
||||
pub use token_mutations::*;
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
inputs::Input,
|
||||
state::{HasCorpus, HasMetadata},
|
||||
utils::Rand,
|
||||
Error,
|
||||
};
|
||||
|
||||
@ -20,24 +17,20 @@ use crate::{
|
||||
|
||||
/// A mutator takes input, and mutates it.
|
||||
/// Simple as that.
|
||||
pub trait Mutator<C, I, R, S>
|
||||
pub trait Mutator<I>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
S: HasCorpus<C, I, R> + HasMetadata,
|
||||
{
|
||||
/// Mutate a given input
|
||||
fn mutate(
|
||||
fn mutate<S>(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// Post-process given the outcome of the execution
|
||||
fn post_exec(
|
||||
fn post_exec<S>(
|
||||
&mut self,
|
||||
_state: &mut S,
|
||||
_is_interesting: u32,
|
||||
|
@ -5,125 +5,83 @@ use crate::{
|
||||
bolts::tuples::TupleList,
|
||||
corpus::Corpus,
|
||||
events::EventManager,
|
||||
executors::{Executor, HasObservers},
|
||||
feedbacks::FeedbacksTuple,
|
||||
executors::{Executor},
|
||||
inputs::Input,
|
||||
observers::ObserversTuple,
|
||||
state::State,
|
||||
utils::Rand,
|
||||
Error,
|
||||
};
|
||||
|
||||
/// A stage is one step in the fuzzing process.
|
||||
/// Multiple stages will be scheduled one by one for each input.
|
||||
pub trait Stage<C, E, EM, FT, I, OC, OFT, OT, R>
|
||||
pub trait Stage<I>
|
||||
where
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
I: Input
|
||||
{
|
||||
/// Run the stage
|
||||
fn perform(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
fn perform<E, EM, S>(
|
||||
&self,
|
||||
executor: &mut E,
|
||||
state: &mut State<C, FT, I, OC, OFT, R>,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
corpus_idx: usize,
|
||||
) -> Result<(), Error>;
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I>;
|
||||
}
|
||||
|
||||
pub trait StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R>
|
||||
pub trait StagesTuple<I>
|
||||
where
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
I: Input
|
||||
{
|
||||
fn perform_all(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
fn perform_all<E, EM, S>(
|
||||
&self,
|
||||
executor: &mut E,
|
||||
state: &mut State<C, FT, I, OC, OFT, R>,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
corpus_idx: usize,
|
||||
) -> Result<(), Error>;
|
||||
fn for_each(&self, f: fn(&dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>));
|
||||
fn for_each_mut(&mut self, f: fn(&mut dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>));
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I>;
|
||||
}
|
||||
|
||||
impl<C, E, EM, FT, I, OC, OFT, OT, R> StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R> for ()
|
||||
impl<I> StagesTuple<I> for ()
|
||||
where
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
I: Input
|
||||
{
|
||||
fn perform_all(
|
||||
&mut self,
|
||||
_rand: &mut R,
|
||||
_executor: &mut E,
|
||||
_state: &mut State<C, FT, I, OC, OFT, R>,
|
||||
_manager: &mut EM,
|
||||
_corpus_idx: usize,
|
||||
) -> Result<(), Error> {
|
||||
fn perform_all<E, EM, S>(
|
||||
&self,
|
||||
executor: &mut E,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
corpus_idx: usize,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I>
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
fn for_each(&self, _f: fn(&dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>)) {}
|
||||
fn for_each_mut(&mut self, _f: fn(&mut dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>)) {}
|
||||
}
|
||||
|
||||
impl<Head, Tail, EM, E, OC, OFT, OT, FT, C, I, R> StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R>
|
||||
for (Head, Tail)
|
||||
impl<Head, Tail, I> StagesTuple<I> for (Head, Tail)
|
||||
where
|
||||
Head: Stage<C, E, EM, FT, I, OC, OFT, OT, R>,
|
||||
Tail: StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R> + TupleList,
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
Head: Stage,
|
||||
Tail: StagesTuple + TupleList,
|
||||
I: Input
|
||||
{
|
||||
fn perform_all(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
fn perform_all<E, EM, S>(
|
||||
&self,
|
||||
executor: &mut E,
|
||||
state: &mut State<C, FT, I, OC, OFT, R>,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
corpus_idx: usize,
|
||||
) -> Result<(), Error> {
|
||||
self.0.perform(rand, executor, state, manager, corpus_idx)?;
|
||||
self.1
|
||||
.perform_all(rand, executor, state, manager, corpus_idx)
|
||||
}
|
||||
|
||||
fn for_each(&self, f: fn(&dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>)) {
|
||||
f(&self.0);
|
||||
self.1.for_each(f)
|
||||
}
|
||||
|
||||
fn for_each_mut(&mut self, f: fn(&mut dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>)) {
|
||||
f(&mut self.0);
|
||||
self.1.for_each_mut(f)
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I>
|
||||
{
|
||||
self.0.perform(executor, state, manager, corpus_idx)?;
|
||||
self.1 .perform_all(executor, state, manager, corpus_idx)
|
||||
}
|
||||
}
|
||||
|
@ -2,14 +2,12 @@ use core::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
events::EventManager,
|
||||
executors::{Executor, HasObservers},
|
||||
feedbacks::FeedbacksTuple,
|
||||
executors::{Executor},
|
||||
inputs::Input,
|
||||
mutators::Mutator,
|
||||
observers::ObserversTuple,
|
||||
stages::Corpus,
|
||||
stages::Stage,
|
||||
state::{HasCorpus, State},
|
||||
state::{HasRand},
|
||||
utils::Rand,
|
||||
Error,
|
||||
};
|
||||
@ -19,19 +17,10 @@ use crate::{
|
||||
/// 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<C, E, EM, FT, I, M, OC, OFT, OT, R>:
|
||||
Stage<C, E, EM, FT, I, OC, OFT, OT, R>
|
||||
pub trait MutationalStage<I, M>: Stage<I>
|
||||
where
|
||||
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
C: Corpus<I, R>,
|
||||
M: Mutator<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
/// The mutator registered for this stage
|
||||
fn mutator(&self) -> &M;
|
||||
@ -40,22 +29,21 @@ where
|
||||
fn mutator_mut(&mut self) -> &mut M;
|
||||
|
||||
/// Gets the number of iterations this mutator should run for.
|
||||
/// This call uses internal mutability, so it may change for each call
|
||||
#[inline]
|
||||
fn iterations(&mut self, rand: &mut R) -> usize {
|
||||
1 + rand.below(128) as usize
|
||||
}
|
||||
fn iterations<S>(&mut self, state: &mut S) -> usize;
|
||||
|
||||
/// Runs this (mutational) stage for the given testcase
|
||||
fn perform_mutational(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
fn perform_mutational<E, EM, S>(
|
||||
&self,
|
||||
executor: &mut E,
|
||||
state: &mut State<C, FT, I, OC, OFT, R>,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
corpus_idx: usize,
|
||||
) -> Result<(), Error> {
|
||||
let num = self.iterations(rand);
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I>
|
||||
{
|
||||
let num = self.iterations(state);
|
||||
for i in 0..num {
|
||||
let mut input_mut = state
|
||||
.corpus()
|
||||
@ -64,7 +52,7 @@ where
|
||||
.load_input()?
|
||||
.clone();
|
||||
self.mutator_mut()
|
||||
.mutate(rand, state, &mut input_mut, i as i32)?;
|
||||
.mutate(state, &mut input_mut, i as i32)?;
|
||||
|
||||
let fitness = state.process_input(input_mut, executor, manager)?;
|
||||
|
||||
@ -74,38 +62,23 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128;
|
||||
|
||||
/// The default mutational stage
|
||||
pub struct StdMutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StdMutationalStage<I, M>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
EM: EventManager<I>,
|
||||
FT: FeedbacksTuple<I>,
|
||||
M: Mutator<I>,
|
||||
I: Input,
|
||||
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
R: Rand,
|
||||
{
|
||||
mutator: M,
|
||||
phantom: PhantomData<(EM, E, OC, OFT, OT, FT, C, I, R)>,
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<C, E, EM, FT, I, M, OC, OFT, OT, R> MutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>
|
||||
for StdMutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>
|
||||
impl<I, M> MutationalStage<I, M> for StdMutationalStage<I, M>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
EM: EventManager<I>,
|
||||
FT: FeedbacksTuple<I>,
|
||||
M: Mutator<I>,
|
||||
I: Input,
|
||||
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
R: Rand,
|
||||
{
|
||||
/// The mutator, added to this stage
|
||||
#[inline]
|
||||
@ -118,47 +91,42 @@ where
|
||||
fn mutator_mut(&mut self) -> &mut M {
|
||||
&mut self.mutator
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, E, EM, FT, I, M, OC, OFT, OT, R> Stage<C, E, EM, FT, I, OC, OFT, OT, R>
|
||||
for StdMutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>
|
||||
where
|
||||
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
#[inline]
|
||||
fn perform(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
executor: &mut E,
|
||||
state: &mut State<C, FT, I, OC, OFT, R>,
|
||||
manager: &mut EM,
|
||||
corpus_idx: usize,
|
||||
) -> Result<(), Error> {
|
||||
self.perform_mutational(rand, executor, state, manager, corpus_idx)
|
||||
/// Gets the number of iterations as a random number
|
||||
fn iterations<R, S>(&mut self, state: &mut S) -> usize
|
||||
where
|
||||
S: HasRand<R>,
|
||||
R: Rand
|
||||
{
|
||||
1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, E, EM, FT, I, M, OC, OFT, OT, R> StdMutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>
|
||||
impl<I, M> Stage<I> for StdMutationalStage<I, M>
|
||||
where
|
||||
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OC: Corpus<I, R>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
C: Corpus<I, R>,
|
||||
M: Mutator<I>,
|
||||
I: Input,
|
||||
{
|
||||
#[inline]
|
||||
fn perform<E, EM, S>(
|
||||
&self,
|
||||
executor: &mut E,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
corpus_idx: usize,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
EM: EventManager<I>,
|
||||
E: Executor<I>
|
||||
{
|
||||
self.perform_mutational(executor, state, manager, corpus_idx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, M> StdMutationalStage<I, M>
|
||||
where
|
||||
M: Mutator<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
/// Creates a new default mutational stage
|
||||
pub fn new(mutator: M) -> Self {
|
||||
|
@ -25,11 +25,10 @@ use crate::{
|
||||
use crate::inputs::bytes::BytesInput;
|
||||
|
||||
/// Trait for elements offering a corpus
|
||||
pub trait HasCorpus<C, I, R>
|
||||
pub trait HasCorpus<C, I>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
/// The testcase corpus
|
||||
fn corpus(&self) -> &C;
|
||||
@ -37,6 +36,17 @@ where
|
||||
fn corpus_mut(&mut self) -> &mut C;
|
||||
}
|
||||
|
||||
/// Trait for elements offering a rand
|
||||
pub trait HasRand<R>
|
||||
where
|
||||
R: Rand,
|
||||
{
|
||||
/// The rand instance
|
||||
fn rand(&self) -> &R;
|
||||
/// The rand instance (mut)
|
||||
fn rand_mut(&mut self) -> &mut R;
|
||||
}
|
||||
|
||||
/// Trait for elements offering metadata
|
||||
pub trait HasMetadata {
|
||||
/// A map, storing all metadata
|
||||
@ -59,13 +69,15 @@ pub trait HasMetadata {
|
||||
#[serde(bound = "FT: serde::de::DeserializeOwned")]
|
||||
pub struct State<C, FT, I, OC, OFT, R>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
OC: Corpus<I, R>,
|
||||
OC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
{
|
||||
/// RNG instance
|
||||
rand: R,
|
||||
/// How many times the executor ran the harness/target
|
||||
executions: usize,
|
||||
/// The corpus
|
||||
@ -82,16 +94,16 @@ where
|
||||
/// Objective Feedbacks
|
||||
objective_feedbacks: OFT,
|
||||
|
||||
phantom: PhantomData<(R, I)>,
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<C, FT, OC, OFT, R> State<C, FT, BytesInput, OC, OFT, R>
|
||||
where
|
||||
C: Corpus<BytesInput, R>,
|
||||
C: Corpus<BytesInput>,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<BytesInput>,
|
||||
OC: Corpus<BytesInput, R>,
|
||||
OC: Corpus<BytesInput>,
|
||||
OFT: FeedbacksTuple<BytesInput>,
|
||||
{
|
||||
pub fn load_from_directory<E, OT, EM>(
|
||||
@ -101,7 +113,7 @@ where
|
||||
in_dir: &Path,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
C: Corpus<BytesInput, R>,
|
||||
C: Corpus<BytesInput>,
|
||||
E: Executor<BytesInput> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
EM: EventManager<BytesInput>,
|
||||
@ -143,7 +155,7 @@ where
|
||||
in_dirs: &[PathBuf],
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
C: Corpus<BytesInput, R>,
|
||||
C: Corpus<BytesInput>,
|
||||
E: Executor<BytesInput> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
EM: EventManager<BytesInput>,
|
||||
@ -164,13 +176,34 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, FT, I, OC, OFT, R> HasCorpus<C, I, R> for State<C, FT, I, OC, OFT, R>
|
||||
impl<C, FT, I, OC, OFT, R> HasRand<R> for State<C, FT, I, OC, OFT, R>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
OC: Corpus<I, R>,
|
||||
OC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
{
|
||||
/// The rand instance
|
||||
fn rand(&self) -> &R {
|
||||
&self.rand
|
||||
}
|
||||
|
||||
/// The rand instance (mut)
|
||||
fn rand_mut(&mut self) -> &mut R {
|
||||
&mut self.rand
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<C, FT, I, OC, OFT, R> HasCorpus<C, I> for State<C, FT, I, OC, OFT, R>
|
||||
where
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
OC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
{
|
||||
/// Returns the corpus
|
||||
@ -187,11 +220,11 @@ where
|
||||
/// Trait for elements offering metadata
|
||||
impl<C, FT, I, OC, OFT, R> HasMetadata for State<C, FT, I, OC, OFT, R>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
OC: Corpus<I, R>,
|
||||
OC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
{
|
||||
/// Get all the metadata into an HashMap
|
||||
@ -209,11 +242,11 @@ where
|
||||
|
||||
impl<C, FT, I, OC, OFT, R> State<C, FT, I, OC, OFT, R>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
OC: Corpus<I, R>,
|
||||
OC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
{
|
||||
/// Get executions
|
||||
@ -299,7 +332,7 @@ where
|
||||
where
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
C: Corpus<I, R>,
|
||||
C: Corpus<I>,
|
||||
EM: EventManager<I>,
|
||||
{
|
||||
executor.pre_exec_observers()?;
|
||||
@ -356,11 +389,11 @@ where
|
||||
#[inline]
|
||||
pub fn add_if_interesting(&mut self, input: I, fitness: u32) -> Result<Option<usize>, Error>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
C: Corpus<I>,
|
||||
{
|
||||
if fitness > 0 {
|
||||
let testcase = self.input_to_testcase(input, fitness)?;
|
||||
Ok(Some(self.corpus_mut().add(testcase)))
|
||||
Ok(Some(C::add(self, testcase)?))
|
||||
} else {
|
||||
self.discard_input(&input)?;
|
||||
Ok(None)
|
||||
@ -371,7 +404,7 @@ where
|
||||
#[inline]
|
||||
pub fn add_if_objective(&mut self, input: I, fitness: u32) -> Result<Option<usize>, Error>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
C: Corpus<I>,
|
||||
{
|
||||
if fitness > 0 {
|
||||
let testcase = self.input_to_testcase(input, fitness)?;
|
||||
@ -394,7 +427,7 @@ where
|
||||
where
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
C: Corpus<I, R>,
|
||||
C: Corpus<I>,
|
||||
EM: EventManager<I>,
|
||||
{
|
||||
let (fitness, obj_fitness) = self.evaluate_input(&input, executor, manager)?;
|
||||
@ -435,7 +468,7 @@ where
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
G: Generator<I, R>,
|
||||
C: Corpus<I, R>,
|
||||
C: Corpus<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
EM: EventManager<I>,
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Utility functions for AFL
|
||||
|
||||
use core::{cell::RefCell, debug_assert, fmt::Debug, time};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
use xxhash_rust::xxh3::xxh3_64_with_seed;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
@ -10,7 +10,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
||||
pub type StdRand = RomuTrioRand;
|
||||
|
||||
/// Ways to get random around here
|
||||
pub trait Rand: Debug + Serialize {
|
||||
pub trait Rand: Debug + Serialize + DeserializeOwned {
|
||||
// Sets the seed of this Rand
|
||||
fn set_seed(&mut self, seed: u64);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user