started moving to no_std

This commit is contained in:
Dominik Maier 2020-11-15 02:04:13 +01:00
parent 629287251f
commit ec36301414
12 changed files with 148 additions and 74 deletions

View File

@ -9,9 +9,12 @@ edition = "2018"
[dev-dependencies] [dev-dependencies]
criterion = "0.3" # Benchmarking criterion = "0.3" # Benchmarking
[features]
default = ["std"]
std = []
[dependencies] [dependencies]
xxhash-rust = { version = "0.8.0-beta.4", features = ["xxh3"] } # xxh3 hashing for rust xxhash-rust = { version = "0.8.0-beta.4", features = ["xxh3"] } # xxh3 hashing for rust
thiserror = "1.0" # A nicer way to write Errors
hashbrown = "0.9" # A faster hashmap, nostd compatible hashbrown = "0.9" # A faster hashmap, nostd compatible
libc = "0.2" # For (*nix) libc libc = "0.2" # For (*nix) libc
num = "*" num = "*"

View File

@ -3,9 +3,12 @@ extern crate alloc;
pub mod testcase; pub mod testcase;
pub use testcase::{Testcase, TestcaseMetadata}; pub use testcase::{Testcase, TestcaseMetadata};
use alloc::borrow::ToOwned;
use alloc::rc::Rc; use alloc::rc::Rc;
use alloc::vec::Vec;
use core::cell::RefCell; use core::cell::RefCell;
use core::marker::PhantomData; use core::marker::PhantomData;
#[cfg(feature = "std")]
use std::path::PathBuf; use std::path::PathBuf;
use crate::inputs::Input; use crate::inputs::Input;
@ -34,16 +37,10 @@ where
} }
/// Add an entry to the corpus /// Add an entry to the corpus
#[allow(unused_mut)] fn add(&mut self, testcase: Rc<RefCell<Testcase<I>>>) {
fn add(&mut self, mut testcase: Rc<RefCell<Testcase<I>>>) {
self.entries_mut().push(testcase); self.entries_mut().push(testcase);
} }
/// Add an input to the corpus
fn add_input(&mut self, input: I) {
self.add(Testcase::new(input.into()).into());
}
/// Removes an entry from the corpus, returning it if it was present. /// Removes an entry from the corpus, returning it if it was present.
fn remove(&mut self, entry: &Testcase<I>) -> Option<Rc<RefCell<Testcase<I>>>> { fn remove(&mut self, entry: &Testcase<I>) -> Option<Rc<RefCell<Testcase<I>>>> {
let mut i: usize = 0; let mut i: usize = 0;
@ -135,6 +132,7 @@ where
} }
} }
#[cfg(feature = "std")]
pub struct OnDiskCorpus<I, R> pub struct OnDiskCorpus<I, R>
where where
I: Input, I: Input,
@ -145,6 +143,7 @@ where
dir_path: PathBuf, dir_path: PathBuf,
} }
#[cfg(feature = "std")]
impl<I, R> HasEntriesVec<I> for OnDiskCorpus<I, R> impl<I, R> HasEntriesVec<I> for OnDiskCorpus<I, R>
where where
I: Input, I: Input,
@ -158,6 +157,7 @@ where
} }
} }
#[cfg(feature = "std")]
impl<I, R> HasRand for OnDiskCorpus<I, R> impl<I, R> HasRand for OnDiskCorpus<I, R>
where where
I: Input, I: Input,
@ -170,6 +170,7 @@ where
} }
} }
#[cfg(feature = "std")]
impl<I, R> Corpus<I> for OnDiskCorpus<I, R> impl<I, R> Corpus<I> for OnDiskCorpus<I, R>
where where
I: Input, I: Input,
@ -179,9 +180,9 @@ where
fn add(&mut self, entry: Rc<RefCell<Testcase<I>>>) { fn add(&mut self, entry: Rc<RefCell<Testcase<I>>>) {
if *entry.borrow().filename() == None { if *entry.borrow().filename() == None {
// TODO walk entry metadatas to ask for pices of filename (e.g. :havoc in AFL) // TODO walk entry metadatas to ask for pices of filename (e.g. :havoc in AFL)
let filename = &(String::from("id:") + &self.entries.len().to_string()); let filename = self.dir_path.join(format!("id_{}", &self.entries.len()));
let filename = self.dir_path.join(filename); let filename_str = filename.to_str().expect("Invalid Path");
*entry.borrow_mut().filename_mut() = Some(filename); *entry.borrow_mut().filename_mut() = Some(filename_str.into());
} }
self.entries.push(entry); self.entries.push(entry);
} }
@ -189,6 +190,7 @@ where
// TODO save and remove files, cache, etc..., ATM use just InMemoryCorpus // TODO save and remove files, cache, etc..., ATM use just InMemoryCorpus
} }
#[cfg(feature = "std")]
impl<I, R> OnDiskCorpus<I, R> impl<I, R> OnDiskCorpus<I, R>
where where
I: Input, I: Input,
@ -352,6 +354,7 @@ And then:
*/ */
#[cfg(test)] #[cfg(test)]
#[cfg(feature = "std")]
mod tests { mod tests {
use crate::corpus::Corpus; use crate::corpus::Corpus;
use crate::corpus::Testcase; use crate::corpus::Testcase;
@ -363,11 +366,11 @@ mod tests {
use std::path::PathBuf; use std::path::PathBuf;
#[test] #[test]
fn test_queuecorpus() { fn test_queuecorpus() {
let rand: Rc<_> = DefaultRand::preseeded().into(); let rand: Rc<_> = DefaultRand::new(0).into();
let mut q = QueueCorpus::new(OnDiskCorpus::new(&rand, PathBuf::from("fancy/path"))); let mut q = QueueCorpus::new(OnDiskCorpus::new(&rand, PathBuf::from("fancy/path")));
let t: Rc<_> = Testcase::with_filename(BytesInput::new(vec![0 as u8; 4]), PathBuf::from("fancyfile")).into(); let t: Rc<_> =
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()
@ -387,6 +390,6 @@ mod tests {
.unwrap() .unwrap()
.to_owned() .to_owned()
); );
assert_eq!(filename, PathBuf::from("fancyfile")); assert_eq!(filename, "fancyfile");
} }
} }

