unfinished generic magics

This commit is contained in:
Andrea Fioraldi 2021-02-18 17:12:27 +01:00
parent 31d94925d0
commit 8b22a06ec9
11 changed files with 810 additions and 422 deletions

225
libafl/src/corpus/minset.rs Normal file
View 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);
}
}
}
}

View 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);
}

View File

@ -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)
}*/
} }

View File

@ -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
View 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,
}
}
}

View File

@ -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 {

View File

@ -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,

View File

@ -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)
} }
} }

View File

@ -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 {

View File

@ -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>,

View File

@ -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);