Corpus maps (#947)
* hashmap corpus for inmemory * corpus_btreemap feature * CorpusId * queue * MinimizerScheduler::remove * fixes * continue * keys * working corpus * ok * weighted left * wip * port weighted scheduler * it compiles * doc * fix mutators * fix queue * fix iter * tests * fix * fix * fix * py * clippy * clippy * clippy * cmin * fix * fix * fix * clippy * remove Corpus::random_id
This commit is contained in:
parent
3345727c94
commit
ec84c71eae
@ -136,7 +136,13 @@ pub fn main() -> Result<(), Error> {
|
|||||||
let mut executor = InProcessExecutor::new(&mut harness, (), &mut fuzzer, &mut state, &mut mgr)?;
|
let mut executor = InProcessExecutor::new(&mut harness, (), &mut fuzzer, &mut state, &mut mgr)?;
|
||||||
|
|
||||||
state.load_initial_inputs_forced(&mut fuzzer, &mut executor, &mut mgr, &[solution_dir])?;
|
state.load_initial_inputs_forced(&mut fuzzer, &mut executor, &mut mgr, &[solution_dir])?;
|
||||||
stages.perform_all(&mut fuzzer, &mut executor, &mut state, &mut mgr, 0)?;
|
stages.perform_all(
|
||||||
|
&mut fuzzer,
|
||||||
|
&mut executor,
|
||||||
|
&mut state,
|
||||||
|
&mut mgr,
|
||||||
|
CorpusId::from(0usize),
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ use libafl::{
|
|||||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||||
token_mutations::Tokens,
|
token_mutations::Tokens,
|
||||||
},
|
},
|
||||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
observers::{HitcountsMapObserver, TimeObserver},
|
||||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||||
stages::mutational::StdMutationalStage,
|
stages::mutational::StdMutationalStage,
|
||||||
state::{HasCorpus, HasMetadata, StdState},
|
state::{HasCorpus, HasMetadata, StdState},
|
||||||
|
@ -29,6 +29,7 @@ frida_cli = ["cli"]
|
|||||||
afl_exec_sec = [] # calculate exec/sec like AFL
|
afl_exec_sec = [] # calculate exec/sec like AFL
|
||||||
errors_backtrace = ["backtrace"]
|
errors_backtrace = ["backtrace"]
|
||||||
cmin = ["z3"] # corpus minimisation
|
cmin = ["z3"] # corpus minimisation
|
||||||
|
corpus_btreemap = []
|
||||||
|
|
||||||
# features hiding dependencies licensed under GPL
|
# features hiding dependencies licensed under GPL
|
||||||
gpl = []
|
gpl = []
|
||||||
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::{
|
use crate::{
|
||||||
corpus::{
|
corpus::{
|
||||||
ondisk::{OnDiskCorpus, OnDiskMetadataFormat},
|
ondisk::{OnDiskCorpus, OnDiskMetadataFormat},
|
||||||
Corpus, Testcase,
|
Corpus, CorpusId, Testcase,
|
||||||
},
|
},
|
||||||
inputs::{Input, UsesInput},
|
inputs::{Input, UsesInput},
|
||||||
Error,
|
Error,
|
||||||
@ -24,7 +24,7 @@ where
|
|||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
inner: OnDiskCorpus<I>,
|
inner: OnDiskCorpus<I>,
|
||||||
cached_indexes: RefCell<VecDeque<usize>>,
|
cached_indexes: RefCell<VecDeque<CorpusId>>,
|
||||||
cache_max_len: usize,
|
cache_max_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,30 +47,28 @@ where
|
|||||||
|
|
||||||
/// Add an entry to the corpus and return its index
|
/// Add an entry to the corpus and return its index
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add(&mut self, testcase: Testcase<I>) -> Result<usize, Error> {
|
fn add(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error> {
|
||||||
self.inner.add(testcase)
|
self.inner.add(testcase)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the testcase at the given idx
|
/// Replaces the testcase at the given idx
|
||||||
#[inline]
|
#[inline]
|
||||||
fn replace(&mut self, idx: usize, testcase: Testcase<I>) -> Result<Testcase<I>, Error> {
|
fn replace(&mut self, idx: CorpusId, testcase: Testcase<I>) -> Result<Testcase<I>, Error> {
|
||||||
// TODO finish
|
// TODO finish
|
||||||
self.inner.replace(idx, testcase)
|
self.inner.replace(idx, testcase)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes an entry from the corpus, returning it if it was present.
|
/// Removes an entry from the corpus, returning it if it was present.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<I>>, Error> {
|
fn remove(&mut self, idx: CorpusId) -> Result<Testcase<I>, Error> {
|
||||||
let testcase = self.inner.remove(idx)?;
|
let testcase = self.inner.remove(idx)?;
|
||||||
if testcase.is_some() {
|
|
||||||
self.cached_indexes.borrow_mut().retain(|e| *e != idx);
|
self.cached_indexes.borrow_mut().retain(|e| *e != idx);
|
||||||
}
|
|
||||||
Ok(testcase)
|
Ok(testcase)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get by id
|
/// Get by id
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error> {
|
fn get(&self, idx: CorpusId) -> Result<&RefCell<Testcase<I>>, Error> {
|
||||||
let testcase = { self.inner.get(idx)? };
|
let testcase = { self.inner.get(idx)? };
|
||||||
if testcase.borrow().input().is_none() {
|
if testcase.borrow().input().is_none() {
|
||||||
let _ = testcase.borrow_mut().load_input()?;
|
let _ = testcase.borrow_mut().load_input()?;
|
||||||
@ -94,15 +92,40 @@ where
|
|||||||
|
|
||||||
/// Current testcase scheduled
|
/// Current testcase scheduled
|
||||||
#[inline]
|
#[inline]
|
||||||
fn current(&self) -> &Option<usize> {
|
fn current(&self) -> &Option<CorpusId> {
|
||||||
self.inner.current()
|
self.inner.current()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Current testcase scheduled (mutable)
|
/// Current testcase scheduled (mutable)
|
||||||
#[inline]
|
#[inline]
|
||||||
fn current_mut(&mut self) -> &mut Option<usize> {
|
fn current_mut(&mut self) -> &mut Option<CorpusId> {
|
||||||
self.inner.current_mut()
|
self.inner.current_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&self, idx: CorpusId) -> Option<CorpusId> {
|
||||||
|
self.inner.next(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn prev(&self, idx: CorpusId) -> Option<CorpusId> {
|
||||||
|
self.inner.prev(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn first(&self) -> Option<CorpusId> {
|
||||||
|
self.inner.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn last(&self) -> Option<CorpusId> {
|
||||||
|
self.inner.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn nth(&self, nth: usize) -> CorpusId {
|
||||||
|
self.inner.nth(nth)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> CachedOnDiskCorpus<I>
|
impl<I> CachedOnDiskCorpus<I>
|
||||||
|
@ -6,11 +6,284 @@ use core::cell::RefCell;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, Testcase},
|
corpus::{Corpus, CorpusId, Testcase},
|
||||||
inputs::{Input, UsesInput},
|
inputs::{Input, UsesInput},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Keep track of the stored `Testcase` and the siblings ids (insertion order)
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(bound = "I: serde::de::DeserializeOwned")]
|
||||||
|
pub struct TestcaseStorageItem<I>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
/// The stored testcase
|
||||||
|
pub testcase: RefCell<Testcase<I>>,
|
||||||
|
/// Previously inserted id
|
||||||
|
pub prev: Option<CorpusId>,
|
||||||
|
/// Following inserted id
|
||||||
|
pub next: Option<CorpusId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
/// The map type in which testcases are stored (enable the feature `corpus_btreemap` to use a `BTreeMap` instead of `HashMap`)
|
||||||
|
pub type TestcaseStorageMap<I> = hashbrown::HashMap<CorpusId, TestcaseStorageItem<I>>;
|
||||||
|
|
||||||
|
#[cfg(feature = "corpus_btreemap")]
|
||||||
|
/// The map type in which testcases are stored (disable the feature `corpus_btreemap` to use a `HashMap` instead of `BTreeMap`)
|
||||||
|
pub type TestcaseStorageMap<I> =
|
||||||
|
alloc::collections::btree_map::BTreeMap<CorpusId, RefCell<Testcase<I>>>;
|
||||||
|
|
||||||
|
/// Storage map for the testcases (used in `Corpus` implementations) with an incremental index
|
||||||
|
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[serde(bound = "I: serde::de::DeserializeOwned")]
|
||||||
|
pub struct TestcaseStorage<I>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
/// The map in which testcases are stored
|
||||||
|
pub map: TestcaseStorageMap<I>,
|
||||||
|
/// The keys in order (use `Vec::binary_search`)
|
||||||
|
pub keys: Vec<CorpusId>,
|
||||||
|
/// The progressive idx
|
||||||
|
progressive_idx: usize,
|
||||||
|
/// First inserted idx
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
first_idx: Option<CorpusId>,
|
||||||
|
/// Last inserted idx
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
last_idx: Option<CorpusId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> UsesInput for TestcaseStorage<I>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
type Input = I;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> TestcaseStorage<I>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
/// Insert a key in the keys set
|
||||||
|
fn insert_key(&mut self, id: CorpusId) {
|
||||||
|
if let Err(idx) = self.keys.binary_search(&id) {
|
||||||
|
self.keys.insert(idx, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a key from the keys set
|
||||||
|
fn remove_key(&mut self, id: CorpusId) {
|
||||||
|
if let Ok(idx) = self.keys.binary_search(&id) {
|
||||||
|
self.keys.remove(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert a testcase assigning a `CorpusId` to it
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
pub fn insert(&mut self, testcase: RefCell<Testcase<I>>) -> CorpusId {
|
||||||
|
let idx = CorpusId::from(self.progressive_idx);
|
||||||
|
self.progressive_idx += 1;
|
||||||
|
let prev = if let Some(last_idx) = self.last_idx {
|
||||||
|
self.map.get_mut(&last_idx).unwrap().next = Some(idx);
|
||||||
|
Some(last_idx)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
if self.first_idx.is_none() {
|
||||||
|
self.first_idx = Some(idx);
|
||||||
|
}
|
||||||
|
self.last_idx = Some(idx);
|
||||||
|
self.insert_key(idx);
|
||||||
|
self.map.insert(
|
||||||
|
idx,
|
||||||
|
TestcaseStorageItem {
|
||||||
|
testcase,
|
||||||
|
prev,
|
||||||
|
next: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
idx
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert a testcase assigning a `CorpusId` to it
|
||||||
|
#[cfg(feature = "corpus_btreemap")]
|
||||||
|
pub fn insert(&mut self, testcase: RefCell<Testcase<I>>) -> CorpusId {
|
||||||
|
let idx = CorpusId::from(self.progressive_idx);
|
||||||
|
self.progressive_idx += 1;
|
||||||
|
self.insert_key(idx);
|
||||||
|
self.map.insert(idx, testcase);
|
||||||
|
idx
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace a testcase given a `CorpusId`
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
pub fn replace(&mut self, idx: CorpusId, testcase: Testcase<I>) -> Option<Testcase<I>> {
|
||||||
|
if let Some(entry) = self.map.get_mut(&idx) {
|
||||||
|
Some(entry.testcase.replace(testcase))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace a testcase given a `CorpusId`
|
||||||
|
#[cfg(feature = "corpus_btreemap")]
|
||||||
|
pub fn replace(&mut self, idx: CorpusId, testcase: Testcase<I>) -> Option<Testcase<I>> {
|
||||||
|
self.map.get_mut(&idx).map(|entry| entry.replace(testcase))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a testcase given a `CorpusId`
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
pub fn remove(&mut self, idx: CorpusId) -> Option<RefCell<Testcase<I>>> {
|
||||||
|
if let Some(item) = self.map.remove(&idx) {
|
||||||
|
self.remove_key(idx);
|
||||||
|
if let Some(prev) = item.prev {
|
||||||
|
self.map.get_mut(&prev).unwrap().next = item.next;
|
||||||
|
} else {
|
||||||
|
// first elem
|
||||||
|
self.first_idx = item.next;
|
||||||
|
}
|
||||||
|
if let Some(next) = item.next {
|
||||||
|
self.map.get_mut(&next).unwrap().prev = item.prev;
|
||||||
|
} else {
|
||||||
|
// last elem
|
||||||
|
self.last_idx = item.prev;
|
||||||
|
}
|
||||||
|
Some(item.testcase)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a testcase given a `CorpusId`
|
||||||
|
#[cfg(feature = "corpus_btreemap")]
|
||||||
|
pub fn remove(&mut self, idx: CorpusId) -> Option<RefCell<Testcase<I>>> {
|
||||||
|
self.remove_key(idx);
|
||||||
|
self.map.remove(&idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a testcase given a `CorpusId`
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
#[must_use]
|
||||||
|
pub fn get(&self, idx: CorpusId) -> Option<&RefCell<Testcase<I>>> {
|
||||||
|
self.map.get(&idx).as_ref().map(|x| &x.testcase)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a testcase given a `CorpusId`
|
||||||
|
#[cfg(feature = "corpus_btreemap")]
|
||||||
|
#[must_use]
|
||||||
|
pub fn get(&self, idx: CorpusId) -> Option<&RefCell<Testcase<I>>> {
|
||||||
|
self.map.get(&idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next id given a `CorpusId` (creation order)
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
#[must_use]
|
||||||
|
fn next(&self, idx: CorpusId) -> Option<CorpusId> {
|
||||||
|
if let Some(item) = self.map.get(&idx) {
|
||||||
|
item.next
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next id given a `CorpusId` (creation order)
|
||||||
|
#[cfg(feature = "corpus_btreemap")]
|
||||||
|
#[must_use]
|
||||||
|
fn next(&self, idx: CorpusId) -> Option<CorpusId> {
|
||||||
|
// TODO see if using self.keys is faster
|
||||||
|
let mut range = self
|
||||||
|
.map
|
||||||
|
.range((core::ops::Bound::Included(idx), core::ops::Bound::Unbounded));
|
||||||
|
if let Some((this_id, _)) = range.next() {
|
||||||
|
if idx != *this_id {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((next_id, _)) = range.next() {
|
||||||
|
Some(*next_id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the previous id given a `CorpusId` (creation order)
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
#[must_use]
|
||||||
|
fn prev(&self, idx: CorpusId) -> Option<CorpusId> {
|
||||||
|
if let Some(item) = self.map.get(&idx) {
|
||||||
|
item.prev
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the previous id given a `CorpusId` (creation order)
|
||||||
|
#[cfg(feature = "corpus_btreemap")]
|
||||||
|
#[must_use]
|
||||||
|
fn prev(&self, idx: CorpusId) -> Option<CorpusId> {
|
||||||
|
// TODO see if using self.keys is faster
|
||||||
|
let mut range = self
|
||||||
|
.map
|
||||||
|
.range((core::ops::Bound::Unbounded, core::ops::Bound::Included(idx)));
|
||||||
|
if let Some((this_id, _)) = range.next_back() {
|
||||||
|
if idx != *this_id {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((prev_id, _)) = range.next_back() {
|
||||||
|
Some(*prev_id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the first created id
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
#[must_use]
|
||||||
|
fn first(&self) -> Option<CorpusId> {
|
||||||
|
self.first_idx
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the first created id
|
||||||
|
#[cfg(feature = "corpus_btreemap")]
|
||||||
|
#[must_use]
|
||||||
|
fn first(&self) -> Option<CorpusId> {
|
||||||
|
self.map.iter().next().map(|x| *x.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the last created id
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
#[must_use]
|
||||||
|
fn last(&self) -> Option<CorpusId> {
|
||||||
|
self.last_idx
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the last created id
|
||||||
|
#[cfg(feature = "corpus_btreemap")]
|
||||||
|
#[must_use]
|
||||||
|
fn last(&self) -> Option<CorpusId> {
|
||||||
|
self.map.iter().next_back().map(|x| *x.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create new `TestcaseStorage`
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
map: TestcaseStorageMap::default(),
|
||||||
|
keys: vec![],
|
||||||
|
progressive_idx: 0,
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
first_idx: None,
|
||||||
|
#[cfg(not(feature = "corpus_btreemap"))]
|
||||||
|
last_idx: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A corpus handling all in memory.
|
/// A corpus handling all in memory.
|
||||||
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(bound = "I: serde::de::DeserializeOwned")]
|
#[serde(bound = "I: serde::de::DeserializeOwned")]
|
||||||
@ -18,8 +291,8 @@ pub struct InMemoryCorpus<I>
|
|||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
entries: Vec<RefCell<Testcase<I>>>,
|
storage: TestcaseStorage<I>,
|
||||||
current: Option<usize>,
|
current: Option<CorpusId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> UsesInput for InMemoryCorpus<I>
|
impl<I> UsesInput for InMemoryCorpus<I>
|
||||||
@ -36,52 +309,76 @@ where
|
|||||||
/// Returns the number of elements
|
/// Returns the number of elements
|
||||||
#[inline]
|
#[inline]
|
||||||
fn count(&self) -> usize {
|
fn count(&self) -> usize {
|
||||||
self.entries.len()
|
self.storage.map.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an entry to the corpus and return its index
|
/// Add an entry to the corpus and return its index
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add(&mut self, testcase: Testcase<I>) -> Result<usize, Error> {
|
fn add(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error> {
|
||||||
self.entries.push(RefCell::new(testcase));
|
Ok(self.storage.insert(RefCell::new(testcase)))
|
||||||
Ok(self.entries.len() - 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the testcase at the given idx
|
/// Replaces the testcase at the given idx
|
||||||
#[inline]
|
#[inline]
|
||||||
fn replace(&mut self, idx: usize, testcase: Testcase<I>) -> Result<Testcase<I>, Error> {
|
fn replace(&mut self, idx: CorpusId, testcase: Testcase<I>) -> Result<Testcase<I>, Error> {
|
||||||
if idx >= self.entries.len() {
|
self.storage
|
||||||
return Err(Error::key_not_found(format!("Index {idx} out of bounds")));
|
.replace(idx, testcase)
|
||||||
}
|
.ok_or_else(|| Error::key_not_found(format!("Index {idx} not found")))
|
||||||
Ok(self.entries[idx].replace(testcase))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes an entry from the corpus, returning it if it was present.
|
/// Removes an entry from the corpus, returning it if it was present.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<I>>, Error> {
|
fn remove(&mut self, idx: CorpusId) -> Result<Testcase<I>, Error> {
|
||||||
if idx >= self.entries.len() {
|
self.storage
|
||||||
Ok(None)
|
.remove(idx)
|
||||||
} else {
|
.map(|x| x.take())
|
||||||
Ok(Some(self.entries.remove(idx).into_inner()))
|
.ok_or_else(|| Error::key_not_found(format!("Index {idx} not found")))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get by id
|
/// Get by id
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error> {
|
fn get(&self, idx: CorpusId) -> Result<&RefCell<Testcase<I>>, Error> {
|
||||||
Ok(&self.entries[idx])
|
self.storage
|
||||||
|
.get(idx)
|
||||||
|
.ok_or_else(|| Error::key_not_found(format!("Index {idx} not found")))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Current testcase scheduled
|
/// Current testcase scheduled
|
||||||
#[inline]
|
#[inline]
|
||||||
fn current(&self) -> &Option<usize> {
|
fn current(&self) -> &Option<CorpusId> {
|
||||||
&self.current
|
&self.current
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Current testcase scheduled (mutable)
|
/// Current testcase scheduled (mutable)
|
||||||
#[inline]
|
#[inline]
|
||||||
fn current_mut(&mut self) -> &mut Option<usize> {
|
fn current_mut(&mut self) -> &mut Option<CorpusId> {
|
||||||
&mut self.current
|
&mut self.current
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&self, idx: CorpusId) -> Option<CorpusId> {
|
||||||
|
self.storage.next(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn prev(&self, idx: CorpusId) -> Option<CorpusId> {
|
||||||
|
self.storage.prev(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn first(&self) -> Option<CorpusId> {
|
||||||
|
self.storage.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn last(&self) -> Option<CorpusId> {
|
||||||
|
self.storage.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn nth(&self, nth: usize) -> CorpusId {
|
||||||
|
self.storage.keys[nth]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> InMemoryCorpus<I>
|
impl<I> InMemoryCorpus<I>
|
||||||
@ -93,7 +390,7 @@ where
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
entries: vec![],
|
storage: TestcaseStorage::new(),
|
||||||
current: None,
|
current: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,8 @@ where
|
|||||||
let mut seed_exprs = HashMap::new();
|
let mut seed_exprs = HashMap::new();
|
||||||
let mut cov_map = HashMap::new();
|
let mut cov_map = HashMap::new();
|
||||||
|
|
||||||
for idx in 0..state.corpus().count() {
|
let mut cur_id = state.corpus().first();
|
||||||
|
while let Some(idx) = cur_id {
|
||||||
let (weight, input) = {
|
let (weight, input) = {
|
||||||
let mut testcase = state.corpus().get(idx)?.borrow_mut();
|
let mut testcase = state.corpus().get(idx)?.borrow_mut();
|
||||||
let weight = TS::compute(&mut *testcase, state)?
|
let weight = TS::compute(&mut *testcase, state)?
|
||||||
@ -151,6 +152,8 @@ where
|
|||||||
|
|
||||||
// Keep track of that seed's index and weight
|
// Keep track of that seed's index and weight
|
||||||
seed_exprs.insert(seed_expr, (idx, weight));
|
seed_exprs.insert(seed_expr, (idx, weight));
|
||||||
|
|
||||||
|
cur_id = state.corpus().next(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (_, cov) in cov_map {
|
for (_, cov) in cov_map {
|
||||||
@ -191,7 +194,9 @@ where
|
|||||||
let removed = state.corpus_mut().remove(idx)?;
|
let removed = state.corpus_mut().remove(idx)?;
|
||||||
// scheduler needs to know we've removed the input, or it will continue to try
|
// scheduler needs to know we've removed the input, or it will continue to try
|
||||||
// to use now-missing inputs
|
// to use now-missing inputs
|
||||||
fuzzer.scheduler_mut().on_remove(state, idx, &removed)?;
|
fuzzer
|
||||||
|
.scheduler_mut()
|
||||||
|
.on_remove(state, idx, &Some(removed))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
@ -18,15 +18,49 @@ pub use cached::CachedOnDiskCorpus;
|
|||||||
|
|
||||||
#[cfg(feature = "cmin")]
|
#[cfg(feature = "cmin")]
|
||||||
pub mod minimizer;
|
pub mod minimizer;
|
||||||
use core::cell::RefCell;
|
use core::{cell::RefCell, fmt};
|
||||||
|
|
||||||
#[cfg(feature = "cmin")]
|
#[cfg(feature = "cmin")]
|
||||||
pub use minimizer::*;
|
pub use minimizer::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{inputs::UsesInput, Error};
|
use crate::{inputs::UsesInput, Error};
|
||||||
|
|
||||||
|
/// An abstraction for the index that identify a testcase in the corpus
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct CorpusId(pub(crate) usize);
|
||||||
|
|
||||||
|
impl fmt::Display for CorpusId {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<usize> for CorpusId {
|
||||||
|
fn from(id: usize) -> Self {
|
||||||
|
Self(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u64> for CorpusId {
|
||||||
|
fn from(id: u64) -> Self {
|
||||||
|
Self(id as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility macro to call `Corpus::random_id`
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! random_corpus_id {
|
||||||
|
($corpus:expr, $rand:expr) => {{
|
||||||
|
let cnt = $corpus.count() as u64;
|
||||||
|
let nth = $rand.below(cnt) as usize;
|
||||||
|
$corpus.nth(nth)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
/// Corpus with all current testcases
|
/// Corpus with all current testcases
|
||||||
pub trait Corpus: UsesInput + serde::Serialize + for<'de> serde::Deserialize<'de> {
|
pub trait Corpus: UsesInput + Serialize + for<'de> Deserialize<'de> {
|
||||||
/// Returns the number of elements
|
/// Returns the number of elements
|
||||||
fn count(&self) -> usize;
|
fn count(&self) -> usize;
|
||||||
|
|
||||||
@ -36,26 +70,95 @@ pub trait Corpus: UsesInput + serde::Serialize + for<'de> serde::Deserialize<'de
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add an entry to the corpus and return its index
|
/// Add an entry to the corpus and return its index
|
||||||
fn add(&mut self, testcase: Testcase<Self::Input>) -> Result<usize, Error>;
|
fn add(&mut self, testcase: Testcase<Self::Input>) -> Result<CorpusId, Error>;
|
||||||
|
|
||||||
/// Replaces the testcase at the given idx, returning the existing.
|
/// Replaces the testcase at the given idx, returning the existing.
|
||||||
fn replace(
|
fn replace(
|
||||||
&mut self,
|
&mut self,
|
||||||
idx: usize,
|
idx: CorpusId,
|
||||||
testcase: Testcase<Self::Input>,
|
testcase: Testcase<Self::Input>,
|
||||||
) -> Result<Testcase<Self::Input>, Error>;
|
) -> Result<Testcase<Self::Input>, Error>;
|
||||||
|
|
||||||
/// 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, idx: usize) -> Result<Option<Testcase<Self::Input>>, Error>;
|
fn remove(&mut self, id: CorpusId) -> Result<Testcase<Self::Input>, Error>;
|
||||||
|
|
||||||
/// Get by id
|
/// Get by id
|
||||||
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<Self::Input>>, Error>;
|
fn get(&self, id: CorpusId) -> Result<&RefCell<Testcase<Self::Input>>, Error>;
|
||||||
|
|
||||||
/// Current testcase scheduled
|
/// Current testcase scheduled
|
||||||
fn current(&self) -> &Option<usize>;
|
fn current(&self) -> &Option<CorpusId>;
|
||||||
|
|
||||||
/// Current testcase scheduled (mutable)
|
/// Current testcase scheduled (mutable)
|
||||||
fn current_mut(&mut self) -> &mut Option<usize>;
|
fn current_mut(&mut self) -> &mut Option<CorpusId>;
|
||||||
|
|
||||||
|
/// Get the next corpus id
|
||||||
|
fn next(&self, id: CorpusId) -> Option<CorpusId>;
|
||||||
|
|
||||||
|
/// Get the prev corpus id
|
||||||
|
fn prev(&self, id: CorpusId) -> Option<CorpusId>;
|
||||||
|
|
||||||
|
/// Get the first inserted corpus id
|
||||||
|
fn first(&self) -> Option<CorpusId>;
|
||||||
|
|
||||||
|
/// Get the last inserted corpus id
|
||||||
|
fn last(&self) -> Option<CorpusId>;
|
||||||
|
|
||||||
|
/// An iterator over very active corpus id
|
||||||
|
fn ids(&self) -> CorpusIdIterator<'_, Self> {
|
||||||
|
CorpusIdIterator {
|
||||||
|
corpus: self,
|
||||||
|
cur: self.first(),
|
||||||
|
cur_back: self.last(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the nth corpus id
|
||||||
|
fn nth(&self, nth: usize) -> CorpusId {
|
||||||
|
self.ids()
|
||||||
|
.nth(nth)
|
||||||
|
.expect("Failed to get the {nth} CorpusId")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `Iterator` over the ids of a `Corpus`
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CorpusIdIterator<'a, C>
|
||||||
|
where
|
||||||
|
C: Corpus,
|
||||||
|
{
|
||||||
|
corpus: &'a C,
|
||||||
|
cur: Option<CorpusId>,
|
||||||
|
cur_back: Option<CorpusId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, C> Iterator for CorpusIdIterator<'a, C>
|
||||||
|
where
|
||||||
|
C: Corpus,
|
||||||
|
{
|
||||||
|
type Item = CorpusId;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if let Some(cur) = self.cur {
|
||||||
|
self.cur = self.corpus.next(cur);
|
||||||
|
Some(cur)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, C> DoubleEndedIterator for CorpusIdIterator<'a, C>
|
||||||
|
where
|
||||||
|
C: Corpus,
|
||||||
|
{
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
if let Some(cur_back) = self.cur_back {
|
||||||
|
self.cur_back = self.corpus.prev(cur_back);
|
||||||
|
Some(cur_back)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `Corpus` Python bindings
|
/// `Corpus` Python bindings
|
||||||
@ -71,7 +174,7 @@ pub mod pybind {
|
|||||||
corpus::{
|
corpus::{
|
||||||
cached::pybind::PythonCachedOnDiskCorpus, inmemory::pybind::PythonInMemoryCorpus,
|
cached::pybind::PythonCachedOnDiskCorpus, inmemory::pybind::PythonInMemoryCorpus,
|
||||||
ondisk::pybind::PythonOnDiskCorpus, testcase::pybind::PythonTestcaseWrapper, Corpus,
|
ondisk::pybind::PythonOnDiskCorpus, testcase::pybind::PythonTestcaseWrapper, Corpus,
|
||||||
Testcase,
|
CorpusId, Testcase,
|
||||||
},
|
},
|
||||||
inputs::{BytesInput, UsesInput},
|
inputs::{BytesInput, UsesInput},
|
||||||
Error,
|
Error,
|
||||||
@ -157,13 +260,13 @@ pub mod pybind {
|
|||||||
|
|
||||||
#[pyo3(name = "current")]
|
#[pyo3(name = "current")]
|
||||||
fn pycurrent(&self) -> Option<usize> {
|
fn pycurrent(&self) -> Option<usize> {
|
||||||
*self.current()
|
self.current().map(|x| x.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyo3(name = "get")]
|
#[pyo3(name = "get")]
|
||||||
fn pyget(&self, idx: usize) -> PythonTestcaseWrapper {
|
fn pyget(&self, idx: usize) -> PythonTestcaseWrapper {
|
||||||
let t: &mut Testcase<BytesInput> = unwrap_me!(self.wrapper, c, {
|
let t: &mut Testcase<BytesInput> = unwrap_me!(self.wrapper, c, {
|
||||||
c.get(idx)
|
c.get(CorpusId::from(idx))
|
||||||
.map(|v| unsafe { v.as_ptr().as_mut().unwrap() })
|
.map(|v| unsafe { v.as_ptr().as_mut().unwrap() })
|
||||||
.expect("PythonCorpus::get failed")
|
.expect("PythonCorpus::get failed")
|
||||||
});
|
});
|
||||||
@ -182,26 +285,26 @@ pub mod pybind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<usize, Error> {
|
fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<CorpusId, Error> {
|
||||||
unwrap_me_mut!(self.wrapper, c, { c.add(testcase) })
|
unwrap_me_mut!(self.wrapper, c, { c.add(testcase) })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn replace(
|
fn replace(
|
||||||
&mut self,
|
&mut self,
|
||||||
idx: usize,
|
idx: CorpusId,
|
||||||
testcase: Testcase<BytesInput>,
|
testcase: Testcase<BytesInput>,
|
||||||
) -> Result<Testcase<BytesInput>, Error> {
|
) -> Result<Testcase<BytesInput>, Error> {
|
||||||
unwrap_me_mut!(self.wrapper, c, { c.replace(idx, testcase) })
|
unwrap_me_mut!(self.wrapper, c, { c.replace(idx, testcase) })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
|
fn remove(&mut self, idx: CorpusId) -> Result<Testcase<BytesInput>, Error> {
|
||||||
unwrap_me_mut!(self.wrapper, c, { c.remove(idx) })
|
unwrap_me_mut!(self.wrapper, c, { c.remove(idx) })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<BytesInput>>, Error> {
|
fn get(&self, idx: CorpusId) -> Result<&RefCell<Testcase<BytesInput>>, Error> {
|
||||||
let ptr = unwrap_me!(self.wrapper, c, {
|
let ptr = unwrap_me!(self.wrapper, c, {
|
||||||
c.get(idx)
|
c.get(idx)
|
||||||
.map(|v| v as *const RefCell<Testcase<BytesInput>>)
|
.map(|v| v as *const RefCell<Testcase<BytesInput>>)
|
||||||
@ -210,16 +313,49 @@ pub mod pybind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn current(&self) -> &Option<usize> {
|
fn current(&self) -> &Option<CorpusId> {
|
||||||
let ptr = unwrap_me!(self.wrapper, c, { c.current() as *const Option<usize> });
|
let ptr = unwrap_me!(self.wrapper, c, { c.current() as *const Option<CorpusId> });
|
||||||
unsafe { ptr.as_ref().unwrap() }
|
unsafe { ptr.as_ref().unwrap() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn current_mut(&mut self) -> &mut Option<usize> {
|
fn current_mut(&mut self) -> &mut Option<CorpusId> {
|
||||||
let ptr = unwrap_me_mut!(self.wrapper, c, { c.current_mut() as *mut Option<usize> });
|
let ptr = unwrap_me_mut!(self.wrapper, c, {
|
||||||
|
c.current_mut() as *mut Option<CorpusId>
|
||||||
|
});
|
||||||
unsafe { ptr.as_mut().unwrap() }
|
unsafe { ptr.as_mut().unwrap() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next(&self, idx: CorpusId) -> Option<CorpusId> {
|
||||||
|
unwrap_me!(self.wrapper, c, { c.next(idx) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prev(&self, idx: CorpusId) -> Option<CorpusId> {
|
||||||
|
unwrap_me!(self.wrapper, c, { c.prev(idx) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first(&self) -> Option<CorpusId> {
|
||||||
|
unwrap_me!(self.wrapper, c, { c.first() })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last(&self) -> Option<CorpusId> {
|
||||||
|
unwrap_me!(self.wrapper, c, { c.last() })
|
||||||
|
}
|
||||||
|
|
||||||
|
/*fn ids<'a>(&'a self) -> CorpusIdIterator<'a, Self> {
|
||||||
|
CorpusIdIterator {
|
||||||
|
corpus: self,
|
||||||
|
cur: self.first(),
|
||||||
|
cur_back: self.last(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_id(&self, next_random: u64) -> CorpusId {
|
||||||
|
let nth = (next_random as usize) % self.count();
|
||||||
|
self.ids()
|
||||||
|
.nth(nth)
|
||||||
|
.expect("Failed to get a random CorpusId")
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register the classes to the python module
|
/// Register the classes to the python module
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
//! The ondisk corpus stores unused testcases to disk.
|
//! The ondisk corpus stores unused testcases to disk.
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use core::{cell::RefCell, time::Duration};
|
use core::{cell::RefCell, time::Duration};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::{fs, fs::File, io::Write};
|
use std::{fs, fs::File, io::Write};
|
||||||
@ -13,7 +12,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::serdeany::SerdeAnyMap,
|
bolts::serdeany::SerdeAnyMap,
|
||||||
corpus::{Corpus, Testcase},
|
corpus::{Corpus, CorpusId, InMemoryCorpus, Testcase},
|
||||||
inputs::{Input, UsesInput},
|
inputs::{Input, UsesInput},
|
||||||
state::HasMetadata,
|
state::HasMetadata,
|
||||||
Error,
|
Error,
|
||||||
@ -48,8 +47,7 @@ pub struct OnDiskCorpus<I>
|
|||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
entries: Vec<RefCell<Testcase<I>>>,
|
inner: InMemoryCorpus<I>,
|
||||||
current: Option<usize>,
|
|
||||||
dir_path: PathBuf,
|
dir_path: PathBuf,
|
||||||
meta_format: Option<OnDiskMetadataFormat>,
|
meta_format: Option<OnDiskMetadataFormat>,
|
||||||
}
|
}
|
||||||
@ -68,57 +66,75 @@ where
|
|||||||
/// Returns the number of elements
|
/// Returns the number of elements
|
||||||
#[inline]
|
#[inline]
|
||||||
fn count(&self) -> usize {
|
fn count(&self) -> usize {
|
||||||
self.entries.len()
|
self.inner.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an entry to the corpus and return its index
|
/// Add an entry to the corpus and return its index
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add(&mut self, mut testcase: Testcase<I>) -> Result<usize, Error> {
|
fn add(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error> {
|
||||||
self.save_testcase(&mut testcase)?;
|
let idx = self.inner.add(testcase)?;
|
||||||
self.entries.push(RefCell::new(testcase));
|
self.save_testcase(&mut self.get(idx).unwrap().borrow_mut(), idx)?;
|
||||||
Ok(self.entries.len() - 1)
|
Ok(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the testcase at the given idx
|
/// Replaces the testcase at the given idx
|
||||||
#[inline]
|
#[inline]
|
||||||
fn replace(&mut self, idx: usize, mut testcase: Testcase<I>) -> Result<Testcase<I>, Error> {
|
fn replace(&mut self, idx: CorpusId, testcase: Testcase<I>) -> Result<Testcase<I>, Error> {
|
||||||
if idx >= self.entries.len() {
|
let entry = self.inner.replace(idx, testcase)?;
|
||||||
return Err(Error::key_not_found(format!("Index {idx} out of bounds")));
|
self.remove_testcase(&entry)?;
|
||||||
}
|
self.save_testcase(&mut self.get(idx).unwrap().borrow_mut(), idx)?;
|
||||||
self.save_testcase(&mut testcase)?;
|
Ok(entry)
|
||||||
let previous = self.entries[idx].replace(testcase);
|
|
||||||
self.remove_testcase(&previous)?;
|
|
||||||
Ok(previous)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes an entry from the corpus, returning it if it was present.
|
/// Removes an entry from the corpus, returning it if it was present.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<I>>, Error> {
|
fn remove(&mut self, idx: CorpusId) -> Result<Testcase<I>, Error> {
|
||||||
if idx >= self.entries.len() {
|
let entry = self.inner.remove(idx)?;
|
||||||
Ok(None)
|
self.remove_testcase(&entry)?;
|
||||||
} else {
|
Ok(entry)
|
||||||
let prev = self.entries.remove(idx).into_inner();
|
|
||||||
self.remove_testcase(&prev)?;
|
|
||||||
Ok(Some(prev))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get by id
|
/// Get by id
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error> {
|
fn get(&self, idx: CorpusId) -> Result<&RefCell<Testcase<I>>, Error> {
|
||||||
Ok(&self.entries[idx])
|
self.inner.get(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Current testcase scheduled
|
/// Current testcase scheduled
|
||||||
#[inline]
|
#[inline]
|
||||||
fn current(&self) -> &Option<usize> {
|
fn current(&self) -> &Option<CorpusId> {
|
||||||
&self.current
|
self.inner.current()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Current testcase scheduled (mutable)
|
/// Current testcase scheduled (mutable)
|
||||||
#[inline]
|
#[inline]
|
||||||
fn current_mut(&mut self) -> &mut Option<usize> {
|
fn current_mut(&mut self) -> &mut Option<CorpusId> {
|
||||||
&mut self.current
|
self.inner.current_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&self, idx: CorpusId) -> Option<CorpusId> {
|
||||||
|
self.inner.next(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn prev(&self, idx: CorpusId) -> Option<CorpusId> {
|
||||||
|
self.inner.prev(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn first(&self) -> Option<CorpusId> {
|
||||||
|
self.inner.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn last(&self) -> Option<CorpusId> {
|
||||||
|
self.inner.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn nth(&self, nth: usize) -> CorpusId {
|
||||||
|
self.inner.nth(nth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,8 +151,7 @@ where
|
|||||||
fn new<I: Input>(dir_path: PathBuf) -> Result<OnDiskCorpus<I>, Error> {
|
fn new<I: Input>(dir_path: PathBuf) -> Result<OnDiskCorpus<I>, Error> {
|
||||||
fs::create_dir_all(&dir_path)?;
|
fs::create_dir_all(&dir_path)?;
|
||||||
Ok(OnDiskCorpus {
|
Ok(OnDiskCorpus {
|
||||||
entries: vec![],
|
inner: InMemoryCorpus::new(),
|
||||||
current: None,
|
|
||||||
dir_path,
|
dir_path,
|
||||||
meta_format: None,
|
meta_format: None,
|
||||||
})
|
})
|
||||||
@ -152,21 +167,16 @@ where
|
|||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
fs::create_dir_all(&dir_path)?;
|
fs::create_dir_all(&dir_path)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
entries: vec![],
|
inner: InMemoryCorpus::new(),
|
||||||
current: None,
|
|
||||||
dir_path,
|
dir_path,
|
||||||
meta_format,
|
meta_format,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_testcase(&mut self, testcase: &mut Testcase<I>) -> Result<(), Error> {
|
fn save_testcase(&self, testcase: &mut Testcase<I>, idx: CorpusId) -> Result<(), Error> {
|
||||||
if testcase.filename().is_none() {
|
if testcase.filename().is_none() {
|
||||||
// TODO walk entry metadata to ask for pieces of filename (e.g. :havoc in AFL)
|
// TODO walk entry metadata to ask for pieces of filename (e.g. :havoc in AFL)
|
||||||
let file_orig = testcase
|
let file_orig = testcase.input().as_ref().unwrap().generate_name(idx.0);
|
||||||
.input()
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.generate_name(self.entries.len());
|
|
||||||
let mut file = file_orig.clone();
|
let mut file = file_orig.clone();
|
||||||
|
|
||||||
let mut ctr = 2;
|
let mut ctr = 2;
|
||||||
@ -224,7 +234,7 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_testcase(&mut self, testcase: &Testcase<I>) -> Result<(), Error> {
|
fn remove_testcase(&self, testcase: &Testcase<I>) -> Result<(), Error> {
|
||||||
if let Some(filename) = testcase.filename() {
|
if let Some(filename) = testcase.filename() {
|
||||||
fs::remove_file(filename)?;
|
fs::remove_file(filename)?;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ use crate::monitors::PerfFeature;
|
|||||||
use crate::state::NopState;
|
use crate::state::NopState;
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::current_time,
|
bolts::current_time,
|
||||||
corpus::{Corpus, Testcase},
|
corpus::{Corpus, CorpusId, Testcase},
|
||||||
events::{Event, EventConfig, EventFirer, EventProcessor, ProgressReporter},
|
events::{Event, EventConfig, EventFirer, EventProcessor, ProgressReporter},
|
||||||
executors::{Executor, ExitKind, HasObservers},
|
executors::{Executor, ExitKind, HasObservers},
|
||||||
feedbacks::Feedback,
|
feedbacks::Feedback,
|
||||||
@ -83,7 +83,7 @@ pub trait ExecutionProcessor<OT>: UsesState {
|
|||||||
observers: &OT,
|
observers: &OT,
|
||||||
exit_kind: &ExitKind,
|
exit_kind: &ExitKind,
|
||||||
send_events: bool,
|
send_events: bool,
|
||||||
) -> Result<(ExecuteInputResult, Option<usize>), Error>
|
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<State = Self::State>;
|
EM: EventFirer<State = Self::State>;
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ pub trait EvaluatorObservers<OT>: UsesState + Sized {
|
|||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: <Self::State as UsesInput>::Input,
|
input: <Self::State as UsesInput>::Input,
|
||||||
send_events: bool,
|
send_events: bool,
|
||||||
) -> Result<(ExecuteInputResult, Option<usize>), Error>
|
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error>
|
||||||
where
|
where
|
||||||
E: Executor<EM, Self> + HasObservers<Observers = OT, State = Self::State>,
|
E: Executor<EM, Self> + HasObservers<Observers = OT, State = Self::State>,
|
||||||
EM: EventFirer<State = Self::State>;
|
EM: EventFirer<State = Self::State>;
|
||||||
@ -120,7 +120,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: <Self::State as UsesInput>::Input,
|
input: <Self::State as UsesInput>::Input,
|
||||||
) -> Result<(ExecuteInputResult, Option<usize>), Error> {
|
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> {
|
||||||
self.evaluate_input_events(state, executor, manager, input, true)
|
self.evaluate_input_events(state, executor, manager, input, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ where
|
|||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: <Self::State as UsesInput>::Input,
|
input: <Self::State as UsesInput>::Input,
|
||||||
send_events: bool,
|
send_events: bool,
|
||||||
) -> Result<(ExecuteInputResult, Option<usize>), Error>;
|
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error>;
|
||||||
|
|
||||||
/// Runs the input and triggers observers and feedback.
|
/// Runs the input and triggers observers and feedback.
|
||||||
/// Adds an input, to the corpus even if it's not considered `interesting` by the `feedback`.
|
/// Adds an input, to the corpus even if it's not considered `interesting` by the `feedback`.
|
||||||
@ -146,7 +146,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: <Self::State as UsesInput>::Input,
|
input: <Self::State as UsesInput>::Input,
|
||||||
) -> Result<usize, Error>;
|
) -> Result<CorpusId, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The main fuzzer trait.
|
/// The main fuzzer trait.
|
||||||
@ -172,7 +172,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut EM::State,
|
state: &mut EM::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<usize, Error>;
|
) -> Result<CorpusId, Error>;
|
||||||
|
|
||||||
/// Fuzz forever (or until stopped)
|
/// Fuzz forever (or until stopped)
|
||||||
fn fuzz_loop(
|
fn fuzz_loop(
|
||||||
@ -181,7 +181,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut EM::State,
|
state: &mut EM::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<CorpusId, Error> {
|
||||||
let mut last = current_time();
|
let mut last = current_time();
|
||||||
let monitor_timeout = STATS_TIMEOUT_DEFAULT;
|
let monitor_timeout = STATS_TIMEOUT_DEFAULT;
|
||||||
loop {
|
loop {
|
||||||
@ -206,19 +206,19 @@ where
|
|||||||
state: &mut EM::State,
|
state: &mut EM::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
iters: u64,
|
iters: u64,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<CorpusId, Error> {
|
||||||
if iters == 0 {
|
if iters == 0 {
|
||||||
return Err(Error::illegal_argument(
|
return Err(Error::illegal_argument(
|
||||||
"Cannot fuzz for 0 iterations!".to_string(),
|
"Cannot fuzz for 0 iterations!".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ret = 0;
|
let mut ret = None;
|
||||||
let mut last = current_time();
|
let mut last = current_time();
|
||||||
let monitor_timeout = STATS_TIMEOUT_DEFAULT;
|
let monitor_timeout = STATS_TIMEOUT_DEFAULT;
|
||||||
|
|
||||||
for _ in 0..iters {
|
for _ in 0..iters {
|
||||||
ret = self.fuzz_one(stages, executor, state, manager)?;
|
ret = Some(self.fuzz_one(stages, executor, state, manager)?);
|
||||||
last = manager.maybe_report_progress(state, last, monitor_timeout)?;
|
last = manager.maybe_report_progress(state, last, monitor_timeout)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +227,7 @@ where
|
|||||||
// But as the state may grow to a few megabytes,
|
// But as the state may grow to a few megabytes,
|
||||||
// for now we won' and the user has to do it (unless we find a way to do this on `Drop`).
|
// for now we won' and the user has to do it (unless we find a way to do this on `Drop`).
|
||||||
|
|
||||||
Ok(ret)
|
Ok(ret.unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +338,7 @@ where
|
|||||||
observers: &OT,
|
observers: &OT,
|
||||||
exit_kind: &ExitKind,
|
exit_kind: &ExitKind,
|
||||||
send_events: bool,
|
send_events: bool,
|
||||||
) -> Result<(ExecuteInputResult, Option<usize>), Error>
|
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<State = Self::State>,
|
EM: EventFirer<State = Self::State>,
|
||||||
{
|
{
|
||||||
@ -451,7 +451,7 @@ where
|
|||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: <Self::State as UsesInput>::Input,
|
input: <Self::State as UsesInput>::Input,
|
||||||
send_events: bool,
|
send_events: bool,
|
||||||
) -> Result<(ExecuteInputResult, Option<usize>), Error>
|
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error>
|
||||||
where
|
where
|
||||||
E: Executor<EM, Self> + HasObservers<Observers = OT, State = Self::State>,
|
E: Executor<EM, Self> + HasObservers<Observers = OT, State = Self::State>,
|
||||||
EM: EventFirer<State = Self::State>,
|
EM: EventFirer<State = Self::State>,
|
||||||
@ -481,7 +481,7 @@ where
|
|||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: <CS::State as UsesInput>::Input,
|
input: <CS::State as UsesInput>::Input,
|
||||||
send_events: bool,
|
send_events: bool,
|
||||||
) -> Result<(ExecuteInputResult, Option<usize>), Error> {
|
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> {
|
||||||
self.evaluate_input_with_observers(state, executor, manager, input, send_events)
|
self.evaluate_input_with_observers(state, executor, manager, input, send_events)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,7 +492,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: <CS::State as UsesInput>::Input,
|
input: <CS::State as UsesInput>::Input,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<CorpusId, Error> {
|
||||||
let exit_kind = self.execute_input(state, executor, manager, &input)?;
|
let exit_kind = self.execute_input(state, executor, manager, &input)?;
|
||||||
let observers = executor.observers();
|
let observers = executor.observers();
|
||||||
// Always consider this to be "interesting"
|
// Always consider this to be "interesting"
|
||||||
@ -543,7 +543,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut CS::State,
|
state: &mut CS::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<CorpusId, Error> {
|
||||||
// Init timer for scheduler
|
// Init timer for scheduler
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
state.introspection_monitor_mut().start_timer();
|
state.introspection_monitor_mut().start_timer();
|
||||||
@ -717,7 +717,7 @@ where
|
|||||||
_executor: &mut E,
|
_executor: &mut E,
|
||||||
_state: &mut EM::State,
|
_state: &mut EM::State,
|
||||||
_manager: &mut EM,
|
_manager: &mut EM,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<CorpusId, Error> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -805,6 +805,7 @@ pub mod pybind {
|
|||||||
BytesInput::new(input),
|
BytesInput::new(input),
|
||||||
)
|
)
|
||||||
.expect("Failed to add input")
|
.expect("Failed to add input")
|
||||||
|
.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fuzz_loop(
|
fn fuzz_loop(
|
||||||
|
@ -14,6 +14,7 @@ use crate::{
|
|||||||
mutations::{buffer_copy, buffer_self_copy, ARITH_MAX},
|
mutations::{buffer_copy, buffer_self_copy, ARITH_MAX},
|
||||||
MutationResult, Mutator, Named,
|
MutationResult, Mutator, Named,
|
||||||
},
|
},
|
||||||
|
random_corpus_id,
|
||||||
state::{HasCorpus, HasMaxSize, HasRand},
|
state::{HasCorpus, HasMaxSize, HasRand},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -320,8 +321,7 @@ where
|
|||||||
let size = input.codes().len();
|
let size = input.codes().len();
|
||||||
|
|
||||||
// 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 count = state.corpus().count();
|
let idx = random_corpus_id!(state.corpus(), state.rand_mut());
|
||||||
let idx = state.rand_mut().below(count as u64) as usize;
|
|
||||||
if let Some(cur) = state.corpus().current() {
|
if let Some(cur) = state.corpus().current() {
|
||||||
if idx == *cur {
|
if idx == *cur {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
@ -397,8 +397,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 count = state.corpus().count();
|
let idx = random_corpus_id!(state.corpus(), state.rand_mut());
|
||||||
let idx = state.rand_mut().below(count as u64) as usize;
|
|
||||||
if let Some(cur) = state.corpus().current() {
|
if let Some(cur) = state.corpus().current() {
|
||||||
if idx == *cur {
|
if idx == *cur {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
|
@ -12,6 +12,7 @@ use crate::{
|
|||||||
generators::GramatronGenerator,
|
generators::GramatronGenerator,
|
||||||
inputs::{GramatronInput, Terminal, UsesInput},
|
inputs::{GramatronInput, Terminal, UsesInput},
|
||||||
mutators::{MutationResult, Mutator},
|
mutators::{MutationResult, Mutator},
|
||||||
|
random_corpus_id,
|
||||||
state::{HasCorpus, HasMetadata, HasRand},
|
state::{HasCorpus, HasMetadata, HasRand},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -110,8 +111,7 @@ where
|
|||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
}
|
}
|
||||||
|
|
||||||
let count = state.corpus().count();
|
let idx = random_corpus_id!(state.corpus(), state.rand_mut());
|
||||||
let idx = state.rand_mut().below(count as u64) as usize;
|
|
||||||
|
|
||||||
let insert_at = state.rand_mut().below(input.terminals().len() as u64) as usize;
|
let insert_at = state.rand_mut().below(input.terminals().len() as u64) as usize;
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ pub use nautilus::*;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::tuples::{HasConstLen, Named},
|
bolts::tuples::{HasConstLen, Named},
|
||||||
|
corpus::CorpusId,
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -61,7 +62,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
_state: &mut S,
|
_state: &mut S,
|
||||||
_stage_idx: i32,
|
_stage_idx: i32,
|
||||||
_corpus_idx: Option<usize>,
|
_corpus_idx: Option<CorpusId>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -85,7 +86,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
stage_idx: i32,
|
stage_idx: i32,
|
||||||
corpus_idx: Option<usize>,
|
corpus_idx: Option<CorpusId>,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
/// Gets the [`Mutator`] at the given index and runs the `mutate` function on it.
|
/// Gets the [`Mutator`] at the given index and runs the `mutate` function on it.
|
||||||
@ -103,7 +104,7 @@ where
|
|||||||
index: usize,
|
index: usize,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
stage_idx: i32,
|
stage_idx: i32,
|
||||||
corpus_idx: Option<usize>,
|
corpus_idx: Option<CorpusId>,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +125,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
_state: &mut S,
|
_state: &mut S,
|
||||||
_stage_idx: i32,
|
_stage_idx: i32,
|
||||||
_corpus_idx: Option<usize>,
|
_corpus_idx: Option<CorpusId>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -144,7 +145,7 @@ where
|
|||||||
_index: usize,
|
_index: usize,
|
||||||
_state: &mut S,
|
_state: &mut S,
|
||||||
_stage_idx: i32,
|
_stage_idx: i32,
|
||||||
_corpus_idx: Option<usize>,
|
_corpus_idx: Option<CorpusId>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -174,7 +175,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
stage_idx: i32,
|
stage_idx: i32,
|
||||||
corpus_idx: Option<usize>,
|
corpus_idx: Option<CorpusId>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.0.post_exec(state, stage_idx, corpus_idx)?;
|
self.0.post_exec(state, stage_idx, corpus_idx)?;
|
||||||
self.1.post_exec_all(state, stage_idx, corpus_idx)
|
self.1.post_exec_all(state, stage_idx, corpus_idx)
|
||||||
@ -199,7 +200,7 @@ where
|
|||||||
index: usize,
|
index: usize,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
stage_idx: i32,
|
stage_idx: i32,
|
||||||
corpus_idx: Option<usize>,
|
corpus_idx: Option<CorpusId>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
self.0.post_exec(state, stage_idx, corpus_idx)
|
self.0.post_exec(state, stage_idx, corpus_idx)
|
||||||
@ -218,6 +219,7 @@ pub mod pybind {
|
|||||||
|
|
||||||
use super::{MutationResult, Mutator};
|
use super::{MutationResult, Mutator};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
corpus::CorpusId,
|
||||||
inputs::{BytesInput, HasBytesVec},
|
inputs::{BytesInput, HasBytesVec},
|
||||||
mutators::scheduled::pybind::PythonStdHavocMutator,
|
mutators::scheduled::pybind::PythonStdHavocMutator,
|
||||||
state::pybind::{PythonStdState, PythonStdStateWrapper},
|
state::pybind::{PythonStdState, PythonStdStateWrapper},
|
||||||
@ -263,13 +265,17 @@ pub mod pybind {
|
|||||||
&mut self,
|
&mut self,
|
||||||
state: &mut PythonStdState,
|
state: &mut PythonStdState,
|
||||||
stage_idx: i32,
|
stage_idx: i32,
|
||||||
corpus_idx: Option<usize>,
|
corpus_idx: Option<CorpusId>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Python::with_gil(|py| -> PyResult<()> {
|
Python::with_gil(|py| -> PyResult<()> {
|
||||||
self.inner.call_method1(
|
self.inner.call_method1(
|
||||||
py,
|
py,
|
||||||
"post_exec",
|
"post_exec",
|
||||||
(PythonStdStateWrapper::wrap(state), stage_idx, corpus_idx),
|
(
|
||||||
|
PythonStdStateWrapper::wrap(state),
|
||||||
|
stage_idx,
|
||||||
|
corpus_idx.map(|x| x.0),
|
||||||
|
),
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
@ -345,7 +351,7 @@ pub mod pybind {
|
|||||||
&mut self,
|
&mut self,
|
||||||
state: &mut PythonStdState,
|
state: &mut PythonStdState,
|
||||||
stage_idx: i32,
|
stage_idx: i32,
|
||||||
corpus_idx: Option<usize>,
|
corpus_idx: Option<CorpusId>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
unwrap_me_mut!(self.wrapper, m, {
|
unwrap_me_mut!(self.wrapper, m, {
|
||||||
m.post_exec(state, stage_idx, corpus_idx)
|
m.post_exec(state, stage_idx, corpus_idx)
|
||||||
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::rands::{Rand, StdRand},
|
bolts::rands::{Rand, StdRand},
|
||||||
corpus::Corpus,
|
corpus::{Corpus, CorpusId},
|
||||||
mutators::{ComposedByMutations, MutationResult, Mutator, MutatorsTuple, ScheduledMutator},
|
mutators::{ComposedByMutations, MutationResult, Mutator, MutatorsTuple, ScheduledMutator},
|
||||||
state::{HasCorpus, HasMetadata, HasRand, HasSolutions},
|
state::{HasCorpus, HasMetadata, HasRand, HasSolutions},
|
||||||
Error,
|
Error,
|
||||||
@ -407,7 +407,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
_stage_idx: i32,
|
_stage_idx: i32,
|
||||||
_corpus_idx: Option<usize>,
|
_corpus_idx: Option<CorpusId>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let before = self.finds_before;
|
let before = self.finds_before;
|
||||||
let after = state.corpus().count() + state.solutions().count();
|
let after = state.corpus().count() + state.solutions().count();
|
||||||
|
@ -11,6 +11,7 @@ use crate::{
|
|||||||
corpus::Corpus,
|
corpus::Corpus,
|
||||||
inputs::{HasBytesVec, UsesInput},
|
inputs::{HasBytesVec, UsesInput},
|
||||||
mutators::{MutationResult, Mutator},
|
mutators::{MutationResult, Mutator},
|
||||||
|
random_corpus_id,
|
||||||
state::{HasCorpus, HasMaxSize, HasRand},
|
state::{HasCorpus, HasMaxSize, HasRand},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -912,8 +913,8 @@ where
|
|||||||
let size = input.bytes().len();
|
let size = input.bytes().len();
|
||||||
|
|
||||||
// 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 count = state.corpus().count();
|
let idx = random_corpus_id!(state.corpus(), state.rand_mut());
|
||||||
let idx = state.rand_mut().below(count as u64) as usize;
|
|
||||||
if let Some(cur) = state.corpus().current() {
|
if let Some(cur) = state.corpus().current() {
|
||||||
if idx == *cur {
|
if idx == *cur {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
@ -990,8 +991,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 count = state.corpus().count();
|
let idx = random_corpus_id!(state.corpus(), state.rand_mut());
|
||||||
let idx = state.rand_mut().below(count as u64) as usize;
|
|
||||||
if let Some(cur) = state.corpus().current() {
|
if let Some(cur) = state.corpus().current() {
|
||||||
if idx == *cur {
|
if idx == *cur {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
@ -1069,8 +1069,7 @@ where
|
|||||||
_stage_idx: i32,
|
_stage_idx: i32,
|
||||||
) -> Result<MutationResult, Error> {
|
) -> Result<MutationResult, Error> {
|
||||||
// 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 count = state.corpus().count();
|
let idx = random_corpus_id!(state.corpus(), state.rand_mut());
|
||||||
let idx = state.rand_mut().below(count as u64) as usize;
|
|
||||||
if let Some(cur) = state.corpus().current() {
|
if let Some(cur) = state.corpus().current() {
|
||||||
if idx == *cur {
|
if idx == *cur {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
|
@ -15,7 +15,7 @@ use crate::{
|
|||||||
tuples::{tuple_list, tuple_list_type, NamedTuple},
|
tuples::{tuple_list, tuple_list_type, NamedTuple},
|
||||||
AsMutSlice, AsSlice,
|
AsMutSlice, AsSlice,
|
||||||
},
|
},
|
||||||
corpus::Corpus,
|
corpus::{Corpus, CorpusId},
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
mutators::{MutationResult, Mutator, MutatorsTuple},
|
mutators::{MutationResult, Mutator, MutatorsTuple},
|
||||||
state::{HasCorpus, HasMetadata, HasRand, State},
|
state::{HasCorpus, HasMetadata, HasRand, State},
|
||||||
@ -321,7 +321,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
_stage_idx: i32,
|
_stage_idx: i32,
|
||||||
corpus_idx: Option<usize>,
|
corpus_idx: Option<CorpusId>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(idx) = corpus_idx {
|
if let Some(idx) = corpus_idx {
|
||||||
let mut testcase = (*state.corpus_mut().get(idx)?).borrow_mut();
|
let mut testcase = (*state.corpus_mut().get(idx)?).borrow_mut();
|
||||||
@ -441,7 +441,9 @@ mod tests {
|
|||||||
.add(Testcase::new(vec![b'd', b'e', b'f'].into()))
|
.add(Testcase::new(vec![b'd', b'e', b'f'].into()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let testcase = corpus.get(0).expect("Corpus did not contain entries");
|
let testcase = corpus
|
||||||
|
.get(corpus.first().unwrap())
|
||||||
|
.expect("Corpus did not contain entries");
|
||||||
let mut input = testcase.borrow_mut().load_input().unwrap().clone();
|
let mut input = testcase.borrow_mut().load_input().unwrap().clone();
|
||||||
|
|
||||||
let mut feedback = ConstFeedback::new(false);
|
let mut feedback = ConstFeedback::new(false);
|
||||||
@ -481,7 +483,9 @@ mod tests {
|
|||||||
.add(Testcase::new(vec![b'd', b'e', b'f'].into()))
|
.add(Testcase::new(vec![b'd', b'e', b'f'].into()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let testcase = corpus.get(0).expect("Corpus did not contain entries");
|
let testcase = corpus
|
||||||
|
.get(corpus.first().unwrap())
|
||||||
|
.expect("Corpus did not contain entries");
|
||||||
let mut input = testcase.borrow_mut().load_input().unwrap().clone();
|
let mut input = testcase.borrow_mut().load_input().unwrap().clone();
|
||||||
let input_prior = input.clone();
|
let input_prior = input.clone();
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{rands::Rand, AsMutSlice, AsSlice, HasLen, HasRefCnt},
|
bolts::{rands::Rand, AsMutSlice, AsSlice, HasLen, HasRefCnt},
|
||||||
corpus::{Corpus, Testcase},
|
corpus::{Corpus, CorpusId, Testcase},
|
||||||
feedbacks::MapIndexesMetadata,
|
feedbacks::MapIndexesMetadata,
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
schedulers::{
|
schedulers::{
|
||||||
@ -74,7 +74,7 @@ impl AccountingIndexesMetadata {
|
|||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct TopAccountingMetadata {
|
pub struct TopAccountingMetadata {
|
||||||
/// map index -> corpus index
|
/// map index -> corpus index
|
||||||
pub map: HashMap<usize, usize>,
|
pub map: HashMap<usize, CorpusId>,
|
||||||
/// If changed sicne the previous add to the corpus
|
/// If changed sicne the previous add to the corpus
|
||||||
pub changed: bool,
|
pub changed: bool,
|
||||||
/// The max accounting seen so far
|
/// The max accounting seen so far
|
||||||
@ -125,7 +125,7 @@ where
|
|||||||
CS::State: HasCorpus + HasMetadata + HasRand + Debug,
|
CS::State: HasCorpus + HasMetadata + HasRand + Debug,
|
||||||
<CS::State as UsesInput>::Input: HasLen,
|
<CS::State as UsesInput>::Input: HasLen,
|
||||||
{
|
{
|
||||||
fn on_add(&self, state: &mut Self::State, idx: usize) -> Result<(), Error> {
|
fn on_add(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
|
||||||
self.update_accounting_score(state, idx)?;
|
self.update_accounting_score(state, idx)?;
|
||||||
self.inner.on_add(state, idx)
|
self.inner.on_add(state, idx)
|
||||||
}
|
}
|
||||||
@ -133,7 +133,7 @@ where
|
|||||||
fn on_replace(
|
fn on_replace(
|
||||||
&self,
|
&self,
|
||||||
state: &mut Self::State,
|
state: &mut Self::State,
|
||||||
idx: usize,
|
idx: CorpusId,
|
||||||
testcase: &Testcase<<Self::State as UsesInput>::Input>,
|
testcase: &Testcase<<Self::State as UsesInput>::Input>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.inner.on_replace(state, idx, testcase)
|
self.inner.on_replace(state, idx, testcase)
|
||||||
@ -142,13 +142,13 @@ where
|
|||||||
fn on_remove(
|
fn on_remove(
|
||||||
&self,
|
&self,
|
||||||
state: &mut Self::State,
|
state: &mut Self::State,
|
||||||
idx: usize,
|
idx: CorpusId,
|
||||||
testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.inner.on_remove(state, idx, testcase)
|
self.inner.on_remove(state, idx, testcase)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
|
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||||
if state
|
if state
|
||||||
.metadata()
|
.metadata()
|
||||||
.get::<TopAccountingMetadata>()
|
.get::<TopAccountingMetadata>()
|
||||||
@ -183,7 +183,11 @@ where
|
|||||||
/// Update the `Corpus` score
|
/// Update the `Corpus` score
|
||||||
#[allow(clippy::unused_self)]
|
#[allow(clippy::unused_self)]
|
||||||
#[allow(clippy::cast_possible_wrap)]
|
#[allow(clippy::cast_possible_wrap)]
|
||||||
pub fn update_accounting_score(&self, state: &mut CS::State, idx: usize) -> Result<(), Error> {
|
pub fn update_accounting_score(
|
||||||
|
&self,
|
||||||
|
state: &mut CS::State,
|
||||||
|
idx: CorpusId,
|
||||||
|
) -> Result<(), Error> {
|
||||||
let mut indexes = vec![];
|
let mut indexes = vec![];
|
||||||
let mut new_favoreds = vec![];
|
let mut new_favoreds = vec![];
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{rands::Rand, serdeany::SerdeAny, AsSlice, HasRefCnt},
|
bolts::{rands::Rand, serdeany::SerdeAny, AsSlice, HasRefCnt},
|
||||||
corpus::{Corpus, Testcase},
|
corpus::{Corpus, CorpusId, Testcase},
|
||||||
feedbacks::MapIndexesMetadata,
|
feedbacks::MapIndexesMetadata,
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
schedulers::{LenTimeMulTestcaseScore, Scheduler, TestcaseScore},
|
schedulers::{LenTimeMulTestcaseScore, Scheduler, TestcaseScore},
|
||||||
@ -30,7 +30,7 @@ crate::impl_serdeany!(IsFavoredMetadata);
|
|||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct TopRatedsMetadata {
|
pub struct TopRatedsMetadata {
|
||||||
/// map index -> corpus index
|
/// map index -> corpus index
|
||||||
pub map: HashMap<usize, usize>,
|
pub map: HashMap<usize, CorpusId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::impl_serdeany!(TopRatedsMetadata);
|
crate::impl_serdeany!(TopRatedsMetadata);
|
||||||
@ -46,7 +46,7 @@ impl TopRatedsMetadata {
|
|||||||
|
|
||||||
/// Getter for map
|
/// Getter for map
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn map(&self) -> &HashMap<usize, usize> {
|
pub fn map(&self) -> &HashMap<usize, CorpusId> {
|
||||||
&self.map
|
&self.map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ where
|
|||||||
CS::State: HasCorpus + HasMetadata + HasRand,
|
CS::State: HasCorpus + HasMetadata + HasRand,
|
||||||
{
|
{
|
||||||
/// Add an entry to the corpus and return its index
|
/// Add an entry to the corpus and return its index
|
||||||
fn on_add(&self, state: &mut CS::State, idx: usize) -> Result<(), Error> {
|
fn on_add(&self, state: &mut CS::State, idx: CorpusId) -> Result<(), Error> {
|
||||||
self.update_score(state, idx)?;
|
self.update_score(state, idx)?;
|
||||||
self.base.on_add(state, idx)
|
self.base.on_add(state, idx)
|
||||||
}
|
}
|
||||||
@ -91,7 +91,7 @@ where
|
|||||||
fn on_replace(
|
fn on_replace(
|
||||||
&self,
|
&self,
|
||||||
state: &mut CS::State,
|
state: &mut CS::State,
|
||||||
idx: usize,
|
idx: CorpusId,
|
||||||
testcase: &Testcase<<CS::State as UsesInput>::Input>,
|
testcase: &Testcase<<CS::State as UsesInput>::Input>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.update_score(state, idx)?;
|
self.update_score(state, idx)?;
|
||||||
@ -102,7 +102,7 @@ where
|
|||||||
fn on_remove(
|
fn on_remove(
|
||||||
&self,
|
&self,
|
||||||
state: &mut CS::State,
|
state: &mut CS::State,
|
||||||
idx: usize,
|
idx: CorpusId,
|
||||||
testcase: &Option<Testcase<<CS::State as UsesInput>::Input>>,
|
testcase: &Option<Testcase<<CS::State as UsesInput>::Input>>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.base.on_remove(state, idx, testcase)?;
|
self.base.on_remove(state, idx, testcase)?;
|
||||||
@ -112,19 +112,13 @@ where
|
|||||||
.drain_filter(|_, other_idx| *other_idx == idx)
|
.drain_filter(|_, other_idx| *other_idx == idx)
|
||||||
.map(|(entry, _)| entry)
|
.map(|(entry, _)| entry)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
meta.map
|
|
||||||
.values_mut()
|
|
||||||
.filter(|other_idx| **other_idx > idx)
|
|
||||||
.for_each(|other_idx| {
|
|
||||||
*other_idx -= 1;
|
|
||||||
});
|
|
||||||
entries
|
entries
|
||||||
} else {
|
} else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
entries.sort_unstable(); // this should already be sorted, but just in case
|
entries.sort_unstable(); // this should already be sorted, but just in case
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
for i in 0..state.corpus().count() {
|
for i in state.corpus().ids() {
|
||||||
let mut old = state.corpus().get(i)?.borrow_mut();
|
let mut old = state.corpus().get(i)?.borrow_mut();
|
||||||
let factor = F::compute(&mut *old, state)?;
|
let factor = F::compute(&mut *old, state)?;
|
||||||
if let Some(old_map) = old.metadata_mut().get_mut::<M>() {
|
if let Some(old_map) = old.metadata_mut().get_mut::<M>() {
|
||||||
@ -169,7 +163,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the next entry
|
/// Gets the next entry
|
||||||
fn next(&self, state: &mut CS::State) -> Result<usize, Error> {
|
fn next(&self, state: &mut CS::State) -> Result<CorpusId, Error> {
|
||||||
self.cull(state)?;
|
self.cull(state)?;
|
||||||
let mut idx = self.base.next(state)?;
|
let mut idx = self.base.next(state)?;
|
||||||
while {
|
while {
|
||||||
@ -197,7 +191,7 @@ where
|
|||||||
/// Update the `Corpus` score using the `MinimizerScheduler`
|
/// Update the `Corpus` score using the `MinimizerScheduler`
|
||||||
#[allow(clippy::unused_self)]
|
#[allow(clippy::unused_self)]
|
||||||
#[allow(clippy::cast_possible_wrap)]
|
#[allow(clippy::cast_possible_wrap)]
|
||||||
pub fn update_score(&self, state: &mut CS::State, idx: usize) -> Result<(), Error> {
|
pub fn update_score(&self, state: &mut CS::State, idx: CorpusId) -> Result<(), Error> {
|
||||||
// Create a new top rated meta if not existing
|
// Create a new top rated meta if not existing
|
||||||
if state.metadata().get::<TopRatedsMetadata>().is_none() {
|
if state.metadata().get::<TopRatedsMetadata>().is_none() {
|
||||||
state.add_metadata(TopRatedsMetadata::new());
|
state.add_metadata(TopRatedsMetadata::new());
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
//! Schedule the access to the Corpus.
|
//! Schedule the access to the Corpus.
|
||||||
|
|
||||||
pub mod queue;
|
use alloc::borrow::ToOwned;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
pub mod testcase_score;
|
||||||
|
pub use testcase_score::{LenTimeMulTestcaseScore, TestcaseScore};
|
||||||
|
|
||||||
|
pub mod queue;
|
||||||
pub use queue::QueueScheduler;
|
pub use queue::QueueScheduler;
|
||||||
|
|
||||||
|
pub mod minimizer;
|
||||||
|
pub use minimizer::{
|
||||||
|
IndexesLenTimeMinimizerScheduler, LenTimeMinimizerScheduler, MinimizerScheduler,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod powersched;
|
||||||
|
pub use powersched::PowerQueueScheduler;
|
||||||
|
|
||||||
pub mod probabilistic_sampling;
|
pub mod probabilistic_sampling;
|
||||||
pub use probabilistic_sampling::ProbabilitySamplingScheduler;
|
pub use probabilistic_sampling::ProbabilitySamplingScheduler;
|
||||||
|
|
||||||
pub mod accounting;
|
pub mod accounting;
|
||||||
pub use accounting::CoverageAccountingScheduler;
|
pub use accounting::CoverageAccountingScheduler;
|
||||||
|
|
||||||
pub mod testcase_score;
|
|
||||||
pub use testcase_score::{LenTimeMulTestcaseScore, TestcaseScore};
|
|
||||||
|
|
||||||
pub mod minimizer;
|
|
||||||
pub use minimizer::{
|
|
||||||
IndexesLenTimeMinimizerScheduler, LenTimeMinimizerScheduler, MinimizerScheduler,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub mod weighted;
|
pub mod weighted;
|
||||||
pub use weighted::{StdWeightedScheduler, WeightedScheduler};
|
pub use weighted::{StdWeightedScheduler, WeightedScheduler};
|
||||||
|
|
||||||
pub mod powersched;
|
|
||||||
use alloc::borrow::ToOwned;
|
|
||||||
|
|
||||||
pub use powersched::PowerQueueScheduler;
|
|
||||||
|
|
||||||
pub mod tuneable;
|
pub mod tuneable;
|
||||||
pub use tuneable::*;
|
pub use tuneable::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::rands::Rand,
|
bolts::rands::Rand,
|
||||||
corpus::{Corpus, Testcase},
|
corpus::{Corpus, CorpusId, Testcase},
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
|
random_corpus_id,
|
||||||
state::{HasCorpus, HasRand, UsesState},
|
state::{HasCorpus, HasRand, UsesState},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -42,7 +42,7 @@ use crate::{
|
|||||||
/// It has hooks to corpus add/replace/remove to allow complex scheduling algorithms to collect data.
|
/// It has hooks to corpus add/replace/remove to allow complex scheduling algorithms to collect data.
|
||||||
pub trait Scheduler: UsesState {
|
pub trait Scheduler: UsesState {
|
||||||
/// Added an entry to the corpus at the given index
|
/// Added an entry to the corpus at the given index
|
||||||
fn on_add(&self, _state: &mut Self::State, _idx: usize) -> Result<(), Error> {
|
fn on_add(&self, _state: &mut Self::State, _idx: CorpusId) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ pub trait Scheduler: UsesState {
|
|||||||
fn on_replace(
|
fn on_replace(
|
||||||
&self,
|
&self,
|
||||||
_state: &mut Self::State,
|
_state: &mut Self::State,
|
||||||
_idx: usize,
|
_idx: CorpusId,
|
||||||
_prev: &Testcase<<Self::State as UsesInput>::Input>,
|
_prev: &Testcase<<Self::State as UsesInput>::Input>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -60,14 +60,14 @@ pub trait Scheduler: UsesState {
|
|||||||
fn on_remove(
|
fn on_remove(
|
||||||
&self,
|
&self,
|
||||||
_state: &mut Self::State,
|
_state: &mut Self::State,
|
||||||
_idx: usize,
|
_idx: CorpusId,
|
||||||
_testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
_testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the next entry
|
/// Gets the next entry
|
||||||
fn next(&self, state: &mut Self::State) -> Result<usize, Error>;
|
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Feed the fuzzer simply with a random testcase on request
|
/// Feed the fuzzer simply with a random testcase on request
|
||||||
@ -88,12 +88,11 @@ where
|
|||||||
S: HasCorpus + HasRand,
|
S: HasCorpus + HasRand,
|
||||||
{
|
{
|
||||||
/// Gets the next entry at random
|
/// Gets the next entry at random
|
||||||
fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
|
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||||
if state.corpus().count() == 0 {
|
if state.corpus().count() == 0 {
|
||||||
Err(Error::empty("No entries in corpus".to_owned()))
|
Err(Error::empty("No entries in corpus".to_owned()))
|
||||||
} else {
|
} else {
|
||||||
let len = state.corpus().count();
|
let id = random_corpus_id!(state.corpus(), state.rand_mut());
|
||||||
let id = state.rand_mut().below(len as u64) as usize;
|
|
||||||
*state.corpus_mut().current_mut() = Some(id);
|
*state.corpus_mut().current_mut() = Some(id);
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ use core::{marker::PhantomData, time::Duration};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, SchedulerTestcaseMetaData},
|
corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData},
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
schedulers::Scheduler,
|
schedulers::Scheduler,
|
||||||
state::{HasCorpus, HasMetadata, UsesState},
|
state::{HasCorpus, HasMetadata, UsesState},
|
||||||
@ -180,7 +180,7 @@ where
|
|||||||
S: HasCorpus + HasMetadata,
|
S: HasCorpus + HasMetadata,
|
||||||
{
|
{
|
||||||
/// Add an entry to the corpus and return its index
|
/// Add an entry to the corpus and return its index
|
||||||
fn on_add(&self, state: &mut Self::State, idx: usize) -> Result<(), Error> {
|
fn on_add(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
|
||||||
if !state.has_metadata::<SchedulerMetadata>() {
|
if !state.has_metadata::<SchedulerMetadata>() {
|
||||||
state.add_metadata::<SchedulerMetadata>(SchedulerMetadata::new(Some(self.strat)));
|
state.add_metadata::<SchedulerMetadata>(SchedulerMetadata::new(Some(self.strat)));
|
||||||
}
|
}
|
||||||
@ -211,13 +211,15 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
|
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||||
if state.corpus().count() == 0 {
|
if state.corpus().count() == 0 {
|
||||||
Err(Error::empty(String::from("No entries in corpus")))
|
Err(Error::empty(String::from("No entries in corpus")))
|
||||||
} else {
|
} else {
|
||||||
let id = match state.corpus().current() {
|
let id = match state.corpus().current() {
|
||||||
Some(cur) => {
|
Some(cur) => {
|
||||||
if *cur + 1 >= state.corpus().count() {
|
if let Some(next) = state.corpus().next(*cur) {
|
||||||
|
next
|
||||||
|
} else {
|
||||||
let psmeta = state
|
let psmeta = state
|
||||||
.metadata_mut()
|
.metadata_mut()
|
||||||
.get_mut::<SchedulerMetadata>()
|
.get_mut::<SchedulerMetadata>()
|
||||||
@ -225,12 +227,10 @@ where
|
|||||||
Error::key_not_found("SchedulerMetadata not found".to_string())
|
Error::key_not_found("SchedulerMetadata not found".to_string())
|
||||||
})?;
|
})?;
|
||||||
psmeta.set_queue_cycles(psmeta.queue_cycles() + 1);
|
psmeta.set_queue_cycles(psmeta.queue_cycles() + 1);
|
||||||
0
|
state.corpus().first().unwrap()
|
||||||
} else {
|
|
||||||
*cur + 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => 0,
|
None => state.corpus().first().unwrap(),
|
||||||
};
|
};
|
||||||
*state.corpus_mut().current_mut() = Some(id);
|
*state.corpus_mut().current_mut() = Some(id);
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::rands::Rand,
|
bolts::rands::Rand,
|
||||||
corpus::Corpus,
|
corpus::{Corpus, CorpusId},
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
schedulers::{Scheduler, TestcaseScore},
|
schedulers::{Scheduler, TestcaseScore},
|
||||||
state::{HasCorpus, HasMetadata, HasRand, UsesState},
|
state::{HasCorpus, HasMetadata, HasRand, UsesState},
|
||||||
@ -29,7 +29,7 @@ where
|
|||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct ProbabilityMetadata {
|
pub struct ProbabilityMetadata {
|
||||||
/// corpus index -> probability
|
/// corpus index -> probability
|
||||||
pub map: HashMap<usize, f64>,
|
pub map: HashMap<CorpusId, f64>,
|
||||||
/// total probability of all items in the map
|
/// total probability of all items in the map
|
||||||
pub total_probability: f64,
|
pub total_probability: f64,
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ where
|
|||||||
/// Calculate the score and store in `ProbabilityMetadata`
|
/// Calculate the score and store in `ProbabilityMetadata`
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
#[allow(clippy::unused_self)]
|
#[allow(clippy::unused_self)]
|
||||||
pub fn store_probability(&self, state: &mut S, idx: usize) -> Result<(), Error> {
|
pub fn store_probability(&self, state: &mut S, idx: CorpusId) -> Result<(), Error> {
|
||||||
let factor = F::compute(&mut *state.corpus().get(idx)?.borrow_mut(), state)?;
|
let factor = F::compute(&mut *state.corpus().get(idx)?.borrow_mut(), state)?;
|
||||||
if factor == 0.0 {
|
if factor == 0.0 {
|
||||||
return Err(Error::illegal_state(
|
return Err(Error::illegal_state(
|
||||||
@ -99,7 +99,7 @@ where
|
|||||||
F: TestcaseScore<S>,
|
F: TestcaseScore<S>,
|
||||||
S: HasCorpus + HasMetadata + HasRand,
|
S: HasCorpus + HasMetadata + HasRand,
|
||||||
{
|
{
|
||||||
fn on_add(&self, state: &mut Self::State, idx: usize) -> Result<(), Error> {
|
fn on_add(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
|
||||||
if state.metadata().get::<ProbabilityMetadata>().is_none() {
|
if state.metadata().get::<ProbabilityMetadata>().is_none() {
|
||||||
state.add_metadata(ProbabilityMetadata::new());
|
state.add_metadata(ProbabilityMetadata::new());
|
||||||
}
|
}
|
||||||
@ -108,7 +108,7 @@ where
|
|||||||
|
|
||||||
/// Gets the next entry
|
/// Gets the next entry
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
|
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||||
if state.corpus().count() == 0 {
|
if state.corpus().count() == 0 {
|
||||||
Err(Error::empty(String::from("No entries in corpus")))
|
Err(Error::empty(String::from("No entries in corpus")))
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,7 +4,7 @@ use alloc::borrow::ToOwned;
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
corpus::{Corpus, CorpusId},
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
schedulers::Scheduler,
|
schedulers::Scheduler,
|
||||||
state::{HasCorpus, UsesState},
|
state::{HasCorpus, UsesState},
|
||||||
@ -29,20 +29,16 @@ where
|
|||||||
S: HasCorpus,
|
S: HasCorpus,
|
||||||
{
|
{
|
||||||
/// Gets the next entry in the queue
|
/// Gets the next entry in the queue
|
||||||
fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
|
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||||
if state.corpus().count() == 0 {
|
if state.corpus().count() == 0 {
|
||||||
Err(Error::empty("No entries in corpus".to_owned()))
|
Err(Error::empty("No entries in corpus".to_owned()))
|
||||||
} else {
|
} else {
|
||||||
let id = match state.corpus().current() {
|
let id = state
|
||||||
Some(cur) => {
|
.corpus()
|
||||||
if *cur + 1 >= state.corpus().count() {
|
.current()
|
||||||
0
|
.map(|id| state.corpus().next(id))
|
||||||
} else {
|
.flatten()
|
||||||
*cur + 1
|
.unwrap_or_else(|| state.corpus().first().unwrap());
|
||||||
}
|
|
||||||
}
|
|
||||||
None => 0,
|
|
||||||
};
|
|
||||||
*state.corpus_mut().current_mut() = Some(id);
|
*state.corpus_mut().current_mut() = Some(id);
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ where
|
|||||||
let mut n_paths = 0;
|
let mut n_paths = 0;
|
||||||
let mut v = 0.0;
|
let mut v = 0.0;
|
||||||
let cur_index = state.corpus().current().unwrap();
|
let cur_index = state.corpus().current().unwrap();
|
||||||
for idx in 0..corpus.count() {
|
for idx in corpus.ids() {
|
||||||
let n_fuzz_entry = if cur_index == idx {
|
let n_fuzz_entry = if cur_index == idx {
|
||||||
entry
|
entry
|
||||||
.metadata()
|
.metadata()
|
||||||
|
@ -8,7 +8,7 @@ use core::marker::PhantomData;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
corpus::{Corpus, CorpusId},
|
||||||
impl_serdeany,
|
impl_serdeany,
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
schedulers::Scheduler,
|
schedulers::Scheduler,
|
||||||
@ -18,7 +18,7 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(Default, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Default, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
struct TuneableSchedulerMetadata {
|
struct TuneableSchedulerMetadata {
|
||||||
next: Option<usize>,
|
next: Option<CorpusId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_serdeany!(TuneableSchedulerMetadata);
|
impl_serdeany!(TuneableSchedulerMetadata);
|
||||||
@ -57,12 +57,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the next corpus id to be used
|
/// Sets the next corpus id to be used
|
||||||
pub fn set_next(state: &mut S, next: usize) {
|
pub fn set_next(state: &mut S, next: CorpusId) {
|
||||||
Self::metadata_mut(state).next = Some(next);
|
Self::metadata_mut(state).next = Some(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the next set corpus id
|
/// Gets the next set corpus id
|
||||||
pub fn get_next(state: &S) -> Option<usize> {
|
pub fn get_next(state: &S) -> Option<CorpusId> {
|
||||||
Self::metadata(state).next
|
Self::metadata(state).next
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,8 +73,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the current corpus entry id
|
/// Gets the current corpus entry id
|
||||||
pub fn get_current(state: &S) -> usize {
|
pub fn get_current(state: &S) -> CorpusId {
|
||||||
state.corpus().current().unwrap_or_default()
|
state
|
||||||
|
.corpus()
|
||||||
|
.current()
|
||||||
|
.unwrap_or_else(|| state.corpus().first().expect("Empty corpus"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,17 +93,17 @@ where
|
|||||||
S: HasCorpus + HasMetadata,
|
S: HasCorpus + HasMetadata,
|
||||||
{
|
{
|
||||||
/// Gets the next entry in the queue
|
/// Gets the next entry in the queue
|
||||||
fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
|
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||||
if state.corpus().count() == 0 {
|
if state.corpus().count() == 0 {
|
||||||
return Err(Error::empty("No entries in corpus".to_owned()));
|
return Err(Error::empty("No entries in corpus".to_owned()));
|
||||||
}
|
}
|
||||||
let id = if let Some(next) = Self::get_next(state) {
|
let id = if let Some(next) = Self::get_next(state) {
|
||||||
// next was set
|
// next was set
|
||||||
next
|
next
|
||||||
} else if Self::get_current(state) + 1 >= state.corpus().count() {
|
} else if let Some(next) = state.corpus().next(Self::get_current(state)) {
|
||||||
0
|
next
|
||||||
} else {
|
} else {
|
||||||
Self::get_current(state) + 1
|
state.corpus().first().unwrap()
|
||||||
};
|
};
|
||||||
*state.corpus_mut().current_mut() = Some(id);
|
*state.corpus_mut().current_mut() = Some(id);
|
||||||
Ok(id)
|
Ok(id)
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
//! The queue corpus scheduler with weighted queue item selection from aflpp (`https://github.com/AFLplusplus/AFLplusplus/blob/1d4f1e48797c064ee71441ba555b29fc3f467983/src/afl-fuzz-queue.c#L32`)
|
//! The queue corpus scheduler with weighted queue item selection from aflpp (`https://github.com/AFLplusplus/AFLplusplus/blob/1d4f1e48797c064ee71441ba555b29fc3f467983/src/afl-fuzz-queue.c#L32`)
|
||||||
//! This queue corpus scheduler needs calibration stage.
|
//! This queue corpus scheduler needs calibration stage.
|
||||||
|
|
||||||
use alloc::{
|
use alloc::string::{String, ToString};
|
||||||
string::{String, ToString},
|
|
||||||
vec::Vec,
|
|
||||||
};
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use hashbrown::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::rands::Rand,
|
bolts::rands::Rand,
|
||||||
corpus::{Corpus, SchedulerTestcaseMetaData, Testcase},
|
corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData, Testcase},
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
|
random_corpus_id,
|
||||||
schedulers::{
|
schedulers::{
|
||||||
powersched::{PowerSchedule, SchedulerMetadata},
|
powersched::{PowerSchedule, SchedulerMetadata},
|
||||||
testcase_score::{CorpusWeightTestcaseScore, TestcaseScore},
|
testcase_score::{CorpusWeightTestcaseScore, TestcaseScore},
|
||||||
@ -29,9 +28,9 @@ pub struct WeightedScheduleMetadata {
|
|||||||
/// The fuzzer execution spent in the current cycles
|
/// The fuzzer execution spent in the current cycles
|
||||||
runs_in_current_cycle: usize,
|
runs_in_current_cycle: usize,
|
||||||
/// Alias table for weighted queue entry selection
|
/// Alias table for weighted queue entry selection
|
||||||
alias_table: Vec<usize>,
|
alias_table: HashMap<CorpusId, CorpusId>,
|
||||||
/// Probability for which queue entry is selected
|
/// Probability for which queue entry is selected
|
||||||
alias_probability: Vec<f64>,
|
alias_probability: HashMap<CorpusId, f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WeightedScheduleMetadata {
|
impl Default for WeightedScheduleMetadata {
|
||||||
@ -46,8 +45,8 @@ impl WeightedScheduleMetadata {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
runs_in_current_cycle: 0,
|
runs_in_current_cycle: 0,
|
||||||
alias_table: vec![0],
|
alias_table: HashMap::default(),
|
||||||
alias_probability: vec![0.0],
|
alias_probability: HashMap::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,23 +63,23 @@ impl WeightedScheduleMetadata {
|
|||||||
|
|
||||||
/// The getter for `alias_table`
|
/// The getter for `alias_table`
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn alias_table(&self) -> &[usize] {
|
pub fn alias_table(&self) -> &HashMap<CorpusId, CorpusId> {
|
||||||
&self.alias_table
|
&self.alias_table
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The setter for `alias_table`
|
/// The setter for `alias_table`
|
||||||
pub fn set_alias_table(&mut self, table: Vec<usize>) {
|
pub fn set_alias_table(&mut self, table: HashMap<CorpusId, CorpusId>) {
|
||||||
self.alias_table = table;
|
self.alias_table = table;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The getter for `alias_probability`
|
/// The getter for `alias_probability`
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn alias_probability(&self) -> &[f64] {
|
pub fn alias_probability(&self) -> &HashMap<CorpusId, f64> {
|
||||||
&self.alias_probability
|
&self.alias_probability
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The setter for `alias_probability`
|
/// The setter for `alias_probability`
|
||||||
pub fn set_alias_probability(&mut self, probability: Vec<f64>) {
|
pub fn set_alias_probability(&mut self, probability: HashMap<CorpusId, f64>) {
|
||||||
self.alias_probability = probability;
|
self.alias_probability = probability;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,25 +136,25 @@ where
|
|||||||
pub fn create_alias_table(&self, state: &mut S) -> Result<(), Error> {
|
pub fn create_alias_table(&self, state: &mut S) -> Result<(), Error> {
|
||||||
let n = state.corpus().count();
|
let n = state.corpus().count();
|
||||||
|
|
||||||
let mut alias_table: Vec<usize> = vec![0; n];
|
let mut alias_table: HashMap<CorpusId, CorpusId> = HashMap::default();
|
||||||
let mut alias_probability: Vec<f64> = vec![0.0; n];
|
let mut alias_probability: HashMap<CorpusId, f64> = HashMap::default();
|
||||||
let mut weights: Vec<f64> = vec![0.0; n];
|
let mut weights: HashMap<CorpusId, f64> = HashMap::default();
|
||||||
|
|
||||||
let mut p_arr: Vec<f64> = vec![0.0; n];
|
let mut p_arr: HashMap<CorpusId, f64> = HashMap::default();
|
||||||
let mut s_arr: Vec<usize> = vec![0; n];
|
let mut s_arr: HashMap<usize, CorpusId> = HashMap::default();
|
||||||
let mut l_arr: Vec<usize> = vec![0; n];
|
let mut l_arr: HashMap<usize, CorpusId> = HashMap::default();
|
||||||
|
|
||||||
let mut sum: f64 = 0.0;
|
let mut sum: f64 = 0.0;
|
||||||
|
|
||||||
for (i, item) in weights.iter_mut().enumerate().take(n) {
|
for i in state.corpus().ids() {
|
||||||
let mut testcase = state.corpus().get(i)?.borrow_mut();
|
let mut testcase = state.corpus().get(i)?.borrow_mut();
|
||||||
let weight = F::compute(&mut *testcase, state)?;
|
let weight = F::compute(&mut *testcase, state)?;
|
||||||
*item = weight;
|
weights.insert(i, weight);
|
||||||
sum += weight;
|
sum += weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..n {
|
for (i, w) in weights.iter() {
|
||||||
p_arr[i] = weights[i] * (n as f64) / sum;
|
p_arr.insert(*i, w * (n as f64) / sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
// # of items in queue S
|
// # of items in queue S
|
||||||
@ -164,12 +163,12 @@ where
|
|||||||
// # of items in queue L
|
// # of items in queue L
|
||||||
let mut n_l = 0;
|
let mut n_l = 0;
|
||||||
// Divide P into two queues, S and L
|
// Divide P into two queues, S and L
|
||||||
for s in (0..n).rev() {
|
for s in state.corpus().ids().rev() {
|
||||||
if p_arr[s] < 1.0 {
|
if *p_arr.get(&s).unwrap() < 1.0 {
|
||||||
s_arr[n_s] = s;
|
s_arr.insert(n_s, s);
|
||||||
n_s += 1;
|
n_s += 1;
|
||||||
} else {
|
} else {
|
||||||
l_arr[n_l] = s;
|
l_arr.insert(n_l, s);
|
||||||
n_l += 1;
|
n_l += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,30 +176,30 @@ where
|
|||||||
while n_s > 0 && n_l > 0 {
|
while n_s > 0 && n_l > 0 {
|
||||||
n_s -= 1;
|
n_s -= 1;
|
||||||
n_l -= 1;
|
n_l -= 1;
|
||||||
let a = s_arr[n_s];
|
let a = *s_arr.get(&n_s).unwrap();
|
||||||
let g = l_arr[n_l];
|
let g = *l_arr.get(&n_l).unwrap();
|
||||||
|
|
||||||
alias_probability[a] = p_arr[a];
|
alias_probability.insert(a, *p_arr.get(&a).unwrap());
|
||||||
alias_table[a] = g;
|
alias_table.insert(a, g);
|
||||||
p_arr[g] = p_arr[g] + p_arr[a] - 1.0;
|
*p_arr.get_mut(&g).unwrap() += p_arr.get(&a).unwrap() - 1.0;
|
||||||
|
|
||||||
if p_arr[g] < 1.0 {
|
if *p_arr.get(&g).unwrap() < 1.0 {
|
||||||
s_arr[n_s] = g;
|
*s_arr.get_mut(&n_s).unwrap() = g;
|
||||||
n_s += 1;
|
n_s += 1;
|
||||||
} else {
|
} else {
|
||||||
l_arr[n_l] = g;
|
*l_arr.get_mut(&n_l).unwrap() = g;
|
||||||
n_l += 1;
|
n_l += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while n_l > 0 {
|
while n_l > 0 {
|
||||||
n_l -= 1;
|
n_l -= 1;
|
||||||
alias_probability[l_arr[n_l]] = 1.0;
|
alias_probability.insert(*l_arr.get(&n_l).unwrap(), 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
while n_s > 0 {
|
while n_s > 0 {
|
||||||
n_s -= 1;
|
n_s -= 1;
|
||||||
alias_probability[s_arr[n_s]] = 1.0;
|
alias_probability.insert(*s_arr.get(&n_s).unwrap(), 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let wsmeta = state
|
let wsmeta = state
|
||||||
@ -230,7 +229,7 @@ where
|
|||||||
S: HasCorpus + HasMetadata + HasRand,
|
S: HasCorpus + HasMetadata + HasRand,
|
||||||
{
|
{
|
||||||
/// Add an entry to the corpus and return its index
|
/// Add an entry to the corpus and return its index
|
||||||
fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> {
|
fn on_add(&self, state: &mut S, idx: CorpusId) -> Result<(), Error> {
|
||||||
if !state.has_metadata::<SchedulerMetadata>() {
|
if !state.has_metadata::<SchedulerMetadata>() {
|
||||||
state.add_metadata(SchedulerMetadata::new(self.strat));
|
state.add_metadata(SchedulerMetadata::new(self.strat));
|
||||||
}
|
}
|
||||||
@ -271,7 +270,7 @@ where
|
|||||||
fn on_replace(
|
fn on_replace(
|
||||||
&self,
|
&self,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
idx: usize,
|
idx: CorpusId,
|
||||||
_testcase: &Testcase<S::Input>,
|
_testcase: &Testcase<S::Input>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Recreate the alias table
|
// Recreate the alias table
|
||||||
@ -281,7 +280,7 @@ where
|
|||||||
fn on_remove(
|
fn on_remove(
|
||||||
&self,
|
&self,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
_idx: usize,
|
_idx: CorpusId,
|
||||||
_testcase: &Option<Testcase<S::Input>>,
|
_testcase: &Option<Testcase<S::Input>>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Recreate the alias table
|
// Recreate the alias table
|
||||||
@ -290,12 +289,13 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::similar_names, clippy::cast_precision_loss)]
|
#[allow(clippy::similar_names, clippy::cast_precision_loss)]
|
||||||
fn next(&self, state: &mut S) -> Result<usize, Error> {
|
fn next(&self, state: &mut S) -> Result<CorpusId, Error> {
|
||||||
if state.corpus().count() == 0 {
|
let corpus_counts = state.corpus().count();
|
||||||
|
if corpus_counts == 0 {
|
||||||
Err(Error::empty(String::from("No entries in corpus")))
|
Err(Error::empty(String::from("No entries in corpus")))
|
||||||
} else {
|
} else {
|
||||||
let corpus_counts = state.corpus().count();
|
let s = random_corpus_id!(state.corpus(), state.rand_mut());
|
||||||
let s = state.rand_mut().below(corpus_counts as u64) as usize;
|
|
||||||
// Choose a random value between 0.000000000 and 1.000000000
|
// Choose a random value between 0.000000000 and 1.000000000
|
||||||
let probability = state.rand_mut().between(0, 1000000000) as f64 / 1000000000_f64;
|
let probability = state.rand_mut().between(0, 1000000000) as f64 / 1000000000_f64;
|
||||||
|
|
||||||
@ -308,16 +308,17 @@ where
|
|||||||
|
|
||||||
let current_cycles = wsmeta.runs_in_current_cycle();
|
let current_cycles = wsmeta.runs_in_current_cycle();
|
||||||
|
|
||||||
|
// TODO deal with corpus_counts decreasing due to removals
|
||||||
if current_cycles >= corpus_counts {
|
if current_cycles >= corpus_counts {
|
||||||
wsmeta.set_runs_current_cycle(0);
|
wsmeta.set_runs_current_cycle(0);
|
||||||
} else {
|
} else {
|
||||||
wsmeta.set_runs_current_cycle(current_cycles + 1);
|
wsmeta.set_runs_current_cycle(current_cycles + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let idx = if probability < wsmeta.alias_probability()[s] {
|
let idx = if probability < *wsmeta.alias_probability().get(&s).unwrap() {
|
||||||
s
|
s
|
||||||
} else {
|
} else {
|
||||||
wsmeta.alias_table()[s]
|
*wsmeta.alias_table().get(&s).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update depth
|
// Update depth
|
||||||
|
@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{current_time, tuples::Named, AsIter},
|
bolts::{current_time, tuples::Named, AsIter},
|
||||||
corpus::{Corpus, SchedulerTestcaseMetaData},
|
corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData},
|
||||||
events::{EventFirer, LogSeverity},
|
events::{EventFirer, LogSeverity},
|
||||||
executors::{Executor, ExitKind, HasObservers},
|
executors::{Executor, ExitKind, HasObservers},
|
||||||
feedbacks::{
|
feedbacks::{
|
||||||
@ -103,7 +103,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut E::State,
|
state: &mut E::State,
|
||||||
mgr: &mut EM,
|
mgr: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Run this stage only once for each corpus entry
|
// Run this stage only once for each corpus entry
|
||||||
if state.corpus().get(corpus_idx)?.borrow_mut().fuzz_level() > 0 {
|
if state.corpus().get(corpus_idx)?.borrow_mut().fuzz_level() > 0 {
|
||||||
|
@ -9,7 +9,7 @@ use core::marker::PhantomData;
|
|||||||
|
|
||||||
use super::{Stage, TracingStage};
|
use super::{Stage, TracingStage};
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
corpus::{Corpus, CorpusId},
|
||||||
executors::{Executor, HasObservers},
|
executors::{Executor, HasObservers},
|
||||||
observers::concolic::ConcolicObserver,
|
observers::concolic::ConcolicObserver,
|
||||||
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata},
|
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata},
|
||||||
@ -45,7 +45,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut TE::State,
|
state: &mut TE::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.inner
|
self.inner
|
||||||
.perform(fuzzer, executor, state, manager, corpus_idx)?;
|
.perform(fuzzer, executor, state, manager, corpus_idx)?;
|
||||||
@ -361,7 +361,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Z::State,
|
state: &mut Z::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
let testcase = state.corpus().get(corpus_idx)?.clone();
|
let testcase = state.corpus().get(corpus_idx)?.clone();
|
||||||
|
@ -7,7 +7,7 @@ use std::{fs, fs::File, io::Write, path::PathBuf};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
corpus::{Corpus, CorpusId},
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
stages::Stage,
|
stages::Stage,
|
||||||
state::{HasCorpus, HasMetadata, HasRand, HasSolutions, UsesState},
|
state::{HasCorpus, HasMetadata, HasRand, HasSolutions, UsesState},
|
||||||
@ -17,8 +17,8 @@ use crate::{
|
|||||||
/// Metadata used to store information about disk dump indexes for names
|
/// Metadata used to store information about disk dump indexes for names
|
||||||
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct DumpToDiskMetadata {
|
pub struct DumpToDiskMetadata {
|
||||||
last_corpus: usize,
|
last_corpus: Option<CorpusId>,
|
||||||
last_solution: usize,
|
last_solution: Option<CorpusId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::impl_serdeany!(DumpToDiskMetadata);
|
crate::impl_serdeany!(DumpToDiskMetadata);
|
||||||
@ -54,17 +54,19 @@ where
|
|||||||
_executor: &mut E,
|
_executor: &mut E,
|
||||||
state: &mut Z::State,
|
state: &mut Z::State,
|
||||||
_manager: &mut EM,
|
_manager: &mut EM,
|
||||||
_corpus_idx: usize,
|
_corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let meta = state
|
let (mut corpus_idx, mut solutions_idx) =
|
||||||
.metadata()
|
if let Some(meta) = state.metadata().get::<DumpToDiskMetadata>() {
|
||||||
.get::<DumpToDiskMetadata>()
|
(
|
||||||
.map_or_else(DumpToDiskMetadata::default, Clone::clone);
|
meta.last_corpus.and_then(|x| state.corpus().next(x)),
|
||||||
|
meta.last_solution.and_then(|x| state.solutions().next(x)),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(state.corpus().first(), state.solutions().first())
|
||||||
|
};
|
||||||
|
|
||||||
let corpus_count = state.corpus().count();
|
while let Some(i) = corpus_idx {
|
||||||
let solutions_count = state.solutions().count();
|
|
||||||
|
|
||||||
for i in meta.last_corpus..corpus_count {
|
|
||||||
let mut testcase = state.corpus().get(i)?.borrow_mut();
|
let mut testcase = state.corpus().get(i)?.borrow_mut();
|
||||||
let input = testcase.load_input()?;
|
let input = testcase.load_input()?;
|
||||||
let bytes = (self.to_bytes)(input);
|
let bytes = (self.to_bytes)(input);
|
||||||
@ -72,9 +74,11 @@ where
|
|||||||
let fname = self.corpus_dir.join(format!("id_{i}"));
|
let fname = self.corpus_dir.join(format!("id_{i}"));
|
||||||
let mut f = File::create(fname)?;
|
let mut f = File::create(fname)?;
|
||||||
drop(f.write_all(&bytes));
|
drop(f.write_all(&bytes));
|
||||||
|
|
||||||
|
corpus_idx = state.corpus().next(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in meta.last_solution..solutions_count {
|
while let Some(i) = solutions_idx {
|
||||||
let mut testcase = state.solutions().get(i)?.borrow_mut();
|
let mut testcase = state.solutions().get(i)?.borrow_mut();
|
||||||
let input = testcase.load_input()?;
|
let input = testcase.load_input()?;
|
||||||
let bytes = (self.to_bytes)(input);
|
let bytes = (self.to_bytes)(input);
|
||||||
@ -82,11 +86,13 @@ where
|
|||||||
let fname = self.solutions_dir.join(format!("id_{i}"));
|
let fname = self.solutions_dir.join(format!("id_{i}"));
|
||||||
let mut f = File::create(fname)?;
|
let mut f = File::create(fname)?;
|
||||||
drop(f.write_all(&bytes));
|
drop(f.write_all(&bytes));
|
||||||
|
|
||||||
|
solutions_idx = state.solutions().next(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.add_metadata(DumpToDiskMetadata {
|
state.add_metadata(DumpToDiskMetadata {
|
||||||
last_corpus: corpus_count,
|
last_corpus: state.corpus().last(),
|
||||||
last_solution: solutions_count,
|
last_solution: state.solutions().last(),
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::monitors::PerfFeature;
|
use crate::monitors::PerfFeature;
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::AsSlice,
|
bolts::AsSlice,
|
||||||
corpus::Corpus,
|
corpus::{Corpus, CorpusId},
|
||||||
executors::{Executor, HasObservers},
|
executors::{Executor, HasObservers},
|
||||||
feedbacks::map::MapNoveltiesMetadata,
|
feedbacks::map::MapNoveltiesMetadata,
|
||||||
inputs::{GeneralizedInput, GeneralizedItem, HasBytesVec, UsesInput},
|
inputs::{GeneralizedInput, GeneralizedItem, HasBytesVec, UsesInput},
|
||||||
@ -31,7 +31,7 @@ const MAX_GENERALIZED_LEN: usize = 8192;
|
|||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct GeneralizedIndexesMetadata {
|
pub struct GeneralizedIndexesMetadata {
|
||||||
/// The set of indexes
|
/// The set of indexes
|
||||||
pub indexes: HashSet<usize>,
|
pub indexes: HashSet<CorpusId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::impl_serdeany!(GeneralizedIndexesMetadata);
|
crate::impl_serdeany!(GeneralizedIndexesMetadata);
|
||||||
@ -95,7 +95,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut E::State,
|
state: &mut E::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if state
|
if state
|
||||||
.metadata()
|
.metadata()
|
||||||
|
@ -54,6 +54,7 @@ pub use dump::*;
|
|||||||
|
|
||||||
use self::push::PushStage;
|
use self::push::PushStage;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
corpus::CorpusId,
|
||||||
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
|
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
|
||||||
executors::{Executor, HasObservers},
|
executors::{Executor, HasObservers},
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
@ -78,7 +79,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Self::State,
|
state: &mut Self::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +98,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +115,7 @@ where
|
|||||||
_: &mut E,
|
_: &mut E,
|
||||||
_: &mut S,
|
_: &mut S,
|
||||||
_: &mut EM,
|
_: &mut EM,
|
||||||
_: usize,
|
_: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -134,7 +135,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Head::State,
|
state: &mut Head::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Perform the current stage
|
// Perform the current stage
|
||||||
self.0
|
self.0
|
||||||
@ -150,7 +151,7 @@ where
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ClosureStage<CB, E, EM, Z>
|
pub struct ClosureStage<CB, E, EM, Z>
|
||||||
where
|
where
|
||||||
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>,
|
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, CorpusId) -> Result<(), Error>,
|
||||||
E: UsesState,
|
E: UsesState,
|
||||||
{
|
{
|
||||||
closure: CB,
|
closure: CB,
|
||||||
@ -159,7 +160,7 @@ where
|
|||||||
|
|
||||||
impl<CB, E, EM, Z> UsesState for ClosureStage<CB, E, EM, Z>
|
impl<CB, E, EM, Z> UsesState for ClosureStage<CB, E, EM, Z>
|
||||||
where
|
where
|
||||||
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>,
|
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, CorpusId) -> Result<(), Error>,
|
||||||
E: UsesState,
|
E: UsesState,
|
||||||
{
|
{
|
||||||
type State = E::State;
|
type State = E::State;
|
||||||
@ -167,7 +168,7 @@ where
|
|||||||
|
|
||||||
impl<CB, E, EM, Z> Stage<E, EM, Z> for ClosureStage<CB, E, EM, Z>
|
impl<CB, E, EM, Z> Stage<E, EM, Z> for ClosureStage<CB, E, EM, Z>
|
||||||
where
|
where
|
||||||
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>,
|
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, CorpusId) -> Result<(), Error>,
|
||||||
E: UsesState,
|
E: UsesState,
|
||||||
EM: UsesState<State = E::State>,
|
EM: UsesState<State = E::State>,
|
||||||
Z: UsesState<State = E::State>,
|
Z: UsesState<State = E::State>,
|
||||||
@ -178,7 +179,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut E::State,
|
state: &mut E::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
(self.closure)(fuzzer, executor, state, manager, corpus_idx)
|
(self.closure)(fuzzer, executor, state, manager, corpus_idx)
|
||||||
}
|
}
|
||||||
@ -187,7 +188,7 @@ where
|
|||||||
/// A stage that takes a closure
|
/// A stage that takes a closure
|
||||||
impl<CB, E, EM, Z> ClosureStage<CB, E, EM, Z>
|
impl<CB, E, EM, Z> ClosureStage<CB, E, EM, Z>
|
||||||
where
|
where
|
||||||
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>,
|
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, CorpusId) -> Result<(), Error>,
|
||||||
E: UsesState,
|
E: UsesState,
|
||||||
{
|
{
|
||||||
/// Create a new [`ClosureStage`]
|
/// Create a new [`ClosureStage`]
|
||||||
@ -202,7 +203,7 @@ where
|
|||||||
|
|
||||||
impl<CB, E, EM, Z> From<CB> for ClosureStage<CB, E, EM, Z>
|
impl<CB, E, EM, Z> From<CB> for ClosureStage<CB, E, EM, Z>
|
||||||
where
|
where
|
||||||
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>,
|
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, CorpusId) -> Result<(), Error>,
|
||||||
E: UsesState,
|
E: UsesState,
|
||||||
{
|
{
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -260,7 +261,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut CS::State,
|
state: &mut CS::State,
|
||||||
event_mgr: &mut EM,
|
event_mgr: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let push_stage = &mut self.push_stage;
|
let push_stage = &mut self.push_stage;
|
||||||
|
|
||||||
@ -365,7 +366,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut ST::State,
|
state: &mut ST::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let condition = &mut self.condition;
|
let condition = &mut self.condition;
|
||||||
if condition(state) == SkippableStageDecision::Perform {
|
if condition(state) == SkippableStageDecision::Perform {
|
||||||
@ -386,6 +387,7 @@ pub mod pybind {
|
|||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
corpus::CorpusId,
|
||||||
events::pybind::PythonEventManager,
|
events::pybind::PythonEventManager,
|
||||||
executors::pybind::PythonExecutor,
|
executors::pybind::PythonExecutor,
|
||||||
fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper},
|
fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper},
|
||||||
@ -421,7 +423,7 @@ pub mod pybind {
|
|||||||
executor: &mut PythonExecutor,
|
executor: &mut PythonExecutor,
|
||||||
state: &mut PythonStdState,
|
state: &mut PythonStdState,
|
||||||
manager: &mut PythonEventManager,
|
manager: &mut PythonEventManager,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Python::with_gil(|py| -> PyResult<()> {
|
Python::with_gil(|py| -> PyResult<()> {
|
||||||
self.inner.call_method1(
|
self.inner.call_method1(
|
||||||
@ -432,7 +434,7 @@ pub mod pybind {
|
|||||||
executor.clone(),
|
executor.clone(),
|
||||||
PythonStdStateWrapper::wrap(state),
|
PythonStdStateWrapper::wrap(state),
|
||||||
manager.clone(),
|
manager.clone(),
|
||||||
corpus_idx,
|
corpus_idx.0,
|
||||||
),
|
),
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -510,7 +512,7 @@ pub mod pybind {
|
|||||||
executor: &mut PythonExecutor,
|
executor: &mut PythonExecutor,
|
||||||
state: &mut PythonStdState,
|
state: &mut PythonStdState,
|
||||||
manager: &mut PythonEventManager,
|
manager: &mut PythonEventManager,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
unwrap_me_mut!(self.wrapper, s, {
|
unwrap_me_mut!(self.wrapper, s, {
|
||||||
s.perform(fuzzer, executor, state, manager, corpus_idx)
|
s.perform(fuzzer, executor, state, manager, corpus_idx)
|
||||||
@ -549,7 +551,7 @@ pub mod pybind {
|
|||||||
executor: &mut PythonExecutor,
|
executor: &mut PythonExecutor,
|
||||||
state: &mut PythonStdState,
|
state: &mut PythonStdState,
|
||||||
manager: &mut PythonEventManager,
|
manager: &mut PythonEventManager,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
for s in &mut self.list {
|
for s in &mut self.list {
|
||||||
s.perform(fuzzer, executor, state, manager, corpus_idx)?;
|
s.perform(fuzzer, executor, state, manager, corpus_idx)?;
|
||||||
|
@ -7,7 +7,7 @@ use core::marker::PhantomData;
|
|||||||
use crate::monitors::PerfFeature;
|
use crate::monitors::PerfFeature;
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::rands::Rand,
|
bolts::rands::Rand,
|
||||||
corpus::Corpus,
|
corpus::{Corpus, CorpusId},
|
||||||
fuzzer::Evaluator,
|
fuzzer::Evaluator,
|
||||||
mark_feature_time,
|
mark_feature_time,
|
||||||
mutators::Mutator,
|
mutators::Mutator,
|
||||||
@ -37,7 +37,7 @@ where
|
|||||||
fn mutator_mut(&mut self) -> &mut M;
|
fn mutator_mut(&mut self) -> &mut M;
|
||||||
|
|
||||||
/// Gets the number of iterations this mutator should run for.
|
/// Gets the number of iterations this mutator should run for.
|
||||||
fn iterations(&self, state: &mut Z::State, corpus_idx: usize) -> Result<u64, Error>;
|
fn iterations(&self, state: &mut Z::State, corpus_idx: CorpusId) -> Result<u64, Error>;
|
||||||
|
|
||||||
/// Runs this (mutational) stage for the given testcase
|
/// Runs this (mutational) stage for the given testcase
|
||||||
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
|
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
|
||||||
@ -47,7 +47,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Z::State,
|
state: &mut Z::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let num = self.iterations(state, corpus_idx)?;
|
let num = self.iterations(state, corpus_idx)?;
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the number of iterations as a random number
|
/// Gets the number of iterations as a random number
|
||||||
fn iterations(&self, state: &mut Z::State, _corpus_idx: usize) -> Result<u64, Error> {
|
fn iterations(&self, state: &mut Z::State, _corpus_idx: CorpusId) -> Result<u64, Error> {
|
||||||
Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS))
|
Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,7 +141,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Z::State,
|
state: &mut Z::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let ret = self.perform_mutational(fuzzer, executor, state, manager, corpus_idx);
|
let ret = self.perform_mutational(fuzzer, executor, state, manager, corpus_idx);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ use alloc::{boxed::Box, vec::Vec};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::anymap::AsAny,
|
bolts::anymap::AsAny,
|
||||||
|
corpus::CorpusId,
|
||||||
stages::{Stage, StagesTuple},
|
stages::{Stage, StagesTuple},
|
||||||
state::UsesState,
|
state::UsesState,
|
||||||
Error,
|
Error,
|
||||||
@ -42,7 +43,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut E::State,
|
state: &mut E::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
for s in &mut self.list {
|
for s in &mut self.list {
|
||||||
s.perform(fuzzer, executor, state, manager, corpus_idx)?;
|
s.perform(fuzzer, executor, state, manager, corpus_idx)?;
|
||||||
|
@ -5,7 +5,7 @@ use core::{fmt::Debug, marker::PhantomData};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::tuples::MatchName,
|
bolts::tuples::MatchName,
|
||||||
corpus::{Corpus, SchedulerTestcaseMetaData},
|
corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData},
|
||||||
executors::{Executor, HasObservers},
|
executors::{Executor, HasObservers},
|
||||||
fuzzer::Evaluator,
|
fuzzer::Evaluator,
|
||||||
mutators::Mutator,
|
mutators::Mutator,
|
||||||
@ -58,7 +58,7 @@ where
|
|||||||
|
|
||||||
/// Gets the number of iterations as a random number
|
/// Gets the number of iterations as a random number
|
||||||
#[allow(clippy::cast_sign_loss)]
|
#[allow(clippy::cast_sign_loss)]
|
||||||
fn iterations(&self, state: &mut E::State, corpus_idx: usize) -> Result<u64, Error> {
|
fn iterations(&self, state: &mut E::State, corpus_idx: CorpusId) -> Result<u64, Error> {
|
||||||
// Update handicap
|
// Update handicap
|
||||||
let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut();
|
let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut();
|
||||||
let score = F::compute(&mut *testcase, state)? as u64;
|
let score = F::compute(&mut *testcase, state)? as u64;
|
||||||
@ -73,7 +73,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut E::State,
|
state: &mut E::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let num = self.iterations(state, corpus_idx)?;
|
let num = self.iterations(state, corpus_idx)?;
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut E::State,
|
state: &mut E::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let ret = self.perform_mutational(fuzzer, executor, state, manager, corpus_idx);
|
let ret = self.perform_mutational(fuzzer, executor, state, manager, corpus_idx);
|
||||||
ret
|
ret
|
||||||
|
@ -17,6 +17,7 @@ pub use mutational::StdMutationalPushStage;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::current_time,
|
bolts::current_time,
|
||||||
|
corpus::CorpusId,
|
||||||
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
|
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
|
||||||
executors::ExitKind,
|
executors::ExitKind,
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
@ -100,7 +101,7 @@ where
|
|||||||
pub errored: bool,
|
pub errored: bool,
|
||||||
|
|
||||||
/// The corpus index we're currently working on
|
/// The corpus index we're currently working on
|
||||||
pub current_corpus_idx: Option<usize>,
|
pub current_corpus_idx: Option<CorpusId>,
|
||||||
|
|
||||||
/// The input we just ran
|
/// The input we just ran
|
||||||
pub current_input: Option<<CS::State as UsesInput>::Input>, // Todo: Get rid of copy
|
pub current_input: Option<<CS::State as UsesInput>::Input>, // Todo: Get rid of copy
|
||||||
@ -196,7 +197,7 @@ where
|
|||||||
fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<CS, EM, OT, Z>;
|
fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<CS, EM, OT, Z>;
|
||||||
|
|
||||||
/// Set the current corpus index this stage works on
|
/// Set the current corpus index this stage works on
|
||||||
fn set_current_corpus_idx(&mut self, corpus_idx: usize) {
|
fn set_current_corpus_idx(&mut self, corpus_idx: CorpusId) {
|
||||||
self.push_stage_helper_mut().current_corpus_idx = Some(corpus_idx);
|
self.push_stage_helper_mut().current_corpus_idx = Some(corpus_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ use super::{PushStage, PushStageHelper, PushStageSharedState};
|
|||||||
use crate::monitors::PerfFeature;
|
use crate::monitors::PerfFeature;
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::rands::Rand,
|
bolts::rands::Rand,
|
||||||
corpus::Corpus,
|
corpus::{Corpus, CorpusId},
|
||||||
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
|
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
|
||||||
executors::ExitKind,
|
executors::ExitKind,
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
@ -48,7 +48,7 @@ where
|
|||||||
+ EvaluatorObservers<OT>
|
+ EvaluatorObservers<OT>
|
||||||
+ HasScheduler<Scheduler = CS>,
|
+ HasScheduler<Scheduler = CS>,
|
||||||
{
|
{
|
||||||
current_corpus_idx: Option<usize>,
|
current_corpus_idx: Option<CorpusId>,
|
||||||
testcases_to_do: usize,
|
testcases_to_do: usize,
|
||||||
testcases_done: usize,
|
testcases_done: usize,
|
||||||
|
|
||||||
@ -72,12 +72,12 @@ where
|
|||||||
{
|
{
|
||||||
/// Gets the number of iterations as a random number
|
/// Gets the number of iterations as a random number
|
||||||
#[allow(clippy::unused_self, clippy::unnecessary_wraps)] // TODO: we should put this function into a trait later
|
#[allow(clippy::unused_self, clippy::unnecessary_wraps)] // TODO: we should put this function into a trait later
|
||||||
fn iterations(&self, state: &mut CS::State, _corpus_idx: usize) -> Result<usize, Error> {
|
fn iterations(&self, state: &mut CS::State, _corpus_idx: CorpusId) -> Result<usize, Error> {
|
||||||
Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize)
|
Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the current corpus index
|
/// Sets the current corpus index
|
||||||
pub fn set_current_corpus_idx(&mut self, current_corpus_idx: usize) {
|
pub fn set_current_corpus_idx(&mut self, current_corpus_idx: CorpusId) {
|
||||||
self.current_corpus_idx = Some(current_corpus_idx);
|
self.current_corpus_idx = Some(current_corpus_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,7 +175,7 @@ where
|
|||||||
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
self.mutator
|
self.mutator
|
||||||
.post_exec(state, self.stage_idx, Some(self.testcases_done))?;
|
.post_exec(state, self.stage_idx, self.current_corpus_idx)?;
|
||||||
mark_feature_time!(state, PerfFeature::MutatePostExec);
|
mark_feature_time!(state, PerfFeature::MutatePostExec);
|
||||||
self.testcases_done += 1;
|
self.testcases_done += 1;
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ use std::{
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
corpus::CorpusId,
|
||||||
fuzzer::Evaluator,
|
fuzzer::Evaluator,
|
||||||
inputs::{Input, UsesInput},
|
inputs::{Input, UsesInput},
|
||||||
stages::Stage,
|
stages::Stage,
|
||||||
@ -64,7 +65,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Z::State,
|
state: &mut Z::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
_corpus_idx: usize,
|
_corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let last = state
|
let last = state
|
||||||
.metadata()
|
.metadata()
|
||||||
|
@ -13,7 +13,7 @@ use ahash::AHasher;
|
|||||||
use crate::monitors::PerfFeature;
|
use crate::monitors::PerfFeature;
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{tuples::Named, HasLen},
|
bolts::{tuples::Named, HasLen},
|
||||||
corpus::{Corpus, Testcase},
|
corpus::{Corpus, CorpusId, Testcase},
|
||||||
events::EventFirer,
|
events::EventFirer,
|
||||||
executors::{Executor, ExitKind, HasObservers},
|
executors::{Executor, ExitKind, HasObservers},
|
||||||
feedbacks::{Feedback, FeedbackFactory, HasObserverName},
|
feedbacks::{Feedback, FeedbackFactory, HasObserverName},
|
||||||
@ -55,7 +55,7 @@ where
|
|||||||
fn mutator_mut(&mut self) -> &mut M;
|
fn mutator_mut(&mut self) -> &mut M;
|
||||||
|
|
||||||
/// Gets the number of iterations this mutator should run for.
|
/// Gets the number of iterations this mutator should run for.
|
||||||
fn iterations(&self, state: &mut CS::State, corpus_idx: usize) -> Result<usize, Error>;
|
fn iterations(&self, state: &mut CS::State, corpus_idx: CorpusId) -> Result<usize, Error>;
|
||||||
|
|
||||||
/// Runs this (mutational) stage for new objectives
|
/// Runs this (mutational) stage for new objectives
|
||||||
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
|
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
|
||||||
@ -65,7 +65,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut CS::State,
|
state: &mut CS::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
base_corpus_idx: usize,
|
base_corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let orig_max_size = state.max_size();
|
let orig_max_size = state.max_size();
|
||||||
// basically copy-pasted from mutational.rs
|
// basically copy-pasted from mutational.rs
|
||||||
@ -207,7 +207,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut CS::State,
|
state: &mut CS::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.perform_minification(fuzzer, executor, state, manager, corpus_idx)?;
|
self.perform_minification(fuzzer, executor, state, manager, corpus_idx)?;
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the number of iterations from a fixed number of runs
|
/// Gets the number of iterations from a fixed number of runs
|
||||||
fn iterations(&self, _state: &mut CS::State, _corpus_idx: usize) -> Result<usize, Error> {
|
fn iterations(&self, _state: &mut CS::State, _corpus_idx: CorpusId) -> Result<usize, Error> {
|
||||||
Ok(self.runs)
|
Ok(self.runs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use core::{fmt::Debug, marker::PhantomData};
|
|||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
use crate::monitors::PerfFeature;
|
use crate::monitors::PerfFeature;
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
corpus::{Corpus, CorpusId},
|
||||||
executors::{Executor, HasObservers, ShadowExecutor},
|
executors::{Executor, HasObservers, ShadowExecutor},
|
||||||
mark_feature_time,
|
mark_feature_time,
|
||||||
observers::ObserversTuple,
|
observers::ObserversTuple,
|
||||||
@ -45,7 +45,7 @@ where
|
|||||||
_executor: &mut E,
|
_executor: &mut E,
|
||||||
state: &mut TE::State,
|
state: &mut TE::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
let input = state
|
let input = state
|
||||||
@ -124,7 +124,7 @@ where
|
|||||||
executor: &mut ShadowExecutor<E, SOT>,
|
executor: &mut ShadowExecutor<E, SOT>,
|
||||||
state: &mut E::State,
|
state: &mut E::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
let input = state
|
let input = state
|
||||||
|
@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::rands::Rand,
|
bolts::rands::Rand,
|
||||||
|
corpus::CorpusId,
|
||||||
impl_serdeany,
|
impl_serdeany,
|
||||||
mutators::Mutator,
|
mutators::Mutator,
|
||||||
stages::{mutational::DEFAULT_MUTATIONAL_MAX_ITERATIONS, MutationalStage, Stage},
|
stages::{mutational::DEFAULT_MUTATIONAL_MAX_ITERATIONS, MutationalStage, Stage},
|
||||||
@ -78,7 +79,7 @@ where
|
|||||||
|
|
||||||
/// Gets the number of iterations as a random number
|
/// Gets the number of iterations as a random number
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
fn iterations(&self, state: &mut Z::State, _corpus_idx: usize) -> Result<u64, Error> {
|
fn iterations(&self, state: &mut Z::State, _corpus_idx: CorpusId) -> Result<u64, Error> {
|
||||||
Ok(if let Some(iters) = get_iters(state)? {
|
Ok(if let Some(iters) = get_iters(state)? {
|
||||||
iters
|
iters
|
||||||
} else {
|
} else {
|
||||||
@ -115,7 +116,7 @@ where
|
|||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
state: &mut Z::State,
|
state: &mut Z::State,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let ret = self.perform_mutational(fuzzer, executor, state, manager, corpus_idx);
|
let ret = self.perform_mutational(fuzzer, executor, state, manager, corpus_idx);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user