wip
This commit is contained in:
parent
b239ecf87a
commit
5fd44ce98e
@ -10,7 +10,7 @@ use core::marker::PhantomData;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
use crate::utils::{HasRand, Rand};
|
use crate::utils::Rand;
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
pub trait HasEntriesVec<I>
|
pub trait HasEntriesVec<I>
|
||||||
@ -25,9 +25,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Corpus with all current testcases
|
/// Corpus with all current testcases
|
||||||
pub trait Corpus<I>: HasEntriesVec<I> + HasRand
|
pub trait Corpus<I, R>: HasEntriesVec<I>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Returns the number of elements
|
/// Returns the number of elements
|
||||||
fn count(&self) -> usize {
|
fn count(&self) -> usize {
|
||||||
@ -58,20 +59,20 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a random entry
|
/// Gets a random entry
|
||||||
fn random_entry(&self) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
|
fn random_entry(&self, rand: &mut R) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
|
||||||
if self.count() == 0 {
|
if self.count() == 0 {
|
||||||
Err(AflError::Empty("No entries in corpus".to_owned()))
|
Err(AflError::Empty("No entries in corpus".to_owned()))
|
||||||
} else {
|
} else {
|
||||||
let len = { self.entries().len() };
|
let len = { self.entries().len() };
|
||||||
let id = self.rand_below(len as u64) as usize;
|
let id = rand.below(len as u64) as usize;
|
||||||
Ok((self.entries()[id].clone(), id))
|
Ok((self.entries()[id].clone(), id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: IntoIter
|
// TODO: IntoIter
|
||||||
/// Gets the next entry
|
/// Gets the next entry
|
||||||
fn next(&mut self) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
|
fn next(&mut self, rand: &mut R) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
|
||||||
self.random_entry()
|
self.random_entry(rand)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,8 +81,8 @@ where
|
|||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
rand: Rc<RefCell<R>>,
|
|
||||||
entries: Vec<Rc<RefCell<Testcase<I>>>>,
|
entries: Vec<Rc<RefCell<Testcase<I>>>>,
|
||||||
|
phantom: PhantomData<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, R> HasEntriesVec<I> for InMemoryCorpus<I, R>
|
impl<I, R> HasEntriesVec<I> for InMemoryCorpus<I, R>
|
||||||
@ -97,19 +98,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, R> HasRand for InMemoryCorpus<I, R>
|
impl<I, R> Corpus<I, R> for InMemoryCorpus<I, R>
|
||||||
where
|
|
||||||
I: Input,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
type R = R;
|
|
||||||
|
|
||||||
fn rand(&self) -> &Rc<RefCell<Self::R>> {
|
|
||||||
&self.rand
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R> Corpus<I> for InMemoryCorpus<I, R>
|
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
@ -122,10 +111,10 @@ where
|
|||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
pub fn new(rand: &Rc<RefCell<R>>) -> Self {
|
pub fn new() -> Self {
|
||||||
InMemoryCorpus {
|
InMemoryCorpus {
|
||||||
rand: Rc::clone(rand),
|
|
||||||
entries: vec![],
|
entries: vec![],
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,9 +125,9 @@ where
|
|||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
rand: Rc<RefCell<R>>,
|
|
||||||
entries: Vec<Rc<RefCell<Testcase<I>>>>,
|
entries: Vec<Rc<RefCell<Testcase<I>>>>,
|
||||||
dir_path: PathBuf,
|
dir_path: PathBuf,
|
||||||
|
phantom: PhantomData<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -156,20 +145,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl<I, R> HasRand for OnDiskCorpus<I, R>
|
impl<I, R> Corpus<I, R> for OnDiskCorpus<I, R>
|
||||||
where
|
|
||||||
I: Input,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
type R = R;
|
|
||||||
|
|
||||||
fn rand(&self) -> &Rc<RefCell<Self::R>> {
|
|
||||||
&self.rand
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl<I, R> Corpus<I> for OnDiskCorpus<I, R>
|
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
@ -194,31 +170,33 @@ where
|
|||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
pub fn new(rand: &Rc<RefCell<R>>, dir_path: PathBuf) -> Self {
|
pub fn new(dir_path: PathBuf) -> Self {
|
||||||
OnDiskCorpus {
|
OnDiskCorpus {
|
||||||
rand: Rc::clone(rand),
|
|
||||||
dir_path: dir_path,
|
dir_path: dir_path,
|
||||||
entries: vec![],
|
entries: vec![],
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Queue-like corpus, wrapping an existing Corpus instance
|
/// A Queue-like corpus, wrapping an existing Corpus instance
|
||||||
pub struct QueueCorpus<I, C>
|
pub struct QueueCorpus<C, I, R>
|
||||||
where
|
where
|
||||||
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
C: Corpus<I>,
|
R: Rand,
|
||||||
{
|
{
|
||||||
corpus: C,
|
corpus: C,
|
||||||
phantom: PhantomData<I>,
|
phantom: PhantomData<(I, R)>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
cycles: u64,
|
cycles: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I, C> HasEntriesVec<I> for QueueCorpus<I, C>
|
impl<C, I, R> HasEntriesVec<I> for QueueCorpus<C, I, R>
|
||||||
where
|
where
|
||||||
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
C: Corpus<I>,
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn entries(&self) -> &[Rc<RefCell<Testcase<I>>>] {
|
fn entries(&self) -> &[Rc<RefCell<Testcase<I>>>] {
|
||||||
self.corpus.entries()
|
self.corpus.entries()
|
||||||
@ -228,22 +206,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I, C> HasRand for QueueCorpus<I, C>
|
impl<C, I, R> Corpus<I, R> for QueueCorpus<C, I, R>
|
||||||
where
|
where
|
||||||
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
C: Corpus<I>,
|
R: Rand,
|
||||||
{
|
|
||||||
type R = C::R;
|
|
||||||
|
|
||||||
fn rand(&self) -> &Rc<RefCell<Self::R>> {
|
|
||||||
self.corpus.rand()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, I, C> Corpus<I> for QueueCorpus<I, C>
|
|
||||||
where
|
|
||||||
I: Input,
|
|
||||||
C: Corpus<I>,
|
|
||||||
{
|
{
|
||||||
/// Returns the number of elements
|
/// Returns the number of elements
|
||||||
fn count(&self) -> usize {
|
fn count(&self) -> usize {
|
||||||
@ -260,12 +227,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a random entry
|
/// Gets a random entry
|
||||||
fn random_entry(&self) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
|
fn random_entry(&self, rand: &mut R) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
|
||||||
self.corpus.random_entry()
|
self.corpus.random_entry(rand)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the next entry
|
/// Gets the next entry
|
||||||
fn next(&mut self) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
|
fn next(&mut self, _rand: &mut R) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
if self.corpus.count() == 0 {
|
if self.corpus.count() == 0 {
|
||||||
return Err(AflError::Empty("Corpus".to_owned()));
|
return Err(AflError::Empty("Corpus".to_owned()));
|
||||||
@ -279,13 +246,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I, C> QueueCorpus<I, C>
|
impl<C, I, R> QueueCorpus<C, I, R>
|
||||||
where
|
where
|
||||||
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
C: Corpus<I>,
|
R: Rand,
|
||||||
{
|
{
|
||||||
pub fn new(corpus: C) -> Self {
|
pub fn new(corpus: C) -> Self {
|
||||||
QueueCorpus::<I, C> {
|
QueueCorpus {
|
||||||
corpus: corpus,
|
corpus: corpus,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
@ -365,13 +333,15 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_queuecorpus() {
|
fn test_queuecorpus() {
|
||||||
let rand: Rc<_> = DefaultRand::new(0).into();
|
let mut rand = DefaultRand::new(0);
|
||||||
let mut q = QueueCorpus::new(OnDiskCorpus::new(&rand, PathBuf::from("fancy/path")));
|
let mut q = QueueCorpus::new(OnDiskCorpus::<BytesInput, DefaultRand>::new(PathBuf::from(
|
||||||
|
"fancy/path",
|
||||||
|
)));
|
||||||
let t: Rc<_> =
|
let t: Rc<_> =
|
||||||
Testcase::with_filename(BytesInput::new(vec![0 as u8; 4]), "fancyfile".into()).into();
|
Testcase::with_filename(BytesInput::new(vec![0 as u8; 4]), "fancyfile".into()).into();
|
||||||
q.add(t);
|
q.add(t);
|
||||||
let filename = q
|
let filename = q
|
||||||
.next()
|
.next(&mut rand)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.0
|
.0
|
||||||
.borrow()
|
.borrow()
|
||||||
@ -381,7 +351,7 @@ mod tests {
|
|||||||
.to_owned();
|
.to_owned();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
filename,
|
filename,
|
||||||
q.next()
|
q.next(&mut rand)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.0
|
.0
|
||||||
.borrow()
|
.borrow()
|
||||||
|
@ -6,21 +6,30 @@ use alloc::vec::Vec;
|
|||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
use crate::corpus::{Corpus, Testcase};
|
use crate::corpus::{Corpus, Testcase};
|
||||||
|
use crate::events::EventManager;
|
||||||
use crate::executors::Executor;
|
use crate::executors::Executor;
|
||||||
use crate::feedbacks::Feedback;
|
use crate::feedbacks::Feedback;
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
use crate::observers::Observer;
|
use crate::observers::Observer;
|
||||||
use crate::stages::Stage;
|
use crate::stages::Stage;
|
||||||
|
use crate::utils::{HasRand, Rand};
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
pub trait StateMetadata: Debug {}
|
pub trait StateMetadata: Debug {
|
||||||
|
/// The name of this metadata - used to find it in the list of avaliable metadatas
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait State<C, E, I>
|
pub trait State<C, E, EM, I, R>: HasRand<R = R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Get executions
|
/// Get executions
|
||||||
fn executions(&self) -> usize;
|
fn executions(&self) -> usize;
|
||||||
@ -28,6 +37,21 @@ where
|
|||||||
/// Set executions
|
/// Set executions
|
||||||
fn set_executions(&mut self, executions: usize);
|
fn set_executions(&mut self, executions: usize);
|
||||||
|
|
||||||
|
fn events_manager(&self) -> &EM;
|
||||||
|
|
||||||
|
fn events_manager_mut(&mut self) -> &mut EM;
|
||||||
|
|
||||||
|
/// Get all the metadatas into an HashMap
|
||||||
|
fn metadatas(&self) -> &HashMap<&'static str, Box<dyn StateMetadata>>;
|
||||||
|
|
||||||
|
/// Get all the metadatas into an HashMap (mutable)
|
||||||
|
fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box<dyn StateMetadata>>;
|
||||||
|
|
||||||
|
/// Add a metadata
|
||||||
|
fn add_metadata(&mut self, meta: Box<dyn StateMetadata>) {
|
||||||
|
self.metadatas_mut().insert(meta.name(), meta);
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the linked observers
|
/// Get the linked observers
|
||||||
fn observers(&self) -> &[Rc<RefCell<dyn Observer>>];
|
fn observers(&self) -> &[Rc<RefCell<dyn Observer>>];
|
||||||
|
|
||||||
@ -105,24 +129,49 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DefaultState<C, E, I>
|
pub struct DefaultState<C, E, EM, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
|
rand: R,
|
||||||
executions: usize,
|
executions: usize,
|
||||||
|
events_manager: EM,
|
||||||
|
metadatas: HashMap<&'static str, Box<dyn StateMetadata>>,
|
||||||
observers: Vec<Rc<RefCell<dyn Observer>>>,
|
observers: Vec<Rc<RefCell<dyn Observer>>>,
|
||||||
feedbacks: Vec<Box<dyn Feedback<I>>>,
|
feedbacks: Vec<Box<dyn Feedback<I>>>,
|
||||||
corpus: C,
|
corpus: C,
|
||||||
executor: E,
|
executor: E,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, E, I> State<C, E, I> for DefaultState<C, E, I>
|
impl<C, E, EM, I, R> HasRand for DefaultState<C, E, EM, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
type R = R;
|
||||||
|
|
||||||
|
fn rand(&self) -> &Self::R {
|
||||||
|
&self.rand
|
||||||
|
}
|
||||||
|
fn rand_mut(&mut self) -> &mut Self::R {
|
||||||
|
&mut self.rand
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, E, EM, I, R> State<C, E, EM, I, R> for DefaultState<C, E, EM, I, R>
|
||||||
|
where
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn executions(&self) -> usize {
|
fn executions(&self) -> usize {
|
||||||
self.executions
|
self.executions
|
||||||
@ -132,6 +181,21 @@ where
|
|||||||
self.executions = executions
|
self.executions = executions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn events_manager(&self) -> &EM {
|
||||||
|
&self.events_manager
|
||||||
|
}
|
||||||
|
fn events_manager_mut(&mut self) -> &mut EM {
|
||||||
|
&mut self.events_manager
|
||||||
|
}
|
||||||
|
|
||||||
|
fn metadatas(&self) -> &HashMap<&'static str, Box<dyn StateMetadata>> {
|
||||||
|
&self.metadatas
|
||||||
|
}
|
||||||
|
|
||||||
|
fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box<dyn StateMetadata>> {
|
||||||
|
&mut self.metadatas
|
||||||
|
}
|
||||||
|
|
||||||
fn observers(&self) -> &[Rc<RefCell<dyn Observer>>] {
|
fn observers(&self) -> &[Rc<RefCell<dyn Observer>>] {
|
||||||
&self.observers
|
&self.observers
|
||||||
}
|
}
|
||||||
@ -165,15 +229,20 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, E, I> DefaultState<C, E, I>
|
impl<C, E, EM, I, R> DefaultState<C, E, EM, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
pub fn new(corpus: C, executor: E) -> Self {
|
pub fn new(corpus: C, executor: E, events_manager: EM, rand: R) -> Self {
|
||||||
DefaultState {
|
DefaultState {
|
||||||
|
rand: rand,
|
||||||
executions: 0,
|
executions: 0,
|
||||||
|
events_manager: events_manager,
|
||||||
|
metadatas: HashMap::default(),
|
||||||
observers: vec![],
|
observers: vec![],
|
||||||
feedbacks: vec![],
|
feedbacks: vec![],
|
||||||
corpus: corpus,
|
corpus: corpus,
|
||||||
@ -182,24 +251,25 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Engine<S, C, E, I>
|
pub trait Engine<S, C, E, EM, I, R>
|
||||||
where
|
where
|
||||||
S: State<C, E, I>,
|
S: State<C, E, EM, I, R>,
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn stages(&self) -> &[Box<dyn Stage<S, C, E, I>>];
|
fn stages(&self) -> &[Box<dyn Stage<S, C, E, EM, I, R>>];
|
||||||
|
|
||||||
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<S, C, E, I>>>;
|
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<S, C, E, EM, I, R>>>;
|
||||||
|
|
||||||
fn add_stage(&mut self, stage: Box<dyn Stage<S, C, E, I>>) {
|
fn add_stage(&mut self, stage: Box<dyn Stage<S, C, E, EM, I, R>>) {
|
||||||
self.stages_mut().push(stage);
|
self.stages_mut().push(stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fuzz_one(&mut self, state: &mut S) -> Result<usize, AflError> {
|
fn fuzz_one(&mut self, state: &mut S) -> Result<usize, AflError> {
|
||||||
let (testcase, idx) = state.corpus_mut().next()?;
|
let (testcase, idx) = state.corpus_mut().next(state.rand_mut())?;
|
||||||
#[cfg(feature = "std")]
|
|
||||||
println!("Cur entry: {}\tExecutions: {}", idx, state.executions());
|
println!("Cur entry: {}\tExecutions: {}", idx, state.executions());
|
||||||
for stage in self.stages_mut() {
|
for stage in self.stages_mut() {
|
||||||
stage.perform(testcase.clone(), state)?;
|
stage.perform(testcase.clone(), state)?;
|
||||||
@ -208,38 +278,44 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DefaultEngine<S, C, E, I>
|
pub struct DefaultEngine<S, C, E, EM, I, R>
|
||||||
where
|
where
|
||||||
S: State<C, E, I>,
|
S: State<C, E, EM, I, R>,
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
stages: Vec<Box<dyn Stage<S, C, E, I>>>,
|
stages: Vec<Box<dyn Stage<S, C, E, EM, I, R>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, C, E, I> Engine<S, C, E, I> for DefaultEngine<S, C, E, I>
|
impl<S, C, E, EM, I, R> Engine<S, C, E, EM, I, R> for DefaultEngine<S, C, E, EM, I, R>
|
||||||
where
|
where
|
||||||
S: State<C, E, I>,
|
S: State<C, E, EM, I, R>,
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn stages(&self) -> &[Box<dyn Stage<S, C, E, I>>] {
|
fn stages(&self) -> &[Box<dyn Stage<S, C, E, EM, I, R>>] {
|
||||||
&self.stages
|
&self.stages
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<S, C, E, I>>> {
|
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<S, C, E, EM, I, R>>> {
|
||||||
&mut self.stages
|
&mut self.stages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, C, E, I> DefaultEngine<S, C, E, I>
|
impl<S, C, E, EM, I, R> DefaultEngine<S, C, E, EM, I, R>
|
||||||
where
|
where
|
||||||
S: State<C, E, I>,
|
S: State<C, E, EM, I, R>,
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
DefaultEngine { stages: vec![] }
|
DefaultEngine { stages: vec![] }
|
||||||
@ -253,6 +329,7 @@ mod tests {
|
|||||||
|
|
||||||
use crate::corpus::{Corpus, InMemoryCorpus, Testcase};
|
use crate::corpus::{Corpus, InMemoryCorpus, Testcase};
|
||||||
use crate::engines::{DefaultEngine, DefaultState, Engine};
|
use crate::engines::{DefaultEngine, DefaultState, Engine};
|
||||||
|
use crate::events::LoggerEventManager;
|
||||||
use crate::executors::inmemory::InMemoryExecutor;
|
use crate::executors::inmemory::InMemoryExecutor;
|
||||||
use crate::executors::{Executor, ExitKind};
|
use crate::executors::{Executor, ExitKind};
|
||||||
use crate::inputs::bytes::BytesInput;
|
use crate::inputs::bytes::BytesInput;
|
||||||
@ -268,19 +345,20 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_engine() {
|
fn test_engine() {
|
||||||
let rand = DefaultRand::new(0).into();
|
let mut corpus = InMemoryCorpus::<BytesInput, DefaultRand>::new();
|
||||||
|
|
||||||
let mut corpus = InMemoryCorpus::<BytesInput, _>::new(&rand);
|
|
||||||
let testcase = Testcase::new(vec![0; 4]).into();
|
let testcase = Testcase::new(vec![0; 4]).into();
|
||||||
corpus.add(testcase);
|
corpus.add(testcase);
|
||||||
|
|
||||||
let executor = InMemoryExecutor::<BytesInput>::new(harness);
|
let executor = InMemoryExecutor::<BytesInput>::new(harness);
|
||||||
let mut state = DefaultState::new(corpus, executor);
|
let events = LoggerEventManager::new();
|
||||||
|
let rand = DefaultRand::new(0);
|
||||||
|
|
||||||
|
let mut state = DefaultState::new(corpus, executor, events, rand);
|
||||||
|
|
||||||
let mut engine = DefaultEngine::new();
|
let mut engine = DefaultEngine::new();
|
||||||
let mut mutator = DefaultScheduledMutator::new(&rand);
|
let mut mutator = DefaultScheduledMutator::new();
|
||||||
mutator.add_mutation(mutation_bitflip);
|
mutator.add_mutation(mutation_bitflip);
|
||||||
let stage = DefaultMutationalStage::new(&rand, mutator);
|
let stage = DefaultMutationalStage::new(mutator);
|
||||||
engine.add_stage(Box::new(stage));
|
engine.add_stage(Box::new(stage));
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -94,3 +94,9 @@ impl EventManager for LoggerEventManager {
|
|||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LoggerEventManager {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
LoggerEventManager {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
use alloc::rc::Rc;
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::cell::RefCell;
|
|
||||||
use core::cmp::min;
|
use core::cmp::min;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::inputs::bytes::BytesInput;
|
use crate::inputs::bytes::BytesInput;
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
use crate::utils::{HasRand, Rand};
|
use crate::utils::Rand;
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
pub trait Generator<I>: HasRand
|
pub trait Generator<I, R>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Generate a new input
|
/// Generate a new input
|
||||||
fn generate(&mut self) -> Result<I, AflError>;
|
fn generate(&mut self, rand: &mut R) -> Result<I, AflError>;
|
||||||
|
|
||||||
/// Generate a new dummy input
|
/// Generate a new dummy input
|
||||||
fn generate_dummy(&self) -> I;
|
fn generate_dummy(&self) -> I;
|
||||||
@ -21,29 +21,21 @@ where
|
|||||||
|
|
||||||
const DUMMY_BYTES_SIZE: usize = 64;
|
const DUMMY_BYTES_SIZE: usize = 64;
|
||||||
|
|
||||||
pub struct RandBytesGenerator<R> {
|
pub struct RandBytesGenerator<R>
|
||||||
rand: Rc<RefCell<R>>,
|
where
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
max_size: usize,
|
max_size: usize,
|
||||||
|
phantom: PhantomData<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> HasRand for RandBytesGenerator<R>
|
impl<R> Generator<BytesInput, R> for RandBytesGenerator<R>
|
||||||
where
|
where
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
type R = R;
|
fn generate(&mut self, rand: &mut R) -> Result<BytesInput, AflError> {
|
||||||
|
let size = rand.below(self.max_size as u64);
|
||||||
fn rand(&self) -> &Rc<RefCell<Self::R>> {
|
let random_bytes: Vec<u8> = (0..size).map(|_| rand.below(256) as u8).collect();
|
||||||
&self.rand
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> Generator<BytesInput> for RandBytesGenerator<R>
|
|
||||||
where
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
fn generate(&mut self) -> Result<BytesInput, AflError> {
|
|
||||||
let size = self.rand_below(self.max_size as u64);
|
|
||||||
let random_bytes: Vec<u8> = (0..size).map(|_| self.rand_below(256) as u8).collect();
|
|
||||||
Ok(BytesInput::new(random_bytes))
|
Ok(BytesInput::new(random_bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,31 +45,32 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<R> RandBytesGenerator<R>
|
||||||
|
where
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
pub fn new(max_size: usize) -> Self {
|
||||||
|
RandBytesGenerator {
|
||||||
|
max_size: max_size,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct RandPrintablesGenerator<R> {
|
pub struct RandPrintablesGenerator<R> {
|
||||||
rand: Rc<RefCell<R>>,
|
|
||||||
max_size: usize,
|
max_size: usize,
|
||||||
|
phantom: PhantomData<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> HasRand for RandPrintablesGenerator<R>
|
impl<R> Generator<BytesInput, R> for RandPrintablesGenerator<R>
|
||||||
where
|
where
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
type R = R;
|
fn generate(&mut self, rand: &mut R) -> Result<BytesInput, AflError> {
|
||||||
|
let size = rand.below(self.max_size as u64);
|
||||||
fn rand(&self) -> &Rc<RefCell<Self::R>> {
|
|
||||||
&self.rand
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> Generator<BytesInput> for RandPrintablesGenerator<R>
|
|
||||||
where
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
fn generate(&mut self) -> Result<BytesInput, AflError> {
|
|
||||||
let size = self.rand_below(self.max_size as u64);
|
|
||||||
let printables = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz \t\n!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".as_bytes();
|
let printables = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz \t\n!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".as_bytes();
|
||||||
let random_bytes: Vec<u8> = (0..size)
|
let random_bytes: Vec<u8> = (0..size)
|
||||||
.map(|_| printables[self.rand_below(printables.len() as u64) as usize])
|
.map(|_| printables[rand.below(printables.len() as u64) as usize])
|
||||||
.collect();
|
.collect();
|
||||||
Ok(BytesInput::new(random_bytes))
|
Ok(BytesInput::new(random_bytes))
|
||||||
}
|
}
|
||||||
@ -87,3 +80,15 @@ where
|
|||||||
BytesInput::new(vec!['0' as u8; size])
|
BytesInput::new(vec!['0' as u8; size])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<R> RandPrintablesGenerator<R>
|
||||||
|
where
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
pub fn new(max_size: usize) -> Self {
|
||||||
|
RandPrintablesGenerator {
|
||||||
|
max_size: max_size,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,18 +4,21 @@ pub use scheduled::DefaultScheduledMutator;
|
|||||||
pub use scheduled::HavocBytesMutator;
|
pub use scheduled::HavocBytesMutator;
|
||||||
pub use scheduled::ScheduledMutator;
|
pub use scheduled::ScheduledMutator;
|
||||||
|
|
||||||
use crate::corpus::Corpus;
|
use crate::corpus::{Corpus, HasCorpus};
|
||||||
|
//use crate::engines::State;
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
use crate::utils::HasRand;
|
use crate::utils::{HasRand, Rand};
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
pub trait Mutator<C, I>: HasRand
|
pub trait Mutator<S, C, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
S: HasRand<R = R> + HasCorpus<C>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Mutate a given input
|
/// Mutate a given input
|
||||||
fn mutate(&mut self, corpus: &mut C, input: &mut I, stage_idx: i32) -> Result<(), AflError>;
|
fn mutate(&mut self, state: &mut S, input: &mut I, stage_idx: i32) -> Result<(), AflError>;
|
||||||
|
|
||||||
/// Post-process given the outcome of the execution
|
/// Post-process given the outcome of the execution
|
||||||
fn post_exec(&mut self, _is_interesting: bool, _stage_idx: i32) -> Result<(), AflError> {
|
fn post_exec(&mut self, _is_interesting: bool, _stage_idx: i32) -> Result<(), AflError> {
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
use crate::inputs::{HasBytesVec, Input};
|
use crate::inputs::{HasBytesVec, Input};
|
||||||
use crate::mutators::Corpus;
|
|
||||||
use crate::mutators::Mutator;
|
use crate::mutators::Mutator;
|
||||||
|
use crate::mutators::{Corpus, HasCorpus};
|
||||||
use crate::utils::{HasRand, Rand};
|
use crate::utils::{HasRand, Rand};
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
use alloc::rc::Rc;
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::cell::RefCell;
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
pub enum MutationResult {
|
pub enum MutationResult {
|
||||||
@ -14,43 +12,53 @@ pub enum MutationResult {
|
|||||||
Skipped,
|
Skipped,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO maybe the mutator arg is not needed
|
||||||
/// The generic function type that identifies mutations
|
/// The generic function type that identifies mutations
|
||||||
type MutationFunction<C, M, I> = fn(&mut M, &mut C, &mut I) -> Result<MutationResult, AflError>;
|
type MutationFunction<M, S, I> = fn(&mut M, &mut S, &mut I) -> Result<MutationResult, AflError>;
|
||||||
|
|
||||||
pub trait ComposedByMutations<C, I>
|
pub trait ComposedByMutations<S, C, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
S: HasRand<R = R> + HasCorpus<C>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Get a mutation by index
|
/// Get a mutation by index
|
||||||
fn mutation_by_idx(&self, index: usize) -> Result<MutationFunction<C, Self, I>, AflError>;
|
fn mutation_by_idx(&self, index: usize) -> Result<MutationFunction<Self, S, I>, AflError>;
|
||||||
|
|
||||||
/// Get the number of mutations
|
/// Get the number of mutations
|
||||||
fn mutations_count(&self) -> usize;
|
fn mutations_count(&self) -> usize;
|
||||||
|
|
||||||
/// Add a mutation
|
/// Add a mutation
|
||||||
fn add_mutation(&mut self, mutation: MutationFunction<C, Self, I>);
|
fn add_mutation(&mut self, mutation: MutationFunction<Self, S, I>);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ScheduledMutator<C, I>: Mutator<C, I> + ComposedByMutations<C, I>
|
pub trait ScheduledMutator<S, C, I, R>:
|
||||||
|
Mutator<S, C, I, R> + ComposedByMutations<S, C, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
S: HasRand<R = R> + HasCorpus<C>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Compute the number of iterations used to apply stacked mutations
|
/// Compute the number of iterations used to apply stacked mutations
|
||||||
fn iterations(&mut self, _input: &I) -> u64 {
|
fn iterations(&mut self, rand: &mut R, _input: &I) -> u64 {
|
||||||
1 << (1 + self.rand_below(7))
|
1 << (1 + rand.below(7))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the next mutation to apply
|
/// Get the next mutation to apply
|
||||||
fn schedule(&mut self, _input: &I) -> Result<MutationFunction<C, Self, I>, AflError> {
|
fn schedule(
|
||||||
|
&mut self,
|
||||||
|
rand: &mut R,
|
||||||
|
_input: &I,
|
||||||
|
) -> Result<MutationFunction<Self, S, I>, AflError> {
|
||||||
let count = self.mutations_count() as u64;
|
let count = self.mutations_count() as u64;
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return Err(AflError::Empty("no mutations".into()));
|
return Err(AflError::Empty("no mutations".into()));
|
||||||
}
|
}
|
||||||
let idx;
|
let idx;
|
||||||
{
|
{
|
||||||
idx = self.rand_below(count) as usize;
|
idx = rand.below(count) as usize;
|
||||||
}
|
}
|
||||||
self.mutation_by_idx(idx)
|
self.mutation_by_idx(idx)
|
||||||
}
|
}
|
||||||
@ -59,59 +67,51 @@ where
|
|||||||
/// Implementations must forward mutate() to this method
|
/// Implementations must forward mutate() to this method
|
||||||
fn scheduled_mutate(
|
fn scheduled_mutate(
|
||||||
&mut self,
|
&mut self,
|
||||||
corpus: &mut C,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
_stage_idx: i32,
|
_stage_idx: i32,
|
||||||
) -> Result<(), AflError> {
|
) -> Result<(), AflError> {
|
||||||
let num = self.iterations(input);
|
let num = self.iterations(state.rand_mut(), input);
|
||||||
for _ in 0..num {
|
for _ in 0..num {
|
||||||
self.schedule(input)?(self, corpus, input)?;
|
self.schedule(state.rand_mut(), input)?(self, state, input)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DefaultScheduledMutator<C, I, R>
|
pub struct DefaultScheduledMutator<S, C, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
rand: Rc<RefCell<R>>,
|
mutations: Vec<MutationFunction<Self, S, I>>,
|
||||||
mutations: Vec<MutationFunction<C, Self, I>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, I, R> HasRand for DefaultScheduledMutator<C, I, R>
|
impl<S, C, I, R> Mutator<S, C, I, R> for DefaultScheduledMutator<S, C, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
type R = R;
|
fn mutate(
|
||||||
|
&mut self,
|
||||||
fn rand(&self) -> &Rc<RefCell<Self::R>> {
|
corpus: &mut C,
|
||||||
&self.rand
|
rand: &mut R,
|
||||||
|
input: &mut I,
|
||||||
|
_stage_idx: i32,
|
||||||
|
) -> Result<(), AflError> {
|
||||||
|
self.scheduled_mutate(corpus, rand, input, _stage_idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, I, R> Mutator<C, I> for DefaultScheduledMutator<C, I, R>
|
impl<S, C, I, R> ComposedByMutations<S, C, I, R> for DefaultScheduledMutator<S, C, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn mutate(&mut self, corpus: &mut C, input: &mut I, _stage_idx: i32) -> Result<(), AflError> {
|
fn mutation_by_idx(&self, index: usize) -> Result<MutationFunction<Self, S, I>, AflError> {
|
||||||
self.scheduled_mutate(corpus, input, _stage_idx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C, I, R> ComposedByMutations<C, I> for DefaultScheduledMutator<C, I, R>
|
|
||||||
where
|
|
||||||
C: Corpus<I>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
fn mutation_by_idx(&self, index: usize) -> Result<MutationFunction<C, Self, I>, AflError> {
|
|
||||||
if index >= self.mutations.len() {
|
if index >= self.mutations.len() {
|
||||||
return Err(AflError::Unknown("oob".into()));
|
return Err(AflError::Unknown("oob".into()));
|
||||||
}
|
}
|
||||||
@ -122,14 +122,14 @@ where
|
|||||||
self.mutations.len()
|
self.mutations.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_mutation(&mut self, mutation: MutationFunction<C, Self, I>) {
|
fn add_mutation(&mut self, mutation: MutationFunction<Self, S, I>) {
|
||||||
self.mutations.push(mutation)
|
self.mutations.push(mutation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, I, R> ScheduledMutator<C, I> for DefaultScheduledMutator<C, I, R>
|
impl<C, I, R> ScheduledMutator<C, I, R> for DefaultScheduledMutator<C, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
@ -138,39 +138,37 @@ where
|
|||||||
|
|
||||||
impl<C, I, R> DefaultScheduledMutator<C, I, R>
|
impl<C, I, R> DefaultScheduledMutator<C, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Create a new DefaultScheduledMutator instance without mutations and corpus
|
/// Create a new DefaultScheduledMutator instance without mutations and corpus
|
||||||
pub fn new(rand: &Rc<RefCell<R>>) -> Self {
|
pub fn new() -> Self {
|
||||||
DefaultScheduledMutator {
|
DefaultScheduledMutator { mutations: vec![] }
|
||||||
rand: Rc::clone(rand),
|
|
||||||
mutations: vec![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new DefaultScheduledMutator instance specifying mutations and corpus too
|
/// Create a new DefaultScheduledMutator instance specifying mutations and corpus too
|
||||||
pub fn new_all(rand: &Rc<RefCell<R>>, mutations: Vec<MutationFunction<C, Self, I>>) -> Self {
|
pub fn new_all(mutations: Vec<MutationFunction<Self, S, I>>) -> Self {
|
||||||
DefaultScheduledMutator {
|
DefaultScheduledMutator {
|
||||||
rand: Rc::clone(rand),
|
|
||||||
mutations: mutations,
|
mutations: mutations,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bitflip mutation for inputs with a bytes vector
|
/// Bitflip mutation for inputs with a bytes vector
|
||||||
pub fn mutation_bitflip<C, M, I>(
|
pub fn mutation_bitflip<M, C, R, I>(
|
||||||
mutator: &mut M,
|
mutator: &mut M,
|
||||||
_corpus: &mut C,
|
_corpus: &mut C,
|
||||||
|
rand: &mut R,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
) -> Result<MutationResult, AflError>
|
) -> Result<MutationResult, AflError>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
M: Mutator<C, I, R>,
|
||||||
M: HasRand,
|
C: Corpus<I, R>,
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
let bit = mutator.rand_below((input.bytes().len() * 8) as u64) as usize;
|
let bit = rand.below((input.bytes().len() * 8) as u64) as usize;
|
||||||
input.bytes_mut()[bit >> 3] ^= (128 >> (bit & 7)) as u8;
|
input.bytes_mut()[bit >> 3] ^= (128 >> (bit & 7)) as u8;
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
}
|
}
|
||||||
@ -192,21 +190,23 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Splicing mutator
|
/// Splicing mutator
|
||||||
pub fn mutation_splice<C, M, I>(
|
pub fn mutation_splice<C, M, R, I>(
|
||||||
mutator: &mut M,
|
mutator: &mut M,
|
||||||
corpus: &mut C,
|
corpus: &mut C,
|
||||||
|
rand: &mut R,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
) -> Result<MutationResult, AflError>
|
) -> Result<MutationResult, AflError>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
M: Mutator<C, I, R>,
|
||||||
M: HasRand,
|
C: Corpus<I, R>,
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
let mut retry_count = 0;
|
let mut retry_count = 0;
|
||||||
// We don't want to use the testcase we're already using for splicing
|
// We don't want to use the testcase we're already using for splicing
|
||||||
let other_rr = loop {
|
let other_rr = loop {
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
let (other_rr, _) = corpus.random_entry()?.clone();
|
let (other_rr, _) = corpus.random_entry(rand)?.clone();
|
||||||
match other_rr.try_borrow_mut() {
|
match other_rr.try_borrow_mut() {
|
||||||
Ok(_) => found = true,
|
Ok(_) => found = true,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@ -238,7 +238,7 @@ where
|
|||||||
counter += 1;
|
counter += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
let split_at = mutator.rand_between(first_diff as u64, last_diff as u64) as usize;
|
let split_at = rand.between(first_diff as u64, last_diff as u64) as usize;
|
||||||
|
|
||||||
// println!("Splicing at {}", split_at);
|
// println!("Splicing at {}", split_at);
|
||||||
|
|
||||||
@ -253,51 +253,48 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Schedule some selected byte level mutations given a ScheduledMutator type
|
/// Schedule some selected byte level mutations given a ScheduledMutator type
|
||||||
pub struct HavocBytesMutator<C, I, S>
|
pub struct HavocBytesMutator<C, I, SM, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
S: ScheduledMutator<C, I>,
|
SM: ScheduledMutator<C, I, R>,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
scheduled: S,
|
scheduled: SM,
|
||||||
phantom: PhantomData<I>,
|
phantom: PhantomData<(I, R)>,
|
||||||
_phantom_corpus: PhantomData<C>,
|
_phantom_corpus: PhantomData<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, I, S> HasRand for HavocBytesMutator<C, I, S>
|
impl<C, I, SM, R> Mutator<C, I, R> for HavocBytesMutator<C, I, SM, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
S: ScheduledMutator<C, I>,
|
SM: ScheduledMutator<C, I, R>,
|
||||||
{
|
R: Rand,
|
||||||
type R = S::R;
|
|
||||||
|
|
||||||
fn rand(&self) -> &Rc<RefCell<Self::R>> {
|
|
||||||
&self.scheduled.rand()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C, I, S> Mutator<C, I> for HavocBytesMutator<C, I, S>
|
|
||||||
where
|
|
||||||
C: Corpus<I>,
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: ScheduledMutator<C, I>,
|
|
||||||
{
|
{
|
||||||
/// Mutate bytes
|
/// Mutate bytes
|
||||||
fn mutate(&mut self, corpus: &mut C, input: &mut I, stage_idx: i32) -> Result<(), AflError> {
|
fn mutate(
|
||||||
self.scheduled.mutate(corpus, input, stage_idx)
|
&mut self,
|
||||||
|
corpus: &mut C,
|
||||||
|
rand: &mut R,
|
||||||
|
input: &mut I,
|
||||||
|
stage_idx: i32,
|
||||||
|
) -> Result<(), AflError> {
|
||||||
|
self.scheduled.mutate(corpus, rand, input, stage_idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, I, S> HavocBytesMutator<C, I, S>
|
impl<C, I, SM, R> HavocBytesMutator<C, I, SM, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
S: ScheduledMutator<C, I>,
|
SM: ScheduledMutator<C, I, R>,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Create a new HavocBytesMutator instance given a ScheduledMutator to wrap
|
/// Create a new HavocBytesMutator instance given a ScheduledMutator to wrap
|
||||||
pub fn new(mut scheduled: S) -> Self {
|
pub fn new(mut scheduled: SM) -> Self {
|
||||||
scheduled.add_mutation(mutation_bitflip);
|
scheduled.add_mutation(mutation_bitflip);
|
||||||
|
scheduled.add_mutation(mutation_splice);
|
||||||
HavocBytesMutator {
|
HavocBytesMutator {
|
||||||
scheduled: scheduled,
|
scheduled: scheduled,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
@ -306,15 +303,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, I, R> HavocBytesMutator<C, I, DefaultScheduledMutator<C, I, R>>
|
impl<C, I, R> HavocBytesMutator<C, I, DefaultScheduledMutator<C, I, R>, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Create a new HavocBytesMutator instance wrapping DefaultScheduledMutator
|
/// Create a new HavocBytesMutator instance wrapping DefaultScheduledMutator
|
||||||
pub fn new_default(rand: &Rc<RefCell<R>>) -> Self {
|
pub fn new_default() -> Self {
|
||||||
let mut scheduled = DefaultScheduledMutator::<C, I, R>::new(rand);
|
let mut scheduled = DefaultScheduledMutator::<C, I, R>::new();
|
||||||
scheduled.add_mutation(mutation_bitflip);
|
scheduled.add_mutation(mutation_bitflip);
|
||||||
scheduled.add_mutation(mutation_splice);
|
scheduled.add_mutation(mutation_splice);
|
||||||
HavocBytesMutator {
|
HavocBytesMutator {
|
||||||
@ -328,29 +325,32 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::inputs::BytesInput;
|
use crate::inputs::BytesInput;
|
||||||
use crate::mutators::scheduled::mutation_splice;
|
use crate::mutators::scheduled::{mutation_splice, DefaultScheduledMutator};
|
||||||
use crate::utils::{DefaultHasRand, Rand, XKCDRand};
|
use crate::utils::{Rand, XKCDRand};
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, InMemoryCorpus, Testcase},
|
corpus::{Corpus, InMemoryCorpus, Testcase},
|
||||||
inputs::HasBytesVec,
|
inputs::HasBytesVec,
|
||||||
};
|
};
|
||||||
use alloc::rc::Rc;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mut_splice() {
|
fn test_mut_splice() {
|
||||||
// With the current impl, seed of 1 will result in a split at pos 2.
|
// With the current impl, seed of 1 will result in a split at pos 2.
|
||||||
let rand: Rc<_> = XKCDRand::new().into();
|
let mut rand = XKCDRand::new();
|
||||||
let mut has_rand = DefaultHasRand::new(&rand);
|
let mut corpus: InMemoryCorpus<BytesInput, _> = InMemoryCorpus::new();
|
||||||
let mut corpus: InMemoryCorpus<BytesInput, _> = InMemoryCorpus::new(&rand);
|
|
||||||
corpus.add(Testcase::new(vec!['a' as u8, 'b' as u8, 'c' as u8]).into());
|
corpus.add(Testcase::new(vec!['a' as u8, 'b' as u8, 'c' as u8]).into());
|
||||||
corpus.add(Testcase::new(vec!['d' as u8, 'e' as u8, 'f' as u8]).into());
|
corpus.add(Testcase::new(vec!['d' as u8, 'e' as u8, 'f' as u8]).into());
|
||||||
|
|
||||||
let (testcase_rr, _) = corpus.next().expect("Corpus did not contain entries");
|
let (testcase_rr, _) = corpus
|
||||||
|
.next(&mut rand)
|
||||||
|
.expect("Corpus did not contain entries");
|
||||||
let mut testcase = testcase_rr.borrow_mut();
|
let mut testcase = testcase_rr.borrow_mut();
|
||||||
let mut input = testcase.load_input().expect("No input in testcase").clone();
|
let mut input = testcase.load_input().expect("No input in testcase").clone();
|
||||||
|
|
||||||
rand.borrow_mut().set_seed(5);
|
rand.set_seed(5);
|
||||||
mutation_splice(&mut has_rand, &mut corpus, &mut input).unwrap();
|
let mut mutator =
|
||||||
|
DefaultScheduledMutator::<InMemoryCorpus<_, _>, BytesInput, XKCDRand>::new();
|
||||||
|
|
||||||
|
mutation_splice(&mut mutator, &mut corpus, &mut rand, &mut input).unwrap();
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
println!("{:?}", input.bytes());
|
println!("{:?}", input.bytes());
|
||||||
|
@ -4,18 +4,22 @@ pub use mutational::DefaultMutationalStage;
|
|||||||
use crate::corpus::testcase::Testcase;
|
use crate::corpus::testcase::Testcase;
|
||||||
use crate::corpus::Corpus;
|
use crate::corpus::Corpus;
|
||||||
use crate::engines::State;
|
use crate::engines::State;
|
||||||
|
use crate::events::EventManager;
|
||||||
use crate::executors::Executor;
|
use crate::executors::Executor;
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
|
use crate::utils::Rand;
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
use alloc::rc::Rc;
|
use alloc::rc::Rc;
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
|
||||||
pub trait Stage<S, C, E, I>
|
pub trait Stage<S, C, E, EM, I, R>
|
||||||
where
|
where
|
||||||
S: State<C, E, I>,
|
S: State<C, E, EM, I, R>,
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Run the stage
|
/// Run the stage
|
||||||
fn perform(
|
fn perform(
|
||||||
|
@ -4,23 +4,26 @@ use core::marker::PhantomData;
|
|||||||
|
|
||||||
use crate::corpus::testcase::Testcase;
|
use crate::corpus::testcase::Testcase;
|
||||||
use crate::engines::State;
|
use crate::engines::State;
|
||||||
|
use crate::events::EventManager;
|
||||||
use crate::executors::Executor;
|
use crate::executors::Executor;
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
use crate::mutators::Mutator;
|
use crate::mutators::Mutator;
|
||||||
use crate::stages::Corpus;
|
use crate::stages::Corpus;
|
||||||
use crate::stages::Stage;
|
use crate::stages::Stage;
|
||||||
use crate::utils::{HasRand, Rand};
|
use crate::utils::Rand;
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
// TODO multi mutators stage
|
// TODO multi mutators stage
|
||||||
|
|
||||||
pub trait MutationalStage<M, S, C, E, I>: Stage<S, C, E, I> + HasRand
|
pub trait MutationalStage<M, S, C, E, EM, I, R>: Stage<S, C, E, EM, I, R>
|
||||||
where
|
where
|
||||||
M: Mutator<C, I, R = Self::R>,
|
M: Mutator<C, I, R>,
|
||||||
S: State<C, E, I>,
|
S: State<C, E, EM, I, R>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
C: Corpus<I>,
|
EM: EventManager,
|
||||||
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;
|
||||||
@ -30,8 +33,8 @@ where
|
|||||||
|
|
||||||
/// 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
|
/// This call uses internal mutability, so it may change for each call
|
||||||
fn iterations(&mut self) -> usize {
|
fn iterations(&mut self, rand: &mut R) -> usize {
|
||||||
1 + self.rand_below(128) as usize
|
1 + rand.below(128) as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs this (mutational) stage for the given testcase
|
/// Runs this (mutational) stage for the given testcase
|
||||||
@ -40,13 +43,12 @@ where
|
|||||||
testcase: Rc<RefCell<Testcase<I>>>,
|
testcase: Rc<RefCell<Testcase<I>>>,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
) -> Result<(), AflError> {
|
) -> Result<(), AflError> {
|
||||||
let num = self.iterations();
|
let num = self.iterations(state.rand_mut());
|
||||||
let input = testcase.borrow_mut().load_input()?.clone();
|
let input = testcase.borrow_mut().load_input()?.clone();
|
||||||
|
|
||||||
for i in 0..num {
|
for i in 0..num {
|
||||||
let mut input_tmp = input.clone();
|
let mut input_tmp = input.clone();
|
||||||
self.mutator_mut()
|
self.mutator_mut().mutate(state, &mut input_tmp, i as i32)?;
|
||||||
.mutate(state.corpus_mut(), &mut input_tmp, i as i32)?;
|
|
||||||
|
|
||||||
let interesting = state.evaluate_input(&input_tmp)?;
|
let interesting = state.evaluate_input(&input_tmp)?;
|
||||||
|
|
||||||
@ -61,39 +63,28 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The default mutational stage
|
/// The default mutational stage
|
||||||
pub struct DefaultMutationalStage<M, C, I, R>
|
pub struct DefaultMutationalStage<M, S, C, E, EM, I, R>
|
||||||
where
|
where
|
||||||
M: Mutator<C, I, R = R>,
|
M: Mutator<C, I, R>,
|
||||||
C: Corpus<I>,
|
S: State<C, E, EM, I, R>,
|
||||||
I: Input,
|
C: Corpus<I, R>,
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
rand: Rc<RefCell<R>>,
|
|
||||||
mutator: M,
|
|
||||||
_phantom_corpus: PhantomData<C>,
|
|
||||||
_phantom_input: PhantomData<I>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M, C, I, R> HasRand for DefaultMutationalStage<M, C, I, R>
|
|
||||||
where
|
|
||||||
M: Mutator<C, I, R = R>,
|
|
||||||
C: Corpus<I>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
type R = R;
|
|
||||||
|
|
||||||
fn rand(&self) -> &Rc<RefCell<R>> {
|
|
||||||
&self.rand
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M, S, C, E, I, R> MutationalStage<M, S, C, E, I> for DefaultMutationalStage<M, C, I, R>
|
|
||||||
where
|
|
||||||
M: Mutator<C, I, R = R>,
|
|
||||||
S: State<C, E, I>,
|
|
||||||
C: Corpus<I>,
|
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
mutator: M,
|
||||||
|
phantom: PhantomData<(S, C, E, EM, I, R)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M, S, C, E, EM, I, R> MutationalStage<M, S, C, E, EM, I, R>
|
||||||
|
for DefaultMutationalStage<M, S, C, E, EM, I, R>
|
||||||
|
where
|
||||||
|
M: Mutator<C, I, R>,
|
||||||
|
S: State<C, E, EM, I, R>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
@ -108,12 +99,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, S, C, E, I, R> Stage<S, C, E, I> for DefaultMutationalStage<M, C, I, R>
|
impl<M, S, C, E, EM, I, R> Stage<S, C, E, EM, I, R> for DefaultMutationalStage<M, S, C, E, EM, I, R>
|
||||||
where
|
where
|
||||||
M: Mutator<C, I, R = R>,
|
M: Mutator<C, I, R>,
|
||||||
S: State<C, E, I>,
|
S: State<C, E, EM, I, R>,
|
||||||
C: Corpus<I>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
@ -126,20 +118,21 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, C, I, R> DefaultMutationalStage<M, C, I, R>
|
impl<M, S, C, E, EM, I, R> DefaultMutationalStage<M, S, C, E, EM, I, R>
|
||||||
where
|
where
|
||||||
M: Mutator<C, I, R = R>,
|
M: Mutator<C, I, R>,
|
||||||
C: Corpus<I>,
|
S: State<C, E, EM, I, R>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
E: Executor<I>,
|
||||||
|
EM: EventManager,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Creates a new default mutational stage
|
/// Creates a new default mutational stage
|
||||||
pub fn new(rand: &Rc<RefCell<R>>, mutator: M) -> Self {
|
pub fn new(mutator: M) -> Self {
|
||||||
DefaultMutationalStage {
|
DefaultMutationalStage {
|
||||||
rand: Rc::clone(rand),
|
|
||||||
mutator: mutator,
|
mutator: mutator,
|
||||||
_phantom_corpus: PhantomData,
|
phantom: PhantomData,
|
||||||
_phantom_input: PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
33
src/utils.rs
33
src/utils.rs
@ -46,10 +46,35 @@ pub trait Rand: Debug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Has a Rand Rc RefCell field (internal mutability), that can be used to get random values
|
/// Has a Rand field, that can be used to get random values
|
||||||
pub trait HasRand {
|
pub trait HasRand {
|
||||||
type R: Rand;
|
type R: Rand;
|
||||||
|
|
||||||
|
/// Get the hold Rand instance
|
||||||
|
fn rand(&self) -> &Self::R;
|
||||||
|
|
||||||
|
/// Get the hold Rand instance (mutable)
|
||||||
|
fn rand_mut(&mut self) -> &mut Self::R;
|
||||||
|
|
||||||
|
// Gets the next 64 bit value
|
||||||
|
fn rand_next(&mut self) -> u64 {
|
||||||
|
self.rand_mut().next()
|
||||||
|
}
|
||||||
|
// Gets a value below the given 64 bit val (inclusive)
|
||||||
|
fn rand_below(&mut self, upper_bound_excl: u64) -> u64 {
|
||||||
|
self.rand_mut().below(upper_bound_excl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a value between the given lower bound (inclusive) and upper bound (inclusive)
|
||||||
|
fn rand_between(&mut self, lower_bound_incl: u64, upper_bound_incl: u64) -> u64 {
|
||||||
|
self.rand_mut().between(lower_bound_incl, upper_bound_incl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Has a Rand Rc RefCell field (internal mutability), that can be used to get random values
|
||||||
|
pub trait HasRandRR {
|
||||||
|
type R: Rand;
|
||||||
|
|
||||||
/// Get the hold Rand instance
|
/// Get the hold Rand instance
|
||||||
fn rand(&self) -> &Rc<RefCell<Self::R>>;
|
fn rand(&self) -> &Rc<RefCell<Self::R>>;
|
||||||
|
|
||||||
@ -172,6 +197,7 @@ impl XKCDRand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/// A very basic HasRand
|
/// A very basic HasRand
|
||||||
pub struct DefaultHasRand<R>
|
pub struct DefaultHasRand<R>
|
||||||
where
|
where
|
||||||
@ -205,6 +231,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/// Get the next higher power of two
|
/// Get the next higher power of two
|
||||||
pub const fn next_pow2(val: u64) -> u64 {
|
pub const fn next_pow2(val: u64) -> u64 {
|
||||||
@ -219,7 +246,7 @@ pub const fn next_pow2(val: u64) -> u64 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::utils::{next_pow2, DefaultHasRand, DefaultRand, HasRand, Rand};
|
use crate::utils::{next_pow2, DefaultRand, HasRand, Rand};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rand() {
|
fn test_rand() {
|
||||||
@ -244,6 +271,7 @@ mod tests {
|
|||||||
assert!(rand.between(11, 20) > 10);
|
assert!(rand.between(11, 20) > 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
#[test]
|
#[test]
|
||||||
fn test_has_rand() {
|
fn test_has_rand() {
|
||||||
let rand = DefaultRand::new(0).into();
|
let rand = DefaultRand::new(0).into();
|
||||||
@ -252,6 +280,7 @@ mod tests {
|
|||||||
assert!(has_rand.rand_below(100) < 100);
|
assert!(has_rand.rand_below(100) < 100);
|
||||||
assert_eq!(has_rand.rand_below(1), 0);
|
assert_eq!(has_rand.rand_below(1), 0);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_next_pow2() {
|
fn test_next_pow2() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user