testcases no longer refcelled
This commit is contained in:
parent
f130e50685
commit
e85582c20b
@ -2,10 +2,10 @@ pub mod testcase;
|
||||
pub use testcase::{Testcase, TestcaseMetadata};
|
||||
|
||||
use alloc::borrow::ToOwned;
|
||||
use alloc::rc::Rc;
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::RefCell;
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -18,10 +18,10 @@ where
|
||||
I: Input,
|
||||
{
|
||||
/// Get the entries vector field
|
||||
fn entries(&self) -> &[Rc<RefCell<Testcase<I>>>];
|
||||
fn entries(&self) -> &[Testcase<I>];
|
||||
|
||||
/// Get the entries vector field (mutable)
|
||||
fn entries_mut(&mut self) -> &mut Vec<Rc<RefCell<Testcase<I>>>>;
|
||||
fn entries_mut(&mut self) -> &mut Vec<Testcase<I>>;
|
||||
}
|
||||
|
||||
/// Corpus with all current testcases
|
||||
@ -36,57 +36,74 @@ where
|
||||
}
|
||||
|
||||
/// Add an entry to the corpus
|
||||
fn add(&mut self, testcase: Rc<RefCell<Testcase<I>>>) {
|
||||
fn add(&mut self, testcase: Testcase<I>) {
|
||||
self.entries_mut().push(testcase);
|
||||
}
|
||||
|
||||
/// Replaces the testcase at the given idx
|
||||
fn replace(&mut self, idx: usize, testcase: Testcase<I>) -> Result<(), AflError> {
|
||||
if self.entries_mut().len() < idx {
|
||||
return Err(AflError::KeyNotFound(format!(
|
||||
"Index {} out of bounds",
|
||||
idx
|
||||
)));
|
||||
}
|
||||
self.entries_mut()[idx] = testcase;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get by id
|
||||
fn get(&self, idx: usize) -> &Testcase<I> {
|
||||
&self.entries()[idx]
|
||||
}
|
||||
|
||||
/// Removes an entry from the corpus, returning it if it was present.
|
||||
fn remove(&mut self, entry: &Testcase<I>) -> Option<Rc<RefCell<Testcase<I>>>> {
|
||||
let mut i: usize = 0;
|
||||
let mut found = false;
|
||||
for x in self.entries() {
|
||||
i = i + 1;
|
||||
if &*x.borrow() as *const _ == entry as *const _ {
|
||||
// TODO check if correct
|
||||
found = true;
|
||||
break;
|
||||
fn remove(&mut self, entry: &Testcase<I>) -> Option<Testcase<I>> {
|
||||
match self.entries().iter().position(|x| ptr::eq(x, entry)) {
|
||||
Some(i) => Some(self.entries_mut().remove(i)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return None;
|
||||
}
|
||||
Some(self.entries_mut().remove(i))
|
||||
}
|
||||
|
||||
/// Gets a random entry
|
||||
fn random_entry(&self, rand: &mut R) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
|
||||
fn random_entry(&self, rand: &mut R) -> Result<(&Testcase<I>, usize), AflError> {
|
||||
if self.count() == 0 {
|
||||
Err(AflError::Empty("No entries in corpus".to_owned()))
|
||||
} else {
|
||||
let len = { self.entries().len() };
|
||||
let id = rand.below(len as u64) as usize;
|
||||
Ok((self.entries()[id].clone(), id))
|
||||
Ok((self.get(id), id))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the testcase for the given idx, with loaded input
|
||||
fn load_testcase(&mut self, idx: usize) -> Result<(), AflError> {
|
||||
let testcase = self.get(idx);
|
||||
// Ensure testcase is loaded
|
||||
match testcase.input() {
|
||||
None => {
|
||||
let new_testcase = match testcase.filename() {
|
||||
Some(filename) => Testcase::load_from_disk(filename)?,
|
||||
None => {
|
||||
return Err(AflError::IllegalState(
|
||||
"Neither input, nor filename specified for testcase".into(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
self.replace(idx, new_testcase)?;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: IntoIter
|
||||
/// Gets the next entry
|
||||
fn next(&mut self, rand: &mut R) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
|
||||
self.random_entry(rand)
|
||||
}
|
||||
}
|
||||
fn next(&mut self, rand: &mut R) -> Result<(&Testcase<I>, usize), AflError>;
|
||||
|
||||
pub trait HasCorpus<C, I, R>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
/// Get the corpus field
|
||||
fn corpus(&self) -> &C;
|
||||
|
||||
/// Get thecorpus field (mutable)
|
||||
fn corpus_mut(&mut self) -> &mut C;
|
||||
/// Returns the testacase we currently use
|
||||
fn current_testcase(&self) -> (&Testcase<I>, usize);
|
||||
}
|
||||
|
||||
pub struct InMemoryCorpus<I, R>
|
||||
@ -94,7 +111,8 @@ where
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
entries: Vec<Rc<RefCell<Testcase<I>>>>,
|
||||
entries: Vec<Testcase<I>>,
|
||||
pos: usize,
|
||||
phantom: PhantomData<R>,
|
||||
}
|
||||
|
||||
@ -103,10 +121,10 @@ where
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
fn entries(&self) -> &[Rc<RefCell<Testcase<I>>>] {
|
||||
fn entries(&self) -> &[Testcase<I>] {
|
||||
&self.entries
|
||||
}
|
||||
fn entries_mut(&mut self) -> &mut Vec<Rc<RefCell<Testcase<I>>>> {
|
||||
fn entries_mut(&mut self) -> &mut Vec<Testcase<I>> {
|
||||
&mut self.entries
|
||||
}
|
||||
}
|
||||
@ -116,7 +134,22 @@ where
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
// Just use the default implementation
|
||||
/// Gets the next entry
|
||||
fn next(&mut self, rand: &mut R) -> Result<(&Testcase<I>, usize), AflError> {
|
||||
if self.count() == 0 {
|
||||
Err(AflError::Empty("No entries in corpus".to_owned()))
|
||||
} else {
|
||||
let len = { self.entries().len() };
|
||||
let id = rand.below(len as u64) as usize;
|
||||
self.pos = id;
|
||||
Ok((self.get(id), id))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the testacase we currently use
|
||||
fn current_testcase(&self) -> (&Testcase<I>, usize) {
|
||||
(self.get(self.pos), self.pos)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, R> InMemoryCorpus<I, R>
|
||||
@ -127,6 +160,7 @@ where
|
||||
pub fn new() -> Self {
|
||||
InMemoryCorpus {
|
||||
entries: vec![],
|
||||
pos: 0,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -138,8 +172,9 @@ where
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
entries: Vec<Rc<RefCell<Testcase<I>>>>,
|
||||
entries: Vec<Testcase<I>>,
|
||||
dir_path: PathBuf,
|
||||
pos: usize,
|
||||
phantom: PhantomData<R>,
|
||||
}
|
||||
|
||||
@ -149,10 +184,10 @@ where
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
fn entries(&self) -> &[Rc<RefCell<Testcase<I>>>] {
|
||||
fn entries(&self) -> &[Testcase<I>] {
|
||||
&self.entries
|
||||
}
|
||||
fn entries_mut(&mut self) -> &mut Vec<Rc<RefCell<Testcase<I>>>> {
|
||||
fn entries_mut(&mut self) -> &mut Vec<Testcase<I>> {
|
||||
&mut self.entries
|
||||
}
|
||||
}
|
||||
@ -164,16 +199,35 @@ where
|
||||
R: Rand,
|
||||
{
|
||||
/// Add an entry and save it to disk
|
||||
fn add(&mut self, entry: Rc<RefCell<Testcase<I>>>) {
|
||||
if *entry.borrow().filename() == None {
|
||||
fn add(&mut self, mut entry: Testcase<I>) {
|
||||
match entry.filename() {
|
||||
None => {
|
||||
// TODO walk entry metadatas to ask for pices of filename (e.g. :havoc in AFL)
|
||||
let filename = self.dir_path.join(format!("id_{}", &self.entries.len()));
|
||||
let filename_str = filename.to_str().expect("Invalid Path");
|
||||
*entry.borrow_mut().filename_mut() = Some(filename_str.into());
|
||||
entry.set_filename(filename_str.into());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.entries.push(entry);
|
||||
}
|
||||
|
||||
fn current_testcase(&self) -> (&Testcase<I>, usize) {
|
||||
(self.get(self.pos), self.pos)
|
||||
}
|
||||
|
||||
/// Gets the next entry
|
||||
fn next(&mut self, rand: &mut R) -> Result<(&Testcase<I>, usize), AflError> {
|
||||
if self.count() == 0 {
|
||||
Err(AflError::Empty("No entries in corpus".to_owned()))
|
||||
} else {
|
||||
let len = { self.entries().len() };
|
||||
let id = rand.below(len as u64) as usize;
|
||||
self.pos = id;
|
||||
Ok((self.get(id), id))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO save and remove files, cache, etc..., ATM use just InMemoryCorpus
|
||||
}
|
||||
|
||||
@ -187,6 +241,7 @@ where
|
||||
OnDiskCorpus {
|
||||
dir_path: dir_path,
|
||||
entries: vec![],
|
||||
pos: 0,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -211,10 +266,10 @@ where
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
fn entries(&self) -> &[Rc<RefCell<Testcase<I>>>] {
|
||||
fn entries(&self) -> &[Testcase<I>] {
|
||||
self.corpus.entries()
|
||||
}
|
||||
fn entries_mut(&mut self) -> &mut Vec<Rc<RefCell<Testcase<I>>>> {
|
||||
fn entries_mut(&mut self) -> &mut Vec<Testcase<I>> {
|
||||
self.corpus.entries_mut()
|
||||
}
|
||||
}
|
||||
@ -230,22 +285,27 @@ where
|
||||
self.corpus.count()
|
||||
}
|
||||
|
||||
fn add(&mut self, entry: Rc<RefCell<Testcase<I>>>) {
|
||||
fn add(&mut self, entry: Testcase<I>) {
|
||||
self.corpus.add(entry);
|
||||
}
|
||||
|
||||
/// 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<Testcase<I>> {
|
||||
self.corpus.remove(entry)
|
||||
}
|
||||
|
||||
/// Gets a random entry
|
||||
fn random_entry(&self, rand: &mut R) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
|
||||
fn random_entry(&self, rand: &mut R) -> Result<(&Testcase<I>, usize), AflError> {
|
||||
self.corpus.random_entry(rand)
|
||||
}
|
||||
|
||||
/// Returns the testacase we currently use
|
||||
fn current_testcase(&self) -> (&Testcase<I>, usize) {
|
||||
(self.get(self.pos - 1), self.pos - 1)
|
||||
}
|
||||
|
||||
/// Gets the next entry
|
||||
fn next(&mut self, _rand: &mut R) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
|
||||
fn next(&mut self, _rand: &mut R) -> Result<(&Testcase<I>, usize), AflError> {
|
||||
self.pos += 1;
|
||||
if self.corpus.count() == 0 {
|
||||
return Err(AflError::Empty("Corpus".to_owned()));
|
||||
@ -255,7 +315,7 @@ where
|
||||
self.pos = 1;
|
||||
self.cycles += 1;
|
||||
}
|
||||
Ok((self.corpus.entries()[self.pos - 1].clone(), self.pos - 1))
|
||||
Ok((&self.corpus.entries()[self.pos - 1], self.pos - 1))
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,7 +401,6 @@ mod tests {
|
||||
use crate::inputs::bytes::BytesInput;
|
||||
use crate::utils::StdRand;
|
||||
|
||||
use alloc::rc::Rc;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
@ -350,14 +409,12 @@ mod tests {
|
||||
let mut q = QueueCorpus::new(OnDiskCorpus::<BytesInput, StdRand>::new(PathBuf::from(
|
||||
"fancy/path",
|
||||
)));
|
||||
let t: Rc<_> =
|
||||
Testcase::with_filename(BytesInput::new(vec![0 as u8; 4]), "fancyfile".into()).into();
|
||||
let t = Testcase::with_filename(BytesInput::new(vec![0 as u8; 4]), "fancyfile".into());
|
||||
q.add(t);
|
||||
let filename = q
|
||||
.next(&mut rand)
|
||||
.unwrap()
|
||||
.0
|
||||
.borrow()
|
||||
.filename()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@ -367,7 +424,6 @@ mod tests {
|
||||
q.next(&mut rand)
|
||||
.unwrap()
|
||||
.0
|
||||
.borrow()
|
||||
.filename()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
|
@ -51,17 +51,10 @@ impl<I> Testcase<I>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
/// Make sure to return a valid input instance loading it from disk if not in memory
|
||||
pub fn load_input(&mut self) -> Result<&I, AflError> {
|
||||
if self.input.is_none() {
|
||||
let input = I::from_file(
|
||||
self.filename
|
||||
.as_ref()
|
||||
.ok_or(AflError::EmptyOptional("filename not specified".into()))?,
|
||||
)?;
|
||||
self.input = Some(input);
|
||||
}
|
||||
Ok(self.input.as_ref().unwrap())
|
||||
/// Returns this testcase with a loaded input
|
||||
pub fn load_from_disk(filename: &str) -> Result<Self, AflError> {
|
||||
let input = I::from_file(filename)?;
|
||||
Ok(Testcase::new(input))
|
||||
}
|
||||
|
||||
/// Get the input, if any
|
||||
|
@ -8,7 +8,7 @@ use core::fmt::Debug;
|
||||
use core::marker::PhantomData;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use crate::corpus::{Corpus, HasCorpus, Testcase};
|
||||
use crate::corpus::{Corpus, Testcase};
|
||||
use crate::events::{EventManager, LoadInitialEvent, UpdateStatsEvent};
|
||||
use crate::executors::Executor;
|
||||
use crate::feedbacks::Feedback;
|
||||
@ -26,7 +26,7 @@ pub trait StateMetadata: Debug {
|
||||
fn name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
pub trait State<C, E, I, R>: HasCorpus<C, I, R>
|
||||
pub trait State<C, E, I, R>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I>,
|
||||
@ -111,10 +111,7 @@ where
|
||||
fn executor_mut(&mut self) -> &mut E;
|
||||
|
||||
/// Runs the input and triggers observers and feedback
|
||||
fn evaluate_input(
|
||||
&mut self,
|
||||
input: I,
|
||||
) -> Result<(bool, Option<Rc<RefCell<Testcase<I>>>>), AflError> {
|
||||
fn evaluate_input(&mut self, input: &I) -> Result<u32, AflError> {
|
||||
self.reset_observers()?;
|
||||
self.executor_mut().run_target(&input)?;
|
||||
self.set_executions(self.executions() + 1);
|
||||
@ -124,29 +121,37 @@ where
|
||||
for feedback in self.feedbacks_mut() {
|
||||
fitness += feedback.is_interesting(&input)?;
|
||||
}
|
||||
Ok(fitness)
|
||||
}
|
||||
|
||||
/// Resets all current feedbacks
|
||||
fn discard_input(&mut self, input: &I) -> Result<(), AflError> {
|
||||
// TODO: This could probably be automatic in the feedback somehow?
|
||||
for feedback in self.feedbacks_mut() {
|
||||
feedback.discard_metadata(input)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a new testcase, appending the metadata from each feedback
|
||||
fn input_to_testcase(&mut self, input: I, fitness: u32) -> Result<Testcase<I>, AflError> {
|
||||
let mut testcase = Testcase::new(input);
|
||||
testcase.set_fitness(fitness);
|
||||
for feedback in self.feedbacks_mut() {
|
||||
feedback.append_metadata(&mut testcase)?;
|
||||
}
|
||||
|
||||
Ok(testcase)
|
||||
}
|
||||
|
||||
/// Adds this input to the corpus, if it's intersting
|
||||
fn add_input(&mut self, corpus: &mut C, input: I) -> Result<(), AflError> {
|
||||
let fitness = self.evaluate_input(&input)?;
|
||||
if fitness > 0 {
|
||||
let testcase: Rc<RefCell<_>> = Testcase::new(input).into();
|
||||
for feedback in self.feedbacks_mut() {
|
||||
feedback.append_metadata(testcase.clone())?;
|
||||
}
|
||||
testcase.borrow_mut().set_fitness(fitness);
|
||||
self.corpus_mut().add(testcase.clone());
|
||||
Ok((true, Some(testcase)))
|
||||
let testcase = self.input_to_testcase(input, fitness)?;
|
||||
corpus.add(testcase);
|
||||
} else {
|
||||
for feedback in self.feedbacks_mut() {
|
||||
feedback.discard_metadata()?;
|
||||
}
|
||||
Ok((false, None))
|
||||
}
|
||||
}
|
||||
|
||||
fn load_initial_input(&mut self, input: I) -> Result<(), AflError> {
|
||||
// Inefficent clone, but who cares this is done once at init
|
||||
let (_, testcase) = self.evaluate_input(input.clone())?;
|
||||
if testcase.is_none() {
|
||||
let testcase = Testcase::new(input).into();
|
||||
self.corpus_mut().add(testcase);
|
||||
self.discard_input(&input)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -155,6 +160,7 @@ where
|
||||
pub fn generate_initial_inputs<S, G, C, E, I, R, EM>(
|
||||
rand: &mut R,
|
||||
state: &mut S,
|
||||
corpus: &mut C,
|
||||
generator: &mut G,
|
||||
events: &mut EM,
|
||||
num: usize,
|
||||
@ -170,7 +176,7 @@ where
|
||||
{
|
||||
for _ in 0..num {
|
||||
let input = generator.generate(rand)?;
|
||||
state.load_initial_input(input)?;
|
||||
state.add_input(corpus, input)?;
|
||||
fire_event!(events, LoadInitialEvent)?;
|
||||
}
|
||||
events.process(state)?;
|
||||
@ -190,26 +196,8 @@ where
|
||||
// additional_corpuses: HashMap<&'static str, Box<dyn Corpus>>,
|
||||
observers: Vec<Rc<RefCell<dyn Observer>>>,
|
||||
feedbacks: Vec<Box<dyn Feedback<I>>>,
|
||||
corpus: C,
|
||||
executor: E,
|
||||
phantom: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<C, E, I, R> HasCorpus<C, I, R> for StdState<C, E, I, R>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
fn corpus(&self) -> &C {
|
||||
&self.corpus
|
||||
}
|
||||
|
||||
/// Get thecorpus field (mutable)
|
||||
fn corpus_mut(&mut self) -> &mut C {
|
||||
&mut self.corpus
|
||||
}
|
||||
phantom: PhantomData<(C, R)>,
|
||||
}
|
||||
|
||||
impl<C, E, I, R> State<C, E, I, R> for StdState<C, E, I, R>
|
||||
@ -274,14 +262,13 @@ where
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
pub fn new(corpus: C, executor: E) -> Self {
|
||||
pub fn new(executor: E) -> Self {
|
||||
StdState {
|
||||
executions: 0,
|
||||
start_time: current_milliseconds(),
|
||||
metadatas: HashMap::default(),
|
||||
observers: vec![],
|
||||
feedbacks: vec![],
|
||||
corpus: corpus,
|
||||
executor: executor,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
@ -309,20 +296,38 @@ where
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
state: &mut S,
|
||||
corpus: &mut C,
|
||||
events: &mut EM,
|
||||
) -> Result<usize, AflError> {
|
||||
let (testcase, idx) = state.corpus_mut().next(rand)?;
|
||||
for stage in self.stages_mut() {
|
||||
stage.perform(rand, state, events, testcase.clone())?;
|
||||
let (testcase, idx) = corpus.next(rand)?;
|
||||
match testcase.input() {
|
||||
None => {
|
||||
// Load from disk.
|
||||
corpus.load_testcase(idx)?;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
|
||||
let input = corpus.get(idx).input().as_ref().unwrap();
|
||||
|
||||
for stage in self.stages_mut() {
|
||||
stage.perform(rand, state, corpus, events, &input)?;
|
||||
}
|
||||
|
||||
events.process(state)?;
|
||||
Ok(idx)
|
||||
}
|
||||
|
||||
fn fuzz_loop(&mut self, rand: &mut R, state: &mut S, events: &mut EM) -> Result<(), AflError> {
|
||||
fn fuzz_loop(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
state: &mut S,
|
||||
corpus: &mut C,
|
||||
events: &mut EM,
|
||||
) -> Result<(), AflError> {
|
||||
let mut last = current_milliseconds();
|
||||
loop {
|
||||
self.fuzz_one(rand, state, events)?;
|
||||
self.fuzz_one(rand, state, corpus, events)?;
|
||||
let cur = current_milliseconds();
|
||||
if cur - last > 60 * 100 {
|
||||
last = cur;
|
||||
@ -414,7 +419,7 @@ mod tests {
|
||||
corpus.add(testcase);
|
||||
|
||||
let executor = InMemoryExecutor::<BytesInput>::new(harness);
|
||||
let mut state = StdState::new(corpus, executor);
|
||||
let mut state = StdState::new(executor);
|
||||
|
||||
let mut events_manager = LoggerEventManager::new(stderr());
|
||||
|
||||
@ -428,7 +433,7 @@ mod tests {
|
||||
|
||||
for i in 0..1000 {
|
||||
engine
|
||||
.fuzz_one(&mut rand, &mut state, &mut events_manager)
|
||||
.fuzz_one(&mut rand, &mut state, &mut corpus, &mut events_manager)
|
||||
.expect(&format!("Error in iter {}", i));
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,6 @@ pub mod shmem_translated;
|
||||
#[cfg(feature = "std")]
|
||||
pub use crate::events::llmp::LLMP;
|
||||
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
//use core::any::TypeId;
|
||||
#[cfg(feature = "std")]
|
||||
use std::io::Write;
|
||||
@ -87,7 +85,7 @@ pub struct NewTestcaseEvent<I>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
testcase: Rc<RefCell<Testcase<I>>>,
|
||||
testcase: Testcase<I>,
|
||||
}
|
||||
|
||||
impl<I> Event for NewTestcaseEvent<I>
|
||||
@ -103,11 +101,11 @@ impl<I> NewTestcaseEvent<I>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
pub fn new(testcase: Rc<RefCell<Testcase<I>>>) -> Self {
|
||||
pub fn new(testcase: Testcase<I>) -> Self {
|
||||
NewTestcaseEvent { testcase: testcase }
|
||||
}
|
||||
|
||||
pub fn testcase(&self) -> &Rc<RefCell<Testcase<I>>> {
|
||||
pub fn testcase(&self) -> &Testcase<I> {
|
||||
&self.testcase
|
||||
}
|
||||
}
|
||||
@ -170,10 +168,10 @@ where
|
||||
for event in &self.events {
|
||||
writeln!(
|
||||
&mut self.writer,
|
||||
"#{}\t[{}] corp: {} exec/s: {}",
|
||||
"#{}\t[{}] exec/s: {}",
|
||||
state.executions(),
|
||||
event,
|
||||
state.corpus().entries().len(),
|
||||
//TODO: Count corpus.entries().len(),
|
||||
state.executions_over_seconds()
|
||||
)?;
|
||||
}
|
||||
|
@ -18,12 +18,12 @@ where
|
||||
fn is_interesting(&mut self, input: &I) -> Result<u32, AflError>;
|
||||
|
||||
/// Append to the testcase the generated metadata in case of a new corpus item
|
||||
fn append_metadata(&mut self, _testcase: Rc<RefCell<Testcase<I>>>) -> Result<(), AflError> {
|
||||
fn append_metadata(&mut self, _testcase: &mut Testcase<I>) -> Result<(), AflError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Discard the stored metadata in case that the testcase is not added to the corpus
|
||||
fn discard_metadata(&mut self) -> Result<(), AflError> {
|
||||
fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -230,16 +230,16 @@ where
|
||||
Ok(interesting)
|
||||
}
|
||||
|
||||
fn append_metadata(&mut self, testcase: Rc<RefCell<Testcase<I>>>) -> Result<(), AflError> {
|
||||
fn append_metadata(&mut self, testcase: &mut Testcase<I>) -> Result<(), AflError> {
|
||||
let meta = Box::new(MapNoveltiesMetadata::new(core::mem::take(
|
||||
&mut self.novelties,
|
||||
)));
|
||||
testcase.borrow_mut().add_metadata(meta);
|
||||
testcase.add_metadata(meta);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Discard the stored metadata in case that the testcase is not added to the corpus
|
||||
fn discard_metadata(&mut self) -> Result<(), AflError> {
|
||||
fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> {
|
||||
self.novelties.clear();
|
||||
Ok(())
|
||||
}
|
||||
|
@ -4,11 +4,7 @@ pub use scheduled::HavocBytesMutator;
|
||||
pub use scheduled::ScheduledMutator;
|
||||
pub use scheduled::StdScheduledMutator;
|
||||
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
|
||||
use crate::corpus::Corpus;
|
||||
use crate::corpus::Testcase;
|
||||
use crate::inputs::Input;
|
||||
use crate::utils::Rand;
|
||||
use crate::AflError;
|
||||
@ -23,7 +19,7 @@ where
|
||||
fn mutate(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
corpus: &mut C,
|
||||
corpus: &C,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<(), AflError>;
|
||||
@ -31,8 +27,8 @@ where
|
||||
/// Post-process given the outcome of the execution
|
||||
fn post_exec(
|
||||
&mut self,
|
||||
_is_interesting: bool,
|
||||
_new_testcase: Option<Rc<RefCell<Testcase<I>>>>,
|
||||
_is_interesting: u32,
|
||||
_input: &I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<(), AflError> {
|
||||
Ok(())
|
||||
|
@ -15,7 +15,7 @@ pub enum MutationResult {
|
||||
// TODO maybe the mutator arg is not needed
|
||||
/// The generic function type that identifies mutations
|
||||
type MutationFunction<M, C, I, R> =
|
||||
fn(&mut M, &mut R, &mut C, &mut I) -> Result<MutationResult, AflError>;
|
||||
fn(&mut M, &mut R, &C, &mut I) -> Result<MutationResult, AflError>;
|
||||
|
||||
pub trait ComposedByMutations<C, I, R>
|
||||
where
|
||||
@ -66,7 +66,7 @@ where
|
||||
fn scheduled_mutate(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
corpus: &mut C,
|
||||
corpus: &C,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<(), AflError> {
|
||||
@ -96,7 +96,7 @@ where
|
||||
fn mutate(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
corpus: &mut C,
|
||||
corpus: &C,
|
||||
input: &mut I,
|
||||
_stage_idx: i32,
|
||||
) -> Result<(), AflError> {
|
||||
@ -155,7 +155,7 @@ where
|
||||
pub fn mutation_bitflip<M, C, I, R>(
|
||||
_mutator: &mut M,
|
||||
rand: &mut R,
|
||||
_corpus: &mut C,
|
||||
_corpus: &C,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, AflError>
|
||||
where
|
||||
@ -179,7 +179,7 @@ where
|
||||
pub fn mutation_byteflip<M, C, I, R>(
|
||||
_mutator: &mut M,
|
||||
rand: &mut R,
|
||||
_corpus: &mut C,
|
||||
_corpus: &C,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, AflError>
|
||||
where
|
||||
@ -203,7 +203,7 @@ where
|
||||
pub fn mutation_byteinc<M, C, I, R>(
|
||||
_mutator: &mut M,
|
||||
rand: &mut R,
|
||||
_corpus: &mut C,
|
||||
_corpus: &C,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, AflError>
|
||||
where
|
||||
@ -227,7 +227,7 @@ where
|
||||
pub fn mutation_bytedec<M, C, I, R>(
|
||||
_mutator: &mut M,
|
||||
rand: &mut R,
|
||||
_corpus: &mut C,
|
||||
_corpus: &C,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, AflError>
|
||||
where
|
||||
@ -251,7 +251,7 @@ where
|
||||
pub fn mutation_byteneg<M, C, I, R>(
|
||||
_mutator: &mut M,
|
||||
rand: &mut R,
|
||||
_corpus: &mut C,
|
||||
_corpus: &C,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, AflError>
|
||||
where
|
||||
@ -292,7 +292,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
|
||||
pub fn mutation_splice<M, C, I, R>(
|
||||
_mutator: &mut M,
|
||||
rand: &mut R,
|
||||
corpus: &mut C,
|
||||
corpus: &C,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, AflError>
|
||||
where
|
||||
@ -301,17 +301,15 @@ where
|
||||
I: Input + HasBytesVec,
|
||||
R: Rand,
|
||||
{
|
||||
// We don't want to use the testcase we're already using for splicing
|
||||
let (other_rr, _) = corpus.random_entry(rand)?.clone();
|
||||
let mut other_testcase = match other_rr.try_borrow_mut() {
|
||||
Ok(x) => x,
|
||||
Err(_) => {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
};
|
||||
|
||||
let other = other_testcase.load_input()?;
|
||||
// TODO: Don't reuse the current testcase!
|
||||
// (We don't want to use the testcase we're already using for splicing)
|
||||
let (other_testcase, _) = corpus.random_entry(rand)?;
|
||||
// TODO: let other = other_testcase.load_input()?;
|
||||
// println!("Input: {:?}, other input: {:?}", input.bytes(), other.bytes());
|
||||
let other = match other_testcase.input() {
|
||||
Some(i) => i,
|
||||
None => return Ok(MutationResult::Skipped), // TODO!!
|
||||
};
|
||||
|
||||
let mut counter = 0;
|
||||
let (first_diff, last_diff) = loop {
|
||||
@ -362,7 +360,7 @@ where
|
||||
fn mutate(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
corpus: &mut C,
|
||||
corpus: &C,
|
||||
input: &mut I,
|
||||
stage_idx: i32,
|
||||
) -> Result<(), AflError> {
|
||||
@ -380,7 +378,7 @@ where
|
||||
/// Create a new HavocBytesMutator instance given a ScheduledMutator to wrap
|
||||
pub fn new(mut scheduled: SM) -> Self {
|
||||
scheduled.add_mutation(mutation_bitflip);
|
||||
//scheduled.add_mutation(mutation_splice);
|
||||
scheduled.add_mutation(mutation_splice);
|
||||
HavocBytesMutator {
|
||||
scheduled: scheduled,
|
||||
phantom: PhantomData,
|
||||
@ -432,13 +430,15 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::inputs::BytesInput;
|
||||
use crate::mutators::scheduled::{mutation_splice, StdScheduledMutator};
|
||||
use crate::mutators::scheduled::StdScheduledMutator;
|
||||
use crate::utils::{Rand, XKCDRand};
|
||||
use crate::{
|
||||
corpus::{Corpus, InMemoryCorpus, Testcase},
|
||||
inputs::HasBytesVec,
|
||||
};
|
||||
|
||||
use super::mutation_splice;
|
||||
|
||||
#[test]
|
||||
fn test_mut_splice() {
|
||||
// With the current impl, seed of 1 will result in a split at pos 2.
|
||||
@ -447,11 +447,10 @@ mod tests {
|
||||
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());
|
||||
|
||||
let (testcase_rr, _) = corpus
|
||||
let (testcase, _) = corpus
|
||||
.next(&mut rand)
|
||||
.expect("Corpus did not contain entries");
|
||||
let mut testcase = testcase_rr.borrow_mut();
|
||||
let mut input = testcase.load_input().expect("No input in testcase").clone();
|
||||
let mut input = testcase.input().as_ref().unwrap().clone();
|
||||
|
||||
rand.set_seed(5);
|
||||
let mut mutator = StdScheduledMutator::new();
|
||||
|
@ -1,10 +1,6 @@
|
||||
pub mod mutational;
|
||||
pub use mutational::StdMutationalStage;
|
||||
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
|
||||
use crate::corpus::testcase::Testcase;
|
||||
use crate::corpus::Corpus;
|
||||
use crate::engines::State;
|
||||
use crate::events::EventManager;
|
||||
@ -27,7 +23,8 @@ where
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
state: &mut S,
|
||||
corpus: &C,
|
||||
events: &mut EM,
|
||||
testcase: Rc<RefCell<Testcase<I>>>,
|
||||
input: &I,
|
||||
) -> Result<(), AflError>;
|
||||
}
|
||||
|
@ -1,17 +1,15 @@
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::corpus::testcase::Testcase;
|
||||
use crate::engines::State;
|
||||
use crate::events::{EventManager, NewTestcaseEvent};
|
||||
use crate::events::EventManager;
|
||||
use crate::executors::Executor;
|
||||
use crate::inputs::Input;
|
||||
use crate::mutators::Mutator;
|
||||
use crate::stages::Corpus;
|
||||
use crate::stages::Stage;
|
||||
use crate::utils::Rand;
|
||||
use crate::{fire_event, AflError};
|
||||
use crate::AflError;
|
||||
use crate::{events::NewTestcaseEvent, fire_event};
|
||||
|
||||
// TODO multi mutators stage
|
||||
|
||||
@ -42,22 +40,27 @@ where
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
state: &mut S,
|
||||
corpus: &C,
|
||||
events: &mut EM,
|
||||
testcase: Rc<RefCell<Testcase<I>>>,
|
||||
input: &I,
|
||||
) -> Result<(), AflError> {
|
||||
let num = self.iterations(rand);
|
||||
for i in 0..num {
|
||||
let mut input = testcase.borrow_mut().load_input()?.clone();
|
||||
let mut input_mut = input.clone();
|
||||
self.mutator_mut()
|
||||
.mutate(rand, state.corpus_mut(), &mut input, i as i32)?;
|
||||
.mutate(rand, corpus, &mut input_mut, i as i32)?;
|
||||
|
||||
let (interesting, new_testcase) = state.evaluate_input(input)?;
|
||||
let interesting = state.evaluate_input(&input_mut)?;
|
||||
|
||||
self.mutator_mut()
|
||||
.post_exec(interesting, new_testcase.clone(), i as i32)?;
|
||||
.post_exec(interesting, &input_mut, i as i32)?;
|
||||
|
||||
if !new_testcase.is_none() {
|
||||
fire_event!(events, NewTestcaseEvent<I>, new_testcase.unwrap())?;
|
||||
if interesting > 0 {
|
||||
let new_testcase = state.input_to_testcase(input_mut, interesting)?;
|
||||
fire_event!(events, NewTestcaseEvent<I>, new_testcase)?;
|
||||
//state.corpus_mut().add(new_testcase); // TODO: Probably no longer needed, once events work
|
||||
} else {
|
||||
state.discard_input(&input_mut)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@ -115,10 +118,11 @@ where
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
state: &mut S,
|
||||
corpus: &C,
|
||||
events: &mut EM,
|
||||
testcase: Rc<RefCell<Testcase<I>>>,
|
||||
input: &I,
|
||||
) -> Result<(), AflError> {
|
||||
self.perform_mutational(rand, state, events, testcase)
|
||||
self.perform_mutational(rand, state, corpus, events, input)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user