View File

@ -7,9 +7,12 @@ use alloc::rc::Rc;
use core::cell::RefCell; use core::cell::RefCell;
use core::convert::Into; use core::convert::Into;
use hashbrown::HashMap; use hashbrown::HashMap;
#[cfg(feature = "std")]
use std::fs::File; use std::fs::File;
#[cfg(feature = "std")]
use std::io::Write; use std::io::Write;
use std::path::{Path, PathBuf}; #[cfg(feature = "std")]
use std::path::Path;
// TODO: Give example // TODO: Give example
/// Metadata for a testcase /// Metadata for a testcase
@ -18,6 +21,24 @@ pub trait TestcaseMetadata {
fn name(&self) -> &'static str; fn name(&self) -> &'static str;
} }
/*
pub trait Testcase<I, T>
where
I: Input,
T: TestcaseMetadata,
{
fn input(&mut self) -> Option<I>
input: Option<I>,
/// Filename, if this testcase is backed by a file in the filesystem
filename: Option<String>,
/// Map of metadatas associated with this testcase
metadatas: HashMap<&'static str, Box<dyn TestcaseMetadata>>,
}
*/
pub enum FileBackedTestcase<I, P> { pub enum FileBackedTestcase<I, P> {
/// A testcase on disk, not yet loaded /// A testcase on disk, not yet loaded
Stored { filename: P }, Stored { filename: P },
@ -109,7 +130,7 @@ where
/// The input of this testcase /// The input of this testcase
input: Option<I>, input: Option<I>,
/// Filename, if this testcase is backed by a file in the filesystem /// Filename, if this testcase is backed by a file in the filesystem
filename: Option<PathBuf>, filename: Option<String>,
/// Map of metadatas associated with this testcase /// Map of metadatas associated with this testcase
metadatas: HashMap<&'static str, Box<dyn TestcaseMetadata>>, metadatas: HashMap<&'static str, Box<dyn TestcaseMetadata>>,
} }
@ -133,7 +154,7 @@ where
// TODO: Implement cache to disk // TODO: Implement cache to disk
match self.input.as_ref() { match self.input.as_ref() {
Some(i) => Ok(i), Some(i) => Ok(i),
None => Err(AflError::NotImplemented("load_input".to_string())), None => Err(AflError::NotImplemented("load_input".into())),
} }
} }
@ -151,15 +172,15 @@ where
} }
/// Get the filename, if any /// Get the filename, if any
pub fn filename(&self) -> &Option<PathBuf> { pub fn filename(&self) -> &Option<String> {
&self.filename &self.filename
} }
/// Get the filename, if any (mutable) /// Get the filename, if any (mutable)
pub fn filename_mut(&mut self) -> &mut Option<PathBuf> { pub fn filename_mut(&mut self) -> &mut Option<String> {
&mut self.filename &mut self.filename
} }
/// Set the filename /// Set the filename
pub fn set_filename(&mut self, filename: Option<PathBuf>) { pub fn set_filename(&mut self, filename: Option<String>) {
self.filename = filename; self.filename = filename;
} }
@ -183,7 +204,7 @@ where
} }
/// Create a new Testcase instace given an input and a filename /// Create a new Testcase instace given an input and a filename
pub fn with_filename(input: I, filename: PathBuf) -> Self { pub fn with_filename(input: I, filename: String) -> Self {
Testcase { Testcase {
input: Some(input), input: Some(input),
filename: Some(filename), filename: Some(filename),

View File

@ -103,7 +103,7 @@ mod tests {
#[test] #[test]
fn test_engine() { fn test_engine() {
let rand: Rc<_> = DefaultRand::preseeded().into(); let rand: Rc<_> = DefaultRand::new(0).into();
let mut corpus = InMemoryCorpus::<BytesInput, _>::new(&rand); let mut corpus = InMemoryCorpus::<BytesInput, _>::new(&rand);
let testcase = Testcase::new(BytesInput::new(vec![0; 4])).into(); let testcase = Testcase::new(BytesInput::new(vec![0; 4])).into();

View File

@ -67,11 +67,11 @@ where
self.observers.push(observer); self.observers.push(observer);
} }
fn observers(&self) -> &Vec<Box<dyn Observer>> { fn observers(&self) -> &[Box<dyn Observer>] {
&self.observers &self.observers
} }
fn feedbacks(&self) -> &Vec<Box<dyn Feedback<I>>> { fn feedbacks(&self) -> &[Box<dyn Feedback<I>>] {
&self.feedbacks &self.feedbacks
} }
@ -211,10 +211,10 @@ mod tests {
impl Observer for Nopserver { impl Observer for Nopserver {
fn reset(&mut self) -> Result<(), AflError> { fn reset(&mut self) -> Result<(), AflError> {
Err(AflError::Unknown("Nop reset, testing only".to_string())) Err(AflError::Unknown("Nop reset, testing only".into()))
} }
fn post_exec(&mut self) -> Result<(), AflError> { fn post_exec(&mut self) -> Result<(), AflError> {
Err(AflError::Unknown("Nop exec, testing only".to_string())) Err(AflError::Unknown("Nop exec, testing only".into()))
} }
} }

View File

@ -1,10 +1,6 @@
extern crate alloc; extern crate alloc;
pub mod inmemory; pub mod inmemory;
use alloc::rc::Rc;
use core::cell::RefCell;
use crate::corpus::Testcase;
use crate::corpus::TestcaseMetadata; use crate::corpus::TestcaseMetadata;
use crate::feedbacks::Feedback; use crate::feedbacks::Feedback;
use crate::inputs::Input; use crate::inputs::Input;
@ -37,13 +33,13 @@ where
fn add_observer(&mut self, observer: Box<dyn Observer>); fn add_observer(&mut self, observer: Box<dyn Observer>);
/// Get the linked observers /// Get the linked observers
fn observers(&self) -> &Vec<Box<dyn Observer>>; fn observers(&self) -> &[Box<dyn Observer>];
/// Adds a feedback /// Adds a feedback
fn add_feedback(&mut self, feedback: Box<dyn Feedback<I>>); fn add_feedback(&mut self, feedback: Box<dyn Feedback<I>>);
/// Returns vector of feebacks /// Returns vector of feebacks
fn feedbacks(&self) -> &Vec<Box<dyn Feedback<I>>>; fn feedbacks(&self) -> &[Box<dyn Feedback<I>>];
/// Returns vector of feebacks (mutable) /// Returns vector of feebacks (mutable)
fn feedbacks_mut(&mut self) -> &mut Vec<Box<dyn Feedback<I>>>; fn feedbacks_mut(&mut self) -> &mut Vec<Box<dyn Feedback<I>>>;
@ -66,12 +62,6 @@ where
} }
if rate_acc >= 25 { if rate_acc >= 25 {
let new_entry = Rc::new(RefCell::new(Testcase::<I>::new(input.clone())));
for meta in metadatas {
new_entry.borrow_mut().add_metadata(meta);
}
//TODO corpus.add(new_entry);
Ok(true) Ok(true)
} else { } else {
Ok(false) Ok(false)

View File

@ -3,6 +3,8 @@ extern crate num;
use core::cell::RefCell; use core::cell::RefCell;
use core::marker::PhantomData; use core::marker::PhantomData;
use alloc::vec::*;
use num::Integer; use num::Integer;
use crate::corpus::TestcaseMetadata; use crate::corpus::TestcaseMetadata;

View File

@ -1,9 +1,10 @@
extern crate alloc; extern crate alloc;
use core::convert::From; use alloc::borrow::ToOwned;
use alloc::rc::Rc; use alloc::rc::Rc;
use alloc::vec::Vec;
use core::cell::RefCell; use core::cell::RefCell;
use core::convert::From;
use crate::inputs::{HasBytesVec, HasTargetBytes, Input}; use crate::inputs::{HasBytesVec, HasTargetBytes, Input};
use crate::AflError; use crate::AflError;
@ -20,7 +21,9 @@ impl Input for BytesInput {
} }
fn deserialize(buf: &[u8]) -> Result<Self, AflError> { fn deserialize(buf: &[u8]) -> Result<Self, AflError> {
Ok(Self { bytes: buf.into() }) Ok(Self {
bytes: buf.to_owned(),
})
} }
} }
@ -32,7 +35,7 @@ impl Into<Rc<RefCell<Self>>> for BytesInput {
} }
impl HasBytesVec for BytesInput { impl HasBytesVec for BytesInput {
fn bytes(&self) -> &Vec<u8> { fn bytes(&self) -> &[u8] {
&self.bytes &self.bytes
} }
fn bytes_mut(&mut self) -> &mut Vec<u8> { fn bytes_mut(&mut self) -> &mut Vec<u8> {
@ -41,7 +44,7 @@ impl HasBytesVec for BytesInput {
} }
impl HasTargetBytes for BytesInput { impl HasTargetBytes for BytesInput {
fn target_bytes(&self) -> &Vec<u8> { fn target_bytes(&self) -> &[u8] {
&self.bytes &self.bytes
} }
} }
@ -71,7 +74,7 @@ mod tests {
#[test] #[test]
fn test_input() { fn test_input() {
let mut rand = DefaultRand::preseeded(); let mut rand = DefaultRand::new(0);
assert_ne!(rand.next(), rand.next()); assert_ne!(rand.next(), rand.next());
assert!(rand.below(100) < 100); assert!(rand.below(100) < 100);
assert_eq!(rand.below(1), 0); assert_eq!(rand.below(1), 0);

View File

@ -3,15 +3,21 @@ extern crate alloc;
pub mod bytes; pub mod bytes;
pub use bytes::BytesInput; pub use bytes::BytesInput;
use alloc::vec::Vec;
use core::clone::Clone; use core::clone::Clone;
use std::io::Write;
#[cfg(feature = "std")]
use std::fs::File;
#[cfg(feature = "std")]
use std::io::{Read, Write};
#[cfg(feature = "std")]
use std::path::Path; use std::path::Path;
use std::{fs::File, io::Read};
use crate::AflError; use crate::AflError;
/// An input for the target /// An input for the target
pub trait Input: Clone { pub trait Input: Clone {
#[cfg(feature = "std")]
/// Write this input to the file /// Write this input to the file
fn to_file<P>(&self, path: P) -> Result<(), AflError> fn to_file<P>(&self, path: P) -> Result<(), AflError>
where where
@ -22,7 +28,15 @@ pub trait Input: Clone {
Ok(()) Ok(())
} }
#[cfg(not(feature = "std"))]
/// Write this input to the file
fn to_file<P>(&self, string: P) -> Result<(), AflError>
where {
Err(AflError::NotImplemented("Not suppored in no_std".into()))
}
/// Load the contents of this input from a file /// Load the contents of this input from a file
#[cfg(feature = "std")]
fn from_file<P>(path: P) -> Result<Self, AflError> fn from_file<P>(path: P) -> Result<Self, AflError>
where where
P: AsRef<Path>, P: AsRef<Path>,
@ -33,6 +47,13 @@ pub trait Input: Clone {
Self::deserialize(&bytes) Self::deserialize(&bytes)
} }
/// Write this input to the file
#[cfg(not(feature = "std"))]
fn from_file<P>(string: P) -> Result<Self, AflError>
where {
Err(AflError::NotImplemented("Not suppored in no_std".into()))
}
/// Serialize this input, for later deserialization. /// Serialize this input, for later deserialization.
/// This is not necessarily the representation to be used by the target /// This is not necessarily the representation to be used by the target
/// Instead, to get bytes for a target, use [HasTargetBytes](afl::inputs::HasTargetBytes). /// Instead, to get bytes for a target, use [HasTargetBytes](afl::inputs::HasTargetBytes).
@ -47,13 +68,13 @@ pub trait Input: Clone {
/// Instead, it can be used as bytes input for a target /// Instead, it can be used as bytes input for a target
pub trait HasTargetBytes { pub trait HasTargetBytes {
/// Target bytes, that can be written to a target /// Target bytes, that can be written to a target
fn target_bytes(&self) -> &Vec<u8>; fn target_bytes(&self) -> &[u8];
} }
/// Contains an internal bytes Vector /// Contains an internal bytes Vector
pub trait HasBytesVec { pub trait HasBytesVec {
/// The internal bytes map /// The internal bytes map
fn bytes(&self) -> &Vec<u8>; fn bytes(&self) -> &[u8];
/// The internal bytes map (as mutable borrow) /// The internal bytes map (as mutable borrow)
fn bytes_mut(&mut self) -> &mut Vec<u8>; fn bytes_mut(&mut self) -> &mut Vec<u8>;
} }

View File

@ -1,3 +1,5 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
extern crate alloc; extern crate alloc;
pub mod corpus; pub mod corpus;
@ -11,32 +13,52 @@ pub mod observers;
pub mod stages; pub mod stages;
pub mod utils; pub mod utils;
use alloc::string::String;
use core::fmt;
#[cfg(feature = "std")]
use std::io; use std::io;
use thiserror::Error;
/// Main error struct for AFL /// Main error struct for AFL
#[derive(Error, Debug)] #[derive(Debug)]
pub enum AflError { pub enum AflError {
#[error("Error in Serialization: `{0}`")]
Serialize(String), Serialize(String),
#[error("File IO failed")] #[cfg(feature = "std")]
File(#[from] io::Error), File(io::Error),
#[error("Optional value `{0}` was not set")]
EmptyOptional(String), EmptyOptional(String),
#[error("Key `{0}` not in Corpus")]
KeyNotFound(String), KeyNotFound(String),
#[error("No items in {0}")]
Empty(String), Empty(String),
#[error("All elements have been processed in {0} iterator")]
IteratorEnd(String), IteratorEnd(String),
#[error("Not implemented: {0}")]
NotImplemented(String), NotImplemented(String),
#[error("Illegal state: {0}")]
IllegalState(String), IllegalState(String),
#[error("Unknown error: {0}")]
Unknown(String), Unknown(String),
} }
impl fmt::Display for AflError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Serialize(s) => write!(f, "Error in Serialization: `{0}`", &s),
#[cfg(feature = "std")]
Self::File(err) => write!(f, "File IO failed: {:?}", &err),
Self::EmptyOptional(s) => write!(f, "Optional value `{0}` was not set", &s),
Self::KeyNotFound(s) => write!(f, "Key `{0}` not in Corpus", &s),
Self::Empty(s) => write!(f, "No items in {0}", &s),
Self::IteratorEnd(s) => {
write!(f, "All elements have been processed in {0} iterator", &s)
}
Self::NotImplemented(s) => write!(f, "Not implemented: {0}", &s),
Self::IllegalState(s) => write!(f, "Illegal state: {0}", &s),
Self::Unknown(s) => write!(f, "Unknown error: {0}", &s),
}
}
}
#[cfg(feature = "std")]
impl From<io::Error> for AflError {
fn from(err: io::Error) -> Self {
Self::File(err)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[test] #[test]

View File

@ -7,6 +7,7 @@ use crate::utils::{HasRand, Rand};
use crate::AflError; use crate::AflError;
use alloc::rc::Rc; use alloc::rc::Rc;
use alloc::vec::Vec;
use core::cell::RefCell; use core::cell::RefCell;
use core::marker::PhantomData; use core::marker::PhantomData;
@ -42,7 +43,7 @@ where
fn schedule(&mut self, _input: &I) -> Result<MutationFunction<C, Self, I>, AflError> { fn schedule(&mut self, _input: &I) -> Result<MutationFunction<C, Self, 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".to_string())); return Err(AflError::Empty("no mutations".into()));
} }
let idx; let idx;
{ {
@ -109,7 +110,7 @@ where
{ {
fn mutation_by_idx(&self, index: usize) -> Result<MutationFunction<C, Self, I>, AflError> { 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".to_string())); return Err(AflError::Unknown("oob".into()));
} }
Ok(self.mutations[index]) Ok(self.mutations[index])
} }
@ -172,7 +173,7 @@ where
} }
/// Returns the first and last diff position between the given vectors, stopping at the min len /// Returns the first and last diff position between the given vectors, stopping at the min len
fn locate_diffs(this: &Vec<u8>, other: &Vec<u8>) -> (i64, i64) { fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
let mut first_diff: i64 = -1; let mut first_diff: i64 = -1;
let mut last_diff: i64 = -1; let mut last_diff: i64 = -1;
for (i, (this_el, other_el)) in this.iter().zip(other.iter()).enumerate() { for (i, (this_el, other_el)) in this.iter().zip(other.iter()).enumerate() {
@ -208,7 +209,7 @@ where
Err(_) => { Err(_) => {
if retry_count == 20 { if retry_count == 20 {
return Err(AflError::Empty( return Err(AflError::Empty(
"No suitable testcase found for splicing".to_owned(), "No suitable testcase found for splicing".into(),
)); ));
} }
retry_count += 1; retry_count += 1;
@ -231,7 +232,7 @@ where
break (f, l); break (f, l);
} }
if counter == 20 { if counter == 20 {
return Err(AflError::Empty("No valid diff found".to_owned())); return Err(AflError::Empty("No valid diff found".into()));
} }
counter += 1; counter += 1;
}; };
@ -324,10 +325,13 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::corpus::{Corpus, InMemoryCorpus}; use crate::inputs::BytesInput;
use crate::inputs::{BytesInput, HasBytesVec};
use crate::mutators::scheduled::mutation_splice; use crate::mutators::scheduled::mutation_splice;
use crate::utils::{DefaultHasRand, Rand, XKCDRand}; use crate::utils::{DefaultHasRand, Rand, XKCDRand};
use crate::{
corpus::{Corpus, InMemoryCorpus, Testcase},
inputs::HasBytesVec,
};
use alloc::rc::Rc; use alloc::rc::Rc;
#[test] #[test]
@ -336,8 +340,8 @@ mod tests {
let rand: Rc<_> = XKCDRand::new().into(); let rand: Rc<_> = XKCDRand::new().into();
let mut has_rand = DefaultHasRand::new(&rand); let mut has_rand = DefaultHasRand::new(&rand);
let mut corpus = InMemoryCorpus::new(&rand); let mut corpus = InMemoryCorpus::new(&rand);
corpus.add_input(BytesInput::new(vec!['a' as u8, 'b' as u8, 'c' as u8])); corpus.add(Testcase::new(BytesInput::new(vec!['a' as u8, 'b' as u8, 'c' as u8])).into());
corpus.add_input(BytesInput::new(vec!['d' as u8, 'e' as u8, 'f' as u8])); corpus.add(Testcase::new(BytesInput::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().expect("Corpus did not contain entries");
let mut testcase = testcase_rr.borrow_mut(); let mut testcase = testcase_rr.borrow_mut();
@ -346,10 +350,11 @@ mod tests {
rand.borrow_mut().set_seed(5); rand.borrow_mut().set_seed(5);
mutation_splice(&mut has_rand, &mut corpus, &mut input).unwrap(); mutation_splice(&mut has_rand, &mut corpus, &mut input).unwrap();
#[cfg(feature = "std")]
println!("{:?}", input.bytes()); println!("{:?}", input.bytes());
// The pre-seeded rand should have spliced at position 2. // The pre-seeded rand should have spliced at position 2.
// TODO: Maybe have a fixed rand for this purpose? // TODO: Maybe have a fixed rand for this purpose?
assert_eq!(input.bytes(), &vec!['a' as u8, 'b' as u8, 'f' as u8]) assert_eq!(input.bytes(), &['a' as u8, 'b' as u8, 'f' as u8])
} }
} }

View File

@ -5,9 +5,11 @@ use alloc::rc::Rc;
use core::cell::RefCell; use core::cell::RefCell;
use core::debug_assert; use core::debug_assert;
use core::fmt::Debug; use core::fmt::Debug;
use std::time::{SystemTime, UNIX_EPOCH};
use xxhash_rust::xxh3::xxh3_64_with_seed; use xxhash_rust::xxh3::xxh3_64_with_seed;
#[cfg(feature = "std")]
use std::time::{SystemTime, UNIX_EPOCH};
pub type DefaultRand = Xoshiro256StarRand; pub type DefaultRand = Xoshiro256StarRand;
/// Ways to get random around here /// Ways to get random around here
@ -128,6 +130,8 @@ impl Xoshiro256StarRand {
} }
/// Creates a rand instance, pre-seeded with the current time in nanoseconds. /// Creates a rand instance, pre-seeded with the current time in nanoseconds.
/// Needs stdlib timer
#[cfg(feature = "std")]
pub fn preseeded() -> Self { pub fn preseeded() -> Self {
let seed = SystemTime::now() let seed = SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
@ -220,7 +224,7 @@ mod tests {
#[test] #[test]
fn test_rand() { fn test_rand() {
let mut rand = DefaultRand::preseeded(); let mut rand = DefaultRand::new(0);
assert_ne!(rand.next(), rand.next()); assert_ne!(rand.next(), rand.next());
assert!(rand.below(100) < 100); assert!(rand.below(100) < 100);
assert_eq!(rand.below(1), 0); assert_eq!(rand.below(1), 0);
@ -230,7 +234,7 @@ mod tests {
#[test] #[test]
fn test_has_rand() { fn test_has_rand() {
let rand = DefaultRand::preseeded().into(); let rand = DefaultRand::new(0).into();
let has_rand = DefaultHasRand::new(&rand); let has_rand = DefaultHasRand::new(&rand);
assert!(has_rand.rand_below(100) < 100); assert!(has_rand.rand_below(100) < 100);