Merge branch 'main' of github.com:AFLplusplus/LibAFL into main
This commit is contained in:
commit
56e05d0ff0
@ -182,8 +182,8 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
let iters = 1_000_000;
|
let iters = 1_000_000;
|
||||||
fuzzer.fuzz_loop_for(
|
fuzzer.fuzz_loop_for(
|
||||||
&mut stages,
|
&mut stages,
|
||||||
&mut state,
|
|
||||||
&mut executor,
|
&mut executor,
|
||||||
|
&mut state,
|
||||||
&mut restarting_mgr,
|
&mut restarting_mgr,
|
||||||
iters,
|
iters,
|
||||||
)?;
|
)?;
|
||||||
|
@ -15,12 +15,13 @@ To build this example, run
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo build --release
|
cargo build --release
|
||||||
|
clang -c weak.c -o weak.o
|
||||||
```
|
```
|
||||||
|
|
||||||
This will build the library with the fuzzer (src/lib.rs) with the libfuzzer compatibility layer and the SanitizerCoverage runtime functions for coverage feedback.
|
This will build the library with the fuzzer (src/lib.rs) with the libfuzzer compatibility layer and the SanitizerCoverage runtime functions for coverage feedback.
|
||||||
In addition, it will also build two C and C++ compiler wrappers (bin/libafl_c(libafl_c/xx).rs) that you must use to compile the target.
|
In addition, it will also build two C and C++ compiler wrappers (bin/libafl_c(libafl_c/xx).rs) that you must use to compile the target.
|
||||||
|
|
||||||
The compiler wrappers, `libafl_cc` and libafl_cxx`, will end up in `./target/release/` (or `./target/debug`, in case you did not build with the `--release` flag).
|
The compiler wrappers, `libafl_cc` and `libafl_cxx`, will end up in `./target/release/` (or `./target/debug`, in case you did not build with the `--release` flag).
|
||||||
|
|
||||||
Then download libpng, and unpack the archive:
|
Then download libpng, and unpack the archive:
|
||||||
```bash
|
```bash
|
||||||
@ -33,7 +34,7 @@ Now compile libpng, using the libafl_cc compiler wrapper:
|
|||||||
```bash
|
```bash
|
||||||
cd libpng-1.6.37
|
cd libpng-1.6.37
|
||||||
./configure
|
./configure
|
||||||
make CC="$(pwd)/../target/release/libafl_cc" CXX="$(pwd)/../target/release/libafl_cxx" -j `nproc`
|
LIBAFL_WEAK=../weak.o make CC="$(pwd)/../target/release/libafl_cc" CXX="$(pwd)/../target/release/libafl_cxx" -j `nproc`
|
||||||
```
|
```
|
||||||
|
|
||||||
You can find the static lib at `libpng-1.6.37/.libs/libpng16.a`.
|
You can find the static lib at `libpng-1.6.37/.libs/libpng16.a`.
|
||||||
@ -42,13 +43,17 @@ Now, we have to build the libfuzzer harness and link all together to create our
|
|||||||
|
|
||||||
```
|
```
|
||||||
cd ..
|
cd ..
|
||||||
./target/release/libafl_cxx ./harness.cc libpng-1.6.37/.libs/libpng16.a -I libpng-1.6.37/ -o fuzzer_libpng -lz -lm
|
LIBAFL_WEAK=./weak.o ./target/release/libafl_cxx ./harness.cc libpng-1.6.37/.libs/libpng16.a -I libpng-1.6.37/ -o fuzzer_libpng -lz -lm
|
||||||
```
|
```
|
||||||
|
|
||||||
Afterward, the fuzzer will be ready to run.
|
Afterward, the fuzzer will be ready to run.
|
||||||
Note that, unless you use the `launcher`, you will have to run the binary multiple times to actually start the fuzz process, see `Run` in the following.
|
Note that, unless you use the `launcher`, you will have to run the binary multiple times to actually start the fuzz process, see `Run` in the following.
|
||||||
This allows you to run multiple different builds of the same fuzzer alongside, for example, with and without ASAN (`-fsanitize=address`) or with different mutators.
|
This allows you to run multiple different builds of the same fuzzer alongside, for example, with and without ASAN (`-fsanitize=address`) or with different mutators.
|
||||||
|
|
||||||
|
This example also shows you how to use a user-defined variable from LibAFL.
|
||||||
|
`diff.patch` adds an array `__libafl_target_list` to `png.c`. In order to read from this variable from LibAFL, you need to weakly define __libafl_target_list as in `weak.c`.
|
||||||
|
For building, you have to set `LIBAFL_WEAK` to point to the compiled `weak.o`, so that the compiler can find this `weak.o` file and link successfully.
|
||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
The first time you run the binary, the broker will open a tcp port (currently on port `1337`), waiting for fuzzer clients to connect. This port is local and only used for the initial handshake. All further communication happens via shared map, to be independent of the kernel. Currently you must run the clients from the libfuzzer_libpng directory for them to be able to access the PNG corpus.
|
The first time you run the binary, the broker will open a tcp port (currently on port `1337`), waiting for fuzzer clients to connect. This port is local and only used for the initial handshake. All further communication happens via shared map, to be independent of the kernel. Currently you must run the clients from the libfuzzer_libpng directory for them to be able to access the PNG corpus.
|
||||||
|
@ -5,6 +5,7 @@ pub fn main() {
|
|||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
let mut dir = env::current_exe().unwrap();
|
let mut dir = env::current_exe().unwrap();
|
||||||
|
let weak = env::var("LIBAFL_WEAK").unwrap();
|
||||||
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
||||||
|
|
||||||
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
||||||
@ -22,6 +23,7 @@ pub fn main() {
|
|||||||
.silence(true)
|
.silence(true)
|
||||||
.from_args(&args)
|
.from_args(&args)
|
||||||
.expect("Failed to parse the command line")
|
.expect("Failed to parse the command line")
|
||||||
|
.add_link_arg(weak)
|
||||||
.link_staticlib(&dir, "libfuzzer_libpng")
|
.link_staticlib(&dir, "libfuzzer_libpng")
|
||||||
.add_arg("-fsanitize-coverage=trace-pc-guard")
|
.add_arg("-fsanitize-coverage=trace-pc-guard")
|
||||||
.run()
|
.run()
|
||||||
|
@ -147,8 +147,8 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
let iters = 1_000_000;
|
let iters = 1_000_000;
|
||||||
fuzzer.fuzz_loop_for(
|
fuzzer.fuzz_loop_for(
|
||||||
&mut stages,
|
&mut stages,
|
||||||
&mut state,
|
|
||||||
&mut executor,
|
&mut executor,
|
||||||
|
&mut state,
|
||||||
&mut restarting_mgr,
|
&mut restarting_mgr,
|
||||||
iters,
|
iters,
|
||||||
)?;
|
)?;
|
||||||
|
3
fuzzers/libfuzzer_reachability/weak.c
Normal file
3
fuzzers/libfuzzer_reachability/weak.c
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include<stddef.h>
|
||||||
|
__attribute__((weak, visibility("default"))) size_t *__libafl_target_list;
|
||||||
|
|
@ -173,8 +173,8 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
let iters = 1_000_000;
|
let iters = 1_000_000;
|
||||||
fuzzer.fuzz_loop_for(
|
fuzzer.fuzz_loop_for(
|
||||||
&mut stages,
|
&mut stages,
|
||||||
&mut state,
|
|
||||||
&mut executor,
|
&mut executor,
|
||||||
|
&mut state,
|
||||||
&mut restarting_mgr,
|
&mut restarting_mgr,
|
||||||
iters,
|
iters,
|
||||||
)?;
|
)?;
|
||||||
|
@ -20,6 +20,7 @@ pub mod shmem;
|
|||||||
pub mod staterestore;
|
pub mod staterestore;
|
||||||
pub mod tuples;
|
pub mod tuples;
|
||||||
|
|
||||||
|
use alloc::string::String;
|
||||||
use core::time;
|
use core::time;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
@ -85,3 +86,10 @@ pub fn current_nanos() -> u64 {
|
|||||||
pub fn current_milliseconds() -> u64 {
|
pub fn current_milliseconds() -> u64 {
|
||||||
current_time().as_millis() as u64
|
current_time().as_millis() as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format a `Duration` into a HMS string
|
||||||
|
#[must_use]
|
||||||
|
pub fn format_duration_hms(duration: &time::Duration) -> String {
|
||||||
|
let secs = duration.as_secs();
|
||||||
|
format!("{}h-{}m-{}s", (secs / 60) / 60, (secs / 60) % 60, secs % 60)
|
||||||
|
}
|
||||||
|
@ -866,7 +866,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Storing state in the last round did not work
|
// Storing state in the last round did not work
|
||||||
panic!("Fuzzer-respawner: Storing state in crashed fuzzer instance did not work, no point to spawn the next client! (Child exited with: {})", child_status);
|
panic!("Fuzzer-respawner: Storing state in crashed fuzzer instance did not work, no point to spawn the next client! This can happen if the child calls `exit()`, in that case make sure it uses `abort()`, if it got killed unrecoverable (OOM), or if there is a bug in the fuzzer itself. (Child exited with: {})", child_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctr = ctr.wrapping_add(1);
|
ctr = ctr.wrapping_add(1);
|
||||||
|
@ -376,7 +376,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Storing state in the last round did not work
|
// Storing state in the last round did not work
|
||||||
panic!("Fuzzer-respawner: Storing state in crashed fuzzer instance did not work, no point to spawn the next client! (Child exited with: {})", child_status);
|
panic!("Fuzzer-respawner: Storing state in crashed fuzzer instance did not work, no point to spawn the next client! This can happen if the child calls `exit()`, in that case make sure it uses `abort()`, if it got killed unrecoverable (OOM), or if there is a bug in the fuzzer itself. (Child exited with: {})", child_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctr = ctr.wrapping_add(1);
|
ctr = ctr.wrapping_add(1);
|
||||||
|
@ -188,8 +188,8 @@ pub trait Fuzzer<E, EM, I, S, ST> {
|
|||||||
fn fuzz_loop_for(
|
fn fuzz_loop_for(
|
||||||
&mut self,
|
&mut self,
|
||||||
stages: &mut ST,
|
stages: &mut ST,
|
||||||
state: &mut S,
|
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
iters: u64,
|
iters: u64,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
|
@ -42,20 +42,20 @@ pub use fuzzer::*;
|
|||||||
|
|
||||||
/// The `stats` module got renamed to [`monitors`].
|
/// The `stats` module got renamed to [`monitors`].
|
||||||
/// It monitors and displays the statistics of the fuzzing process.
|
/// It monitors and displays the statistics of the fuzzing process.
|
||||||
#[deprecated(since = "0.6.0", note = "The `stats` module got renamed to `monitors`")]
|
#[deprecated(since = "0.7.0", note = "The `stats` module got renamed to `monitors`")]
|
||||||
pub mod stats {
|
pub mod stats {
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "0.6.0",
|
since = "0.7.0",
|
||||||
note = "Use monitors::MultiMonitor instead of stats::MultiStats!"
|
note = "Use monitors::MultiMonitor instead of stats::MultiStats!"
|
||||||
)]
|
)]
|
||||||
pub use crate::monitors::MultiMonitor as MultiStats;
|
pub use crate::monitors::MultiMonitor as MultiStats;
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "0.6.0",
|
since = "0.7.0",
|
||||||
note = "Use monitors::SimpleMonitor instead of stats::SimpleStats!"
|
note = "Use monitors::SimpleMonitor instead of stats::SimpleStats!"
|
||||||
)]
|
)]
|
||||||
pub use crate::monitors::SimpleMonitor as SimpleStats;
|
pub use crate::monitors::SimpleMonitor as SimpleStats;
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "0.6.0",
|
since = "0.7.0",
|
||||||
note = "Use monitors::UserMonitor instead of stats::SimpleStats!"
|
note = "Use monitors::UserMonitor instead of stats::SimpleStats!"
|
||||||
)]
|
)]
|
||||||
pub use crate::monitors::UserStats;
|
pub use crate::monitors::UserStats;
|
||||||
|
@ -13,7 +13,7 @@ use hashbrown::HashMap;
|
|||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
use alloc::string::ToString;
|
use alloc::string::ToString;
|
||||||
|
|
||||||
use crate::bolts::current_time;
|
use crate::bolts::{current_time, format_duration_hms};
|
||||||
|
|
||||||
const CLIENT_STATS_TIME_WINDOW_SECS: u64 = 5; // 5 seconds
|
const CLIENT_STATS_TIME_WINDOW_SECS: u64 = 5; // 5 seconds
|
||||||
|
|
||||||
@ -269,10 +269,10 @@ where
|
|||||||
|
|
||||||
fn display(&mut self, event_msg: String, sender_id: u32) {
|
fn display(&mut self, event_msg: String, sender_id: u32) {
|
||||||
let fmt = format!(
|
let fmt = format!(
|
||||||
"{}: [{} #{}] clients: {}, corpus: {}, objectives: {}, executions: {}, exec/sec: {}",
|
"[{} #{}] run time: {}, clients: {}, corpus: {}, objectives: {}, executions: {}, exec/sec: {}",
|
||||||
(current_time() - self.start_time).as_millis(),
|
|
||||||
event_msg,
|
event_msg,
|
||||||
sender_id,
|
sender_id,
|
||||||
|
format_duration_hms(&(current_time() - self.start_time)),
|
||||||
self.client_stats().len(),
|
self.client_stats().len(),
|
||||||
self.corpus_size(),
|
self.corpus_size(),
|
||||||
self.objective_size(),
|
self.objective_size(),
|
||||||
|
@ -7,7 +7,7 @@ use core::{time, time::Duration};
|
|||||||
use alloc::string::ToString;
|
use alloc::string::ToString;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::current_time,
|
bolts::{current_time, format_duration_hms},
|
||||||
monitors::{ClientStats, Monitor},
|
monitors::{ClientStats, Monitor},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,8 +50,9 @@ where
|
|||||||
};
|
};
|
||||||
let head = format!("{}{} {}", event_msg, pad, sender);
|
let head = format!("{}{} {}", event_msg, pad, sender);
|
||||||
let global_fmt = format!(
|
let global_fmt = format!(
|
||||||
"[{}] (GLOBAL) clients: {}, corpus: {}, objectives: {}, executions: {}, exec/sec: {}",
|
"[{}] (GLOBAL) run time: {}, clients: {}, corpus: {}, objectives: {}, executions: {}, exec/sec: {}",
|
||||||
head,
|
head,
|
||||||
|
format_duration_hms(&(current_time() - self.start_time)),
|
||||||
self.client_stats().len(),
|
self.client_stats().len(),
|
||||||
self.corpus_size(),
|
self.corpus_size(),
|
||||||
self.objective_size(),
|
self.objective_size(),
|
||||||
|
@ -26,6 +26,11 @@ pub use concolic::ConcolicTracingStage;
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use concolic::SimpleConcolicMutationalStage;
|
pub use concolic::SimpleConcolicMutationalStage;
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub mod sync;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub use sync::*;
|
||||||
|
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use core::{convert::From, marker::PhantomData};
|
use core::{convert::From, marker::PhantomData};
|
||||||
|
|
||||||
|
@ -58,7 +58,6 @@ where
|
|||||||
{
|
{
|
||||||
initialized: bool,
|
initialized: bool,
|
||||||
state: Rc<RefCell<S>>,
|
state: Rc<RefCell<S>>,
|
||||||
current_iter: Option<usize>,
|
|
||||||
current_corpus_idx: Option<usize>,
|
current_corpus_idx: Option<usize>,
|
||||||
testcases_to_do: usize,
|
testcases_to_do: usize,
|
||||||
testcases_done: usize,
|
testcases_done: usize,
|
||||||
@ -201,7 +200,7 @@ where
|
|||||||
// We already ran once
|
// We already ran once
|
||||||
self.post_exec()
|
self.post_exec()
|
||||||
} else {
|
} else {
|
||||||
self.init() // TODO: Corpus idx
|
self.init()
|
||||||
};
|
};
|
||||||
if let Err(err) = step_success {
|
if let Err(err) = step_success {
|
||||||
//let errored = true;
|
//let errored = true;
|
||||||
@ -264,7 +263,6 @@ where
|
|||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
initialized: false,
|
initialized: false,
|
||||||
state,
|
state,
|
||||||
current_iter: None,
|
|
||||||
current_corpus_idx: None, // todo
|
current_corpus_idx: None, // todo
|
||||||
testcases_to_do: 0,
|
testcases_to_do: 0,
|
||||||
testcases_done: 0,
|
testcases_done: 0,
|
||||||
|
183
libafl/src/stages/sync.rs
Normal file
183
libafl/src/stages/sync.rs
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
//| The [`MutationalStage`] is the default stage used during fuzzing.
|
||||||
|
//! For the current input, it will perform a range of random mutations, and then run them in the executor.
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{
|
||||||
|
fs,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
time::SystemTime,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
bolts::rands::Rand,
|
||||||
|
corpus::Corpus,
|
||||||
|
fuzzer::Evaluator,
|
||||||
|
inputs::Input,
|
||||||
|
stages::Stage,
|
||||||
|
state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand},
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct SyncFromDiskMetadata {
|
||||||
|
pub last_time: SystemTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::impl_serdeany!(SyncFromDiskMetadata);
|
||||||
|
|
||||||
|
impl SyncFromDiskMetadata {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(last_time: SystemTime) -> Self {
|
||||||
|
Self { last_time }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A stage that loads testcases from disk to sync with other fuzzers such as AFL++
|
||||||
|
pub struct SyncFromDiskStage<C, CB, E, EM, I, R, S, Z>
|
||||||
|
where
|
||||||
|
C: Corpus<I>,
|
||||||
|
CB: FnMut(&mut Z, &mut S, &Path) -> Result<I, Error>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
S: HasClientPerfMonitor + HasCorpus<C, I> + HasRand<R> + HasMetadata,
|
||||||
|
Z: Evaluator<E, EM, I, S>,
|
||||||
|
{
|
||||||
|
sync_dir: PathBuf,
|
||||||
|
load_callback: CB,
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
phantom: PhantomData<(C, E, EM, I, R, S, Z)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, CB, E, EM, I, R, S, Z> Stage<E, EM, S, Z> for SyncFromDiskStage<C, CB, E, EM, I, R, S, Z>
|
||||||
|
where
|
||||||
|
C: Corpus<I>,
|
||||||
|
CB: FnMut(&mut Z, &mut S, &Path) -> Result<I, Error>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
S: HasClientPerfMonitor + HasCorpus<C, I> + HasRand<R> + HasMetadata,
|
||||||
|
Z: Evaluator<E, EM, I, S>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn perform(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
executor: &mut E,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
_corpus_idx: usize,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let last = state
|
||||||
|
.metadata()
|
||||||
|
.get::<SyncFromDiskMetadata>()
|
||||||
|
.map(|m| m.last_time);
|
||||||
|
let path = self.sync_dir.clone();
|
||||||
|
if let Some(max_time) =
|
||||||
|
self.load_from_directory(&path, &last, fuzzer, executor, state, manager)?
|
||||||
|
{
|
||||||
|
if last.is_none() {
|
||||||
|
state
|
||||||
|
.metadata_mut()
|
||||||
|
.insert(SyncFromDiskMetadata::new(max_time));
|
||||||
|
} else {
|
||||||
|
state
|
||||||
|
.metadata_mut()
|
||||||
|
.get_mut::<SyncFromDiskMetadata>()
|
||||||
|
.unwrap()
|
||||||
|
.last_time = max_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
state.introspection_monitor_mut().finish_stage();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, CB, E, EM, I, R, S, Z> SyncFromDiskStage<C, CB, E, EM, I, R, S, Z>
|
||||||
|
where
|
||||||
|
C: Corpus<I>,
|
||||||
|
CB: FnMut(&mut Z, &mut S, &Path) -> Result<I, Error>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
S: HasClientPerfMonitor + HasCorpus<C, I> + HasRand<R> + HasMetadata,
|
||||||
|
Z: Evaluator<E, EM, I, S>,
|
||||||
|
{
|
||||||
|
/// Creates a new [`SyncFromDiskStage`]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(sync_dir: PathBuf, load_callback: CB) -> Self {
|
||||||
|
Self {
|
||||||
|
sync_dir,
|
||||||
|
load_callback,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_from_directory(
|
||||||
|
&mut self,
|
||||||
|
in_dir: &Path,
|
||||||
|
last: &Option<SystemTime>,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
executor: &mut E,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
) -> Result<Option<SystemTime>, Error> {
|
||||||
|
let mut max_time = None;
|
||||||
|
for entry in fs::read_dir(in_dir)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let path = entry.path();
|
||||||
|
let attributes = fs::metadata(&path);
|
||||||
|
|
||||||
|
if attributes.is_err() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let attr = attributes?;
|
||||||
|
|
||||||
|
if attr.is_file() && attr.len() > 0 {
|
||||||
|
if let Ok(time) = attr.modified() {
|
||||||
|
if let Some(l) = last {
|
||||||
|
if time.duration_since(*l).is_err() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max_time = Some(max_time.map_or(time, |t: SystemTime| t.max(time)));
|
||||||
|
let input = (self.load_callback)(fuzzer, state, &path)?;
|
||||||
|
drop(fuzzer.evaluate_input(state, executor, manager, input)?);
|
||||||
|
}
|
||||||
|
} else if attr.is_dir() {
|
||||||
|
let dir_max_time =
|
||||||
|
self.load_from_directory(&path, last, fuzzer, executor, state, manager)?;
|
||||||
|
if let Some(time) = dir_max_time {
|
||||||
|
max_time = Some(max_time.map_or(time, |t: SystemTime| t.max(time)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(max_time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, E, EM, I, R, S, Z>
|
||||||
|
SyncFromDiskStage<C, fn(&mut Z, &mut S, &Path) -> Result<I, Error>, E, EM, I, R, S, Z>
|
||||||
|
where
|
||||||
|
C: Corpus<I>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
S: HasClientPerfMonitor + HasCorpus<C, I> + HasRand<R> + HasMetadata,
|
||||||
|
Z: Evaluator<E, EM, I, S>,
|
||||||
|
{
|
||||||
|
/// Creates a new [`SyncFromDiskStage`] invoking `Input::from_file` to load inputs
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_from_file(sync_dir: PathBuf) -> Self {
|
||||||
|
fn load_callback<Z, S, I: Input>(_: &mut Z, _: &mut S, p: &Path) -> Result<I, Error> {
|
||||||
|
I::from_file(p)
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
sync_dir,
|
||||||
|
load_callback: load_callback::<_, _, I>,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user