testcases no longer refcelled

This commit is contained in:
Dominik Maier 2020-11-24 19:35:02 +01:00
parent f130e50685
commit e85582c20b
9 changed files with 238 additions and 190 deletions

View File

@ -2,10 +2,10 @@ pub mod testcase;
pub use testcase::{Testcase, TestcaseMetadata}; pub use testcase::{Testcase, TestcaseMetadata};
use alloc::borrow::ToOwned; use alloc::borrow::ToOwned;
use alloc::rc::Rc;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::cell::RefCell;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::ptr;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::path::PathBuf; use std::path::PathBuf;
@ -18,10 +18,10 @@ where
I: Input, I: Input,
{ {
/// Get the entries vector field /// Get the entries vector field
fn entries(&self) -> &[Rc<RefCell<Testcase<I>>>]; fn entries(&self) -> &[Testcase<I>];
/// Get the entries vector field (mutable) /// 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 /// Corpus with all current testcases
@ -36,57 +36,74 @@ where
} }
/// Add an entry to the corpus /// 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); 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. /// 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>> {
let mut i: usize = 0; match self.entries().iter().position(|x| ptr::eq(x, entry)) {
let mut found = false; Some(i) => Some(self.entries_mut().remove(i)),
for x in self.entries() { None => None,
i = i + 1;
if &*x.borrow() as *const _ == entry as *const _ {
// TODO check if correct
found = true;
break;
} }
} }
if !found {
return None;
}
Some(self.entries_mut().remove(i))
}
/// Gets a random 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> {
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 = rand.below(len as u64) as usize; 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 // TODO: IntoIter
/// Gets the next entry /// 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.random_entry(rand)
}
}
pub trait HasCorpus<C, I, R> /// Returns the testacase we currently use
where fn current_testcase(&self) -> (&Testcase<I>, usize);
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;
} }
pub struct InMemoryCorpus<I, R> pub struct InMemoryCorpus<I, R>
@ -94,7 +111,8 @@ where
I: Input, I: Input,
R: Rand, R: Rand,
{ {
entries: Vec<Rc<RefCell<Testcase<I>>>>, entries: Vec<Testcase<I>>,
pos: usize,
phantom: PhantomData<R>, phantom: PhantomData<R>,
} }
@ -103,10 +121,10 @@ where
I: Input, I: Input,
R: Rand, R: Rand,
{ {
fn entries(&self) -> &[Rc<RefCell<Testcase<I>>>] { fn entries(&self) -> &[Testcase<I>] {
&self.entries &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 &mut self.entries
} }
} }
@ -116,7 +134,22 @@ where
I: Input, I: Input,
R: Rand, 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> impl<I, R> InMemoryCorpus<I, R>
@ -127,6 +160,7 @@ where
pub fn new() -> Self { pub fn new() -> Self {
InMemoryCorpus { InMemoryCorpus {
entries: vec![], entries: vec![],
pos: 0,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -138,8 +172,9 @@ where
I: Input, I: Input,
R: Rand, R: Rand,
{ {
entries: Vec<Rc<RefCell<Testcase<I>>>>, entries: Vec<Testcase<I>>,
dir_path: PathBuf, dir_path: PathBuf,
pos: usize,
phantom: PhantomData<R>, phantom: PhantomData<R>,
} }
@ -149,10 +184,10 @@ where
I: Input, I: Input,
R: Rand, R: Rand,
{ {
fn entries(&self) -> &[Rc<RefCell<Testcase<I>>>] { fn entries(&self) -> &[Testcase<I>] {
&self.entries &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 &mut self.entries
} }
} }
@ -164,16 +199,35 @@ where
R: Rand, R: Rand,
{ {
/// Add an entry and save it to disk /// Add an entry and save it to disk
fn add(&mut self, entry: Rc<RefCell<Testcase<I>>>) { fn add(&mut self, mut entry: Testcase<I>) {
if *entry.borrow().filename() == None { match entry.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 = self.dir_path.join(format!("id_{}", &self.entries.len())); let filename = self.dir_path.join(format!("id_{}", &self.entries.len()));
let filename_str = filename.to_str().expect("Invalid Path"); 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); 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 // TODO save and remove files, cache, etc..., ATM use just InMemoryCorpus
} }
@ -187,6 +241,7 @@ where
OnDiskCorpus { OnDiskCorpus {
dir_path: dir_path, dir_path: dir_path,
entries: vec![], entries: vec![],
pos: 0,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -211,10 +266,10 @@ where
I: Input, I: Input,
R: Rand, R: Rand,
{ {
fn entries(&self) -> &[Rc<RefCell<Testcase<I>>>] { fn entries(&self) -> &[Testcase<I>] {
self.corpus.entries() 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() self.corpus.entries_mut()
} }
} }
@ -230,22 +285,27 @@ where
self.corpus.count() self.corpus.count()
} }
fn add(&mut self, entry: Rc<RefCell<Testcase<I>>>) { fn add(&mut self, entry: Testcase<I>) {
self.corpus.add(entry); self.corpus.add(entry);
} }
/// 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<Testcase<I>> {
self.corpus.remove(entry) self.corpus.remove(entry)
} }
/// Gets a random 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) 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 /// 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; 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()));
@ -255,7 +315,7 @@ where
self.pos = 1; self.pos = 1;
self.cycles += 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::inputs::bytes::BytesInput;
use crate::utils::StdRand; use crate::utils::StdRand;
use alloc::rc::Rc;
use std::path::PathBuf; use std::path::PathBuf;
#[test] #[test]
@ -350,14 +409,12 @@ mod tests {
let mut q = QueueCorpus::new(OnDiskCorpus::<BytesInput, StdRand>::new(PathBuf::from( let mut q = QueueCorpus::new(OnDiskCorpus::<BytesInput, StdRand>::new(PathBuf::from(
"fancy/path", "fancy/path",
))); )));
let t: Rc<_> = let t = Testcase::with_filename(BytesInput::new(vec![0 as u8; 4]), "fancyfile".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(&mut rand) .next(&mut rand)
.unwrap() .unwrap()
.0 .0
.borrow()
.filename() .filename()
.as_ref() .as_ref()
.unwrap() .unwrap()
@ -367,7 +424,6 @@ mod tests {
q.next(&mut rand) q.next(&mut rand)
.unwrap() .unwrap()
.0 .0
.borrow()
.filename() .filename()
.as_ref() .as_ref()
.unwrap() .unwrap()

View File

@ -51,17 +51,10 @@ impl<I> Testcase<I>
where where
I: Input, I: Input,
{ {
/// Make sure to return a valid input instance loading it from disk if not in memory /// Returns this testcase with a loaded input
pub fn load_input(&mut self) -> Result<&I, AflError> { pub fn load_from_disk(filename: &str) -> Result<Self, AflError> {
if self.input.is_none() { let input = I::from_file(filename)?;
let input = I::from_file( Ok(Testcase::new(input))
self.filename
.as_ref()
.ok_or(AflError::EmptyOptional("filename not specified".into()))?,
)?;
self.input = Some(input);
}
Ok(self.input.as_ref().unwrap())
} }
/// Get the input, if any /// Get the input, if any

View File

@ -8,7 +8,7 @@ use core::fmt::Debug;
use core::marker::PhantomData; use core::marker::PhantomData;
use hashbrown::HashMap; use hashbrown::HashMap;
use crate::corpus::{Corpus, HasCorpus, Testcase}; use crate::corpus::{Corpus, Testcase};
use crate::events::{EventManager, LoadInitialEvent, UpdateStatsEvent}; use crate::events::{EventManager, LoadInitialEvent, UpdateStatsEvent};
use crate::executors::Executor; use crate::executors::Executor;
use crate::feedbacks::Feedback; use crate::feedbacks::Feedback;
@ -26,7 +26,7 @@ pub trait StateMetadata: Debug {
fn name(&self) -> &'static str; fn name(&self) -> &'static str;
} }
pub trait State<C, E, I, R>: HasCorpus<C, I, R> pub trait State<C, E, I, R>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
E: Executor<I>, E: Executor<I>,
@ -111,10 +111,7 @@ where
fn executor_mut(&mut self) -> &mut E; fn executor_mut(&mut self) -> &mut E;
/// Runs the input and triggers observers and feedback /// Runs the input and triggers observers and feedback
fn evaluate_input( fn evaluate_input(&mut self, input: &I) -> Result<u32, AflError> {
&mut self,
input: I,
) -> Result<(bool, Option<Rc<RefCell<Testcase<I>>>>), AflError> {
self.reset_observers()?; self.reset_observers()?;
self.executor_mut().run_target(&input)?; self.executor_mut().run_target(&input)?;
self.set_executions(self.executions() + 1); self.set_executions(self.executions() + 1);
@ -124,29 +121,37 @@ where
for feedback in self.feedbacks_mut() { for feedback in self.feedbacks_mut() {
fitness += feedback.is_interesting(&input)?; 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 { if fitness > 0 {
let testcase: Rc<RefCell<_>> = Testcase::new(input).into(); let testcase = self.input_to_testcase(input, fitness)?;
for feedback in self.feedbacks_mut() { corpus.add(testcase);
feedback.append_metadata(testcase.clone())?;
}
testcase.borrow_mut().set_fitness(fitness);
self.corpus_mut().add(testcase.clone());
Ok((true, Some(testcase)))
} else { } else {
for feedback in self.feedbacks_mut() { self.discard_input(&input)?;
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);
} }
Ok(()) Ok(())
} }
@ -155,6 +160,7 @@ where
pub fn generate_initial_inputs<S, G, C, E, I, R, EM>( pub fn generate_initial_inputs<S, G, C, E, I, R, EM>(
rand: &mut R, rand: &mut R,
state: &mut S, state: &mut S,
corpus: &mut C,
generator: &mut G, generator: &mut G,
events: &mut EM, events: &mut EM,
num: usize, num: usize,
@ -170,7 +176,7 @@ where
{ {
for _ in 0..num { for _ in 0..num {
let input = generator.generate(rand)?; let input = generator.generate(rand)?;
state.load_initial_input(input)?; state.add_input(corpus, input)?;
fire_event!(events, LoadInitialEvent)?; fire_event!(events, LoadInitialEvent)?;
} }
events.process(state)?; events.process(state)?;
@ -190,26 +196,8 @@ where
// additional_corpuses: HashMap<&'static str, Box<dyn Corpus>>, // additional_corpuses: HashMap<&'static str, Box<dyn Corpus>>,
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,
executor: E, executor: E,
phantom: PhantomData<R>, phantom: PhantomData<(C, 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
}
} }
impl<C, E, I, R> State<C, E, I, R> for StdState<C, E, I, R> impl<C, E, I, R> State<C, E, I, R> for StdState<C, E, I, R>
@ -274,14 +262,13 @@ where
I: Input, I: Input,
R: Rand, R: Rand,
{ {
pub fn new(corpus: C, executor: E) -> Self { pub fn new(executor: E) -> Self {
StdState { StdState {
executions: 0, executions: 0,
start_time: current_milliseconds(), start_time: current_milliseconds(),
metadatas: HashMap::default(), metadatas: HashMap::default(),
observers: vec![], observers: vec![],
feedbacks: vec![], feedbacks: vec![],
corpus: corpus,
executor: executor, executor: executor,
phantom: PhantomData, phantom: PhantomData,
} }
@ -309,20 +296,38 @@ where
&mut self, &mut self,
rand: &mut R, rand: &mut R,
state: &mut S, state: &mut S,
corpus: &mut C,
events: &mut EM, events: &mut EM,
) -> Result<usize, AflError> { ) -> Result<usize, AflError> {
let (testcase, idx) = state.corpus_mut().next(rand)?; let (testcase, idx) = corpus.next(rand)?;
for stage in self.stages_mut() { match testcase.input() {
stage.perform(rand, state, events, testcase.clone())?; 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)?; events.process(state)?;
Ok(idx) 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(); let mut last = current_milliseconds();
loop { loop {
self.fuzz_one(rand, state, events)?; self.fuzz_one(rand, state, corpus, events)?;
let cur = current_milliseconds(); let cur = current_milliseconds();
if cur - last > 60 * 100 { if cur - last > 60 * 100 {
last = cur; last = cur;
@ -414,7 +419,7 @@ mod tests {
corpus.add(testcase); corpus.add(testcase);
let executor = InMemoryExecutor::<BytesInput>::new(harness); 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()); let mut events_manager = LoggerEventManager::new(stderr());
@ -428,7 +433,7 @@ mod tests {
for i in 0..1000 { for i in 0..1000 {
engine 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)); .expect(&format!("Error in iter {}", i));
} }
} }

View File

@ -8,8 +8,6 @@ pub mod shmem_translated;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use crate::events::llmp::LLMP; pub use crate::events::llmp::LLMP;
use alloc::rc::Rc;
use core::cell::RefCell;
//use core::any::TypeId; //use core::any::TypeId;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::io::Write; use std::io::Write;
@ -87,7 +85,7 @@ pub struct NewTestcaseEvent<I>
where where
I: Input, I: Input,
{ {
testcase: Rc<RefCell<Testcase<I>>>, testcase: Testcase<I>,
} }
impl<I> Event for NewTestcaseEvent<I> impl<I> Event for NewTestcaseEvent<I>
@ -103,11 +101,11 @@ impl<I> NewTestcaseEvent<I>
where where
I: Input, I: Input,
{ {
pub fn new(testcase: Rc<RefCell<Testcase<I>>>) -> Self { pub fn new(testcase: Testcase<I>) -> Self {
NewTestcaseEvent { testcase: testcase } NewTestcaseEvent { testcase: testcase }
} }
pub fn testcase(&self) -> &Rc<RefCell<Testcase<I>>> { pub fn testcase(&self) -> &Testcase<I> {
&self.testcase &self.testcase
} }
} }
@ -170,10 +168,10 @@ where
for event in &self.events { for event in &self.events {
writeln!( writeln!(
&mut self.writer, &mut self.writer,
"#{}\t[{}] corp: {} exec/s: {}", "#{}\t[{}] exec/s: {}",
state.executions(), state.executions(),
event, event,
state.corpus().entries().len(), //TODO: Count corpus.entries().len(),
state.executions_over_seconds() state.executions_over_seconds()
)?; )?;
} }

View File

@ -18,12 +18,12 @@ where
fn is_interesting(&mut self, input: &I) -> Result<u32, AflError>; fn is_interesting(&mut self, input: &I) -> Result<u32, AflError>;
/// Append to the testcase the generated metadata in case of a new corpus item /// 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(()) Ok(())
} }
/// Discard the stored metadata in case that the testcase is not added to the corpus /// 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(()) Ok(())
} }
} }
@ -230,16 +230,16 @@ where
Ok(interesting) 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( let meta = Box::new(MapNoveltiesMetadata::new(core::mem::take(
&mut self.novelties, &mut self.novelties,
))); )));
testcase.borrow_mut().add_metadata(meta); testcase.add_metadata(meta);
Ok(()) Ok(())
} }
/// Discard the stored metadata in case that the testcase is not added to the corpus /// 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(); self.novelties.clear();
Ok(()) Ok(())
} }

View File

@ -4,11 +4,7 @@ pub use scheduled::HavocBytesMutator;
pub use scheduled::ScheduledMutator; pub use scheduled::ScheduledMutator;
pub use scheduled::StdScheduledMutator; pub use scheduled::StdScheduledMutator;
use alloc::rc::Rc;
use core::cell::RefCell;
use crate::corpus::Corpus; use crate::corpus::Corpus;
use crate::corpus::Testcase;
use crate::inputs::Input; use crate::inputs::Input;
use crate::utils::Rand; use crate::utils::Rand;
use crate::AflError; use crate::AflError;
@ -23,7 +19,7 @@ where
fn mutate( fn mutate(
&mut self, &mut self,
rand: &mut R, rand: &mut R,
corpus: &mut C, corpus: &C,
input: &mut I, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<(), AflError>; ) -> Result<(), AflError>;
@ -31,8 +27,8 @@ where
/// Post-process given the outcome of the execution /// Post-process given the outcome of the execution
fn post_exec( fn post_exec(
&mut self, &mut self,
_is_interesting: bool, _is_interesting: u32,
_new_testcase: Option<Rc<RefCell<Testcase<I>>>>, _input: &I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<(), AflError> { ) -> Result<(), AflError> {
Ok(()) Ok(())

View File

@ -15,7 +15,7 @@ pub enum MutationResult {
// TODO maybe the mutator arg is not needed // TODO maybe the mutator arg is not needed
/// The generic function type that identifies mutations /// The generic function type that identifies mutations
type MutationFunction<M, C, I, R> = 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> pub trait ComposedByMutations<C, I, R>
where where
@ -66,7 +66,7 @@ where
fn scheduled_mutate( fn scheduled_mutate(
&mut self, &mut self,
rand: &mut R, rand: &mut R,
corpus: &mut C, corpus: &C,
input: &mut I, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<(), AflError> { ) -> Result<(), AflError> {
@ -96,7 +96,7 @@ where
fn mutate( fn mutate(
&mut self, &mut self,
rand: &mut R, rand: &mut R,
corpus: &mut C, corpus: &C,
input: &mut I, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<(), AflError> { ) -> Result<(), AflError> {
@ -155,7 +155,7 @@ where
pub fn mutation_bitflip<M, C, I, R>( pub fn mutation_bitflip<M, C, I, R>(
_mutator: &mut M, _mutator: &mut M,
rand: &mut R, rand: &mut R,
_corpus: &mut C, _corpus: &C,
input: &mut I, input: &mut I,
) -> Result<MutationResult, AflError> ) -> Result<MutationResult, AflError>
where where
@ -179,7 +179,7 @@ where
pub fn mutation_byteflip<M, C, I, R>( pub fn mutation_byteflip<M, C, I, R>(
_mutator: &mut M, _mutator: &mut M,
rand: &mut R, rand: &mut R,
_corpus: &mut C, _corpus: &C,
input: &mut I, input: &mut I,
) -> Result<MutationResult, AflError> ) -> Result<MutationResult, AflError>
where where
@ -203,7 +203,7 @@ where
pub fn mutation_byteinc<M, C, I, R>( pub fn mutation_byteinc<M, C, I, R>(
_mutator: &mut M, _mutator: &mut M,
rand: &mut R, rand: &mut R,
_corpus: &mut C, _corpus: &C,
input: &mut I, input: &mut I,
) -> Result<MutationResult, AflError> ) -> Result<MutationResult, AflError>
where where
@ -227,7 +227,7 @@ where
pub fn mutation_bytedec<M, C, I, R>( pub fn mutation_bytedec<M, C, I, R>(
_mutator: &mut M, _mutator: &mut M,
rand: &mut R, rand: &mut R,
_corpus: &mut C, _corpus: &C,
input: &mut I, input: &mut I,
) -> Result<MutationResult, AflError> ) -> Result<MutationResult, AflError>
where where
@ -251,7 +251,7 @@ where
pub fn mutation_byteneg<M, C, I, R>( pub fn mutation_byteneg<M, C, I, R>(
_mutator: &mut M, _mutator: &mut M,
rand: &mut R, rand: &mut R,
_corpus: &mut C, _corpus: &C,
input: &mut I, input: &mut I,
) -> Result<MutationResult, AflError> ) -> Result<MutationResult, AflError>
where where
@ -292,7 +292,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
pub fn mutation_splice<M, C, I, R>( pub fn mutation_splice<M, C, I, R>(
_mutator: &mut M, _mutator: &mut M,
rand: &mut R, rand: &mut R,
corpus: &mut C, corpus: &C,
input: &mut I, input: &mut I,
) -> Result<MutationResult, AflError> ) -> Result<MutationResult, AflError>
where where
@ -301,17 +301,15 @@ where
I: Input + HasBytesVec, I: Input + HasBytesVec,
R: Rand, R: Rand,
{ {
// We don't want to use the testcase we're already using for splicing // TODO: Don't reuse the current testcase!
let (other_rr, _) = corpus.random_entry(rand)?.clone(); // (We don't want to use the testcase we're already using for splicing)
let mut other_testcase = match other_rr.try_borrow_mut() { let (other_testcase, _) = corpus.random_entry(rand)?;
Ok(x) => x, // TODO: let other = other_testcase.load_input()?;
Err(_) => {
return Ok(MutationResult::Skipped);
}
};
let other = other_testcase.load_input()?;
// println!("Input: {:?}, other input: {:?}", input.bytes(), other.bytes()); // 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 mut counter = 0;
let (first_diff, last_diff) = loop { let (first_diff, last_diff) = loop {
@ -362,7 +360,7 @@ where
fn mutate( fn mutate(
&mut self, &mut self,
rand: &mut R, rand: &mut R,
corpus: &mut C, corpus: &C,
input: &mut I, input: &mut I,
stage_idx: i32, stage_idx: i32,
) -> Result<(), AflError> { ) -> Result<(), AflError> {
@ -380,7 +378,7 @@ where
/// 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: SM) -> Self { pub fn new(mut scheduled: SM) -> Self {
scheduled.add_mutation(mutation_bitflip); scheduled.add_mutation(mutation_bitflip);
//scheduled.add_mutation(mutation_splice); scheduled.add_mutation(mutation_splice);
HavocBytesMutator { HavocBytesMutator {
scheduled: scheduled, scheduled: scheduled,
phantom: PhantomData, phantom: PhantomData,
@ -432,13 +430,15 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::inputs::BytesInput; use crate::inputs::BytesInput;
use crate::mutators::scheduled::{mutation_splice, StdScheduledMutator}; use crate::mutators::scheduled::StdScheduledMutator;
use crate::utils::{Rand, XKCDRand}; use crate::utils::{Rand, XKCDRand};
use crate::{ use crate::{
corpus::{Corpus, InMemoryCorpus, Testcase}, corpus::{Corpus, InMemoryCorpus, Testcase},
inputs::HasBytesVec, inputs::HasBytesVec,
}; };
use super::mutation_splice;
#[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.
@ -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!['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 let (testcase, _) = corpus
.next(&mut rand) .next(&mut rand)
.expect("Corpus did not contain entries"); .expect("Corpus did not contain entries");
let mut testcase = testcase_rr.borrow_mut(); let mut input = testcase.input().as_ref().unwrap().clone();
let mut input = testcase.load_input().expect("No input in testcase").clone();
rand.set_seed(5); rand.set_seed(5);
let mut mutator = StdScheduledMutator::new(); let mut mutator = StdScheduledMutator::new();

View File

@ -1,10 +1,6 @@
pub mod mutational; pub mod mutational;
pub use mutational::StdMutationalStage; pub use mutational::StdMutationalStage;
use alloc::rc::Rc;
use core::cell::RefCell;
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::events::EventManager;
@ -27,7 +23,8 @@ where
&mut self, &mut self,
rand: &mut R, rand: &mut R,
state: &mut S, state: &mut S,
corpus: &C,
events: &mut EM, events: &mut EM,
testcase: Rc<RefCell<Testcase<I>>>, input: &I,
) -> Result<(), AflError>; ) -> Result<(), AflError>;
} }

View File

@ -1,17 +1,15 @@
use alloc::rc::Rc;
use core::cell::RefCell;
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::corpus::testcase::Testcase;
use crate::engines::State; use crate::engines::State;
use crate::events::{EventManager, NewTestcaseEvent}; 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::Rand; use crate::utils::Rand;
use crate::{fire_event, AflError}; use crate::AflError;
use crate::{events::NewTestcaseEvent, fire_event};
// TODO multi mutators stage // TODO multi mutators stage
@ -42,22 +40,27 @@ where
&mut self, &mut self,
rand: &mut R, rand: &mut R,
state: &mut S, state: &mut S,
corpus: &C,
events: &mut EM, events: &mut EM,
testcase: Rc<RefCell<Testcase<I>>>, input: &I,
) -> Result<(), AflError> { ) -> Result<(), AflError> {
let num = self.iterations(rand); let num = self.iterations(rand);
for i in 0..num { for i in 0..num {
let mut input = testcase.borrow_mut().load_input()?.clone(); let mut input_mut = input.clone();
self.mutator_mut() 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() 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() { if interesting > 0 {
fire_event!(events, NewTestcaseEvent<I>, new_testcase.unwrap())?; 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(()) Ok(())
@ -115,10 +118,11 @@ where
&mut self, &mut self,
rand: &mut R, rand: &mut R,
state: &mut S, state: &mut S,
corpus: &C,
events: &mut EM, events: &mut EM,
testcase: Rc<RefCell<Testcase<I>>>, input: &I,
) -> Result<(), AflError> { ) -> Result<(), AflError> {
self.perform_mutational(rand, state, events, testcase) self.perform_mutational(rand, state, corpus, events, input)
} }
} }