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.
|
//! 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 mod testcase;
|
||||||
pub use testcase::Testcase;
|
pub use testcase::Testcase;
|
||||||
|
|
||||||
pub mod inmemory;
|
use alloc::{vec::Vec};
|
||||||
pub use inmemory::InMemoryCorpus;
|
use core::{cell::RefCell};
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
use crate::{
|
||||||
pub mod ondisk;
|
inputs::Input,
|
||||||
#[cfg(feature = "std")]
|
state::{HasCorpus, HasRand},
|
||||||
pub use ondisk::OnDiskCorpus;
|
utils::Rand,
|
||||||
|
Error,
|
||||||
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
|
/// 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
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
|
||||||
{
|
{
|
||||||
/// Returns the number of elements
|
/// Returns the number of elements
|
||||||
#[inline]
|
fn count(&self) -> usize;
|
||||||
fn count(&self) -> usize {
|
|
||||||
self.entries().len()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO implement a was_fuzzed counter
|
|
||||||
|
|
||||||
/// Add an entry to the corpus and return its index
|
/// Add an entry to the corpus and return its index
|
||||||
#[inline]
|
fn add(&mut self, testcase: Testcase<I>) -> Result<usize, Error>;
|
||||||
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
|
/// Replaces the testcase at the given idx
|
||||||
fn replace(&mut self, idx: usize, testcase: Testcase<I>) -> Result<(), Error> {
|
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)));
|
/// Removes an entry from the corpus, returning it if it was present.
|
||||||
}
|
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<I>>, Error>;
|
||||||
self.entries_mut()[idx] = RefCell::new(testcase);
|
|
||||||
|
/// 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get by id
|
/// Replaces the testcase at the given idx
|
||||||
#[inline]
|
fn on_replace<C, I, R, S>(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error>
|
||||||
fn get(&self, idx: usize) -> &RefCell<Testcase<I>> {
|
where
|
||||||
&self.entries()[idx]
|
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.
|
/// Removes an entry from the corpus, returning it if it was present.
|
||||||
#[inline]
|
fn on_remove<C, I, R, S>(&self, state: &mut S, idx: usize, testcase: &Option<Testcase<I>>) -> Result<(), Error>
|
||||||
fn remove(&mut self, entry: &Testcase<I>) -> Option<Testcase<I>> {
|
where
|
||||||
match self
|
S: HasCorpus<C, I> + HasRand<R>,
|
||||||
.entries()
|
C: Corpus<I>,
|
||||||
.iter()
|
I: Input,
|
||||||
.position(|x| ptr::eq(x.as_ptr(), entry))
|
R: Rand
|
||||||
{
|
{
|
||||||
Some(i) => Some(self.entries_mut().remove(i).into_inner()),
|
Ok(())
|
||||||
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
|
// TODO: IntoIter
|
||||||
/// Gets the next entry
|
/// 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.0.discard_metadata(input)?;
|
||||||
self.1.discard_metadata_all(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
|
/// 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 stats;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
pub mod fuzzer;
|
||||||
|
pub use fuzzer::*;
|
||||||
|
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use core::{fmt, marker::PhantomData};
|
use core::{fmt};
|
||||||
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};
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::{env::VarError, io, num::ParseIntError, string::FromUtf8Error};
|
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
|
/// Main error struct for AFL
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -8,10 +8,7 @@ pub mod token_mutations;
|
|||||||
pub use token_mutations::*;
|
pub use token_mutations::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
state::{HasCorpus, HasMetadata},
|
|
||||||
utils::Rand,
|
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -20,24 +17,20 @@ use crate::{
|
|||||||
|
|
||||||
/// A mutator takes input, and mutates it.
|
/// A mutator takes input, and mutates it.
|
||||||
/// Simple as that.
|
/// Simple as that.
|
||||||
pub trait Mutator<C, I, R, S>
|
pub trait Mutator<I>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
|
||||||
S: HasCorpus<C, I, R> + HasMetadata,
|
|
||||||
{
|
{
|
||||||
/// Mutate a given input
|
/// Mutate a given input
|
||||||
fn mutate(
|
fn mutate<S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
rand: &mut R,
|
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
stage_idx: i32,
|
stage_idx: i32,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
/// Post-process given the outcome of the execution
|
/// Post-process given the outcome of the execution
|
||||||
fn post_exec(
|
fn post_exec<S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_state: &mut S,
|
_state: &mut S,
|
||||||
_is_interesting: u32,
|
_is_interesting: u32,
|
||||||
|
@ -5,125 +5,83 @@ use crate::{
|
|||||||
bolts::tuples::TupleList,
|
bolts::tuples::TupleList,
|
||||||
corpus::Corpus,
|
corpus::Corpus,
|
||||||
events::EventManager,
|
events::EventManager,
|
||||||
executors::{Executor, HasObservers},
|
executors::{Executor},
|
||||||
feedbacks::FeedbacksTuple,
|
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
observers::ObserversTuple,
|
|
||||||
state::State,
|
|
||||||
utils::Rand,
|
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A stage is one step in the fuzzing process.
|
/// A stage is one step in the fuzzing process.
|
||||||
/// Multiple stages will be scheduled one by one for each input.
|
/// 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
|
where
|
||||||
EM: EventManager<I>,
|
I: Input
|
||||||
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,
|
|
||||||
{
|
{
|
||||||
/// Run the stage
|
/// Run the stage
|
||||||
fn perform(
|
fn perform<E, EM, S>(
|
||||||
&mut self,
|
&self,
|
||||||
rand: &mut R,
|
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut State<C, FT, I, OC, OFT, R>,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
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
|
where
|
||||||
EM: EventManager<I>,
|
I: Input
|
||||||
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 perform_all(
|
fn perform_all<E, EM, S>(
|
||||||
&mut self,
|
&self,
|
||||||
rand: &mut R,
|
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut State<C, FT, I, OC, OFT, R>,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: usize,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>
|
||||||
fn for_each(&self, f: fn(&dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>));
|
where
|
||||||
fn for_each_mut(&mut self, f: fn(&mut dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>));
|
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
|
where
|
||||||
EM: EventManager<I>,
|
I: Input
|
||||||
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 perform_all(
|
fn perform_all<E, EM, S>(
|
||||||
&mut self,
|
&self,
|
||||||
_rand: &mut R,
|
executor: &mut E,
|
||||||
_executor: &mut E,
|
state: &mut S,
|
||||||
_state: &mut State<C, FT, I, OC, OFT, R>,
|
manager: &mut EM,
|
||||||
_manager: &mut EM,
|
corpus_idx: usize,
|
||||||
_corpus_idx: usize,
|
) -> Result<(), Error>
|
||||||
) -> Result<(), Error> {
|
where
|
||||||
|
EM: EventManager<I>,
|
||||||
|
E: Executor<I>
|
||||||
|
{
|
||||||
Ok(())
|
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>
|
impl<Head, Tail, I> StagesTuple<I> for (Head, Tail)
|
||||||
for (Head, Tail)
|
|
||||||
where
|
where
|
||||||
Head: Stage<C, E, EM, FT, I, OC, OFT, OT, R>,
|
Head: Stage,
|
||||||
Tail: StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R> + TupleList,
|
Tail: StagesTuple + TupleList,
|
||||||
EM: EventManager<I>,
|
I: Input
|
||||||
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 perform_all(
|
fn perform_all<E, EM, S>(
|
||||||
&mut self,
|
&self,
|
||||||
rand: &mut R,
|
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut State<C, FT, I, OC, OFT, R>,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: usize,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error>
|
||||||
self.0.perform(rand, executor, state, manager, corpus_idx)?;
|
where
|
||||||
self.1
|
EM: EventManager<I>,
|
||||||
.perform_all(rand, executor, state, manager, corpus_idx)
|
E: Executor<I>
|
||||||
}
|
{
|
||||||
|
self.0.perform(executor, state, manager, corpus_idx)?;
|
||||||
fn for_each(&self, f: fn(&dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>)) {
|
self.1 .perform_all(executor, state, manager, corpus_idx)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,12 @@ use core::marker::PhantomData;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
events::EventManager,
|
events::EventManager,
|
||||||
executors::{Executor, HasObservers},
|
executors::{Executor},
|
||||||
feedbacks::FeedbacksTuple,
|
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
mutators::Mutator,
|
mutators::Mutator,
|
||||||
observers::ObserversTuple,
|
|
||||||
stages::Corpus,
|
stages::Corpus,
|
||||||
stages::Stage,
|
stages::Stage,
|
||||||
state::{HasCorpus, State},
|
state::{HasRand},
|
||||||
utils::Rand,
|
utils::Rand,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -19,19 +17,10 @@ use crate::{
|
|||||||
/// A Mutational stage is the stage in a fuzzing run that mutates inputs.
|
/// A Mutational stage is the stage in a fuzzing run that mutates inputs.
|
||||||
/// Mutational stages will usually have a range of mutations that are
|
/// Mutational stages will usually have a range of mutations that are
|
||||||
/// being applied to the input one by one, between executions.
|
/// being applied to the input one by one, between executions.
|
||||||
pub trait MutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>:
|
pub trait MutationalStage<I, M>: Stage<I>
|
||||||
Stage<C, E, EM, FT, I, OC, OFT, OT, R>
|
|
||||||
where
|
where
|
||||||
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
|
M: Mutator<I>,
|
||||||
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,
|
I: Input,
|
||||||
R: Rand,
|
|
||||||
{
|
{
|
||||||
/// The mutator registered for this stage
|
/// The mutator registered for this stage
|
||||||
fn mutator(&self) -> &M;
|
fn mutator(&self) -> &M;
|
||||||
@ -40,22 +29,21 @@ where
|
|||||||
fn mutator_mut(&mut self) -> &mut M;
|
fn mutator_mut(&mut self) -> &mut M;
|
||||||
|
|
||||||
/// Gets the number of iterations this mutator should run for.
|
/// Gets the number of iterations this mutator should run for.
|
||||||
/// This call uses internal mutability, so it may change for each call
|
fn iterations<S>(&mut self, state: &mut S) -> usize;
|
||||||
#[inline]
|
|
||||||
fn iterations(&mut self, rand: &mut R) -> usize {
|
|
||||||
1 + rand.below(128) as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs this (mutational) stage for the given testcase
|
/// Runs this (mutational) stage for the given testcase
|
||||||
fn perform_mutational(
|
fn perform_mutational<E, EM, S>(
|
||||||
&mut self,
|
&self,
|
||||||
rand: &mut R,
|
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut State<C, FT, I, OC, OFT, R>,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: usize,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error>
|
||||||
let num = self.iterations(rand);
|
where
|
||||||
|
EM: EventManager<I>,
|
||||||
|
E: Executor<I>
|
||||||
|
{
|
||||||
|
let num = self.iterations(state);
|
||||||
for i in 0..num {
|
for i in 0..num {
|
||||||
let mut input_mut = state
|
let mut input_mut = state
|
||||||
.corpus()
|
.corpus()
|
||||||
@ -64,7 +52,7 @@ where
|
|||||||
.load_input()?
|
.load_input()?
|
||||||
.clone();
|
.clone();
|
||||||
self.mutator_mut()
|
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)?;
|
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
|
/// 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
|
where
|
||||||
C: Corpus<I, R>,
|
M: Mutator<I>,
|
||||||
E: Executor<I> + HasObservers<OT>,
|
|
||||||
EM: EventManager<I>,
|
|
||||||
FT: FeedbacksTuple<I>,
|
|
||||||
I: Input,
|
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,
|
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>
|
impl<I, M> MutationalStage<I, M> for StdMutationalStage<I, M>
|
||||||
for StdMutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>
|
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
M: Mutator<I>,
|
||||||
E: Executor<I> + HasObservers<OT>,
|
|
||||||
EM: EventManager<I>,
|
|
||||||
FT: FeedbacksTuple<I>,
|
|
||||||
I: Input,
|
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
|
/// The mutator, added to this stage
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -118,47 +91,42 @@ where
|
|||||||
fn mutator_mut(&mut self) -> &mut M {
|
fn mutator_mut(&mut self) -> &mut M {
|
||||||
&mut self.mutator
|
&mut self.mutator
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<C, E, EM, FT, I, M, OC, OFT, OT, R> Stage<C, E, EM, FT, I, OC, OFT, OT, R>
|
/// Gets the number of iterations as a random number
|
||||||
for StdMutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>
|
fn iterations<R, S>(&mut self, state: &mut S) -> usize
|
||||||
where
|
where
|
||||||
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
|
S: HasRand<R>,
|
||||||
EM: EventManager<I>,
|
R: Rand
|
||||||
E: Executor<I> + HasObservers<OT>,
|
{
|
||||||
OC: Corpus<I, R>,
|
1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
where
|
||||||
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
|
M: Mutator<I>,
|
||||||
EM: EventManager<I>,
|
I: Input,
|
||||||
E: Executor<I> + HasObservers<OT>,
|
{
|
||||||
OC: Corpus<I, R>,
|
#[inline]
|
||||||
OFT: FeedbacksTuple<I>,
|
fn perform<E, EM, S>(
|
||||||
OT: ObserversTuple,
|
&self,
|
||||||
FT: FeedbacksTuple<I>,
|
executor: &mut E,
|
||||||
C: Corpus<I, R>,
|
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,
|
I: Input,
|
||||||
R: Rand,
|
|
||||||
{
|
{
|
||||||
/// Creates a new default mutational stage
|
/// Creates a new default mutational stage
|
||||||
pub fn new(mutator: M) -> Self {
|
pub fn new(mutator: M) -> Self {
|
||||||
|
@ -25,11 +25,10 @@ use crate::{
|
|||||||
use crate::inputs::bytes::BytesInput;
|
use crate::inputs::bytes::BytesInput;
|
||||||
|
|
||||||
/// Trait for elements offering a corpus
|
/// Trait for elements offering a corpus
|
||||||
pub trait HasCorpus<C, I, R>
|
pub trait HasCorpus<C, I>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
|
||||||
{
|
{
|
||||||
/// The testcase corpus
|
/// The testcase corpus
|
||||||
fn corpus(&self) -> &C;
|
fn corpus(&self) -> &C;
|
||||||
@ -37,6 +36,17 @@ where
|
|||||||
fn corpus_mut(&mut self) -> &mut C;
|
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
|
/// Trait for elements offering metadata
|
||||||
pub trait HasMetadata {
|
pub trait HasMetadata {
|
||||||
/// A map, storing all metadata
|
/// A map, storing all metadata
|
||||||
@ -59,13 +69,15 @@ pub trait HasMetadata {
|
|||||||
#[serde(bound = "FT: serde::de::DeserializeOwned")]
|
#[serde(bound = "FT: serde::de::DeserializeOwned")]
|
||||||
pub struct State<C, FT, I, OC, OFT, R>
|
pub struct State<C, FT, I, OC, OFT, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
FT: FeedbacksTuple<I>,
|
FT: FeedbacksTuple<I>,
|
||||||
OC: Corpus<I, R>,
|
OC: Corpus<I>,
|
||||||
OFT: FeedbacksTuple<I>,
|
OFT: FeedbacksTuple<I>,
|
||||||
{
|
{
|
||||||
|
/// RNG instance
|
||||||
|
rand: R,
|
||||||
/// How many times the executor ran the harness/target
|
/// How many times the executor ran the harness/target
|
||||||
executions: usize,
|
executions: usize,
|
||||||
/// The corpus
|
/// The corpus
|
||||||
@ -82,16 +94,16 @@ where
|
|||||||
/// Objective Feedbacks
|
/// Objective Feedbacks
|
||||||
objective_feedbacks: OFT,
|
objective_feedbacks: OFT,
|
||||||
|
|
||||||
phantom: PhantomData<(R, I)>,
|
phantom: PhantomData<I>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl<C, FT, OC, OFT, R> State<C, FT, BytesInput, OC, OFT, R>
|
impl<C, FT, OC, OFT, R> State<C, FT, BytesInput, OC, OFT, R>
|
||||||
where
|
where
|
||||||
C: Corpus<BytesInput, R>,
|
C: Corpus<BytesInput>,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
FT: FeedbacksTuple<BytesInput>,
|
FT: FeedbacksTuple<BytesInput>,
|
||||||
OC: Corpus<BytesInput, R>,
|
OC: Corpus<BytesInput>,
|
||||||
OFT: FeedbacksTuple<BytesInput>,
|
OFT: FeedbacksTuple<BytesInput>,
|
||||||
{
|
{
|
||||||
pub fn load_from_directory<E, OT, EM>(
|
pub fn load_from_directory<E, OT, EM>(
|
||||||
@ -101,7 +113,7 @@ where
|
|||||||
in_dir: &Path,
|
in_dir: &Path,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
C: Corpus<BytesInput, R>,
|
C: Corpus<BytesInput>,
|
||||||
E: Executor<BytesInput> + HasObservers<OT>,
|
E: Executor<BytesInput> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
EM: EventManager<BytesInput>,
|
EM: EventManager<BytesInput>,
|
||||||
@ -143,7 +155,7 @@ where
|
|||||||
in_dirs: &[PathBuf],
|
in_dirs: &[PathBuf],
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
C: Corpus<BytesInput, R>,
|
C: Corpus<BytesInput>,
|
||||||
E: Executor<BytesInput> + HasObservers<OT>,
|
E: Executor<BytesInput> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
EM: EventManager<BytesInput>,
|
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
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
FT: FeedbacksTuple<I>,
|
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>,
|
OFT: FeedbacksTuple<I>,
|
||||||
{
|
{
|
||||||
/// Returns the corpus
|
/// Returns the corpus
|
||||||
@ -187,11 +220,11 @@ where
|
|||||||
/// Trait for elements offering metadata
|
/// Trait for elements offering metadata
|
||||||
impl<C, FT, I, OC, OFT, R> HasMetadata for State<C, FT, I, OC, OFT, R>
|
impl<C, FT, I, OC, OFT, R> HasMetadata for State<C, FT, I, OC, OFT, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
FT: FeedbacksTuple<I>,
|
FT: FeedbacksTuple<I>,
|
||||||
OC: Corpus<I, R>,
|
OC: Corpus<I>,
|
||||||
OFT: FeedbacksTuple<I>,
|
OFT: FeedbacksTuple<I>,
|
||||||
{
|
{
|
||||||
/// Get all the metadata into an HashMap
|
/// 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>
|
impl<C, FT, I, OC, OFT, R> State<C, FT, I, OC, OFT, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
FT: FeedbacksTuple<I>,
|
FT: FeedbacksTuple<I>,
|
||||||
OC: Corpus<I, R>,
|
OC: Corpus<I>,
|
||||||
OFT: FeedbacksTuple<I>,
|
OFT: FeedbacksTuple<I>,
|
||||||
{
|
{
|
||||||
/// Get executions
|
/// Get executions
|
||||||
@ -299,7 +332,7 @@ where
|
|||||||
where
|
where
|
||||||
E: Executor<I> + HasObservers<OT>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I>,
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I>,
|
||||||
{
|
{
|
||||||
executor.pre_exec_observers()?;
|
executor.pre_exec_observers()?;
|
||||||
@ -356,11 +389,11 @@ where
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn add_if_interesting(&mut self, input: I, fitness: u32) -> Result<Option<usize>, Error>
|
pub fn add_if_interesting(&mut self, input: I, fitness: u32) -> Result<Option<usize>, Error>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I>,
|
||||||
{
|
{
|
||||||
if fitness > 0 {
|
if fitness > 0 {
|
||||||
let testcase = self.input_to_testcase(input, fitness)?;
|
let testcase = self.input_to_testcase(input, fitness)?;
|
||||||
Ok(Some(self.corpus_mut().add(testcase)))
|
Ok(Some(C::add(self, testcase)?))
|
||||||
} else {
|
} else {
|
||||||
self.discard_input(&input)?;
|
self.discard_input(&input)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@ -371,7 +404,7 @@ where
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn add_if_objective(&mut self, input: I, fitness: u32) -> Result<Option<usize>, Error>
|
pub fn add_if_objective(&mut self, input: I, fitness: u32) -> Result<Option<usize>, Error>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I>,
|
||||||
{
|
{
|
||||||
if fitness > 0 {
|
if fitness > 0 {
|
||||||
let testcase = self.input_to_testcase(input, fitness)?;
|
let testcase = self.input_to_testcase(input, fitness)?;
|
||||||
@ -394,7 +427,7 @@ where
|
|||||||
where
|
where
|
||||||
E: Executor<I> + HasObservers<OT>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I>,
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I>,
|
||||||
{
|
{
|
||||||
let (fitness, obj_fitness) = self.evaluate_input(&input, executor, manager)?;
|
let (fitness, obj_fitness) = self.evaluate_input(&input, executor, manager)?;
|
||||||
@ -435,7 +468,7 @@ where
|
|||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
G: Generator<I, R>,
|
G: Generator<I, R>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I>,
|
||||||
E: Executor<I> + HasObservers<OT>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I>,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Utility functions for AFL
|
//! Utility functions for AFL
|
||||||
|
|
||||||
use core::{cell::RefCell, debug_assert, fmt::Debug, time};
|
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;
|
use xxhash_rust::xxh3::xxh3_64_with_seed;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -10,7 +10,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
|||||||
pub type StdRand = RomuTrioRand;
|
pub type StdRand = RomuTrioRand;
|
||||||
|
|
||||||
/// Ways to get random around here
|
/// Ways to get random around here
|
||||||
pub trait Rand: Debug + Serialize {
|
pub trait Rand: Debug + Serialize + DeserializeOwned {
|
||||||
// Sets the seed of this Rand
|
// Sets the seed of this Rand
|
||||||
fn set_seed(&mut self, seed: u64);
|
fn set_seed(&mut self, seed: u64);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user