Move Input
loading and dumping APIs from Testcase
to Corpus
(#1201)
* Less allocatiosn for filenames * clippy for wasm fuzzer * Reworked filename and rename APIs * python, clippy * fmt * More cleanup, fixed metadata location * clippy * fix fuzzbench_text / cached len, invert parameters (state first) * clippy * oops * Caching for paths * simplified, fixed * no_std * cached_len * Nider API for input getting
This commit is contained in:
parent
fd68c8a81f
commit
96e24d1c8b
@ -23,15 +23,16 @@ use crate::utils::set_panic_hook;
|
|||||||
|
|
||||||
// defined for internal use by libafl
|
// defined for internal use by libafl
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
|
||||||
pub extern "C" fn external_current_millis() -> u64 {
|
pub extern "C" fn external_current_millis() -> u64 {
|
||||||
let window: Window = web_sys::window().expect("should be in browser to run this demo");
|
let window: Window = web_sys::window().expect("should be in browser to run this demo");
|
||||||
let performance: Performance = window
|
let performance: Performance = window
|
||||||
.performance()
|
.performance()
|
||||||
.expect("should be in browser to run this demo");
|
.expect("should be in browser to run this demo");
|
||||||
let now = performance.now() as u64;
|
performance.now() as u64
|
||||||
now
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::missing_panics_doc)]
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn fuzz() {
|
pub fn fuzz() {
|
||||||
set_panic_hook();
|
set_panic_hook();
|
||||||
@ -39,7 +40,7 @@ pub fn fuzz() {
|
|||||||
let mut signals = [0u8; 64];
|
let mut signals = [0u8; 64];
|
||||||
let signals_ptr = signals.as_mut_ptr();
|
let signals_ptr = signals.as_mut_ptr();
|
||||||
let signals_set = |i: usize| unsafe {
|
let signals_set = |i: usize| unsafe {
|
||||||
*signals_ptr.offset(i as isize) += 1;
|
*signals_ptr.add(i) += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The closure that we want to fuzz
|
// The closure that we want to fuzz
|
||||||
|
@ -28,6 +28,7 @@ clap = { version = "4.0", features = ["default"] }
|
|||||||
nix = "0.26"
|
nix = "0.26"
|
||||||
mimalloc = { version = "*", default-features = false }
|
mimalloc = { version = "*", default-features = false }
|
||||||
content_inspector = "0.2.4"
|
content_inspector = "0.2.4"
|
||||||
|
#log = "0.4"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "fuzzbench"
|
name = "fuzzbench"
|
||||||
|
@ -288,6 +288,12 @@ fn fuzz_binary(
|
|||||||
// This way, we are able to continue fuzzing afterwards.
|
// This way, we are able to continue fuzzing afterwards.
|
||||||
let mut shmem_provider = StdShMemProvider::new()?;
|
let mut shmem_provider = StdShMemProvider::new()?;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// For debugging
|
||||||
|
let mut mgr = SimpleEventManager::new(monitor);
|
||||||
|
let mut state = None;
|
||||||
|
*/
|
||||||
|
|
||||||
let (state, mut mgr) = match SimpleRestartingEventManager::launch(monitor, &mut shmem_provider)
|
let (state, mut mgr) = match SimpleRestartingEventManager::launch(monitor, &mut shmem_provider)
|
||||||
{
|
{
|
||||||
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
|
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
|
||||||
@ -435,8 +441,8 @@ fn fuzz_binary(
|
|||||||
if state.must_load_initial_inputs() {
|
if state.must_load_initial_inputs() {
|
||||||
state
|
state
|
||||||
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &[seed_dir.clone()])
|
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &[seed_dir.clone()])
|
||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|e| {
|
||||||
println!("Failed to load initial corpus at {:?}", &seed_dir);
|
println!("Failed to load initial corpus at {seed_dir:?} - {e:?}");
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
});
|
});
|
||||||
println!("We imported {} inputs from disk.", state.corpus().count());
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
@ -491,6 +497,14 @@ fn fuzz_text(
|
|||||||
// This way, we are able to continue fuzzing afterwards.
|
// This way, we are able to continue fuzzing afterwards.
|
||||||
let mut shmem_provider = StdShMemProvider::new()?;
|
let mut shmem_provider = StdShMemProvider::new()?;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// For debugging
|
||||||
|
log::set_max_level(log::LevelFilter::Trace);
|
||||||
|
SimpleStderrLogger::set_logger()?;
|
||||||
|
let mut mgr = SimpleEventManager::new(monitor);
|
||||||
|
let mut state = None;
|
||||||
|
*/
|
||||||
|
|
||||||
let (state, mut mgr) = match SimpleRestartingEventManager::launch(monitor, &mut shmem_provider)
|
let (state, mut mgr) = match SimpleRestartingEventManager::launch(monitor, &mut shmem_provider)
|
||||||
{
|
{
|
||||||
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
|
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
|
||||||
@ -654,8 +668,8 @@ fn fuzz_text(
|
|||||||
if state.must_load_initial_inputs() {
|
if state.must_load_initial_inputs() {
|
||||||
state
|
state
|
||||||
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &[seed_dir.clone()])
|
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &[seed_dir.clone()])
|
||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|e| {
|
||||||
println!("Failed to load initial corpus at {:?}", &seed_dir);
|
println!("Failed to load initial corpus at {seed_dir:?} {e:?}");
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
});
|
});
|
||||||
println!("We imported {} inputs from disk.", state.corpus().count());
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
|
@ -25,7 +25,7 @@ impl<S> TestcaseScore<S> for PacketLenTestcaseScore
|
|||||||
where
|
where
|
||||||
S: HasCorpus<Input = PacketData> + HasMetadata,
|
S: HasCorpus<Input = PacketData> + HasMetadata,
|
||||||
{
|
{
|
||||||
fn compute(entry: &mut Testcase<PacketData>, _state: &S) -> Result<f64, Error> {
|
fn compute(_state: &S, entry: &mut Testcase<PacketData>) -> Result<f64, Error> {
|
||||||
Ok(entry
|
Ok(entry
|
||||||
.metadata_map()
|
.metadata_map()
|
||||||
.get::<PacketLenMetadata>()
|
.get::<PacketLenMetadata>()
|
||||||
|
7
libafl/.fancyfile.metadata
Normal file
7
libafl/.fancyfile.metadata
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"map": {}
|
||||||
|
},
|
||||||
|
"exec_time": null,
|
||||||
|
"executions": 0
|
||||||
|
}
|
@ -73,7 +73,7 @@ where
|
|||||||
fn get(&self, idx: CorpusId) -> 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 _: &I = testcase.borrow_mut().load_input()?;
|
self.load_input_into(&mut testcase.borrow_mut())?;
|
||||||
let mut borrowed_num = 0;
|
let mut borrowed_num = 0;
|
||||||
while self.cached_indexes.borrow().len() >= self.cache_max_len {
|
while self.cached_indexes.borrow().len() >= self.cache_max_len {
|
||||||
let removed = self.cached_indexes.borrow_mut().pop_front().unwrap();
|
let removed = self.cached_indexes.borrow_mut().pop_front().unwrap();
|
||||||
@ -128,6 +128,16 @@ where
|
|||||||
fn nth(&self, nth: usize) -> CorpusId {
|
fn nth(&self, nth: usize) -> CorpusId {
|
||||||
self.inner.nth(nth)
|
self.inner.nth(nth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn load_input_into(&self, testcase: &mut Testcase<Self::Input>) -> Result<(), Error> {
|
||||||
|
self.inner.load_input_into(testcase)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn store_input_from(&self, testcase: &Testcase<Self::Input>) -> Result<(), Error> {
|
||||||
|
self.inner.store_input_from(testcase)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> HasTestcase for CachedOnDiskCorpus<I>
|
impl<I> HasTestcase for CachedOnDiskCorpus<I>
|
||||||
|
@ -380,6 +380,17 @@ where
|
|||||||
fn nth(&self, nth: usize) -> CorpusId {
|
fn nth(&self, nth: usize) -> CorpusId {
|
||||||
self.storage.keys[nth]
|
self.storage.keys[nth]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn load_input_into(&self, _: &mut Testcase<Self::Input>) -> Result<(), Error> {
|
||||||
|
// Inputs never get evicted, nothing to load here.
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn store_input_from(&self, _: &Testcase<Self::Input>) -> Result<(), Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> HasTestcase for InMemoryCorpus<I>
|
impl<I> HasTestcase for InMemoryCorpus<I>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
//! For a lower memory footprint, consider using [`crate::corpus::CachedOnDiskCorpus`]
|
//! For a lower memory footprint, consider using [`crate::corpus::CachedOnDiskCorpus`]
|
||||||
//! which only stores a certain number of [`Testcase`]s and removes additional ones in a FIFO manner.
|
//! which only stores a certain number of [`Testcase`]s and removes additional ones in a FIFO manner.
|
||||||
|
|
||||||
|
use alloc::string::String;
|
||||||
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};
|
||||||
@ -72,7 +73,9 @@ where
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn add(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error> {
|
fn add(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error> {
|
||||||
let idx = self.inner.add(testcase)?;
|
let idx = self.inner.add(testcase)?;
|
||||||
self.save_testcase(&mut self.get(idx).unwrap().borrow_mut(), idx)?;
|
let testcase = &mut self.get(idx).unwrap().borrow_mut();
|
||||||
|
self.save_testcase(testcase, idx)?;
|
||||||
|
*testcase.input_mut() = None;
|
||||||
Ok(idx)
|
Ok(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +84,9 @@ where
|
|||||||
fn replace(&mut self, idx: CorpusId, testcase: Testcase<I>) -> Result<Testcase<I>, Error> {
|
fn replace(&mut self, idx: CorpusId, testcase: Testcase<I>) -> Result<Testcase<I>, Error> {
|
||||||
let entry = self.inner.replace(idx, testcase)?;
|
let entry = self.inner.replace(idx, testcase)?;
|
||||||
self.remove_testcase(&entry)?;
|
self.remove_testcase(&entry)?;
|
||||||
self.save_testcase(&mut self.get(idx).unwrap().borrow_mut(), idx)?;
|
let testcase = &mut self.get(idx).unwrap().borrow_mut();
|
||||||
|
self.save_testcase(testcase, idx)?;
|
||||||
|
*testcase.input_mut() = None;
|
||||||
Ok(entry)
|
Ok(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +140,28 @@ where
|
|||||||
fn nth(&self, nth: usize) -> CorpusId {
|
fn nth(&self, nth: usize) -> CorpusId {
|
||||||
self.inner.nth(nth)
|
self.inner.nth(nth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_input_into(&self, testcase: &mut Testcase<Self::Input>) -> Result<(), Error> {
|
||||||
|
if testcase.input_mut().is_none() {
|
||||||
|
let Some(file_path) = testcase.file_path().as_ref() else {
|
||||||
|
return Err(Error::illegal_argument("No file path set for testcase. Could not load inputs."));
|
||||||
|
};
|
||||||
|
let input = I::from_file(file_path)?;
|
||||||
|
testcase.set_input(input);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn store_input_from(&self, testcase: &Testcase<Self::Input>) -> Result<(), Error> {
|
||||||
|
// Store the input to disk
|
||||||
|
let Some(file_path) = testcase.file_path() else {
|
||||||
|
return Err(Error::illegal_argument("No file path set for testcase. Could not store input to disk."));
|
||||||
|
};
|
||||||
|
let Some(input) = testcase.input() else {
|
||||||
|
return Err(Error::illegal_argument("No input available for testcase. Could not store anything."));
|
||||||
|
};
|
||||||
|
input.to_file(file_path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> HasTestcase for InMemoryOnDiskCorpus<I>
|
impl<I> HasTestcase for InMemoryOnDiskCorpus<I>
|
||||||
@ -212,47 +239,109 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the filename for a [`Testcase`].
|
||||||
|
/// If an error gets returned from the corpus (i.e., file exists), we'll have to retry with a different filename.
|
||||||
|
#[inline]
|
||||||
|
pub fn rename_testcase(
|
||||||
|
&self,
|
||||||
|
testcase: &mut Testcase<I>,
|
||||||
|
filename: String,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if testcase.filename().is_some() {
|
||||||
|
// We are renaming!
|
||||||
|
|
||||||
|
let old_filename = testcase.filename_mut().take().unwrap();
|
||||||
|
let new_filename = filename;
|
||||||
|
|
||||||
|
// Do operations below when new filename is specified
|
||||||
|
if old_filename == new_filename {
|
||||||
|
*testcase.filename_mut() = Some(old_filename);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_lock_filename = format!(".{new_filename}.lafl_lock");
|
||||||
|
|
||||||
|
// Try to create lock file for new testcases
|
||||||
|
if OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.write(true)
|
||||||
|
.open(self.dir_path.join(new_lock_filename))
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
*testcase.filename_mut() = Some(old_filename);
|
||||||
|
return Err(Error::illegal_state(
|
||||||
|
"unable to create lock file for new testcase",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_file_path = self.dir_path.join(&new_filename);
|
||||||
|
|
||||||
|
fs::rename(testcase.file_path().as_ref().unwrap(), &new_file_path)?;
|
||||||
|
|
||||||
|
let new_metadata_path = {
|
||||||
|
if let Some(old_metadata_path) = testcase.metadata_path() {
|
||||||
|
// We have metadata. Let's rename it.
|
||||||
|
let new_metadata_path = self.dir_path.join(format!(".{new_filename}.metadata"));
|
||||||
|
fs::rename(old_metadata_path, &new_metadata_path)?;
|
||||||
|
|
||||||
|
Some(new_metadata_path)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
*testcase.metadata_path_mut() = new_metadata_path;
|
||||||
|
*testcase.filename_mut() = Some(new_filename);
|
||||||
|
*testcase.file_path_mut() = Some(new_file_path);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::illegal_argument(
|
||||||
|
"Cannot rename testcase without name!",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn save_testcase(&self, testcase: &mut Testcase<I>, idx: CorpusId) -> Result<(), Error> {
|
fn save_testcase(&self, testcase: &mut Testcase<I>, idx: CorpusId) -> Result<(), Error> {
|
||||||
if testcase.filename().is_none() {
|
let file_name_orig = testcase.filename_mut().take().unwrap_or_else(|| {
|
||||||
// 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.input().as_ref().unwrap().generate_name(idx.0);
|
testcase.input().as_ref().unwrap().generate_name(idx.0)
|
||||||
let mut file = file_orig.clone();
|
});
|
||||||
|
if testcase.file_path().is_some() {
|
||||||
|
// We already have a valid path, no need to do calculate anything
|
||||||
|
*testcase.filename_mut() = Some(file_name_orig);
|
||||||
|
} else {
|
||||||
|
// New testcase, we need to save it.
|
||||||
|
let mut file_name = file_name_orig.clone();
|
||||||
|
|
||||||
let mut ctr = 2;
|
let mut ctr = 2;
|
||||||
let filename = loop {
|
let (file_name, lockfile_path) = loop {
|
||||||
let lockfile = format!(".{file}.lafl_lock");
|
let lockfile_name = format!(".{file_name}.lafl_lock");
|
||||||
|
let lockfile_path = self.dir_path.join(lockfile_name);
|
||||||
|
|
||||||
if OpenOptions::new()
|
if OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.create_new(true)
|
.create_new(true)
|
||||||
.open(self.dir_path.join(lockfile))
|
.open(&lockfile_path)
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
break file;
|
break (file_name, lockfile_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
file = format!("{file_orig}-{ctr}");
|
file_name = format!("{file_name_orig}-{ctr}");
|
||||||
ctr += 1;
|
ctr += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
let file_path = self.dir_path.join(filename.clone());
|
*testcase.file_path_mut() = Some(self.dir_path.join(&file_name));
|
||||||
let filename_str = file_path.to_str().expect("Invalid Path");
|
*testcase.filename_mut() = Some(file_name);
|
||||||
testcase.set_filename(filename_str.into())?;
|
|
||||||
|
fs::remove_file(lockfile_path)?;
|
||||||
|
}
|
||||||
|
|
||||||
let lock_file_path = self.dir_path.join(format!(".{filename}.lafl_lock"));
|
|
||||||
fs::remove_file(lock_file_path)?;
|
|
||||||
};
|
|
||||||
if self.meta_format.is_some() {
|
if self.meta_format.is_some() {
|
||||||
let mut filename = PathBuf::from(testcase.filename().as_ref().unwrap());
|
let metafile_name = format!(".{}.metadata", testcase.filename().as_ref().unwrap());
|
||||||
filename.set_file_name(format!(
|
let metafile_path = self.dir_path.join(&metafile_name);
|
||||||
".{}.metadata",
|
let mut tmpfile_path = metafile_path.clone();
|
||||||
filename.file_name().unwrap().to_string_lossy()
|
tmpfile_path.set_file_name(format!(".{metafile_name}.tmp",));
|
||||||
));
|
|
||||||
let mut tmpfile_name = PathBuf::from(&filename);
|
|
||||||
tmpfile_name.set_file_name(format!(
|
|
||||||
".{}.tmp",
|
|
||||||
tmpfile_name.file_name().unwrap().to_string_lossy()
|
|
||||||
));
|
|
||||||
|
|
||||||
let ondisk_meta = OnDiskMetadata {
|
let ondisk_meta = OnDiskMetadata {
|
||||||
metadata: testcase.metadata_map(),
|
metadata: testcase.metadata_map(),
|
||||||
@ -260,7 +349,7 @@ where
|
|||||||
executions: testcase.executions(),
|
executions: testcase.executions(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut tmpfile = File::create(&tmpfile_name)?;
|
let mut tmpfile = File::create(&tmpfile_path)?;
|
||||||
|
|
||||||
let serialized = match self.meta_format.as_ref().unwrap() {
|
let serialized = match self.meta_format.as_ref().unwrap() {
|
||||||
OnDiskMetadataFormat::Postcard => postcard::to_allocvec(&ondisk_meta)?,
|
OnDiskMetadataFormat::Postcard => postcard::to_allocvec(&ondisk_meta)?,
|
||||||
@ -272,25 +361,23 @@ where
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
};
|
};
|
||||||
tmpfile.write_all(&serialized)?;
|
tmpfile.write_all(&serialized)?;
|
||||||
fs::rename(&tmpfile_name, &filename)?;
|
fs::rename(&tmpfile_path, &metafile_path)?;
|
||||||
|
*testcase.metadata_path_mut() = Some(metafile_path);
|
||||||
}
|
}
|
||||||
testcase
|
|
||||||
.store_input()
|
self.store_input_from(testcase)?;
|
||||||
.expect("Could not save testcase to disk");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_testcase(&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(self.dir_path.join(filename))?;
|
||||||
}
|
|
||||||
if self.meta_format.is_some() {
|
if self.meta_format.is_some() {
|
||||||
let mut filename = PathBuf::from(testcase.filename().as_ref().unwrap());
|
fs::remove_file(self.dir_path.join(format!(".{filename}.metadata")))?;
|
||||||
filename.set_file_name(format!(
|
}
|
||||||
".{}.metadata",
|
// also try to remove the corresponding `.lafl_lock` file if it still exists
|
||||||
filename.file_name().unwrap().to_string_lossy()
|
// (even though it shouldn't exist anymore, at this point in time)
|
||||||
));
|
let _ = fs::remove_file(self.dir_path.join(format!(".{filename}.lafl_lock")));
|
||||||
fs::remove_file(filename)?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ where
|
|||||||
while let Some(idx) = cur_id {
|
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(state, &mut *testcase)?
|
||||||
.to_u64()
|
.to_u64()
|
||||||
.expect("Weight must be computable.");
|
.expect("Weight must be computable.");
|
||||||
let input = testcase
|
let input = testcase
|
||||||
|
@ -71,7 +71,7 @@ macro_rules! random_corpus_id {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Corpus with all current testcases
|
/// Corpus with all current [`Testcase`]s, or solutions
|
||||||
pub trait Corpus: UsesInput + Serialize + for<'de> 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;
|
||||||
@ -84,7 +84,7 @@ pub trait Corpus: UsesInput + Serialize + for<'de> 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<CorpusId, 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: CorpusId,
|
idx: CorpusId,
|
||||||
@ -130,9 +130,23 @@ pub trait Corpus: UsesInput + Serialize + for<'de> Deserialize<'de> {
|
|||||||
.nth(nth)
|
.nth(nth)
|
||||||
.expect("Failed to get the {nth} CorpusId")
|
.expect("Failed to get the {nth} CorpusId")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Method to load the input for this [`Testcase`] from persistent storage,
|
||||||
|
/// if necessary, and if was not already loaded (`== Some(input)`).
|
||||||
|
/// After this call, `testcase.input()` must always return `Some(input)`.
|
||||||
|
fn load_input_into(&self, testcase: &mut Testcase<Self::Input>) -> Result<(), Error>;
|
||||||
|
|
||||||
|
/// Method to store the input of this `Testcase` to persistent storage, if necessary.
|
||||||
|
fn store_input_from(&self, testcase: &Testcase<Self::Input>) -> Result<(), Error>;
|
||||||
|
|
||||||
|
/// Loads the `Input` for a given [`CorpusId`] from the [`Corpus`], and returns the clone.
|
||||||
|
fn cloned_input_for_id(&self, idx: CorpusId) -> Result<Self::Input, Error> {
|
||||||
|
let mut testcase = self.get(idx)?.borrow_mut();
|
||||||
|
Ok(testcase.load_input(self)?.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `Iterator` over the ids of a `Corpus`
|
/// [`Iterator`] over the ids of a [`Corpus`]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CorpusIdIterator<'a, C>
|
pub struct CorpusIdIterator<'a, C>
|
||||||
where
|
where
|
||||||
@ -368,6 +382,14 @@ pub mod pybind {
|
|||||||
unwrap_me!(self.wrapper, c, { c.last() })
|
unwrap_me!(self.wrapper, c, { c.last() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_input_into(&self, testcase: &mut Testcase<BytesInput>) -> Result<(), Error> {
|
||||||
|
unwrap_me!(self.wrapper, c, { c.load_input_into(testcase) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn store_input_from(&self, testcase: &Testcase<BytesInput>) -> Result<(), Error> {
|
||||||
|
unwrap_me!(self.wrapper, c, { c.store_input_from(testcase) })
|
||||||
|
}
|
||||||
|
|
||||||
/*fn ids<'a>(&'a self) -> CorpusIdIterator<'a, Self> {
|
/*fn ids<'a>(&'a self) -> CorpusIdIterator<'a, Self> {
|
||||||
CorpusIdIterator {
|
CorpusIdIterator {
|
||||||
corpus: self,
|
corpus: self,
|
||||||
|
@ -138,6 +138,16 @@ where
|
|||||||
fn nth(&self, nth: usize) -> CorpusId {
|
fn nth(&self, nth: usize) -> CorpusId {
|
||||||
self.inner.nth(nth)
|
self.inner.nth(nth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn load_input_into(&self, testcase: &mut Testcase<Self::Input>) -> Result<(), Error> {
|
||||||
|
self.inner.load_input_into(testcase)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn store_input_from(&self, testcase: &Testcase<Self::Input>) -> Result<(), Error> {
|
||||||
|
self.inner.store_input_from(testcase)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> HasTestcase for OnDiskCorpus<I>
|
impl<I> HasTestcase for OnDiskCorpus<I>
|
||||||
|
@ -9,10 +9,11 @@ use core::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::fs;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::Corpus;
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{serdeany::SerdeAnyMap, HasLen},
|
bolts::{serdeany::SerdeAnyMap, HasLen},
|
||||||
corpus::CorpusId,
|
corpus::CorpusId,
|
||||||
@ -43,12 +44,18 @@ pub struct Testcase<I>
|
|||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
/// The input of this testcase
|
/// The [`Input`] of this [`Testcase`], or `None`, if it is not currently in memory
|
||||||
input: Option<I>,
|
input: Option<I>,
|
||||||
/// Filename, if this testcase is backed by a file in the filesystem
|
/// The filename for this [`Testcase`]
|
||||||
filename: Option<String>,
|
filename: Option<String>,
|
||||||
/// Map of metadata associated with this testcase
|
/// Complete path to the [`Input`] on disk, if this [`Testcase`] is backed by a file in the filesystem
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
file_path: Option<PathBuf>,
|
||||||
|
/// Map of metadata associated with this [`Testcase`]
|
||||||
metadata: SerdeAnyMap,
|
metadata: SerdeAnyMap,
|
||||||
|
/// Complete path to the metadata [`SerdeAnyMap`] on disk, if this [`Testcase`] is backed by a file in the filesystem
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
metadata_path: Option<PathBuf>,
|
||||||
/// Time needed to execute the input
|
/// Time needed to execute the input
|
||||||
exec_time: Option<Duration>,
|
exec_time: Option<Duration>,
|
||||||
/// Cached len of the input, if any
|
/// Cached len of the input, if any
|
||||||
@ -83,36 +90,13 @@ impl<I> Testcase<I>
|
|||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
/// Returns this testcase with a loaded input
|
/// Returns this [`Testcase`] with a loaded `Input`]
|
||||||
pub fn load_input(&mut self) -> Result<&I, Error> {
|
pub fn load_input<C: Corpus<Input = I>>(&mut self, corpus: &C) -> Result<&I, Error> {
|
||||||
if self.input.is_none() {
|
corpus.load_input_into(self)?;
|
||||||
self.input = Some(I::from_file(self.filename.as_ref().unwrap())?);
|
|
||||||
}
|
|
||||||
Ok(self.input.as_ref().unwrap())
|
Ok(self.input.as_ref().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store the input to disk if possible
|
/// Get the input, if available any
|
||||||
pub fn store_input(&mut self) -> Result<bool, Error> {
|
|
||||||
match self.filename() {
|
|
||||||
Some(fname) => {
|
|
||||||
let saved = match self.input() {
|
|
||||||
None => false,
|
|
||||||
Some(i) => {
|
|
||||||
i.to_file(fname)?;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if saved {
|
|
||||||
// remove the input from memory
|
|
||||||
*self.input_mut() = None;
|
|
||||||
}
|
|
||||||
Ok(saved)
|
|
||||||
}
|
|
||||||
None => Ok(false),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the input, if any
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn input(&self) -> &Option<I> {
|
pub fn input(&self) -> &Option<I> {
|
||||||
&self.input
|
&self.input
|
||||||
@ -144,55 +128,32 @@ where
|
|||||||
&mut self.filename
|
&mut self.filename
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the filename
|
/// Get the filename path, if any
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn set_filename(&mut self, filename: String) -> Result<(), Error> {
|
pub fn file_path(&self) -> &Option<PathBuf> {
|
||||||
use std::fs::OpenOptions;
|
&self.file_path
|
||||||
|
|
||||||
if self.filename.is_some() {
|
|
||||||
let f = self.filename.clone().unwrap();
|
|
||||||
let old_filename = f.as_str();
|
|
||||||
|
|
||||||
let new_filename = filename.as_str();
|
|
||||||
|
|
||||||
// Do operations below when new filename is specified
|
|
||||||
if old_filename.eq(new_filename) {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_lock_filename = format!(".{new_filename}.lafl_lock");
|
|
||||||
|
|
||||||
// Try to create lock file for new testcases
|
|
||||||
if OpenOptions::new()
|
|
||||||
.create(true)
|
|
||||||
.write(true)
|
|
||||||
.open(&new_lock_filename)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
return Err(Error::illegal_state(
|
|
||||||
"unable to create lock file for new testcase",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::rename(old_filename, new_filename)?;
|
|
||||||
|
|
||||||
let old_metadata_filename = format!(".{old_filename}.metadata");
|
|
||||||
let new_metadata_filename = format!(".{new_filename}.metadata");
|
|
||||||
fs::rename(old_metadata_filename, new_metadata_filename)?;
|
|
||||||
|
|
||||||
fs::remove_file(&new_lock_filename)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.filename = Some(filename);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the filename path, if any (mutable)
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn set_filename(&mut self, filename: String) -> Result<(), Error> {
|
pub fn file_path_mut(&mut self) -> &mut Option<PathBuf> {
|
||||||
self.filename = Some(filename);
|
&mut self.file_path
|
||||||
Ok(())
|
}
|
||||||
|
|
||||||
|
/// Get the metadata path, if any
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub fn metadata_path(&self) -> &Option<PathBuf> {
|
||||||
|
&self.metadata_path
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the metadata path, if any (mutable)
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub fn metadata_path_mut(&mut self) -> &mut Option<PathBuf> {
|
||||||
|
&mut self.metadata_path
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the execution time of the testcase
|
/// Get the execution time of the testcase
|
||||||
@ -313,6 +274,10 @@ where
|
|||||||
scheduled_count: 0,
|
scheduled_count: 0,
|
||||||
executions: 0,
|
executions: 0,
|
||||||
parent_id: None,
|
parent_id: None,
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
file_path: None,
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
metadata_path: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,25 +287,30 @@ impl<I> Testcase<I>
|
|||||||
where
|
where
|
||||||
I: Input + HasLen,
|
I: Input + HasLen,
|
||||||
{
|
{
|
||||||
/// Get the cached len
|
/// Get the cached `len`. Will `Error::EmptyOptional` if `len` is not yet cached.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn cached_len(&mut self) -> Result<usize, Error> {
|
pub fn cached_len(&mut self) -> Option<usize> {
|
||||||
Ok(match &self.input {
|
self.cached_len
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `len` or calculate it, if not yet calculated.
|
||||||
|
#[allow(clippy::len_without_is_empty)]
|
||||||
|
pub fn load_len<C: Corpus<Input = I>>(&mut self, corpus: &C) -> Result<usize, Error> {
|
||||||
|
match &self.input {
|
||||||
Some(i) => {
|
Some(i) => {
|
||||||
let l = i.len();
|
let l = i.len();
|
||||||
self.cached_len = Some(l);
|
self.cached_len = Some(l);
|
||||||
l
|
Ok(l)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
if let Some(l) = self.cached_len {
|
if let Some(l) = self.cached_len {
|
||||||
l
|
Ok(l)
|
||||||
} else {
|
} else {
|
||||||
let l = self.load_input()?.len();
|
corpus.load_input_into(self)?;
|
||||||
self.cached_len = Some(l);
|
self.load_len(corpus)
|
||||||
l
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,11 +441,7 @@ pub mod pybind {
|
|||||||
use pyo3::{prelude::*, types::PyDict};
|
use pyo3::{prelude::*, types::PyDict};
|
||||||
|
|
||||||
use super::{HasMetadata, Testcase};
|
use super::{HasMetadata, Testcase};
|
||||||
use crate::{
|
use crate::{bolts::ownedref::OwnedMutPtr, inputs::BytesInput, pybind::PythonMetadata};
|
||||||
bolts::ownedref::OwnedMutPtr,
|
|
||||||
inputs::{BytesInput, HasBytesVec},
|
|
||||||
pybind::PythonMetadata,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// `PythonTestcase` with fixed generics
|
/// `PythonTestcase` with fixed generics
|
||||||
pub type PythonTestcase = Testcase<BytesInput>;
|
pub type PythonTestcase = Testcase<BytesInput>;
|
||||||
@ -514,14 +480,6 @@ pub mod pybind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_input(&mut self) -> &[u8] {
|
|
||||||
self.inner
|
|
||||||
.as_mut()
|
|
||||||
.load_input()
|
|
||||||
.expect("Failed to load input")
|
|
||||||
.bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
fn exec_time_ms(&self) -> Option<u128> {
|
fn exec_time_ms(&self) -> Option<u128> {
|
||||||
self.inner.as_ref().exec_time().map(|t| t.as_millis())
|
self.inner.as_ref().exec_time().map(|t| t.as_millis())
|
||||||
|
@ -9,14 +9,14 @@ use serde_json;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::tuples::Named,
|
bolts::tuples::Named,
|
||||||
corpus::Testcase,
|
corpus::{Corpus, Testcase},
|
||||||
events::EventFirer,
|
events::EventFirer,
|
||||||
executors::ExitKind,
|
executors::ExitKind,
|
||||||
feedbacks::Feedback,
|
feedbacks::Feedback,
|
||||||
generators::NautilusContext,
|
generators::NautilusContext,
|
||||||
inputs::{NautilusInput, UsesInput},
|
inputs::{NautilusInput, UsesInput},
|
||||||
observers::ObserversTuple,
|
observers::ObserversTuple,
|
||||||
state::{HasClientPerfMonitor, HasMetadata},
|
state::{HasClientPerfMonitor, HasCorpus, HasMetadata},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -82,7 +82,10 @@ impl<'a, S> Named for NautilusFeedback<'a, S> {
|
|||||||
|
|
||||||
impl<'a, S> Feedback<S> for NautilusFeedback<'a, S>
|
impl<'a, S> Feedback<S> for NautilusFeedback<'a, S>
|
||||||
where
|
where
|
||||||
S: HasMetadata + HasClientPerfMonitor + UsesInput<Input = NautilusInput>,
|
S: HasMetadata
|
||||||
|
+ HasClientPerfMonitor
|
||||||
|
+ UsesInput<Input = NautilusInput>
|
||||||
|
+ HasCorpus<Input = NautilusInput>,
|
||||||
{
|
{
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
@ -109,7 +112,8 @@ where
|
|||||||
where
|
where
|
||||||
OT: ObserversTuple<S>,
|
OT: ObserversTuple<S>,
|
||||||
{
|
{
|
||||||
let input = testcase.load_input()?.clone();
|
state.corpus().load_input_into(testcase)?;
|
||||||
|
let input = testcase.input().as_ref().unwrap().clone();
|
||||||
let meta = state
|
let meta = state
|
||||||
.metadata_map_mut()
|
.metadata_map_mut()
|
||||||
.get_mut::<NautilusChunksMetadata>()
|
.get_mut::<NautilusChunksMetadata>()
|
||||||
|
@ -332,13 +332,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let other_size = state
|
let other_size = {
|
||||||
.corpus()
|
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||||
.get(idx)?
|
other_testcase.load_input(state.corpus())?.codes().len()
|
||||||
.borrow_mut()
|
};
|
||||||
.load_input()?
|
|
||||||
.codes()
|
|
||||||
.len();
|
|
||||||
if other_size < 2 {
|
if other_size < 2 {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
}
|
}
|
||||||
@ -348,9 +346,6 @@ where
|
|||||||
let to = state.rand_mut().below(size as u64) as usize;
|
let to = state.rand_mut().below(size as u64) as usize;
|
||||||
let mut len = 1 + state.rand_mut().below((other_size - from) as u64) as usize;
|
let mut len = 1 + state.rand_mut().below((other_size - from) as u64) as usize;
|
||||||
|
|
||||||
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
|
||||||
let other = other_testcase.load_input()?;
|
|
||||||
|
|
||||||
if size + len > max_size {
|
if size + len > max_size {
|
||||||
if max_size > size {
|
if max_size > size {
|
||||||
len = max_size - size;
|
len = max_size - size;
|
||||||
@ -359,6 +354,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||||
|
// no need to `load_input` again - we did that above already.
|
||||||
|
let other = other_testcase.input().as_ref().unwrap();
|
||||||
|
|
||||||
input.codes_mut().resize(size + len, 0);
|
input.codes_mut().resize(size + len, 0);
|
||||||
unsafe {
|
unsafe {
|
||||||
buffer_self_copy(input.codes_mut(), to, to + len, size - to);
|
buffer_self_copy(input.codes_mut(), to, to + len, size - to);
|
||||||
@ -410,13 +409,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let other_size = state
|
let other_size = {
|
||||||
.corpus()
|
// new scope to make the borrow checker happy
|
||||||
.get(idx)?
|
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||||
.borrow_mut()
|
other_testcase.load_input(state.corpus())?.codes().len()
|
||||||
.load_input()?
|
};
|
||||||
.codes()
|
|
||||||
.len();
|
|
||||||
if other_size < 2 {
|
if other_size < 2 {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
}
|
}
|
||||||
@ -425,8 +423,9 @@ where
|
|||||||
let len = state.rand_mut().below(min(other_size - from, size) as u64) as usize;
|
let len = state.rand_mut().below(min(other_size - from, size) as u64) as usize;
|
||||||
let to = state.rand_mut().below((size - len) as u64) as usize;
|
let to = state.rand_mut().below((size - len) as u64) as usize;
|
||||||
|
|
||||||
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
let other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||||
let other = other_testcase.load_input()?;
|
// no need to load the input again, it'll already be present at this point.
|
||||||
|
let other = other_testcase.input().as_ref().unwrap();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
buffer_copy(input.codes_mut(), other.codes(), from, to, len);
|
buffer_copy(input.codes_mut(), other.codes(), from, to, len);
|
||||||
|
@ -117,11 +117,10 @@ where
|
|||||||
|
|
||||||
let rand_num = state.rand_mut().next() as usize;
|
let rand_num = state.rand_mut().next() as usize;
|
||||||
|
|
||||||
let mut other_testcase = state.testcase_mut(idx)?;
|
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||||
other_testcase.load_input()?; // Preload the input
|
|
||||||
|
|
||||||
if !other_testcase.has_metadata::<GramatronIdxMapMetadata>() {
|
if !other_testcase.has_metadata::<GramatronIdxMapMetadata>() {
|
||||||
let meta = GramatronIdxMapMetadata::new(other_testcase.input().as_ref().unwrap());
|
let meta = GramatronIdxMapMetadata::new(other_testcase.load_input(state.corpus())?);
|
||||||
other_testcase.add_metadata(meta);
|
other_testcase.add_metadata(meta);
|
||||||
}
|
}
|
||||||
let meta = other_testcase
|
let meta = other_testcase
|
||||||
|
@ -1114,13 +1114,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let other_size = state
|
let other_size = {
|
||||||
.corpus()
|
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||||
.get(idx)?
|
other_testcase.load_input(state.corpus())?.bytes().len()
|
||||||
.borrow_mut()
|
};
|
||||||
.load_input()?
|
|
||||||
.bytes()
|
|
||||||
.len();
|
|
||||||
if other_size < 2 {
|
if other_size < 2 {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
}
|
}
|
||||||
@ -1128,9 +1126,6 @@ where
|
|||||||
let range = rand_range(state, other_size, min(other_size, max_size - size));
|
let range = rand_range(state, other_size, min(other_size, max_size - size));
|
||||||
let target = state.rand_mut().below(size as u64) as usize;
|
let target = state.rand_mut().below(size as u64) as usize;
|
||||||
|
|
||||||
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
|
||||||
let other = other_testcase.load_input()?;
|
|
||||||
|
|
||||||
input.bytes_mut().resize(size + range.len(), 0);
|
input.bytes_mut().resize(size + range.len(), 0);
|
||||||
unsafe {
|
unsafe {
|
||||||
buffer_self_copy(
|
buffer_self_copy(
|
||||||
@ -1139,6 +1134,13 @@ where
|
|||||||
target + range.len(),
|
target + range.len(),
|
||||||
size - target,
|
size - target,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||||
|
// No need to load the input again, it'll still be cached.
|
||||||
|
let other = other_testcase.input().as_ref().unwrap();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
buffer_copy(
|
buffer_copy(
|
||||||
input.bytes_mut(),
|
input.bytes_mut(),
|
||||||
other.bytes(),
|
other.bytes(),
|
||||||
@ -1193,13 +1195,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let other_size = state
|
let other_size = {
|
||||||
.corpus()
|
let mut testcase = state.corpus().get(idx)?.borrow_mut();
|
||||||
.get(idx)?
|
testcase.load_input(state.corpus())?.bytes().len()
|
||||||
.borrow_mut()
|
};
|
||||||
.load_input()?
|
|
||||||
.bytes()
|
|
||||||
.len();
|
|
||||||
if other_size < 2 {
|
if other_size < 2 {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
}
|
}
|
||||||
@ -1207,8 +1207,9 @@ where
|
|||||||
let target = state.rand_mut().below(size as u64) as usize;
|
let target = state.rand_mut().below(size as u64) as usize;
|
||||||
let range = rand_range(state, other_size, min(other_size, size - target));
|
let range = rand_range(state, other_size, min(other_size, size - target));
|
||||||
|
|
||||||
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
let other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||||
let other = other_testcase.load_input()?;
|
// No need to load the input again, it'll still be cached.
|
||||||
|
let other = other_testcase.input().as_ref().unwrap();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
buffer_copy(
|
buffer_copy(
|
||||||
@ -1279,7 +1280,7 @@ where
|
|||||||
|
|
||||||
let (first_diff, last_diff) = {
|
let (first_diff, last_diff) = {
|
||||||
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||||
let other = other_testcase.load_input()?;
|
let other = other_testcase.load_input(state.corpus())?;
|
||||||
|
|
||||||
let mut counter: u32 = 0;
|
let mut counter: u32 = 0;
|
||||||
loop {
|
loop {
|
||||||
@ -1297,8 +1298,10 @@ where
|
|||||||
|
|
||||||
let split_at = state.rand_mut().between(first_diff, last_diff) as usize;
|
let split_at = state.rand_mut().between(first_diff, last_diff) as usize;
|
||||||
|
|
||||||
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
let other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||||
let other = other_testcase.load_input()?;
|
// Input will already be loaded.
|
||||||
|
let other = other_testcase.input().as_ref().unwrap();
|
||||||
|
|
||||||
input
|
input
|
||||||
.bytes_mut()
|
.bytes_mut()
|
||||||
.splice(split_at.., other.bytes()[split_at..].iter().copied());
|
.splice(split_at.., other.bytes()[split_at..].iter().copied());
|
||||||
|
@ -440,10 +440,7 @@ 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
|
let mut input = corpus.cloned_input_for_id(corpus.first().unwrap()).unwrap();
|
||||||
.get(corpus.first().unwrap())
|
|
||||||
.expect("Corpus did not contain entries");
|
|
||||||
let mut input = testcase.borrow_mut().load_input().unwrap().clone();
|
|
||||||
|
|
||||||
let mut feedback = ConstFeedback::new(false);
|
let mut feedback = ConstFeedback::new(false);
|
||||||
let mut objective = ConstFeedback::new(false);
|
let mut objective = ConstFeedback::new(false);
|
||||||
@ -481,10 +478,7 @@ 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
|
let mut input = corpus.cloned_input_for_id(corpus.first().unwrap()).unwrap();
|
||||||
.get(corpus.first().unwrap())
|
|
||||||
.expect("Corpus did not contain entries");
|
|
||||||
let mut input = testcase.borrow_mut().load_input().unwrap().clone();
|
|
||||||
let input_prior = input.clone();
|
let input_prior = input.clone();
|
||||||
|
|
||||||
let mut feedback = ConstFeedback::new(false);
|
let mut feedback = ConstFeedback::new(false);
|
||||||
|
@ -369,7 +369,7 @@ where
|
|||||||
{
|
{
|
||||||
/// Compute the `weight` used in weighted corpus entry selection algo
|
/// Compute the `weight` used in weighted corpus entry selection algo
|
||||||
#[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
|
#[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
|
||||||
fn compute(entry: &mut Testcase<S::Input>, state: &S) -> Result<f64, Error> {
|
fn compute(state: &S, entry: &mut Testcase<S::Input>) -> Result<f64, Error> {
|
||||||
// subtract # initial inputs to the corpus count
|
// subtract # initial inputs to the corpus count
|
||||||
let mut energy = 0;
|
let mut energy = 0;
|
||||||
let mut average_cost = (state.corpus().count() / state.executions()) as u64;
|
let mut average_cost = (state.corpus().count() / state.executions()) as u64;
|
||||||
|
@ -116,7 +116,7 @@ where
|
|||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
for i in state.corpus().ids() {
|
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(state, &mut *old)?;
|
||||||
if let Some(old_map) = old.metadata_map_mut().get_mut::<M>() {
|
if let Some(old_map) = old.metadata_map_mut().get_mut::<M>() {
|
||||||
let mut e_iter = entries.iter();
|
let mut e_iter = entries.iter();
|
||||||
let mut map_iter = old_map.as_slice().iter(); // ASSERTION: guaranteed to be in order?
|
let mut map_iter = old_map.as_slice().iter(); // ASSERTION: guaranteed to be in order?
|
||||||
@ -256,7 +256,7 @@ where
|
|||||||
let mut new_favoreds = vec![];
|
let mut new_favoreds = vec![];
|
||||||
{
|
{
|
||||||
let mut entry = state.corpus().get(idx)?.borrow_mut();
|
let mut entry = state.corpus().get(idx)?.borrow_mut();
|
||||||
let factor = F::compute(&mut *entry, state)?;
|
let factor = F::compute(state, &mut *entry)?;
|
||||||
let meta = entry.metadata_map_mut().get_mut::<M>().ok_or_else(|| {
|
let meta = entry.metadata_map_mut().get_mut::<M>().ok_or_else(|| {
|
||||||
Error::key_not_found(format!(
|
Error::key_not_found(format!(
|
||||||
"Metadata needed for MinimizerScheduler not found in testcase #{idx}"
|
"Metadata needed for MinimizerScheduler not found in testcase #{idx}"
|
||||||
@ -270,7 +270,7 @@ where
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut old = state.corpus().get(*old_idx)?.borrow_mut();
|
let mut old = state.corpus().get(*old_idx)?.borrow_mut();
|
||||||
if factor > F::compute(&mut *old, state)? {
|
if factor > F::compute(state, &mut *old)? {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ where
|
|||||||
#[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: CorpusId) -> 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(state, &mut *state.corpus().get(idx)?.borrow_mut())?;
|
||||||
if factor == 0.0 {
|
if factor == 0.0 {
|
||||||
return Err(Error::illegal_state(
|
return Err(Error::illegal_state(
|
||||||
"Infinity probability calculated for probabilistic sampling scheduler",
|
"Infinity probability calculated for probabilistic sampling scheduler",
|
||||||
@ -186,7 +186,7 @@ mod tests {
|
|||||||
where
|
where
|
||||||
S: HasMetadata + HasCorpus,
|
S: HasMetadata + HasCorpus,
|
||||||
{
|
{
|
||||||
fn compute(_: &mut Testcase<S::Input>, _state: &S) -> Result<f64, Error> {
|
fn compute(_state: &S, _: &mut Testcase<S::Input>) -> Result<f64, Error> {
|
||||||
Ok(FACTOR)
|
Ok(FACTOR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,10 +107,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut q =
|
let mut q =
|
||||||
OnDiskCorpus::<BytesInput>::new(PathBuf::from("target/.test/fancy/path")).unwrap();
|
OnDiskCorpus::<BytesInput>::new(PathBuf::from("target/.test/fancy/path")).unwrap();
|
||||||
let t = Testcase::with_filename(
|
let t = Testcase::with_filename(BytesInput::new(vec![0_u8; 4]), "fancyfile".into());
|
||||||
BytesInput::new(vec![0_u8; 4]),
|
|
||||||
"target/.test/fancy/path/fancyfile".into(),
|
|
||||||
);
|
|
||||||
q.add(t).unwrap();
|
q.add(t).unwrap();
|
||||||
|
|
||||||
let objective_q =
|
let objective_q =
|
||||||
@ -133,7 +130,7 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
assert_eq!(filename, "target/.test/fancy/path/fancyfile");
|
assert_eq!(filename, "fancyfile");
|
||||||
|
|
||||||
fs::remove_dir_all("target/.test/fancy").unwrap();
|
fs::remove_dir_all("target/.test/fancy").unwrap();
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ where
|
|||||||
S: HasMetadata + HasCorpus,
|
S: HasMetadata + HasCorpus,
|
||||||
{
|
{
|
||||||
/// Computes the favor factor of a [`Testcase`]. Lower is better.
|
/// Computes the favor factor of a [`Testcase`]. Lower is better.
|
||||||
fn compute(entry: &mut Testcase<S::Input>, state: &S) -> Result<f64, Error>;
|
fn compute(state: &S, entry: &mut Testcase<S::Input>) -> Result<f64, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiply the testcase size with the execution time.
|
/// Multiply the testcase size with the execution time.
|
||||||
@ -36,9 +36,10 @@ where
|
|||||||
S::Input: HasLen,
|
S::Input: HasLen,
|
||||||
{
|
{
|
||||||
#[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
|
#[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
|
||||||
fn compute(entry: &mut Testcase<S::Input>, _state: &S) -> Result<f64, Error> {
|
fn compute(state: &S, entry: &mut Testcase<S::Input>) -> Result<f64, Error> {
|
||||||
// TODO maybe enforce entry.exec_time().is_some()
|
// TODO maybe enforce entry.exec_time().is_some()
|
||||||
Ok(entry.exec_time().map_or(1, |d| d.as_millis()) as f64 * entry.cached_len()? as f64)
|
Ok(entry.exec_time().map_or(1, |d| d.as_millis()) as f64
|
||||||
|
* entry.load_len(state.corpus())? as f64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +66,7 @@ where
|
|||||||
clippy::cast_sign_loss,
|
clippy::cast_sign_loss,
|
||||||
clippy::cast_lossless
|
clippy::cast_lossless
|
||||||
)]
|
)]
|
||||||
fn compute(entry: &mut Testcase<S::Input>, state: &S) -> Result<f64, Error> {
|
fn compute(state: &S, entry: &mut Testcase<S::Input>) -> Result<f64, Error> {
|
||||||
let psmeta = state.metadata::<SchedulerMetadata>()?;
|
let psmeta = state.metadata::<SchedulerMetadata>()?;
|
||||||
|
|
||||||
let fuzz_mu = if let Some(strat) = psmeta.strat() {
|
let fuzz_mu = if let Some(strat) = psmeta.strat() {
|
||||||
@ -273,7 +274,7 @@ where
|
|||||||
{
|
{
|
||||||
/// Compute the `weight` used in weighted corpus entry selection algo
|
/// Compute the `weight` used in weighted corpus entry selection algo
|
||||||
#[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
|
#[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
|
||||||
fn compute(entry: &mut Testcase<S::Input>, state: &S) -> Result<f64, Error> {
|
fn compute(state: &S, entry: &mut Testcase<S::Input>) -> Result<f64, Error> {
|
||||||
let mut weight = 1.0;
|
let mut weight = 1.0;
|
||||||
let psmeta = state.metadata::<SchedulerMetadata>()?;
|
let psmeta = state.metadata::<SchedulerMetadata>()?;
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ where
|
|||||||
|
|
||||||
for i in state.corpus().ids() {
|
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(state, &mut *testcase)?;
|
||||||
weights.insert(i, weight);
|
weights.insert(i, weight);
|
||||||
sum += weight;
|
sum += weight;
|
||||||
}
|
}
|
||||||
|
@ -115,12 +115,7 @@ where
|
|||||||
|
|
||||||
let mut iter = self.stage_max;
|
let mut iter = self.stage_max;
|
||||||
|
|
||||||
let input = state
|
let input = state.corpus().cloned_input_for_id(corpus_idx)?;
|
||||||
.corpus()
|
|
||||||
.get(corpus_idx)?
|
|
||||||
.borrow_mut()
|
|
||||||
.load_input()?
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
// Run once to get the initial calibration map
|
// Run once to get the initial calibration map
|
||||||
executor.observers_mut().pre_exec_all(state, &input)?;
|
executor.observers_mut().pre_exec_all(state, &input)?;
|
||||||
@ -158,12 +153,7 @@ where
|
|||||||
let mut has_errors = false;
|
let mut has_errors = false;
|
||||||
|
|
||||||
while i < iter {
|
while i < iter {
|
||||||
let input = state
|
let input = state.corpus().cloned_input_for_id(corpus_idx)?;
|
||||||
.corpus()
|
|
||||||
.get(corpus_idx)?
|
|
||||||
.borrow_mut()
|
|
||||||
.load_input()?
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
executor.observers_mut().pre_exec_all(state, &input)?;
|
executor.observers_mut().pre_exec_all(state, &input)?;
|
||||||
start = current_time();
|
start = current_time();
|
||||||
|
@ -155,13 +155,7 @@ where
|
|||||||
corpus_idx: CorpusId,
|
corpus_idx: CorpusId,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Result<E::Input, Error> {
|
) -> Result<E::Input, Error> {
|
||||||
let mut input = state
|
let mut input = state.corpus().cloned_input_for_id(corpus_idx)?;
|
||||||
.corpus()
|
|
||||||
.get(corpus_idx)?
|
|
||||||
.borrow_mut()
|
|
||||||
.load_input()
|
|
||||||
.unwrap()
|
|
||||||
.clone();
|
|
||||||
// The backup of the input
|
// The backup of the input
|
||||||
let backup = input.clone();
|
let backup = input.clone();
|
||||||
// This is the buffer we'll randomly mutate during type_replace
|
// This is the buffer we'll randomly mutate during type_replace
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! The [`DumpToDiskStage`] is a stage that dumps the corpus and the solutions to disk to e.g. allow AFL to sync
|
//! The [`DumpToDiskStage`] is a stage that dumps the corpus and the solutions to disk to e.g. allow AFL to sync
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::{string::String, vec::Vec};
|
||||||
use core::{clone::Clone, marker::PhantomData};
|
use core::{clone::Clone, marker::PhantomData};
|
||||||
use std::{fs, fs::File, io::Write, path::PathBuf};
|
use std::{fs, fs::File, io::Write, path::PathBuf};
|
||||||
|
|
||||||
@ -68,10 +68,16 @@ where
|
|||||||
|
|
||||||
while let Some(i) = corpus_idx {
|
while let Some(i) = corpus_idx {
|
||||||
let mut testcase = state.corpus().get(i)?.borrow_mut();
|
let mut testcase = state.corpus().get(i)?.borrow_mut();
|
||||||
let input = testcase.load_input()?;
|
state.corpus().load_input_into(&mut testcase)?;
|
||||||
let bytes = (self.to_bytes)(input);
|
let bytes = (self.to_bytes)(testcase.input().as_ref().unwrap());
|
||||||
|
|
||||||
let fname = self.corpus_dir.join(format!("id_{i}"));
|
let fname = self.corpus_dir.join(format!(
|
||||||
|
"id_{i}_{}",
|
||||||
|
testcase
|
||||||
|
.filename()
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(|| "unnamed", String::as_str)
|
||||||
|
));
|
||||||
let mut f = File::create(fname)?;
|
let mut f = File::create(fname)?;
|
||||||
drop(f.write_all(&bytes));
|
drop(f.write_all(&bytes));
|
||||||
|
|
||||||
@ -80,10 +86,16 @@ where
|
|||||||
|
|
||||||
while let Some(i) = solutions_idx {
|
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()?;
|
state.solutions().load_input_into(&mut testcase)?;
|
||||||
let bytes = (self.to_bytes)(input);
|
let bytes = (self.to_bytes)(testcase.input().as_ref().unwrap());
|
||||||
|
|
||||||
let fname = self.solutions_dir.join(format!("id_{i}"));
|
let fname = self.solutions_dir.join(format!(
|
||||||
|
"id_{i}_{}",
|
||||||
|
testcase
|
||||||
|
.filename()
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(|| "unnamed", String::as_str)
|
||||||
|
));
|
||||||
let mut f = File::create(fname)?;
|
let mut f = File::create(fname)?;
|
||||||
drop(f.write_all(&bytes));
|
drop(f.write_all(&bytes));
|
||||||
|
|
||||||
|
@ -79,10 +79,13 @@ where
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let (mut payload, original, novelties) = {
|
let (mut payload, original, novelties) = {
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
state.corpus().get(corpus_idx)?.borrow_mut().load_input()?;
|
{
|
||||||
|
let corpus = state.corpus();
|
||||||
|
let mut testcase = corpus.get(corpus_idx)?.borrow_mut();
|
||||||
|
corpus.load_input_into(&mut testcase)?;
|
||||||
|
}
|
||||||
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
||||||
let mut entry = state.corpus().get(corpus_idx)?.borrow_mut();
|
let mut entry = state.corpus().get(corpus_idx)?.borrow_mut();
|
||||||
|
|
||||||
let input = entry.input_mut().as_mut().unwrap();
|
let input = entry.input_mut().as_mut().unwrap();
|
||||||
|
|
||||||
let payload: Vec<_> = input.bytes().iter().map(|&x| Some(x)).collect();
|
let payload: Vec<_> = input.bytes().iter().map(|&x| Some(x)).collect();
|
||||||
|
@ -64,16 +64,18 @@ where
|
|||||||
impl<I, S> MutatedTransform<I, S> for I
|
impl<I, S> MutatedTransform<I, S> for I
|
||||||
where
|
where
|
||||||
I: Input + Clone,
|
I: Input + Clone,
|
||||||
|
S: HasCorpus<Input = I>,
|
||||||
{
|
{
|
||||||
type Post = ();
|
type Post = ();
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_transform_from(
|
fn try_transform_from(
|
||||||
base: &mut Testcase<I>,
|
base: &mut Testcase<I>,
|
||||||
_state: &S,
|
state: &S,
|
||||||
_corpus_idx: CorpusId,
|
_corpus_idx: CorpusId,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
Ok(base.load_input()?.clone())
|
state.corpus().load_input_into(base)?;
|
||||||
|
Ok(base.input().as_ref().unwrap().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -55,7 +55,7 @@ where
|
|||||||
fn iterations(&self, state: &mut E::State, corpus_idx: CorpusId) -> 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(state, &mut *testcase)? as u64;
|
||||||
|
|
||||||
Ok(score)
|
Ok(score)
|
||||||
}
|
}
|
||||||
|
@ -137,14 +137,15 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
let mut input = state
|
|
||||||
.corpus()
|
let input = state
|
||||||
.get(self.current_corpus_idx.unwrap())
|
.corpus_mut()
|
||||||
.unwrap()
|
.cloned_input_for_id(self.current_corpus_idx.unwrap());
|
||||||
.borrow_mut()
|
let mut input = match input {
|
||||||
.load_input()
|
Err(e) => return Some(Err(e)),
|
||||||
.unwrap()
|
Ok(input) => input,
|
||||||
.clone();
|
};
|
||||||
|
|
||||||
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
||||||
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
|
@ -268,7 +268,7 @@ where
|
|||||||
last_id.map_or_else(|| state.corpus().first(), |id| state.corpus().next(id));
|
last_id.map_or_else(|| state.corpus().first(), |id| state.corpus().next(id));
|
||||||
|
|
||||||
while let Some(id) = cur_id {
|
while let Some(id) = cur_id {
|
||||||
let input = state.testcase_mut(id)?.load_input()?.clone();
|
let input = state.corpus().cloned_input_for_id(id)?;
|
||||||
|
|
||||||
self.client.fire(
|
self.client.fire(
|
||||||
state,
|
state,
|
||||||
|
@ -72,12 +72,7 @@ where
|
|||||||
let num = self.iterations(state, base_corpus_idx)?;
|
let num = self.iterations(state, base_corpus_idx)?;
|
||||||
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
let mut base = state
|
let mut base = state.corpus().cloned_input_for_id(base_corpus_idx)?;
|
||||||
.corpus()
|
|
||||||
.get(base_corpus_idx)?
|
|
||||||
.borrow_mut()
|
|
||||||
.load_input()?
|
|
||||||
.clone();
|
|
||||||
let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher();
|
let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher();
|
||||||
base.hash(&mut hasher);
|
base.hash(&mut hasher);
|
||||||
let base_hash = hasher.finish();
|
let base_hash = hasher.finish();
|
||||||
|
@ -51,12 +51,8 @@ where
|
|||||||
corpus_idx: CorpusId,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
let input = state
|
let input = state.corpus().cloned_input_for_id(corpus_idx)?;
|
||||||
.corpus()
|
|
||||||
.get(corpus_idx)?
|
|
||||||
.borrow_mut()
|
|
||||||
.load_input()?
|
|
||||||
.clone();
|
|
||||||
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
||||||
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
@ -142,12 +138,7 @@ where
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// First run with the un-mutated input
|
// First run with the un-mutated input
|
||||||
|
|
||||||
let unmutated_input = state
|
let unmutated_input = state.corpus().cloned_input_for_id(corpus_idx)?;
|
||||||
.corpus()
|
|
||||||
.get(corpus_idx)?
|
|
||||||
.borrow_mut()
|
|
||||||
.load_input()?
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
if let Some(name) = &self.cmplog_observer_name {
|
if let Some(name) = &self.cmplog_observer_name {
|
||||||
if let Some(ob) = self
|
if let Some(ob) = self
|
||||||
@ -277,12 +268,8 @@ where
|
|||||||
corpus_idx: CorpusId,
|
corpus_idx: CorpusId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
let input = state
|
let input = state.corpus().cloned_input_for_id(corpus_idx)?;
|
||||||
.corpus()
|
|
||||||
.get(corpus_idx)?
|
|
||||||
.borrow_mut()
|
|
||||||
.load_input()?
|
|
||||||
.clone();
|
|
||||||
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
||||||
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user