Implement CanTrack tracking enforcement through rust types (#1886)
* sample implementation of tracking enforcement (incomplete) * helpful compiler output * make it look like a real compiler output * ensure that the macro may be used outside of libafl * separate index/novelty tracking funcs * default const generic values so that we don't need to change this everywhere * fix tests * rollback unnecessary specification of stdmapobserver * register metadata in doc tests * doc fixes * doc cleanup * doc cleanup 2 * reduce implementor overhead to zero * renaming/docs fixes * asref isn't reflexive?? * generalization stage updates * add better documentation about require_{indices,novelties}_tracking * remaining generic updates * round one CI pass (knowingly introduces breaking changes) * typo * round 2 clippy * rollback: libafl_frida changes * fmt * moar porting * fix remaining fuzzers * fix windows build, maybe * fixup libafl_libfuzzer * fmt nighlty all the things * attempt to fix some broken additions * fix fmt * oops * fix new invocation * minimizer scheduler fixes * fix accounting * rename * fix * Fix build * Sort generics * Move more generics into the right place * Rename A -> C * Fix test * Fix test some more * Fix doc some more * critical formatting * More A->C * CanTrack harder --------- Co-authored-by: Dominik Maier <dmnk@google.com>
This commit is contained in:
parent
ec935bf95f
commit
3d702f403b
@ -117,7 +117,7 @@ For bugs, feel free to open issues or contact us directly. Thank you for your su
|
||||
|
||||
Even though we will gladly assist you in finishing up your PR, try to
|
||||
- keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/build.rs#L26))
|
||||
- run `cargo fmt` on your code before pushing
|
||||
- run `cargo +nightly fmt` on your code before pushing
|
||||
- check the output of `cargo clippy --all` or `./clippy.sh`
|
||||
- run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code.
|
||||
|
||||
|
@ -15,7 +15,7 @@ use libafl::{
|
||||
GrimoireRandomDeleteMutator, GrimoireRecursiveReplacementMutator,
|
||||
GrimoireStringReplacementMutator, Tokens,
|
||||
},
|
||||
observers::StdMapObserver,
|
||||
observers::{CanTrack, StdMapObserver},
|
||||
schedulers::QueueScheduler,
|
||||
stages::{mutational::StdMutationalStage, GeneralizationStage},
|
||||
state::StdState,
|
||||
@ -83,9 +83,11 @@ pub fn main() {
|
||||
};
|
||||
|
||||
// Create an observation channel using the signals map
|
||||
let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) };
|
||||
let observer = unsafe {
|
||||
StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()).track_novelties()
|
||||
};
|
||||
// Feedback to rate the interestingness of an input
|
||||
let mut feedback = MaxMapFeedback::tracking(&observer, false, true);
|
||||
let mut feedback = MaxMapFeedback::new(&observer);
|
||||
|
||||
// A feedback to choose if an input is a solution or not
|
||||
let mut objective = CrashFeedback::new();
|
||||
|
@ -19,6 +19,9 @@ command = "cargo"
|
||||
args = ["build" , "--profile", "${PROFILE}", "--bin", "${FUZZER_NAME}"]
|
||||
dependencies = [ "cc" ]
|
||||
|
||||
[tasks.build]
|
||||
alias = "fuzzer"
|
||||
|
||||
# Run the fuzzer
|
||||
[tasks.run]
|
||||
command = "${CARGO_TARGET_DIR}/${PROFILE_DIR}/${FUZZER_NAME}"
|
||||
|
@ -54,7 +54,7 @@ pub fn main() {
|
||||
|
||||
// Feedback to rate the interestingness of an input
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let mut feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
// A feedback to choose if an input is a solution or not
|
||||
// We want to do the same crash deduplication that AFL does
|
||||
|
@ -12,7 +12,7 @@ use libafl::{
|
||||
inputs::BytesInput,
|
||||
monitors::SimpleMonitor,
|
||||
mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::mutational::StdMutationalStage,
|
||||
state::{HasCorpus, StdState},
|
||||
@ -101,8 +101,9 @@ pub fn main() {
|
||||
let shmem_buf = shmem.as_mut_slice();
|
||||
|
||||
// Create an observation channel using the signals map
|
||||
let edges_observer =
|
||||
unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) };
|
||||
let edges_observer = unsafe {
|
||||
HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)).track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -111,7 +112,7 @@ pub fn main() {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -151,7 +152,7 @@ pub fn main() {
|
||||
let mut mgr = SimpleEventManager::new(monitor);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -12,7 +12,7 @@ use libafl::{
|
||||
inputs::BytesInput,
|
||||
monitors::SimpleMonitor,
|
||||
mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::mutational::StdMutationalStage,
|
||||
state::{HasCorpus, StdState},
|
||||
@ -101,8 +101,9 @@ pub fn main() {
|
||||
let shmem_buf = shmem.as_mut_slice();
|
||||
|
||||
// Create an observation channel using the signals map
|
||||
let edges_observer =
|
||||
unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) };
|
||||
let edges_observer = unsafe {
|
||||
HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)).track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -111,7 +112,7 @@ pub fn main() {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -151,7 +152,7 @@ pub fn main() {
|
||||
let mut mgr = SimpleEventManager::new(monitor);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -1,9 +1,5 @@
|
||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||
//! The example harness is built for libpng.
|
||||
use mimalloc::MiMalloc;
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
use std::{path::PathBuf, ptr::null};
|
||||
|
||||
use frida_gum::Gum;
|
||||
@ -20,7 +16,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::{I2SRandReplace, Tokens},
|
||||
},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::{ShadowTracingStage, StdMutationalStage},
|
||||
state::{HasCorpus, StdState},
|
||||
@ -39,7 +35,7 @@ use libafl_bolts::{
|
||||
#[cfg(unix)]
|
||||
use libafl_frida::asan::{
|
||||
asan_rt::AsanRuntime,
|
||||
errors::{AsanErrorsFeedback, AsanErrorsObserver},
|
||||
errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS},
|
||||
};
|
||||
use libafl_frida::{
|
||||
cmplog_rt::CmpLogRuntime,
|
||||
@ -48,6 +44,10 @@ use libafl_frida::{
|
||||
helper::FridaInstrumentationHelper,
|
||||
};
|
||||
use libafl_targets::cmplog::CmpLogObserver;
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
pub unsafe fn lib(main: extern "C" fn(i32, *const *const u8, *const *const u8) -> i32) {
|
||||
color_backtrace::install();
|
||||
@ -104,7 +104,7 @@ unsafe fn fuzz(
|
||||
|
||||
let coverage = CoverageRuntime::new();
|
||||
#[cfg(unix)]
|
||||
let asan = AsanRuntime::new(options);
|
||||
let asan = AsanRuntime::new(&options);
|
||||
|
||||
#[cfg(unix)]
|
||||
let mut frida_helper =
|
||||
@ -118,7 +118,8 @@ unsafe fn fuzz(
|
||||
"edges",
|
||||
frida_helper.map_mut_ptr().unwrap(),
|
||||
MAP_SIZE,
|
||||
));
|
||||
))
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -127,7 +128,7 @@ unsafe fn fuzz(
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -177,7 +178,8 @@ unsafe fn fuzz(
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
@ -233,7 +235,8 @@ unsafe fn fuzz(
|
||||
"edges",
|
||||
frida_helper.map_mut_ptr().unwrap(),
|
||||
MAP_SIZE,
|
||||
));
|
||||
))
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -242,7 +245,7 @@ unsafe fn fuzz(
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -290,7 +293,8 @@ unsafe fn fuzz(
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
@ -361,7 +365,8 @@ unsafe fn fuzz(
|
||||
"edges",
|
||||
frida_helper.map_mut_ptr().unwrap(),
|
||||
MAP_SIZE,
|
||||
));
|
||||
))
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -370,7 +375,7 @@ unsafe fn fuzz(
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -418,7 +423,8 @@ unsafe fn fuzz(
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -26,7 +26,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::{I2SRandReplace, Tokens},
|
||||
},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::{ShadowTracingStage, StdMutationalStage},
|
||||
state::{HasCorpus, StdState},
|
||||
@ -113,7 +113,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
"edges",
|
||||
frida_helper.map_mut_ptr().unwrap(),
|
||||
MAP_SIZE,
|
||||
));
|
||||
))
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -122,7 +123,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -171,7 +172,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
@ -227,7 +229,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
"edges",
|
||||
frida_helper.map_mut_ptr().unwrap(),
|
||||
MAP_SIZE,
|
||||
));
|
||||
))
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -236,7 +239,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -284,7 +287,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
@ -356,7 +360,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
"edges",
|
||||
frida_helper.map_mut_ptr().unwrap(),
|
||||
MAP_SIZE,
|
||||
));
|
||||
))
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -365,7 +370,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -413,7 +418,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -1,9 +1,5 @@
|
||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||
//! The example harness is built for libpng.
|
||||
use mimalloc::MiMalloc;
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use frida_gum::Gum;
|
||||
@ -20,7 +16,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::{I2SRandReplace, Tokens},
|
||||
},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::{ShadowTracingStage, StdMutationalStage},
|
||||
state::{HasCorpus, StdState},
|
||||
@ -39,7 +35,7 @@ use libafl_bolts::{
|
||||
#[cfg(unix)]
|
||||
use libafl_frida::asan::{
|
||||
asan_rt::AsanRuntime,
|
||||
errors::{AsanErrorsFeedback, AsanErrorsObserver},
|
||||
errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS},
|
||||
};
|
||||
use libafl_frida::{
|
||||
cmplog_rt::CmpLogRuntime,
|
||||
@ -48,6 +44,10 @@ use libafl_frida::{
|
||||
helper::FridaInstrumentationHelper,
|
||||
};
|
||||
use libafl_targets::cmplog::CmpLogObserver;
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
/// The main fn, usually parsing parameters, and starting the fuzzer
|
||||
pub fn main() {
|
||||
@ -108,7 +108,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
"edges",
|
||||
frida_helper.map_mut_ptr().unwrap(),
|
||||
MAP_SIZE,
|
||||
));
|
||||
))
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -117,7 +118,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -167,7 +168,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
@ -224,7 +226,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
"edges",
|
||||
frida_helper.map_mut_ptr().unwrap(),
|
||||
MAP_SIZE,
|
||||
));
|
||||
))
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -233,7 +236,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -281,7 +284,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
@ -352,7 +356,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
"edges",
|
||||
frida_helper.map_mut_ptr().unwrap(),
|
||||
MAP_SIZE,
|
||||
));
|
||||
))
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -361,7 +366,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -409,7 +414,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -28,7 +28,7 @@ use libafl::{
|
||||
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
|
||||
StdMOptMutator, StdScheduledMutator, Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
|
||||
},
|
||||
@ -242,14 +242,15 @@ fn fuzz(
|
||||
|
||||
// Create an observation channel using the coverage map
|
||||
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
|
||||
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") });
|
||||
let edges_observer =
|
||||
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let cmplog_observer = CmpLogObserver::new("cmplog", true);
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -307,11 +308,10 @@ fn fuzz(
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::FAST),
|
||||
));
|
||||
StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -31,7 +31,7 @@ use libafl::{
|
||||
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
|
||||
StdMOptMutator, StdScheduledMutator, Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
|
||||
},
|
||||
@ -252,14 +252,15 @@ fn fuzz(
|
||||
"edges",
|
||||
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE),
|
||||
)
|
||||
});
|
||||
})
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let cmplog_observer = CmpLogObserver::new("cmplog", true);
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -317,11 +318,10 @@ fn fuzz(
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::FAST),
|
||||
));
|
||||
StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -26,7 +26,7 @@ use libafl::{
|
||||
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
|
||||
StdMOptMutator, StdScheduledMutator, Tokens,
|
||||
},
|
||||
observers::{ConstMapObserver, HitcountsMapObserver, TimeObserver},
|
||||
observers::{CanTrack, ConstMapObserver, HitcountsMapObserver, TimeObserver},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler,
|
||||
},
|
||||
@ -242,6 +242,7 @@ fn fuzz(
|
||||
"edges",
|
||||
edges.as_mut_ptr(),
|
||||
))
|
||||
.track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
@ -250,7 +251,7 @@ fn fuzz(
|
||||
// Create an observation channel using cmplog map
|
||||
let cmplog_observer = unsafe { CmpLogObserver::with_map_ptr("cmplog", cmplog_map_ptr, true) };
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -299,11 +300,10 @@ fn fuzz(
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
PowerSchedule::FAST,
|
||||
));
|
||||
PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -21,7 +21,9 @@ use libafl::{
|
||||
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
|
||||
StdMOptMutator, StdScheduledMutator, Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, StdCmpValuesObserver, StdMapObserver, TimeObserver},
|
||||
observers::{
|
||||
CanTrack, HitcountsMapObserver, StdCmpValuesObserver, StdMapObserver, TimeObserver,
|
||||
},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
|
||||
},
|
||||
@ -248,13 +250,14 @@ fn fuzz(
|
||||
std::env::set_var("AFL_MAP_SIZE", format!("{}", MAP_SIZE));
|
||||
|
||||
// Create an observation channel using the hitcounts map of AFL++
|
||||
let edges_observer =
|
||||
unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) };
|
||||
let edges_observer = unsafe {
|
||||
HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)).track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -300,11 +303,14 @@ fn fuzz(
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::EXPLORE),
|
||||
));
|
||||
StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::EXPLORE),
|
||||
),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -21,7 +21,7 @@ use libafl::{
|
||||
scheduled::havoc_mutations, token_mutations::AFLppRedQueen, tokens_mutations,
|
||||
StdMOptMutator, Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
|
||||
},
|
||||
@ -251,13 +251,14 @@ fn fuzz(
|
||||
std::env::set_var("AFL_MAP_SIZE", format!("{MAP_SIZE}"));
|
||||
|
||||
// Create an observation channel using the hitcounts map of AFL++
|
||||
let edges_observer =
|
||||
unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) };
|
||||
let edges_observer = unsafe {
|
||||
HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)).track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -303,11 +304,14 @@ fn fuzz(
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::EXPLORE),
|
||||
));
|
||||
StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::EXPLORE),
|
||||
),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -25,7 +25,7 @@ use libafl::{
|
||||
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
|
||||
StdMOptMutator, StdScheduledMutator, Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler,
|
||||
},
|
||||
@ -53,6 +53,7 @@ use libafl_qemu::{
|
||||
elf::EasyElf,
|
||||
filter_qemu_args,
|
||||
hooks::QemuHooks,
|
||||
Emulator,
|
||||
GuestReg,
|
||||
//snapshot::QemuSnapshotHelper,
|
||||
MmapPerms,
|
||||
@ -259,6 +260,7 @@ fn fuzz(
|
||||
edges_map_mut_slice(),
|
||||
addr_of_mut!(MAX_EDGES_NUM),
|
||||
))
|
||||
.track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
@ -267,7 +269,7 @@ fn fuzz(
|
||||
// Create an observation channel using cmplog map
|
||||
let cmplog_observer = CmpLogObserver::new("cmplog", true);
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -316,11 +318,10 @@ fn fuzz(
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
PowerSchedule::FAST,
|
||||
));
|
||||
PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -34,7 +34,7 @@ use libafl::{
|
||||
token_mutations::I2SRandReplace,
|
||||
tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
|
||||
},
|
||||
@ -310,14 +310,15 @@ fn fuzz_binary(
|
||||
|
||||
// Create an observation channel using the coverage map
|
||||
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
|
||||
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") });
|
||||
let edges_observer =
|
||||
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let cmplog_observer = CmpLogObserver::new("cmplog", true);
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -374,11 +375,14 @@ fn fuzz_binary(
|
||||
let power = StdPowerMutationalStage::new(mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::EXPLORE),
|
||||
));
|
||||
StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::EXPLORE),
|
||||
),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
@ -516,7 +520,9 @@ fn fuzz_text(
|
||||
|
||||
// Create an observation channel using the coverage map
|
||||
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
|
||||
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") });
|
||||
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") })
|
||||
.track_indices()
|
||||
.track_novelties();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -524,7 +530,7 @@ fn fuzz_text(
|
||||
let cmplog_observer = CmpLogObserver::new("cmplog", true);
|
||||
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, true);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -594,11 +600,14 @@ fn fuzz_text(
|
||||
let grimoire = StdMutationalStage::transforming(grimoire_mutator);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::EXPLORE),
|
||||
));
|
||||
StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::EXPLORE),
|
||||
),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -25,7 +25,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::{I2SRandReplace, Tokens},
|
||||
},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::{StdMutationalStage, TracingStage},
|
||||
state::{HasCorpus, StdState},
|
||||
@ -136,7 +136,8 @@ pub extern "C" fn LLVMFuzzerRunDriver(
|
||||
let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_slice(
|
||||
"edges",
|
||||
edges.into_iter().next().unwrap(),
|
||||
));
|
||||
))
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -148,7 +149,7 @@ pub extern "C" fn LLVMFuzzerRunDriver(
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -183,7 +184,8 @@ pub extern "C" fn LLVMFuzzerRunDriver(
|
||||
}
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -1,9 +1,5 @@
|
||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||
//! The example harness is built for libpng.
|
||||
use mimalloc::MiMalloc;
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
use core::time::Duration;
|
||||
#[cfg(feature = "crash")]
|
||||
use std::ptr;
|
||||
@ -22,7 +18,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
|
||||
},
|
||||
@ -37,6 +33,10 @@ use libafl_bolts::{
|
||||
AsSlice,
|
||||
};
|
||||
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
/// The main fn, `no_mangle` as it is a C main
|
||||
#[cfg(not(test))]
|
||||
@ -85,12 +85,13 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
EDGES_MAP.as_mut_ptr(),
|
||||
MAX_EDGES_NUM,
|
||||
))
|
||||
.track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -147,11 +148,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
let mut stages = tuple_list!(calibration, power);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::FAST),
|
||||
));
|
||||
StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -2,10 +2,6 @@
|
||||
//! The example harness is built for libpng.
|
||||
//! In this example, you will see the use of the `launcher` feature.
|
||||
//! The `launcher` will spawn new processes for each cpu core.
|
||||
use mimalloc::MiMalloc;
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
use core::time::Duration;
|
||||
use std::{env, net::SocketAddr, path::PathBuf};
|
||||
|
||||
@ -23,7 +19,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{CoverageAccountingScheduler, QueueScheduler},
|
||||
stages::mutational::StdMutationalStage,
|
||||
state::{HasCorpus, StdState},
|
||||
@ -40,6 +36,10 @@ use libafl_bolts::{
|
||||
use libafl_targets::{
|
||||
libfuzzer_initialize, libfuzzer_test_one_input, ACCOUNTING_MEMOP_MAP, EDGES_MAP, MAX_EDGES_NUM,
|
||||
};
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
/// Parse a millis string to a [`Duration`]. Used for arg parsing.
|
||||
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||
@ -55,11 +55,11 @@ fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||
)]
|
||||
struct Opt {
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
value_parser = Cores::from_cmdline,
|
||||
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||
name = "CORES"
|
||||
short,
|
||||
long,
|
||||
value_parser = Cores::from_cmdline,
|
||||
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||
name = "CORES"
|
||||
)]
|
||||
cores: Cores,
|
||||
|
||||
@ -94,12 +94,12 @@ struct Opt {
|
||||
output: PathBuf,
|
||||
|
||||
#[arg(
|
||||
value_parser = timeout_from_millis_str,
|
||||
short,
|
||||
long,
|
||||
help = "Set the execution timeout in milliseconds, default is 10000",
|
||||
name = "TIMEOUT",
|
||||
default_value = "10000"
|
||||
value_parser = timeout_from_millis_str,
|
||||
short,
|
||||
long,
|
||||
help = "Set the execution timeout in milliseconds, default is 10000",
|
||||
name = "TIMEOUT",
|
||||
default_value = "10000"
|
||||
)]
|
||||
timeout: Duration,
|
||||
/*
|
||||
@ -140,7 +140,8 @@ pub extern "C" fn libafl_main() {
|
||||
// Create an observation channel using the coverage map
|
||||
let edges_observer = HitcountsMapObserver::new(unsafe {
|
||||
StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), MAX_EDGES_NUM)
|
||||
});
|
||||
})
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -149,7 +150,7 @@ pub extern "C" fn libafl_main() {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -194,10 +195,12 @@ pub extern "C" fn libafl_main() {
|
||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler =
|
||||
CoverageAccountingScheduler::new(&mut state, QueueScheduler::new(), unsafe {
|
||||
&ACCOUNTING_MEMOP_MAP
|
||||
});
|
||||
let scheduler = CoverageAccountingScheduler::new(
|
||||
&edges_observer,
|
||||
&mut state,
|
||||
QueueScheduler::new(),
|
||||
unsafe { &ACCOUNTING_MEMOP_MAP },
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -1,9 +1,5 @@
|
||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||
//! The example harness is built for libpng.
|
||||
use mimalloc::MiMalloc;
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
use core::time::Duration;
|
||||
#[cfg(feature = "crash")]
|
||||
use std::ptr;
|
||||
@ -22,7 +18,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
|
||||
},
|
||||
@ -37,6 +33,10 @@ use libafl_bolts::{
|
||||
AsSlice,
|
||||
};
|
||||
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
/// The main fn, `no_mangle` as it is a C main
|
||||
#[cfg(not(test))]
|
||||
@ -99,12 +99,13 @@ fn fuzz(
|
||||
EDGES_MAP.as_mut_ptr(),
|
||||
MAX_EDGES_NUM,
|
||||
))
|
||||
.track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -163,11 +164,10 @@ fn fuzz(
|
||||
let mut stages = tuple_list!(calibration, power, aflstats);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::FAST),
|
||||
));
|
||||
StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -2,10 +2,6 @@
|
||||
//! The example harness is built for libpng.
|
||||
//! In this example, you will see the use of the `launcher` feature.
|
||||
//! The `launcher` will spawn new processes for each cpu core.
|
||||
use mimalloc::MiMalloc;
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
use core::time::Duration;
|
||||
use std::{env, net::SocketAddr, path::PathBuf};
|
||||
|
||||
@ -23,7 +19,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::mutational::StdMutationalStage,
|
||||
state::{HasCorpus, StdState},
|
||||
@ -38,6 +34,10 @@ use libafl_bolts::{
|
||||
AsSlice,
|
||||
};
|
||||
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer};
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
/// Parse a millis string to a [`Duration`]. Used for arg parsing.
|
||||
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||
@ -53,11 +53,11 @@ fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||
)]
|
||||
struct Opt {
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
value_parser = Cores::from_cmdline,
|
||||
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||
name = "CORES"
|
||||
short,
|
||||
long,
|
||||
value_parser = Cores::from_cmdline,
|
||||
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||
name = "CORES"
|
||||
)]
|
||||
cores: Cores,
|
||||
|
||||
@ -92,12 +92,12 @@ struct Opt {
|
||||
output: PathBuf,
|
||||
|
||||
#[arg(
|
||||
value_parser = timeout_from_millis_str,
|
||||
short,
|
||||
long,
|
||||
help = "Set the exeucution timeout in milliseconds, default is 10000",
|
||||
name = "TIMEOUT",
|
||||
default_value = "10000"
|
||||
value_parser = timeout_from_millis_str,
|
||||
short,
|
||||
long,
|
||||
help = "Set the exeucution timeout in milliseconds, default is 10000",
|
||||
name = "TIMEOUT",
|
||||
default_value = "10000"
|
||||
)]
|
||||
timeout: Duration,
|
||||
/*
|
||||
@ -138,7 +138,8 @@ pub extern "C" fn libafl_main() {
|
||||
|
||||
let mut run_client = |state: Option<_>, mut mgr, _core_id: CoreId| {
|
||||
// Create an observation channel using the coverage map
|
||||
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") });
|
||||
let edges_observer =
|
||||
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -147,7 +148,7 @@ pub extern "C" fn libafl_main() {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -192,7 +193,8 @@ pub extern "C" fn libafl_main() {
|
||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -1,9 +1,5 @@
|
||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||
//! The example harness is built for libpng.
|
||||
use mimalloc::MiMalloc;
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
use core::time::Duration;
|
||||
#[cfg(feature = "crash")]
|
||||
use std::ptr;
|
||||
@ -25,7 +21,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
|
||||
},
|
||||
@ -40,6 +36,10 @@ use libafl_bolts::{
|
||||
AsSlice,
|
||||
};
|
||||
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer};
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
/// The main fn, `no_mangle` as it is a C main
|
||||
#[cfg(not(test))]
|
||||
@ -82,14 +82,15 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
};
|
||||
|
||||
// Create an observation channel using the coverage map
|
||||
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") });
|
||||
let edges_observer =
|
||||
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
|
||||
|
||||
let minimizer = StdCorpusMinimizer::new(&edges_observer);
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -146,11 +147,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
let mut stages = tuple_list!(calibration, power);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::FAST),
|
||||
));
|
||||
StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -2,10 +2,6 @@
|
||||
//! The example harness is built for libpng.
|
||||
//! In this example, you will see the use of the `launcher` feature.
|
||||
//! The `launcher` will spawn new processes for each cpu core.
|
||||
use mimalloc::MiMalloc;
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
use core::time::Duration;
|
||||
use std::{env, net::SocketAddr, path::PathBuf};
|
||||
|
||||
@ -23,7 +19,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::mutational::StdMutationalStage,
|
||||
state::{HasCorpus, StdState},
|
||||
@ -38,6 +34,10 @@ use libafl_bolts::{
|
||||
AsSlice,
|
||||
};
|
||||
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer};
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
/// Parse a millis string to a [`Duration`]. Used for arg parsing.
|
||||
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||
@ -53,11 +53,11 @@ fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||
)]
|
||||
struct Opt {
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
value_parser = Cores::from_cmdline,
|
||||
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||
name = "CORES"
|
||||
short,
|
||||
long,
|
||||
value_parser = Cores::from_cmdline,
|
||||
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||
name = "CORES"
|
||||
)]
|
||||
cores: Cores,
|
||||
|
||||
@ -92,12 +92,12 @@ struct Opt {
|
||||
output: PathBuf,
|
||||
|
||||
#[arg(
|
||||
value_parser = timeout_from_millis_str,
|
||||
short,
|
||||
long,
|
||||
help = "Set the exeucution timeout in milliseconds, default is 10000",
|
||||
name = "TIMEOUT",
|
||||
default_value = "10000"
|
||||
value_parser = timeout_from_millis_str,
|
||||
short,
|
||||
long,
|
||||
help = "Set the exeucution timeout in milliseconds, default is 10000",
|
||||
name = "TIMEOUT",
|
||||
default_value = "10000"
|
||||
)]
|
||||
timeout: Duration,
|
||||
/*
|
||||
@ -139,7 +139,8 @@ pub extern "C" fn libafl_main() {
|
||||
|
||||
let mut run_client = |state: Option<_>, mut restarting_mgr, _core_id| {
|
||||
// Create an observation channel using the coverage map
|
||||
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") });
|
||||
let edges_observer =
|
||||
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -148,7 +149,7 @@ pub extern "C" fn libafl_main() {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -193,7 +194,8 @@ pub extern "C" fn libafl_main() {
|
||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -2,9 +2,6 @@
|
||||
//! The example harness is built for libpng.
|
||||
//! In this example, you will see the use of the `launcher` feature.
|
||||
//! The `launcher` will spawn new processes for each cpu core.
|
||||
use mimalloc::MiMalloc;
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
use core::time::Duration;
|
||||
use std::{env, net::SocketAddr, path::PathBuf};
|
||||
@ -26,7 +23,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::mutational::StdMutationalStage,
|
||||
state::{HasCorpus, StdState},
|
||||
@ -41,6 +38,10 @@ use libafl_bolts::{
|
||||
AsSlice,
|
||||
};
|
||||
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer};
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
/// Parse a millis string to a [`Duration`]. Used for arg parsing.
|
||||
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||
@ -56,11 +57,11 @@ fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||
)]
|
||||
struct Opt {
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
value_parser = Cores::from_cmdline,
|
||||
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||
name = "CORES"
|
||||
short,
|
||||
long,
|
||||
value_parser = Cores::from_cmdline,
|
||||
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||
name = "CORES"
|
||||
)]
|
||||
cores: Cores,
|
||||
|
||||
@ -95,12 +96,12 @@ struct Opt {
|
||||
output: PathBuf,
|
||||
|
||||
#[arg(
|
||||
value_parser = timeout_from_millis_str,
|
||||
short,
|
||||
long,
|
||||
help = "Set the exeucution timeout in milliseconds, default is 10000",
|
||||
name = "TIMEOUT",
|
||||
default_value = "10000"
|
||||
value_parser = timeout_from_millis_str,
|
||||
short,
|
||||
long,
|
||||
help = "Set the exeucution timeout in milliseconds, default is 10000",
|
||||
name = "TIMEOUT",
|
||||
default_value = "10000"
|
||||
)]
|
||||
timeout: Duration,
|
||||
|
||||
@ -163,7 +164,8 @@ pub extern "C" fn libafl_main() {
|
||||
mut restarting_mgr: LlmpRestartingEventManager<_, _, _>,
|
||||
core_id| {
|
||||
// Create an observation channel using the coverage map
|
||||
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") });
|
||||
let edges_observer =
|
||||
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -172,7 +174,7 @@ pub extern "C" fn libafl_main() {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -217,7 +219,8 @@ pub extern "C" fn libafl_main() {
|
||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -1,9 +1,5 @@
|
||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||
//! The example harness is built for libpng.
|
||||
use mimalloc::MiMalloc;
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
use core::time::Duration;
|
||||
#[cfg(feature = "crash")]
|
||||
use std::ptr;
|
||||
@ -22,7 +18,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
|
||||
},
|
||||
@ -37,6 +33,10 @@ use libafl_bolts::{
|
||||
AsSlice,
|
||||
};
|
||||
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
/// The main fn, `no_mangle` as it is a C main
|
||||
#[no_mangle]
|
||||
@ -83,12 +83,13 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
EDGES_MAP.as_mut_ptr(),
|
||||
MAX_EDGES_NUM,
|
||||
))
|
||||
.track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -145,11 +146,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
let mut stages = tuple_list!(calibration, power);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::FAST),
|
||||
));
|
||||
StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -19,7 +19,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, StdScheduledMutator},
|
||||
token_mutations::I2SRandReplace,
|
||||
},
|
||||
observers::TimeObserver,
|
||||
observers::{CanTrack, TimeObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::{ShadowTracingStage, StdMutationalStage},
|
||||
state::{HasCorpus, StdState},
|
||||
@ -68,7 +68,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
|
||||
// Create an observation channel using the coverage map
|
||||
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
|
||||
let edges_observer = unsafe { std_edges_map_observer("edges") };
|
||||
let edges_observer = unsafe { std_edges_map_observer("edges").track_indices() };
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -79,7 +79,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -109,7 +109,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
println!("We're a client, let's fuzz :)");
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -1,11 +1,7 @@
|
||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||
//! The example harness is built for `stb_image`.
|
||||
use mimalloc::MiMalloc;
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
use std::{
|
||||
env,
|
||||
env, fs,
|
||||
path::PathBuf,
|
||||
process::{Child, Command, Stdio},
|
||||
time::Duration,
|
||||
@ -32,7 +28,7 @@ use libafl::{
|
||||
serialization_format::{DEFAULT_ENV_NAME, DEFAULT_SIZE},
|
||||
ConcolicObserver,
|
||||
},
|
||||
TimeObserver,
|
||||
TimeObserver, CanTrack,
|
||||
},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::{
|
||||
@ -52,6 +48,10 @@ use libafl_bolts::{
|
||||
use libafl_targets::{
|
||||
libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer, CmpLogObserver,
|
||||
};
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Opt {
|
||||
@ -60,7 +60,6 @@ struct Opt {
|
||||
concolic: bool,
|
||||
}
|
||||
|
||||
use std::fs;
|
||||
pub fn main() {
|
||||
// Registry the metadata types used in this fuzzer
|
||||
// Needed only on no_std
|
||||
@ -107,7 +106,7 @@ fn fuzz(
|
||||
|
||||
// Create an observation channel using the coverage map
|
||||
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
|
||||
let edges_observer = unsafe { std_edges_map_observer("edges") };
|
||||
let edges_observer = unsafe { std_edges_map_observer("edges").track_indices() };
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -118,7 +117,7 @@ fn fuzz(
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -148,7 +147,7 @@ fn fuzz(
|
||||
println!("We're a client, let's fuzz :)");
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -11,7 +11,7 @@ use libafl::{
|
||||
inputs::{BytesInput, HasTargetBytes},
|
||||
monitors::MultiMonitor,
|
||||
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
observers::{HitcountsMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
|
||||
},
|
||||
@ -61,12 +61,13 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
};
|
||||
|
||||
// Create an observation channel using the coverage map
|
||||
let edges_observer = unsafe { HitcountsMapObserver::new(std_edges_map_observer("edges")) };
|
||||
let edges_observer =
|
||||
unsafe { HitcountsMapObserver::new(std_edges_map_observer("edges")).track_indices() };
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -112,11 +113,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
let mut stages = tuple_list!(calibration, power);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
Some(PowerSchedule::FAST),
|
||||
));
|
||||
StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -30,6 +30,7 @@ use libafl_bolts::{
|
||||
use libafl_qemu::{
|
||||
edges::{QemuEdgeCoverageChildHelper, EDGES_MAP_PTR, EDGES_MAP_SIZE},
|
||||
elf::EasyElf,
|
||||
emu::Emulator,
|
||||
ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitReason,
|
||||
QemuExitReasonError, QemuForkExecutor, QemuHooks, QemuShutdownCause, Regs,
|
||||
};
|
||||
@ -63,10 +64,10 @@ impl From<Version> for Str {
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
#[command(
|
||||
name = format!("qemu_cmin-{}",env!("CPU_TARGET")),
|
||||
version = Version::default(),
|
||||
about,
|
||||
long_about = "Tool for generating minimizing corpus using QEMU instrumentation"
|
||||
name = format ! ("qemu_cmin-{}", env ! ("CPU_TARGET")),
|
||||
version = Version::default(),
|
||||
about,
|
||||
long_about = "Tool for generating minimizing corpus using QEMU instrumentation"
|
||||
)]
|
||||
pub struct FuzzerOptions {
|
||||
#[arg(long, help = "Output directory")]
|
||||
@ -171,7 +172,7 @@ pub fn fuzz() -> Result<(), Error> {
|
||||
))
|
||||
};
|
||||
|
||||
let mut feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let mut feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
#[allow(clippy::let_unit_value)]
|
||||
let mut objective = ();
|
||||
|
@ -18,7 +18,7 @@ use libafl::{
|
||||
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
|
||||
StdMOptMutator, StdScheduledMutator, Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
|
||||
schedulers::{
|
||||
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler,
|
||||
},
|
||||
@ -81,12 +81,13 @@ impl<'a, M: Monitor> Instance<'a, M> {
|
||||
edges_map_mut_slice(),
|
||||
addr_of_mut!(MAX_EDGES_NUM),
|
||||
))
|
||||
.track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -124,11 +125,10 @@ impl<'a, M: Monitor> Instance<'a, M> {
|
||||
};
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new(
|
||||
&mut state,
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
PowerSchedule::FAST,
|
||||
));
|
||||
PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST),
|
||||
);
|
||||
|
||||
let observers = tuple_list!(edges_observer, time_observer);
|
||||
|
||||
|
@ -13,7 +13,7 @@ use libafl::{
|
||||
inputs::BytesInput,
|
||||
monitors::MultiMonitor,
|
||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||
observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver},
|
||||
observers::{HitcountsMapObserver, TimeObserver, TrackingHinted, VariableMapObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::{CalibrationStage, StdMutationalStage},
|
||||
state::{HasCorpus, StdState},
|
||||
@ -157,6 +157,7 @@ pub fn fuzz() {
|
||||
edges_map_mut_slice(),
|
||||
addr_of_mut!(MAX_EDGES_NUM),
|
||||
))
|
||||
.track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
@ -166,7 +167,7 @@ pub fn fuzz() {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, true),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -194,7 +195,8 @@ pub fn fuzz() {
|
||||
});
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
@ -206,7 +208,7 @@ pub fn fuzz() {
|
||||
|
||||
// Setup an havoc mutator with a mutational stage
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations());
|
||||
let calibration_feedback = MaxMapFeedback::tracking(&edges_observer, true, true);
|
||||
let calibration_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
let mut stages = tuple_list!(
|
||||
StdMutationalStage::new(mutator),
|
||||
CalibrationStage::new(&calibration_feedback)
|
||||
|
@ -13,7 +13,7 @@ use libafl::{
|
||||
inputs::{BytesInput, HasTargetBytes},
|
||||
monitors::MultiMonitor,
|
||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||
observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver},
|
||||
observers::{HitcountsMapObserver, TimeObserver, TrackingHinted, VariableMapObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::StdMutationalStage,
|
||||
state::{HasCorpus, StdState},
|
||||
@ -164,6 +164,7 @@ pub fn fuzz() {
|
||||
edges_map_mut_slice(),
|
||||
addr_of_mut!(MAX_EDGES_NUM),
|
||||
))
|
||||
.track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
@ -173,7 +174,7 @@ pub fn fuzz() {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, true),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -201,7 +202,8 @@ pub fn fuzz() {
|
||||
});
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -13,7 +13,7 @@ use libafl::{
|
||||
inputs::BytesInput,
|
||||
monitors::MultiMonitor,
|
||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||
observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver},
|
||||
observers::{HitcountsMapObserver, TimeObserver, TrackingHinted, VariableMapObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::{CalibrationStage, StdMutationalStage},
|
||||
state::{HasCorpus, StdState},
|
||||
@ -98,6 +98,7 @@ pub fn fuzz() {
|
||||
edges_map_mut_slice(),
|
||||
addr_of_mut!(MAX_EDGES_NUM),
|
||||
))
|
||||
.track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
@ -107,7 +108,7 @@ pub fn fuzz() {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, true),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -135,7 +136,8 @@ pub fn fuzz() {
|
||||
});
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
@ -147,7 +149,7 @@ pub fn fuzz() {
|
||||
|
||||
// Setup an havoc mutator with a mutational stage
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations());
|
||||
let calibration_feedback = MaxMapFeedback::tracking(&edges_observer, true, true);
|
||||
let calibration_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
let mut stages = tuple_list!(
|
||||
StdMutationalStage::new(mutator),
|
||||
CalibrationStage::new(&calibration_feedback)
|
||||
|
@ -15,7 +15,7 @@ use libafl::{
|
||||
fuzzer::StdFuzzer,
|
||||
inputs::HasTargetBytes,
|
||||
monitors::MultiMonitor,
|
||||
observers::{HitcountsMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver},
|
||||
schedulers::{powersched::PowerSchedule, PowerQueueScheduler},
|
||||
stages::{calibrate::CalibrationStage, power::StdPowerMutationalStage},
|
||||
state::{HasCorpus, StdState},
|
||||
@ -81,12 +81,13 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
};
|
||||
|
||||
// Create an observation channel using the coverage map
|
||||
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") });
|
||||
let edges_observer =
|
||||
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
|
||||
let calibration = CalibrationStage::new(&map_feedback);
|
||||
|
||||
@ -132,11 +133,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
let mut stages = tuple_list!(calibration, power);
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = PacketLenMinimizerScheduler::new(PowerQueueScheduler::new(
|
||||
&mut state,
|
||||
let scheduler = PacketLenMinimizerScheduler::new(
|
||||
&edges_observer,
|
||||
PowerSchedule::FAST,
|
||||
));
|
||||
PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST),
|
||||
);
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -32,8 +32,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub type PacketLenMinimizerScheduler<CS> =
|
||||
MinimizerScheduler<CS, PacketLenTestcaseScore, MapIndexesMetadata>;
|
||||
pub type PacketLenMinimizerScheduler<CS, O> =
|
||||
MinimizerScheduler<CS, PacketLenTestcaseScore, MapIndexesMetadata, O>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
||||
pub struct PacketLenFeedback {
|
||||
|
@ -133,7 +133,7 @@ agpl = ["nautilus"]
|
||||
nautilus = ["grammartec", "std", "serde_json/std"]
|
||||
|
||||
[build-dependencies]
|
||||
reqwest = { version = "0.11", features = ["blocking"], optional = true}
|
||||
reqwest = { version = "0.11", features = ["blocking"], optional = true }
|
||||
rustversion = "1.0"
|
||||
zip = { version = "0.6", optional = true }
|
||||
|
||||
@ -148,15 +148,15 @@ libafl_derive = { version = "0.11.2", path = "../libafl_derive", optional = true
|
||||
|
||||
rustversion = "1.0"
|
||||
tuple_list = { version = "0.1.3" }
|
||||
hashbrown = { version = "0.14", features = ["serde", "ahash"], default-features=false } # A faster hashmap, nostd compatible
|
||||
hashbrown = { version = "0.14", features = ["serde", "ahash"], default-features = false } # A faster hashmap, nostd compatible
|
||||
num-traits = { version = "0.2", default-features = false }
|
||||
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } # serialization lib
|
||||
postcard = { version = "1.0", features = ["alloc"], default-features = false } # no_std compatible serde serialization format
|
||||
bincode = {version = "1.3", optional = true }
|
||||
bincode = { version = "1.3", optional = true }
|
||||
c2rust-bitfields = { version = "0.18", features = ["no_std"] }
|
||||
ahash = { version = "0.8", default-features=false } # The hash function already used in hashbrown
|
||||
ahash = { version = "0.8", default-features = false } # The hash function already used in hashbrown
|
||||
meminterval = { version = "0.4", features = ["serde"] }
|
||||
backtrace = {version = "0.3", optional = true} # Used to get the stacktrace in StacktraceObserver
|
||||
backtrace = { version = "0.3", optional = true } # Used to get the stacktrace in StacktraceObserver
|
||||
typed-builder = { version = "0.16", optional = true } # Implement the builder pattern at compiletime
|
||||
|
||||
serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc"] }
|
||||
@ -167,7 +167,7 @@ libm = "0.2.2"
|
||||
ratatui = { version = "0.23.0", default-features = false, features = ['crossterm'], optional = true } # Commandline rendering, for TUI Monitor
|
||||
crossterm = { version = "0.27.0", optional = true }
|
||||
|
||||
prometheus-client = { version= "0.21", optional = true} # For the prometheus monitor
|
||||
prometheus-client = { version = "0.21", optional = true } # For the prometheus monitor
|
||||
tide = { version = "0.16.0", optional = true }
|
||||
async-std = { version = "1.12.0", features = ["attributes"], optional = true }
|
||||
futures = { version = "0.3.24", optional = true }
|
||||
@ -186,6 +186,9 @@ bitvec = { version = "1.0", optional = true, features = ["serde"] } # used for s
|
||||
|
||||
arrayvec = { version = "0.7.4", optional = true, default-features = false } # used for fixed-len collects
|
||||
|
||||
const_format = "0.2.32" # used for providing helpful compiler output
|
||||
const_panic = "0.2.8" # similarly, for formatting const panic output
|
||||
|
||||
# optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable)
|
||||
serial_test = { version = "2", optional = true, default-features = false, features = ["logging"] }
|
||||
|
||||
|
@ -49,32 +49,25 @@ where
|
||||
///
|
||||
/// Algorithm based on WMOPT: <https://hexhive.epfl.ch/publications/files/21ISSTA2.pdf>
|
||||
#[derive(Debug)]
|
||||
pub struct MapCorpusMinimizer<E, O, T, TS>
|
||||
where
|
||||
E: UsesState,
|
||||
E::State: HasCorpus + HasMetadata,
|
||||
TS: TestcaseScore<E::State>,
|
||||
{
|
||||
pub struct MapCorpusMinimizer<C, E, O, T, TS> {
|
||||
obs_name: String,
|
||||
phantom: PhantomData<(E, O, T, TS)>,
|
||||
phantom: PhantomData<(C, E, O, T, TS)>,
|
||||
}
|
||||
|
||||
/// Standard corpus minimizer, which weights inputs by length and time.
|
||||
pub type StdCorpusMinimizer<E, O, T> =
|
||||
MapCorpusMinimizer<E, O, T, LenTimeMulTestcaseScore<<E as UsesState>::State>>;
|
||||
pub type StdCorpusMinimizer<C, E, O, T> =
|
||||
MapCorpusMinimizer<C, E, O, T, LenTimeMulTestcaseScore<<E as UsesState>::State>>;
|
||||
|
||||
impl<E, O, T, TS> MapCorpusMinimizer<E, O, T, TS>
|
||||
impl<C, E, O, T, TS> MapCorpusMinimizer<C, E, O, T, TS>
|
||||
where
|
||||
E: UsesState,
|
||||
E::State: HasCorpus + HasMetadata,
|
||||
TS: TestcaseScore<E::State>,
|
||||
C: Named,
|
||||
{
|
||||
/// Constructs a new `MapCorpusMinimizer` from a provided observer. This observer will be used
|
||||
/// in the future to get observed maps from an executed input.
|
||||
pub fn new(obs: &O) -> Self
|
||||
where
|
||||
O: Named,
|
||||
{
|
||||
pub fn new(obs: &C) -> Self {
|
||||
Self {
|
||||
obs_name: obs.name().to_string(),
|
||||
phantom: PhantomData,
|
||||
@ -82,10 +75,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, O, T, TS> CorpusMinimizer<E> for MapCorpusMinimizer<E, O, T, TS>
|
||||
impl<C, E, O, T, TS> CorpusMinimizer<E> for MapCorpusMinimizer<C, E, O, T, TS>
|
||||
where
|
||||
E: UsesState,
|
||||
for<'a> O: MapObserver<Entry = T> + AsIter<'a, Item = T>,
|
||||
C: AsRef<O>,
|
||||
E::State: HasMetadata + HasCorpus + HasExecutions,
|
||||
T: Copy + Hash + Eq,
|
||||
TS: TestcaseScore<E::State>,
|
||||
@ -165,10 +159,11 @@ where
|
||||
)?;
|
||||
|
||||
let seed_expr = Bool::fresh_const(&ctx, "seed");
|
||||
let obs: &O = executor
|
||||
let obs = executor
|
||||
.observers()
|
||||
.match_name::<O>(&self.obs_name)
|
||||
.expect("Observer must be present.");
|
||||
.match_name::<C>(&self.obs_name)
|
||||
.expect("Observer must be present.")
|
||||
.as_ref();
|
||||
|
||||
// Store coverage, mapping coverage map indices to hit counts (if present) and the
|
||||
// associated seeds for the map indices with those hit counts.
|
||||
|
@ -1499,7 +1499,7 @@ where
|
||||
}
|
||||
|
||||
/// A manager-like llmp client that converts between input types
|
||||
pub struct LlmpEventConverter<IC, ICB, DI, S, SP>
|
||||
pub struct LlmpEventConverter<DI, IC, ICB, S, SP>
|
||||
where
|
||||
S: UsesInput,
|
||||
SP: ShMemProvider + 'static,
|
||||
@ -1517,7 +1517,7 @@ where
|
||||
phantom: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<IC, ICB, DI, S, SP> core::fmt::Debug for LlmpEventConverter<IC, ICB, DI, S, SP>
|
||||
impl<DI, IC, ICB, S, SP> core::fmt::Debug for LlmpEventConverter<DI, IC, ICB, S, SP>
|
||||
where
|
||||
SP: ShMemProvider + 'static,
|
||||
S: UsesInput,
|
||||
@ -1539,7 +1539,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<IC, ICB, DI, S, SP> LlmpEventConverter<IC, ICB, DI, S, SP>
|
||||
impl<DI, IC, ICB, S, SP> LlmpEventConverter<DI, IC, ICB, S, SP>
|
||||
where
|
||||
S: UsesInput + HasExecutions + HasMetadata,
|
||||
SP: ShMemProvider + 'static,
|
||||
@ -1734,7 +1734,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<IC, ICB, DI, S, SP> UsesState for LlmpEventConverter<IC, ICB, DI, S, SP>
|
||||
impl<DI, IC, ICB, S, SP> UsesState for LlmpEventConverter<DI, IC, ICB, S, SP>
|
||||
where
|
||||
S: State,
|
||||
SP: ShMemProvider,
|
||||
@ -1745,7 +1745,7 @@ where
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<IC, ICB, DI, S, SP> EventFirer for LlmpEventConverter<IC, ICB, DI, S, SP>
|
||||
impl<DI, IC, ICB, S, SP> EventFirer for LlmpEventConverter<DI, IC, ICB, S, SP>
|
||||
where
|
||||
S: State,
|
||||
SP: ShMemProvider,
|
||||
|
@ -636,13 +636,14 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
|
||||
|
||||
/// Builds `ForkserverExecutor` downsizing the coverage map to fit exaclty the AFL++ map size.
|
||||
#[allow(clippy::pedantic)]
|
||||
pub fn build_dynamic_map<MO, OT, S>(
|
||||
pub fn build_dynamic_map<A, MO, OT, S>(
|
||||
&mut self,
|
||||
mut map_observer: MO,
|
||||
mut map_observer: A,
|
||||
other_observers: OT,
|
||||
) -> Result<ForkserverExecutor<(MO, OT), S, SP>, Error>
|
||||
) -> Result<ForkserverExecutor<(A, OT), S, SP>, Error>
|
||||
where
|
||||
MO: Observer<S> + MapObserver + Truncate, // TODO maybe enforce Entry = u8 for the cov map
|
||||
MO: MapObserver + Truncate, // TODO maybe enforce Entry = u8 for the cov map
|
||||
A: Observer<S> + AsRef<MO> + AsMut<MO>,
|
||||
OT: ObserversTuple<S> + Prepend<MO, PreprendResult = OT>,
|
||||
S: UsesInput,
|
||||
S::Input: Input + HasTargetBytes,
|
||||
@ -660,10 +661,10 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
|
||||
);
|
||||
|
||||
if let Some(dynamic_map_size) = self.map_size {
|
||||
map_observer.truncate(dynamic_map_size);
|
||||
map_observer.as_mut().truncate(dynamic_map_size);
|
||||
}
|
||||
|
||||
let observers: (MO, OT) = other_observers.prepend(map_observer);
|
||||
let observers = (map_observer, other_observers);
|
||||
|
||||
if self.uses_shmem_testcase && map.is_none() {
|
||||
return Err(Error::illegal_state(
|
||||
|
@ -23,28 +23,29 @@ use crate::{
|
||||
feedbacks::{Feedback, HasObserverName},
|
||||
inputs::UsesInput,
|
||||
monitors::{AggregatorOps, UserStats, UserStatsValue},
|
||||
observers::{MapObserver, Observer, ObserversTuple, UsesObserver},
|
||||
observers::{CanTrack, MapObserver, Observer, ObserversTuple, UsesObserver},
|
||||
state::State,
|
||||
Error, HasMetadata, HasNamedMetadata,
|
||||
};
|
||||
|
||||
/// A [`MapFeedback`] that implements the AFL algorithm using an [`OrReducer`] combining the bits for the history map and the bit from ``HitcountsMapObserver``.
|
||||
pub type AflMapFeedback<O, S, T> = MapFeedback<DifferentIsNovel, O, OrReducer, S, T>;
|
||||
/// A [`MapFeedback`] that implements the AFL algorithm using an [`OrReducer`] combining the bits for the history map and the bit from (`HitcountsMapObserver`)[`crate::observers::HitcountsMapObserver`].
|
||||
pub type AflMapFeedback<C, O, S, T> = MapFeedback<C, DifferentIsNovel, O, OrReducer, S, T>;
|
||||
|
||||
/// A [`MapFeedback`] that strives to maximize the map contents.
|
||||
pub type MaxMapFeedback<O, S, T> = MapFeedback<DifferentIsNovel, O, MaxReducer, S, T>;
|
||||
pub type MaxMapFeedback<C, O, S, T> = MapFeedback<C, DifferentIsNovel, O, MaxReducer, S, T>;
|
||||
/// A [`MapFeedback`] that strives to minimize the map contents.
|
||||
pub type MinMapFeedback<O, S, T> = MapFeedback<DifferentIsNovel, O, MinReducer, S, T>;
|
||||
pub type MinMapFeedback<C, O, S, T> = MapFeedback<C, DifferentIsNovel, O, MinReducer, S, T>;
|
||||
|
||||
/// A [`MapFeedback`] that always returns `true` for `is_interesting`. Useful for tracing all executions.
|
||||
pub type AlwaysInterestingMapFeedback<O, S, T> = MapFeedback<AllIsNovel, O, NopReducer, S, T>;
|
||||
pub type AlwaysInterestingMapFeedback<C, O, S, T> = MapFeedback<C, AllIsNovel, O, NopReducer, S, T>;
|
||||
|
||||
/// A [`MapFeedback`] that strives to maximize the map contents,
|
||||
/// but only, if a value is larger than `pow2` of the previous.
|
||||
pub type MaxMapPow2Feedback<O, S, T> = MapFeedback<NextPow2IsNovel, O, MaxReducer, S, T>;
|
||||
pub type MaxMapPow2Feedback<C, O, S, T> = MapFeedback<C, NextPow2IsNovel, O, MaxReducer, S, T>;
|
||||
/// A [`MapFeedback`] that strives to maximize the map contents,
|
||||
/// but only, if a value is larger than `pow2` of the previous.
|
||||
pub type MaxMapOneOrFilledFeedback<O, S, T> = MapFeedback<OneOrFilledIsNovel, O, MaxReducer, S, T>;
|
||||
pub type MaxMapOneOrFilledFeedback<C, O, S, T> =
|
||||
MapFeedback<C, OneOrFilledIsNovel, O, MaxReducer, S, T>;
|
||||
|
||||
/// A `Reducer` function is used to aggregate values for the novelty search
|
||||
pub trait Reducer<T>: 'static
|
||||
@ -174,6 +175,7 @@ fn saturating_next_power_of_two<T: PrimInt>(n: T) -> T {
|
||||
/// Consider as novelty if the reduced value is different from the old value.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DifferentIsNovel {}
|
||||
|
||||
impl<T> IsNovel<T> for DifferentIsNovel
|
||||
where
|
||||
T: PartialEq + Default + Copy + 'static,
|
||||
@ -187,6 +189,7 @@ where
|
||||
/// Only consider as novel the values which are at least the next pow2 class of the old value
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NextPow2IsNovel {}
|
||||
|
||||
impl<T> IsNovel<T> for NextPow2IsNovel
|
||||
where
|
||||
T: PrimInt + Default + Copy + 'static,
|
||||
@ -207,6 +210,7 @@ where
|
||||
/// Only consider `T::one()` or `T::max_value()`, if they are bigger than the old value, as novel
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OneOrFilledIsNovel {}
|
||||
|
||||
impl<T> IsNovel<T> for OneOrFilledIsNovel
|
||||
where
|
||||
T: PrimInt + Default + Copy + 'static,
|
||||
@ -239,6 +243,7 @@ impl AsSlice for MapIndexesMetadata {
|
||||
self.list.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMutSlice for MapIndexesMetadata {
|
||||
type Entry = usize;
|
||||
/// Convert to a slice
|
||||
@ -286,6 +291,7 @@ impl AsSlice for MapNoveltiesMetadata {
|
||||
self.list.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMutSlice for MapNoveltiesMetadata {
|
||||
type Entry = usize;
|
||||
/// Convert to a slice
|
||||
@ -294,6 +300,7 @@ impl AsMutSlice for MapNoveltiesMetadata {
|
||||
self.list.as_mut_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl MapNoveltiesMetadata {
|
||||
/// Creates a new [`struct@MapNoveltiesMetadata`]
|
||||
#[must_use]
|
||||
@ -376,9 +383,7 @@ where
|
||||
|
||||
/// The most common AFL-like feedback type
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MapFeedback<N, O, R, S, T> {
|
||||
/// Indexes used in the last observation
|
||||
indexes: bool,
|
||||
pub struct MapFeedback<C, N, O, R, S, T> {
|
||||
/// New indexes observed in the last observation
|
||||
novelties: Option<Vec<usize>>,
|
||||
/// Name identifier of this instance
|
||||
@ -388,24 +393,25 @@ pub struct MapFeedback<N, O, R, S, T> {
|
||||
/// Name of the feedback as shown in the `UserStats`
|
||||
stats_name: String,
|
||||
/// Phantom Data of Reducer
|
||||
phantom: PhantomData<(N, O, R, S, T)>,
|
||||
phantom: PhantomData<(C, N, O, R, S, T)>,
|
||||
}
|
||||
|
||||
impl<N, O, R, S, T> UsesObserver<S> for MapFeedback<N, O, R, S, T>
|
||||
impl<C, N, O, R, S, T> UsesObserver<S> for MapFeedback<C, N, O, R, S, T>
|
||||
where
|
||||
S: UsesInput,
|
||||
O: Observer<S>,
|
||||
C: AsRef<O> + Observer<S>,
|
||||
{
|
||||
type Observer = O;
|
||||
type Observer = C;
|
||||
}
|
||||
|
||||
impl<N, O, R, S, T> Feedback<S> for MapFeedback<N, O, R, S, T>
|
||||
impl<C, N, O, R, S, T> Feedback<S> for MapFeedback<C, N, O, R, S, T>
|
||||
where
|
||||
N: IsNovel<T>,
|
||||
O: MapObserver<Entry = T> + for<'it> AsIter<'it, Item = T>,
|
||||
R: Reducer<T>,
|
||||
S: State + HasNamedMetadata,
|
||||
T: Default + Copy + Serialize + for<'de> Deserialize<'de> + PartialEq + Debug + 'static,
|
||||
C: CanTrack + AsRef<O>,
|
||||
{
|
||||
fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
|
||||
// Initialize `MapFeedbackMetadata` with an empty vector and add it to the state.
|
||||
@ -461,7 +467,10 @@ where
|
||||
let meta = MapNoveltiesMetadata::new(novelties);
|
||||
testcase.add_metadata(meta);
|
||||
}
|
||||
let observer = observers.match_name::<O>(&self.observer_name).unwrap();
|
||||
let observer = observers
|
||||
.match_name::<C>(&self.observer_name)
|
||||
.unwrap()
|
||||
.as_ref();
|
||||
let initial = observer.initial();
|
||||
let map_state = state
|
||||
.named_metadata_map_mut()
|
||||
@ -473,7 +482,7 @@ where
|
||||
}
|
||||
|
||||
let history_map = map_state.history_map.as_mut_slice();
|
||||
if self.indexes {
|
||||
if C::INDICES {
|
||||
let mut indices = Vec::new();
|
||||
|
||||
for (i, value) in observer
|
||||
@ -540,11 +549,12 @@ where
|
||||
|
||||
/// Specialize for the common coverage map size, maximization of u8s
|
||||
#[rustversion::nightly]
|
||||
impl<O, S> Feedback<S> for MapFeedback<DifferentIsNovel, O, MaxReducer, S, u8>
|
||||
impl<C, O, S> Feedback<S> for MapFeedback<C, DifferentIsNovel, O, MaxReducer, S, u8>
|
||||
where
|
||||
O: MapObserver<Entry = u8> + AsSlice<Entry = u8>,
|
||||
for<'it> O: AsIter<'it, Item = u8>,
|
||||
S: State + HasNamedMetadata,
|
||||
C: CanTrack + AsRef<O>,
|
||||
{
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
@ -565,7 +575,10 @@ where
|
||||
|
||||
let mut interesting = false;
|
||||
// TODO Replace with match_name_type when stable
|
||||
let observer = observers.match_name::<O>(&self.observer_name).unwrap();
|
||||
let observer = observers
|
||||
.match_name::<C>(&self.observer_name)
|
||||
.unwrap()
|
||||
.as_ref();
|
||||
|
||||
let map_state = state
|
||||
.named_metadata_map_mut()
|
||||
@ -656,21 +669,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, O, R, S, T> Named for MapFeedback<N, O, R, S, T> {
|
||||
impl<C, N, O, R, S, T> Named for MapFeedback<C, N, O, R, S, T> {
|
||||
#[inline]
|
||||
fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, O, R, S, T> HasObserverName for MapFeedback<N, O, R, S, T>
|
||||
impl<C, N, O, R, S, T> HasObserverName for MapFeedback<C, N, O, R, S, T>
|
||||
where
|
||||
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
|
||||
R: Reducer<T>,
|
||||
N: IsNovel<T>,
|
||||
O: MapObserver<Entry = T>,
|
||||
for<'it> O: AsIter<'it, Item = T>,
|
||||
S: HasNamedMetadata,
|
||||
O: Named,
|
||||
C: AsRef<O>,
|
||||
{
|
||||
#[inline]
|
||||
fn observer_name(&self) -> &str {
|
||||
@ -682,7 +691,7 @@ fn create_stats_name(name: &str) -> String {
|
||||
name.to_lowercase()
|
||||
}
|
||||
|
||||
impl<N, O, R, S, T> MapFeedback<N, O, R, S, T>
|
||||
impl<C, N, O, R, S, T> MapFeedback<C, N, O, R, S, T>
|
||||
where
|
||||
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
|
||||
R: Reducer<T>,
|
||||
@ -690,13 +699,14 @@ where
|
||||
for<'it> O: AsIter<'it, Item = T>,
|
||||
N: IsNovel<T>,
|
||||
S: UsesInput + HasNamedMetadata,
|
||||
C: CanTrack + AsRef<O>,
|
||||
{
|
||||
/// Create new `MapFeedback`
|
||||
#[must_use]
|
||||
pub fn new(map_observer: &O) -> Self {
|
||||
pub fn new(map_observer: &C) -> Self {
|
||||
let map_observer = map_observer.as_ref();
|
||||
Self {
|
||||
indexes: false,
|
||||
novelties: None,
|
||||
novelties: if C::NOVELTIES { Some(vec![]) } else { None },
|
||||
name: map_observer.name().to_string(),
|
||||
observer_name: map_observer.name().to_string(),
|
||||
stats_name: create_stats_name(map_observer.name()),
|
||||
@ -704,40 +714,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new `MapFeedback` specifying if it must track indexes of used entries and/or novelties
|
||||
#[must_use]
|
||||
pub fn tracking(map_observer: &O, track_indexes: bool, track_novelties: bool) -> Self {
|
||||
Self {
|
||||
indexes: track_indexes,
|
||||
novelties: if track_novelties { Some(vec![]) } else { None },
|
||||
name: map_observer.name().to_string(),
|
||||
observer_name: map_observer.name().to_string(),
|
||||
stats_name: create_stats_name(map_observer.name()),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new `MapFeedback`
|
||||
#[must_use]
|
||||
pub fn with_names(name: &'static str, observer_name: &'static str) -> Self {
|
||||
Self {
|
||||
indexes: false,
|
||||
novelties: None,
|
||||
name: name.to_string(),
|
||||
observer_name: observer_name.to_string(),
|
||||
stats_name: create_stats_name(name),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creating a new `MapFeedback` with a specific name. This is usefully whenever the same
|
||||
/// feedback is needed twice, but with a different history. Using `new()` always results in the
|
||||
/// same name and therefore also the same history.
|
||||
#[must_use]
|
||||
pub fn with_name(name: &'static str, map_observer: &O) -> Self {
|
||||
pub fn with_name(name: &'static str, map_observer: &C) -> Self {
|
||||
let map_observer = map_observer.as_ref();
|
||||
Self {
|
||||
indexes: false,
|
||||
novelties: None,
|
||||
novelties: if C::NOVELTIES { Some(vec![]) } else { None },
|
||||
name: name.to_string(),
|
||||
observer_name: map_observer.name().to_string(),
|
||||
stats_name: create_stats_name(name),
|
||||
@ -745,24 +729,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new `MapFeedback` specifying if it must track indexes of used entries and/or novelties
|
||||
#[must_use]
|
||||
pub fn with_names_tracking(
|
||||
name: &'static str,
|
||||
observer_name: &'static str,
|
||||
track_indexes: bool,
|
||||
track_novelties: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
indexes: track_indexes,
|
||||
novelties: if track_novelties { Some(vec![]) } else { None },
|
||||
observer_name: observer_name.to_string(),
|
||||
stats_name: create_stats_name(name),
|
||||
name: name.to_string(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
@ -780,7 +746,10 @@ where
|
||||
{
|
||||
let mut interesting = false;
|
||||
// TODO Replace with match_name_type when stable
|
||||
let observer = observers.match_name::<O>(&self.observer_name).unwrap();
|
||||
let observer = observers
|
||||
.match_name::<C>(&self.observer_name)
|
||||
.unwrap()
|
||||
.as_ref();
|
||||
|
||||
let map_state = state
|
||||
.named_metadata_map_mut()
|
||||
|
@ -80,10 +80,347 @@ fn hash_slice<T>(slice: &[T]) -> u64 {
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
/// Trait marker which indicates that this [`MapObserver`] is tracked for indices or novelties.
|
||||
/// Implementors of feedbacks similar to [`crate::feedbacks::MapFeedback`] may wish to use this to
|
||||
/// ensure that edge metadata is recorded as is appropriate for the provided observer.
|
||||
///
|
||||
/// If you get a type constraint failure for your map due to this type being unfulfilled, you must
|
||||
/// call [`CanTrack::track_indices`] or [`CanTrack::track_novelties`] **at
|
||||
/// the initialisation site of your map**.
|
||||
///
|
||||
/// This trait allows various components which interact with map metadata to ensure that the
|
||||
/// information they need is actually recorded by the map feedback.
|
||||
/// For example, if you are using [`crate::schedulers::MinimizerScheduler`]:
|
||||
/// ```
|
||||
/// # use libafl::corpus::InMemoryCorpus;
|
||||
/// # use libafl::feedbacks::{Feedback, MapFeedbackMetadata};
|
||||
/// use libafl::feedbacks::MaxMapFeedback;
|
||||
/// # use libafl::inputs::BytesInput;
|
||||
/// use libafl::observers::{StdMapObserver, CanTrack};
|
||||
/// use libafl::schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler};
|
||||
/// # use libafl::state::StdState;
|
||||
/// # use libafl_bolts::serdeany::RegistryBuilder;
|
||||
/// #
|
||||
/// # #[cfg(any(not(feature = "serdeany_autoreg"), miri))]
|
||||
/// # unsafe { MapFeedbackMetadata::<u8>::register() }
|
||||
/// # #[cfg(not(feature = "std"))]
|
||||
/// # #[no_mangle]
|
||||
/// # pub extern "C" fn external_current_millis() -> u64 { 0 }
|
||||
///
|
||||
/// use libafl_bolts::ownedref::OwnedMutSlice;
|
||||
/// # use libafl_bolts::rands::StdRand;
|
||||
///
|
||||
/// // initialise your map as necessary
|
||||
/// let edges_observer = StdMapObserver::from_ownedref("edges", OwnedMutSlice::from(vec![0u8; 16]));
|
||||
/// // inform the feedback to track indices (required by IndexesLenTimeMinimizerScheduler), but not novelties
|
||||
/// // this *MUST* be done before it is passed to MaxMapFeedback!
|
||||
/// let edges_observer = edges_observer.track_indices();
|
||||
///
|
||||
/// // init the feedback
|
||||
/// let mut feedback = MaxMapFeedback::new(&edges_observer);
|
||||
/// #
|
||||
/// # // init the state
|
||||
/// # let mut state = StdState::new(
|
||||
/// # StdRand::with_seed(0),
|
||||
/// # InMemoryCorpus::<BytesInput>::new(),
|
||||
/// # InMemoryCorpus::new(),
|
||||
/// # &mut feedback,
|
||||
/// # &mut ()
|
||||
/// # ).unwrap();
|
||||
/// # feedback.init_state(&mut state).unwrap();
|
||||
///
|
||||
/// let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
/// # scheduler.cull(&state).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// [`MapObserver`] implementors: see [`StdMapObserver`] for an example implementation.
|
||||
pub trait CanTrack {
|
||||
/// The resulting type of enabling index tracking.
|
||||
type WithIndexTracking: CanTrack;
|
||||
/// The resulting type of enabling novelty tracking.
|
||||
type WithNoveltiesTracking: CanTrack;
|
||||
|
||||
/// Whether indices should be tracked for this [`MapObserver`].
|
||||
const INDICES: bool;
|
||||
/// Whether novelties should be tracked for this [`MapObserver`].
|
||||
const NOVELTIES: bool;
|
||||
|
||||
/// Convert this map observer into one that tracks indices.
|
||||
fn track_indices(self) -> Self::WithIndexTracking;
|
||||
/// Convert this map observer into one that tracks novelties.
|
||||
fn track_novelties(self) -> Self::WithNoveltiesTracking;
|
||||
}
|
||||
|
||||
/// Struct which wraps [`MapObserver`] instances to explicitly give them tracking data.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This is a bit of a magic structure. We pass it to the observer tuple as itself, but when its
|
||||
/// referred to with `match_name`, there is a cast from this type to its inner type. This is
|
||||
/// *guaranteed to be safe* by `#[repr(transparent)]`.
|
||||
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct ExplicitTracking<T, const ITH: bool, const NTH: bool>(T);
|
||||
|
||||
impl<T, const ITH: bool, const NTH: bool> CanTrack for ExplicitTracking<T, ITH, NTH> {
|
||||
type WithIndexTracking = ExplicitTracking<T, true, NTH>;
|
||||
type WithNoveltiesTracking = ExplicitTracking<T, ITH, true>;
|
||||
const INDICES: bool = ITH;
|
||||
const NOVELTIES: bool = NTH;
|
||||
|
||||
fn track_indices(self) -> Self::WithIndexTracking {
|
||||
ExplicitTracking::<T, true, NTH>(self.0)
|
||||
}
|
||||
|
||||
fn track_novelties(self) -> Self::WithNoveltiesTracking {
|
||||
ExplicitTracking::<T, ITH, true>(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const ITH: bool, const NTH: bool> AsRef<T> for ExplicitTracking<T, ITH, NTH> {
|
||||
fn as_ref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const ITH: bool, const NTH: bool> AsMut<T> for ExplicitTracking<T, ITH, NTH> {
|
||||
fn as_mut(&mut self) -> &mut T {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const ITH: bool, const NTH: bool> Named for ExplicitTracking<T, ITH, NTH>
|
||||
where
|
||||
T: Named,
|
||||
{
|
||||
fn name(&self) -> &str {
|
||||
self.0.name()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, T, const ITH: bool, const NTH: bool> Observer<S> for ExplicitTracking<T, ITH, NTH>
|
||||
where
|
||||
S: UsesInput,
|
||||
T: Observer<S>,
|
||||
{
|
||||
fn flush(&mut self) -> Result<(), Error> {
|
||||
self.0.flush()
|
||||
}
|
||||
|
||||
fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
|
||||
self.0.pre_exec(state, input)
|
||||
}
|
||||
|
||||
fn post_exec(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &S::Input,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<(), Error> {
|
||||
self.0.post_exec(state, input, exit_kind)
|
||||
}
|
||||
|
||||
fn pre_exec_child(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
|
||||
self.0.pre_exec_child(state, input)
|
||||
}
|
||||
|
||||
fn post_exec_child(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &S::Input,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<(), Error> {
|
||||
self.0.post_exec_child(state, input, exit_kind)
|
||||
}
|
||||
|
||||
fn observes_stdout(&self) -> bool {
|
||||
self.0.observes_stdout()
|
||||
}
|
||||
|
||||
fn observes_stderr(&self) -> bool {
|
||||
self.0.observes_stderr()
|
||||
}
|
||||
|
||||
fn observe_stdout(&mut self, stdout: &[u8]) {
|
||||
self.0.observe_stdout(stdout);
|
||||
}
|
||||
|
||||
fn observe_stderr(&mut self, stderr: &[u8]) {
|
||||
self.0.observe_stderr(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, T, OTA, OTB, const ITH: bool, const NTH: bool> DifferentialObserver<OTA, OTB, S>
|
||||
for ExplicitTracking<T, ITH, NTH>
|
||||
where
|
||||
OTA: ObserversTuple<S>,
|
||||
OTB: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
T: DifferentialObserver<OTA, OTB, S>,
|
||||
{
|
||||
fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> {
|
||||
self.as_mut().pre_observe_first(observers)
|
||||
}
|
||||
|
||||
fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> {
|
||||
self.as_mut().post_observe_first(observers)
|
||||
}
|
||||
|
||||
fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> {
|
||||
self.as_mut().pre_observe_second(observers)
|
||||
}
|
||||
|
||||
fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> {
|
||||
self.as_mut().post_observe_second(observers)
|
||||
}
|
||||
}
|
||||
|
||||
/// Module which holds the necessary functions and types for map-relevant macros, namely
|
||||
/// [`crate::require_index_tracking`] and [`crate::require_novelties_tracking`].
|
||||
pub mod macros {
|
||||
pub use const_format::{concatcp, str_repeat};
|
||||
pub use const_panic::{concat_panic, FmtArg};
|
||||
|
||||
/// Use in the constructor of your component which requires index tracking of a
|
||||
/// [`super::MapObserver`]. See [`super::CanTrack`] for details.
|
||||
///
|
||||
/// As an example, if you are developing the type `MyCustomScheduler<O>` which requires novelty
|
||||
/// tracking, use this in your constructor:
|
||||
/// ```
|
||||
/// # use libafl::observers::{MapObserver, CanTrack};
|
||||
/// # use libafl::require_index_tracking;
|
||||
/// # use core::marker::PhantomData;
|
||||
/// #
|
||||
/// # struct MyCustomScheduler<C, O> {
|
||||
/// # phantom: PhantomData<(C, O)>,
|
||||
/// # }
|
||||
/// #
|
||||
/// impl<C, O> MyCustomScheduler<C, O> where O: MapObserver, C: CanTrack + AsRef<O> {
|
||||
/// pub fn new(obs: &C) -> Self {
|
||||
/// require_index_tracking!("MyCustomScheduler", C);
|
||||
/// todo!("Construct your type")
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! require_index_tracking {
|
||||
($name: literal, $obs: ident) => {
|
||||
struct SanityCheck<O: $crate::observers::CanTrack> {
|
||||
phantom: ::core::marker::PhantomData<O>,
|
||||
}
|
||||
|
||||
impl<O: $crate::observers::CanTrack> SanityCheck<O> {
|
||||
#[rustfmt::skip]
|
||||
const MESSAGE: &'static str = {
|
||||
const LINE_OFFSET: usize = line!().ilog10() as usize + 2;
|
||||
const SPACING: &str = $crate::observers::map::macros::str_repeat!(" ", LINE_OFFSET);
|
||||
$crate::observers::map::macros::concatcp!(
|
||||
"\n",
|
||||
SPACING, "|\n",
|
||||
SPACING, "= note: index tracking is required by ", $name, "\n",
|
||||
SPACING, "= note: see the documentation of CanTrack for details\n",
|
||||
SPACING, "|\n",
|
||||
SPACING, "= hint: call `.track_indices()` on the map observer passed to ", $name, " at the point where it is defined\n",
|
||||
SPACING, "|\n",
|
||||
SPACING, "| ",
|
||||
)
|
||||
};
|
||||
const TRACKING_SANITY: bool = {
|
||||
if !O::INDICES {
|
||||
panic!("{}", Self::MESSAGE)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
};
|
||||
|
||||
#[inline(always)]
|
||||
fn check_sanity() {
|
||||
if !Self::TRACKING_SANITY {
|
||||
unreachable!("{}", Self::MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
SanityCheck::<$obs>::check_sanity(); // check that tracking is enabled for this map
|
||||
};
|
||||
}
|
||||
|
||||
/// Use in the constructor of your component which requires novelties tracking of a
|
||||
/// [`super::MapObserver`]. See [`super::CanTrack`] for details on the concept.
|
||||
///
|
||||
/// As an example, if you are developing the type `MyCustomScheduler<O>` which requires novelty
|
||||
/// tracking, use this in your constructor:
|
||||
/// ```
|
||||
/// # use libafl::observers::{MapObserver, CanTrack};
|
||||
/// # use libafl::require_novelties_tracking;
|
||||
/// # use core::marker::PhantomData;
|
||||
/// #
|
||||
/// # struct MyCustomScheduler<C, O> {
|
||||
/// # phantom: PhantomData<(C, O)>,
|
||||
/// # }
|
||||
/// #
|
||||
/// impl<C, O> MyCustomScheduler<C, O> where O: MapObserver, C: CanTrack + AsRef<O> {
|
||||
/// pub fn new(obs: &C) -> Self {
|
||||
/// require_novelties_tracking!("MyCustomScheduler", C);
|
||||
/// todo!("Construct your type")
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! require_novelties_tracking {
|
||||
($name: literal, $obs: ident) => {
|
||||
struct SanityCheck<O: $crate::observers::CanTrack> {
|
||||
phantom: ::core::marker::PhantomData<O>,
|
||||
}
|
||||
|
||||
impl<O: $crate::observers::CanTrack> SanityCheck<O> {
|
||||
#[rustfmt::skip]
|
||||
const MESSAGE: &'static str = {
|
||||
const LINE_OFFSET: usize = line!().ilog10() as usize + 2;
|
||||
const SPACING: &str =
|
||||
$crate::observers::map::macros::str_repeat!(" ", LINE_OFFSET);
|
||||
$crate::observers::map::macros::concatcp!(
|
||||
"\n",
|
||||
SPACING, "|\n",
|
||||
SPACING, "= note: novelty tracking is required by ", $name, "\n",
|
||||
SPACING, "= note: see the documentation of CanTrack for details\n",
|
||||
SPACING, "|\n",
|
||||
SPACING, "= hint: call `.track_novelties()` on the map observer passed to ", $name, " at the point where it is defined\n",
|
||||
SPACING, "|\n",
|
||||
SPACING, "| ",
|
||||
)
|
||||
};
|
||||
const TRACKING_SANITY: bool = {
|
||||
if !O::NOVELTIES {
|
||||
panic!("{}", Self::MESSAGE)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
};
|
||||
|
||||
#[inline(always)]
|
||||
fn check_sanity() {
|
||||
if !Self::TRACKING_SANITY {
|
||||
unreachable!("{}", Self::MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
SanityCheck::<$obs>::check_sanity(); // check that tracking is enabled for this map
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`MapObserver`] observes the static map, as oftentimes used for AFL-like coverage information
|
||||
///
|
||||
/// When referring to this type in a constraint (e.g. `O: MapObserver`), ensure that you only refer
|
||||
/// to instances of a second type, e.g. `C: AsRef<O>` or `A: AsMut<O>`. Map observer instances are
|
||||
/// passed around in a way that may be potentially wrapped by e.g. [`ExplicitTracking`] as a way to
|
||||
/// encode metadata into the type. This is an unfortunate additional requirement that we can't get
|
||||
/// around without specialization.
|
||||
///
|
||||
/// See [`crate::require_index_tracking`] for an example of how to do so.
|
||||
///
|
||||
/// TODO: enforce `iter() -> AssociatedTypeIter` when generic associated types stabilize
|
||||
pub trait MapObserver: HasLen + Named + Serialize + serde::de::DeserializeOwned
|
||||
pub trait MapObserver:
|
||||
HasLen + Named + Serialize + serde::de::DeserializeOwned + AsRef<Self> + AsMut<Self>
|
||||
// where
|
||||
// for<'it> &'it Self: IntoIterator<Item = &'it Self::Entry>
|
||||
{
|
||||
@ -118,6 +455,24 @@ pub trait MapObserver: HasLen + Named + Serialize + serde::de::DeserializeOwned
|
||||
fn how_many_set(&self, indexes: &[usize]) -> usize;
|
||||
}
|
||||
|
||||
impl<M> CanTrack for M
|
||||
where
|
||||
M: MapObserver,
|
||||
{
|
||||
type WithIndexTracking = ExplicitTracking<Self, true, false>;
|
||||
type WithNoveltiesTracking = ExplicitTracking<Self, false, true>;
|
||||
const INDICES: bool = false;
|
||||
const NOVELTIES: bool = false;
|
||||
|
||||
fn track_indices(self) -> Self::WithIndexTracking {
|
||||
ExplicitTracking::<Self, true, false>(self)
|
||||
}
|
||||
|
||||
fn track_novelties(self) -> Self::WithNoveltiesTracking {
|
||||
ExplicitTracking::<Self, false, true>(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// A Simple iterator calling `MapObserver::get`
|
||||
#[derive(Debug)]
|
||||
pub struct MapObserverSimpleIterator<'a, O>
|
||||
@ -346,6 +701,24 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, const DIFFERENTIAL: bool> AsRef<Self> for StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize,
|
||||
{
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, const DIFFERENTIAL: bool> AsMut<Self> for StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize,
|
||||
{
|
||||
fn as_mut(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, const DIFFERENTIAL: bool> MapObserver for StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Bounded
|
||||
@ -455,6 +828,7 @@ where
|
||||
self.map.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, const DIFFERENTIAL: bool> AsMutSlice for StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
@ -830,6 +1204,24 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, const N: usize> AsRef<Self> for ConstMapObserver<'a, T, N>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize,
|
||||
{
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, const N: usize> AsMut<Self> for ConstMapObserver<'a, T, N>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize,
|
||||
{
|
||||
fn as_mut(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, const N: usize> MapObserver for ConstMapObserver<'a, T, N>
|
||||
where
|
||||
T: Bounded
|
||||
@ -922,6 +1314,7 @@ where
|
||||
self.map.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, const N: usize> AsMutSlice for ConstMapObserver<'a, T, N>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
@ -1142,6 +1535,24 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> AsRef<Self> for VariableMapObserver<'a, T>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + PartialEq + Bounded,
|
||||
{
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> AsMut<Self> for VariableMapObserver<'a, T>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + PartialEq + Bounded,
|
||||
{
|
||||
fn as_mut(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> MapObserver for VariableMapObserver<'a, T>
|
||||
where
|
||||
T: Bounded
|
||||
@ -1243,6 +1654,7 @@ where
|
||||
&self.map.as_slice()[..cnt]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> AsMutSlice for VariableMapObserver<'a, T>
|
||||
where
|
||||
T: 'static
|
||||
@ -1305,8 +1717,8 @@ where
|
||||
|
||||
/// Map observer with AFL-like hitcounts postprocessing
|
||||
///
|
||||
/// [`MapObserver`]s that are not slice-backed,
|
||||
/// such as [`MultiMapObserver`], can use [`HitcountsIterableMapObserver`] instead.
|
||||
/// [`MapObserver`]s that are not slice-backed, such as [`MultiMapObserver`], can use
|
||||
/// [`HitcountsIterableMapObserver`] instead.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(bound = "M: serde::de::DeserializeOwned")]
|
||||
pub struct HitcountsMapObserver<M>
|
||||
@ -1396,6 +1808,24 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> AsRef<Self> for HitcountsMapObserver<M>
|
||||
where
|
||||
M: MapObserver<Entry = u8>,
|
||||
{
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> AsMut<Self> for HitcountsMapObserver<M>
|
||||
where
|
||||
M: MapObserver<Entry = u8>,
|
||||
{
|
||||
fn as_mut(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> MapObserver for HitcountsMapObserver<M>
|
||||
where
|
||||
M: MapObserver<Entry = u8>,
|
||||
@ -1478,7 +1908,7 @@ where
|
||||
|
||||
impl<M> HitcountsMapObserver<M>
|
||||
where
|
||||
M: Serialize + serde::de::DeserializeOwned,
|
||||
M: MapObserver,
|
||||
{
|
||||
/// Creates a new [`MapObserver`]
|
||||
pub fn new(base: M) -> Self {
|
||||
@ -1645,6 +2075,26 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> AsRef<Self> for HitcountsIterableMapObserver<M>
|
||||
where
|
||||
M: MapObserver<Entry = u8>,
|
||||
for<'it> M: AsIterMut<'it, Item = u8>,
|
||||
{
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> AsMut<Self> for HitcountsIterableMapObserver<M>
|
||||
where
|
||||
M: MapObserver<Entry = u8>,
|
||||
for<'it> M: AsIterMut<'it, Item = u8>,
|
||||
{
|
||||
fn as_mut(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> MapObserver for HitcountsIterableMapObserver<M>
|
||||
where
|
||||
M: MapObserver<Entry = u8>,
|
||||
@ -1714,6 +2164,7 @@ where
|
||||
self.base.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> AsMutSlice for HitcountsIterableMapObserver<M>
|
||||
where
|
||||
M: MapObserver + AsMutSlice,
|
||||
@ -1890,6 +2341,24 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, const DIFFERENTIAL: bool> AsRef<Self> for MultiMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: 'static + Default + Copy + Serialize + Debug,
|
||||
{
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, const DIFFERENTIAL: bool> AsMut<Self> for MultiMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: 'static + Default + Copy + Serialize + Debug,
|
||||
{
|
||||
fn as_mut(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, const DIFFERENTIAL: bool> MapObserver for MultiMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: 'static
|
||||
@ -2245,6 +2714,24 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<Self> for OwnedMapObserver<T>
|
||||
where
|
||||
T: 'static + Default + Copy + Serialize,
|
||||
{
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsMut<Self> for OwnedMapObserver<T>
|
||||
where
|
||||
T: 'static + Default + Copy + Serialize,
|
||||
{
|
||||
fn as_mut(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> MapObserver for OwnedMapObserver<T>
|
||||
where
|
||||
T: 'static
|
||||
|
@ -11,7 +11,7 @@ use crate::{
|
||||
corpus::{Corpus, CorpusId},
|
||||
feedbacks::MapIndexesMetadata,
|
||||
inputs::UsesInput,
|
||||
observers::ObserversTuple,
|
||||
observers::{CanTrack, ObserversTuple},
|
||||
schedulers::{
|
||||
minimizer::{IsFavoredMetadata, MinimizerScheduler, DEFAULT_SKIP_NON_FAVORED_PROB},
|
||||
LenTimeMulTestcaseScore, Scheduler,
|
||||
@ -106,7 +106,7 @@ impl TopAccountingMetadata {
|
||||
|
||||
/// A minimizer scheduler using coverage accounting
|
||||
#[derive(Debug)]
|
||||
pub struct CoverageAccountingScheduler<'a, CS>
|
||||
pub struct CoverageAccountingScheduler<'a, CS, O>
|
||||
where
|
||||
CS: UsesState,
|
||||
CS::State: Debug,
|
||||
@ -117,10 +117,11 @@ where
|
||||
CS,
|
||||
LenTimeMulTestcaseScore<<CS as UsesState>::State>,
|
||||
MapIndexesMetadata,
|
||||
O,
|
||||
>,
|
||||
}
|
||||
|
||||
impl<'a, CS> UsesState for CoverageAccountingScheduler<'a, CS>
|
||||
impl<'a, CS, O> UsesState for CoverageAccountingScheduler<'a, CS, O>
|
||||
where
|
||||
CS: UsesState,
|
||||
CS::State: Debug,
|
||||
@ -128,11 +129,12 @@ where
|
||||
type State = CS::State;
|
||||
}
|
||||
|
||||
impl<'a, CS> Scheduler for CoverageAccountingScheduler<'a, CS>
|
||||
impl<'a, CS, O> Scheduler for CoverageAccountingScheduler<'a, CS, O>
|
||||
where
|
||||
CS: Scheduler,
|
||||
CS::State: HasCorpus + HasMetadata + HasRand + Debug,
|
||||
<CS::State as UsesInput>::Input: HasLen,
|
||||
O: CanTrack,
|
||||
{
|
||||
fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
|
||||
self.update_accounting_score(state, idx)?;
|
||||
@ -190,11 +192,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, CS> CoverageAccountingScheduler<'a, CS>
|
||||
impl<'a, CS, O> CoverageAccountingScheduler<'a, CS, O>
|
||||
where
|
||||
CS: Scheduler,
|
||||
CS::State: HasCorpus + HasMetadata + HasRand + Debug,
|
||||
<CS::State as UsesInput>::Input: HasLen,
|
||||
O: CanTrack,
|
||||
{
|
||||
/// Update the `Corpus` score
|
||||
#[allow(clippy::unused_self)]
|
||||
@ -307,7 +310,9 @@ where
|
||||
|
||||
/// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`]
|
||||
/// and has a default probability to skip non-faved Testcases of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
|
||||
pub fn new(state: &mut CS::State, base: CS, accounting_map: &'a [u32]) -> Self {
|
||||
///
|
||||
/// Provide the observer responsible for determining new indexes.
|
||||
pub fn new(observer: &O, state: &mut CS::State, base: CS, accounting_map: &'a [u32]) -> Self {
|
||||
match state.metadata_map().get::<TopAccountingMetadata>() {
|
||||
Some(meta) => {
|
||||
if meta.max_accounting.len() != accounting_map.len() {
|
||||
@ -320,14 +325,17 @@ where
|
||||
}
|
||||
Self {
|
||||
accounting_map,
|
||||
inner: MinimizerScheduler::new(base),
|
||||
inner: MinimizerScheduler::new(observer, base),
|
||||
skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`]
|
||||
/// and has a non-default probability to skip non-faved Testcases using (`skip_non_favored_prob`).
|
||||
///
|
||||
/// Provide the observer responsible for determining new indexes.
|
||||
pub fn with_skip_prob(
|
||||
observer: &O,
|
||||
state: &mut CS::State,
|
||||
base: CS,
|
||||
skip_non_favored_prob: u64,
|
||||
@ -345,7 +353,7 @@ where
|
||||
}
|
||||
Self {
|
||||
accounting_map,
|
||||
inner: MinimizerScheduler::with_skip_prob(base, skip_non_favored_prob),
|
||||
inner: MinimizerScheduler::with_skip_prob(observer, base, skip_non_favored_prob),
|
||||
skip_non_favored_prob,
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,8 @@ use crate::{
|
||||
corpus::{Corpus, CorpusId, Testcase},
|
||||
feedbacks::MapIndexesMetadata,
|
||||
inputs::UsesInput,
|
||||
observers::ObserversTuple,
|
||||
observers::{CanTrack, ObserversTuple},
|
||||
require_index_tracking,
|
||||
schedulers::{LenTimeMulTestcaseScore, RemovableScheduler, Scheduler, TestcaseScore},
|
||||
state::{HasCorpus, HasRand, UsesState},
|
||||
Error, HasMetadata,
|
||||
@ -70,26 +71,27 @@ impl Default for TopRatedsMetadata {
|
||||
/// corpus that exercise all the requested features (e.g. all the coverage seen so far)
|
||||
/// prioritizing [`Testcase`]`s` using [`TestcaseScore`]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MinimizerScheduler<CS, F, M> {
|
||||
pub struct MinimizerScheduler<CS, F, M, O> {
|
||||
base: CS,
|
||||
skip_non_favored_prob: u64,
|
||||
remove_metadata: bool,
|
||||
phantom: PhantomData<(F, M)>,
|
||||
phantom: PhantomData<(F, M, O)>,
|
||||
}
|
||||
|
||||
impl<CS, F, M> UsesState for MinimizerScheduler<CS, F, M>
|
||||
impl<CS, F, M, O> UsesState for MinimizerScheduler<CS, F, M, O>
|
||||
where
|
||||
CS: UsesState,
|
||||
{
|
||||
type State = CS::State;
|
||||
}
|
||||
|
||||
impl<CS, F, M> RemovableScheduler for MinimizerScheduler<CS, F, M>
|
||||
impl<CS, F, M, O> RemovableScheduler for MinimizerScheduler<CS, F, M, O>
|
||||
where
|
||||
CS: RemovableScheduler,
|
||||
F: TestcaseScore<CS::State>,
|
||||
M: AsSlice<Entry = usize> + SerdeAny + HasRefCnt,
|
||||
CS::State: HasCorpus + HasMetadata + HasRand,
|
||||
O: CanTrack,
|
||||
{
|
||||
/// Replaces the testcase at the given idx
|
||||
fn on_replace(
|
||||
@ -191,12 +193,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<CS, F, M> Scheduler for MinimizerScheduler<CS, F, M>
|
||||
impl<CS, F, M, O> Scheduler for MinimizerScheduler<CS, F, M, O>
|
||||
where
|
||||
CS: Scheduler,
|
||||
F: TestcaseScore<CS::State>,
|
||||
M: AsSlice<Entry = usize> + SerdeAny + HasRefCnt,
|
||||
CS::State: HasCorpus + HasMetadata + HasRand,
|
||||
O: CanTrack,
|
||||
{
|
||||
/// Called when a [`Testcase`] is added to the corpus
|
||||
fn on_add(&mut self, state: &mut CS::State, idx: CorpusId) -> Result<(), Error> {
|
||||
@ -246,12 +249,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<CS, F, M> MinimizerScheduler<CS, F, M>
|
||||
impl<CS, F, M, O> MinimizerScheduler<CS, F, M, O>
|
||||
where
|
||||
CS: Scheduler,
|
||||
F: TestcaseScore<CS::State>,
|
||||
M: AsSlice<Entry = usize> + SerdeAny + HasRefCnt,
|
||||
CS::State: HasCorpus + HasMetadata + HasRand,
|
||||
O: CanTrack,
|
||||
{
|
||||
/// Update the [`Corpus`] score using the [`MinimizerScheduler`]
|
||||
#[allow(clippy::unused_self)]
|
||||
@ -371,7 +375,10 @@ where
|
||||
/// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
|
||||
/// This will remove the metadata `M` when it is no longer needed, after consumption. This might
|
||||
/// for example be a `MapIndexesMetadata`.
|
||||
pub fn new(base: CS) -> Self {
|
||||
///
|
||||
/// When calling, pass the edges observer which will provided the indexes to minimize over.
|
||||
pub fn new(_observer: &O, base: CS) -> Self {
|
||||
require_index_tracking!("MinimizerScheduler", O);
|
||||
Self {
|
||||
base,
|
||||
skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB,
|
||||
@ -383,7 +390,10 @@ where
|
||||
/// Creates a new [`MinimizerScheduler`] that wraps a `base` [`Scheduler`]
|
||||
/// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
|
||||
/// This method will prevent the metadata `M` from being removed at the end of scoring.
|
||||
pub fn non_metadata_removing(base: CS) -> Self {
|
||||
///
|
||||
/// When calling, pass the edges observer which will provided the indexes to minimize over.
|
||||
pub fn non_metadata_removing(_observer: &O, base: CS) -> Self {
|
||||
require_index_tracking!("MinimizerScheduler", O);
|
||||
Self {
|
||||
base,
|
||||
skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB,
|
||||
@ -394,7 +404,10 @@ where
|
||||
|
||||
/// Creates a new [`MinimizerScheduler`] that wraps a `base` [`Scheduler`]
|
||||
/// and has a non-default probability to skip non-faved [`Testcase`]s using (`skip_non_favored_prob`).
|
||||
pub fn with_skip_prob(base: CS, skip_non_favored_prob: u64) -> Self {
|
||||
///
|
||||
/// When calling, pass the edges observer which will provided the indexes to minimize over.
|
||||
pub fn with_skip_prob(_observer: &O, base: CS, skip_non_favored_prob: u64) -> Self {
|
||||
require_index_tracking!("MinimizerScheduler", O);
|
||||
Self {
|
||||
base,
|
||||
skip_non_favored_prob,
|
||||
@ -405,10 +418,14 @@ where
|
||||
}
|
||||
|
||||
/// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`.
|
||||
pub type LenTimeMinimizerScheduler<CS, M> =
|
||||
MinimizerScheduler<CS, LenTimeMulTestcaseScore<<CS as UsesState>::State>, M>;
|
||||
pub type LenTimeMinimizerScheduler<CS, M, O> =
|
||||
MinimizerScheduler<CS, LenTimeMulTestcaseScore<<CS as UsesState>::State>, M, O>;
|
||||
|
||||
/// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`
|
||||
/// that exercise all the entries registered in the [`MapIndexesMetadata`].
|
||||
pub type IndexesLenTimeMinimizerScheduler<CS> =
|
||||
MinimizerScheduler<CS, LenTimeMulTestcaseScore<<CS as UsesState>::State>, MapIndexesMetadata>;
|
||||
pub type IndexesLenTimeMinimizerScheduler<CS, O> = MinimizerScheduler<
|
||||
CS,
|
||||
LenTimeMulTestcaseScore<<CS as UsesState>::State>,
|
||||
MapIndexesMetadata,
|
||||
O,
|
||||
>;
|
||||
|
@ -66,10 +66,11 @@ where
|
||||
}
|
||||
|
||||
/// Defines the common metadata operations for the AFL-style schedulers
|
||||
pub trait AflScheduler<O, S>: Scheduler
|
||||
pub trait AflScheduler<C, O, S>: Scheduler
|
||||
where
|
||||
Self::State: HasCorpus + HasMetadata + HasTestcase,
|
||||
O: MapObserver,
|
||||
C: AsRef<O>,
|
||||
{
|
||||
/// Return the last hash
|
||||
fn last_hash(&self) -> usize;
|
||||
@ -117,8 +118,9 @@ where
|
||||
OT: ObserversTuple<Self::State>,
|
||||
{
|
||||
let observer = observers
|
||||
.match_name::<O>(self.map_observer_name())
|
||||
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?;
|
||||
.match_name::<C>(self.map_observer_name())
|
||||
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
|
||||
.as_ref();
|
||||
|
||||
let mut hash = observer.hash() as usize;
|
||||
|
||||
|
@ -6,6 +6,7 @@ use alloc::{
|
||||
};
|
||||
use core::{marker::PhantomData, time::Duration};
|
||||
|
||||
use libafl_bolts::Named;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
@ -170,24 +171,25 @@ pub enum PowerSchedule {
|
||||
/// Note that this corpus is merely holding the metadata necessary for the power calculation
|
||||
/// and here we DON'T actually calculate the power (we do it in the stage)
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PowerQueueScheduler<O, S> {
|
||||
pub struct PowerQueueScheduler<C, O, S> {
|
||||
strat: PowerSchedule,
|
||||
map_observer_name: String,
|
||||
last_hash: usize,
|
||||
phantom: PhantomData<(O, S)>,
|
||||
phantom: PhantomData<(C, O, S)>,
|
||||
}
|
||||
|
||||
impl<O, S> UsesState for PowerQueueScheduler<O, S>
|
||||
impl<C, O, S> UsesState for PowerQueueScheduler<C, O, S>
|
||||
where
|
||||
S: State,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<O, S> RemovableScheduler for PowerQueueScheduler<O, S>
|
||||
impl<C, O, S> RemovableScheduler for PowerQueueScheduler<C, O, S>
|
||||
where
|
||||
S: State + HasTestcase + HasMetadata + HasCorpus,
|
||||
O: MapObserver,
|
||||
C: AsRef<O>,
|
||||
{
|
||||
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
|
||||
fn on_remove(
|
||||
@ -210,10 +212,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<O, S> AflScheduler<O, S> for PowerQueueScheduler<O, S>
|
||||
impl<C, O, S> AflScheduler<C, O, S> for PowerQueueScheduler<C, O, S>
|
||||
where
|
||||
S: HasCorpus + HasMetadata + HasTestcase + State,
|
||||
O: MapObserver,
|
||||
C: AsRef<O>,
|
||||
{
|
||||
fn last_hash(&self) -> usize {
|
||||
self.last_hash
|
||||
@ -228,10 +231,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<O, S> Scheduler for PowerQueueScheduler<O, S>
|
||||
impl<C, O, S> Scheduler for PowerQueueScheduler<C, O, S>
|
||||
where
|
||||
S: HasCorpus + HasMetadata + HasTestcase + State,
|
||||
O: MapObserver,
|
||||
C: AsRef<O>,
|
||||
{
|
||||
/// Called when a [`Testcase`] is added to the corpus
|
||||
fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
|
||||
@ -287,14 +291,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<O, S> PowerQueueScheduler<O, S>
|
||||
impl<C, O, S> PowerQueueScheduler<C, O, S>
|
||||
where
|
||||
S: HasMetadata,
|
||||
O: MapObserver,
|
||||
C: AsRef<O> + Named,
|
||||
{
|
||||
/// Create a new [`PowerQueueScheduler`]
|
||||
#[must_use]
|
||||
pub fn new(state: &mut S, map_observer: &O, strat: PowerSchedule) -> Self {
|
||||
pub fn new(state: &mut S, map_observer: &C, strat: PowerSchedule) -> Self {
|
||||
if !state.has_metadata::<SchedulerMetadata>() {
|
||||
state.add_metadata::<SchedulerMetadata>(SchedulerMetadata::new(Some(strat)));
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
//! 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 AFL++](https://github.com/AFLplusplus/AFLplusplus/blob/1d4f1e48797c064ee71441ba555b29fc3f467983/src/afl-fuzz-queue.c#L32).
|
||||
//! This queue corpus scheduler needs calibration stage.
|
||||
|
||||
use alloc::string::{String, ToString};
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use libafl_bolts::rands::Rand;
|
||||
use libafl_bolts::{rands::Rand, Named};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
@ -92,29 +92,30 @@ libafl_bolts::impl_serdeany!(WeightedScheduleMetadata);
|
||||
|
||||
/// A corpus scheduler using power schedules with weighted queue item selection algo.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WeightedScheduler<F, O, S> {
|
||||
pub struct WeightedScheduler<C, F, O, S> {
|
||||
table_invalidated: bool,
|
||||
strat: Option<PowerSchedule>,
|
||||
map_observer_name: String,
|
||||
last_hash: usize,
|
||||
phantom: PhantomData<(F, O, S)>,
|
||||
phantom: PhantomData<(C, F, O, S)>,
|
||||
}
|
||||
|
||||
impl<F, O, S> WeightedScheduler<F, O, S>
|
||||
impl<C, F, O, S> WeightedScheduler<C, F, O, S>
|
||||
where
|
||||
F: TestcaseScore<S>,
|
||||
O: MapObserver,
|
||||
S: HasCorpus + HasMetadata + HasRand,
|
||||
C: AsRef<O> + Named,
|
||||
{
|
||||
/// Create a new [`WeightedScheduler`] without any power schedule
|
||||
#[must_use]
|
||||
pub fn new(state: &mut S, map_observer: &O) -> Self {
|
||||
pub fn new(state: &mut S, map_observer: &C) -> Self {
|
||||
Self::with_schedule(state, map_observer, None)
|
||||
}
|
||||
|
||||
/// Create a new [`WeightedScheduler`]
|
||||
#[must_use]
|
||||
pub fn with_schedule(state: &mut S, map_observer: &O, strat: Option<PowerSchedule>) -> Self {
|
||||
pub fn with_schedule(state: &mut S, map_observer: &C, strat: Option<PowerSchedule>) -> Self {
|
||||
let _ = state.metadata_or_insert_with(|| SchedulerMetadata::new(strat));
|
||||
let _ = state.metadata_or_insert_with(WeightedScheduleMetadata::new);
|
||||
|
||||
@ -218,18 +219,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, O, S> UsesState for WeightedScheduler<F, O, S>
|
||||
impl<C, F, O, S> UsesState for WeightedScheduler<C, F, O, S>
|
||||
where
|
||||
S: State,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<F, O, S> RemovableScheduler for WeightedScheduler<F, O, S>
|
||||
impl<C, F, O, S> RemovableScheduler for WeightedScheduler<C, F, O, S>
|
||||
where
|
||||
F: TestcaseScore<S>,
|
||||
O: MapObserver,
|
||||
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State,
|
||||
C: AsRef<O> + Named,
|
||||
{
|
||||
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
|
||||
fn on_remove(
|
||||
@ -254,11 +256,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, O, S> AflScheduler<O, S> for WeightedScheduler<F, O, S>
|
||||
impl<C, F, O, S> AflScheduler<C, O, S> for WeightedScheduler<C, F, O, S>
|
||||
where
|
||||
F: TestcaseScore<S>,
|
||||
S: HasCorpus + HasMetadata + HasTestcase + HasRand + State,
|
||||
O: MapObserver,
|
||||
S: HasCorpus + HasMetadata + HasTestcase + HasRand + State,
|
||||
C: AsRef<O> + Named,
|
||||
{
|
||||
fn last_hash(&self) -> usize {
|
||||
self.last_hash
|
||||
@ -273,11 +276,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, O, S> Scheduler for WeightedScheduler<F, O, S>
|
||||
impl<C, F, O, S> Scheduler for WeightedScheduler<C, F, O, S>
|
||||
where
|
||||
F: TestcaseScore<S>,
|
||||
O: MapObserver,
|
||||
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State,
|
||||
C: AsRef<O> + Named,
|
||||
{
|
||||
/// Called when a [`Testcase`] is added to the corpus
|
||||
fn on_add(&mut self, state: &mut S, idx: CorpusId) -> Result<(), Error> {
|
||||
@ -356,5 +360,5 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// The standard corpus weight, same as aflpp
|
||||
pub type StdWeightedScheduler<O, S> = WeightedScheduler<CorpusWeightTestcaseScore<S>, O, S>;
|
||||
/// The standard corpus weight, same as in `AFL++`
|
||||
pub type StdWeightedScheduler<C, O, S> = WeightedScheduler<C, CorpusWeightTestcaseScore<S>, O, S>;
|
||||
|
@ -64,31 +64,32 @@ impl UnstableEntriesMetadata {
|
||||
|
||||
/// The calibration stage will measure the average exec time and the target's stability for this input.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CalibrationStage<O, OT, S> {
|
||||
pub struct CalibrationStage<C, O, OT, S> {
|
||||
map_observer_name: String,
|
||||
map_name: String,
|
||||
stage_max: usize,
|
||||
/// If we should track stability
|
||||
track_stability: bool,
|
||||
restart_helper: ExecutionCountRestartHelper,
|
||||
phantom: PhantomData<(O, OT, S)>,
|
||||
phantom: PhantomData<(C, O, OT, S)>,
|
||||
}
|
||||
|
||||
const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1
|
||||
const CAL_STAGE_MAX: usize = 8; // AFL++'s CAL_CYCLES + 1
|
||||
|
||||
impl<O, OT, S> UsesState for CalibrationStage<O, OT, S>
|
||||
impl<C, O, OT, S> UsesState for CalibrationStage<C, O, OT, S>
|
||||
where
|
||||
S: State,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<E, EM, O, OT, Z> Stage<E, EM, Z> for CalibrationStage<O, OT, E::State>
|
||||
impl<C, E, EM, O, OT, Z> Stage<E, EM, Z> for CalibrationStage<C, O, OT, E::State>
|
||||
where
|
||||
E: Executor<EM, Z> + HasObservers<Observers = OT>,
|
||||
EM: EventFirer<State = E::State>,
|
||||
O: MapObserver,
|
||||
C: AsRef<O>,
|
||||
for<'de> <O as MapObserver>::Entry: Serialize + Deserialize<'de> + 'static,
|
||||
OT: ObserversTuple<E::State>,
|
||||
E::State: HasCorpus + HasMetadata + HasNamedMetadata + HasExecutions,
|
||||
@ -147,8 +148,9 @@ where
|
||||
|
||||
let map_first = &executor
|
||||
.observers()
|
||||
.match_name::<O>(&self.map_observer_name)
|
||||
.match_name::<C>(&self.map_observer_name)
|
||||
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
|
||||
.as_ref()
|
||||
.to_vec();
|
||||
|
||||
let mut unstable_entries: Vec<usize> = vec![];
|
||||
@ -190,8 +192,9 @@ where
|
||||
if self.track_stability {
|
||||
let map = &executor
|
||||
.observers()
|
||||
.match_name::<O>(&self.map_observer_name)
|
||||
.match_name::<C>(&self.map_observer_name)
|
||||
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
|
||||
.as_ref()
|
||||
.to_vec();
|
||||
|
||||
let history_map = &mut state
|
||||
@ -246,8 +249,9 @@ where
|
||||
if state.has_metadata::<SchedulerMetadata>() {
|
||||
let map = executor
|
||||
.observers()
|
||||
.match_name::<O>(&self.map_observer_name)
|
||||
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?;
|
||||
.match_name::<C>(&self.map_observer_name)
|
||||
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
|
||||
.as_ref();
|
||||
|
||||
let mut bitmap_size = map.count_bytes();
|
||||
assert!(bitmap_size != 0);
|
||||
@ -335,9 +339,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<O, OT, S> CalibrationStage<O, OT, S>
|
||||
impl<C, O, OT, S> CalibrationStage<C, O, OT, S>
|
||||
where
|
||||
O: MapObserver,
|
||||
C: AsRef<O>,
|
||||
OT: ObserversTuple<S>,
|
||||
S: HasCorpus + HasMetadata + HasNamedMetadata,
|
||||
{
|
||||
@ -345,8 +350,9 @@ where
|
||||
#[must_use]
|
||||
pub fn new<F>(map_feedback: &F) -> Self
|
||||
where
|
||||
F: HasObserverName + Named + UsesObserver<S, Observer = O>,
|
||||
F: HasObserverName + Named + UsesObserver<S, Observer = C>,
|
||||
for<'it> O: AsIter<'it, Item = O::Entry>,
|
||||
C: AsRef<O>,
|
||||
{
|
||||
Self {
|
||||
map_observer_name: map_feedback.observer_name().to_string(),
|
||||
@ -362,8 +368,9 @@ where
|
||||
#[must_use]
|
||||
pub fn ignore_stability<F>(map_feedback: &F) -> Self
|
||||
where
|
||||
F: HasObserverName + Named + UsesObserver<S, Observer = O>,
|
||||
F: HasObserverName + Named + UsesObserver<S, Observer = C>,
|
||||
for<'it> O: AsIter<'it, Item = O::Entry>,
|
||||
C: AsRef<O>,
|
||||
{
|
||||
Self {
|
||||
map_observer_name: map_feedback.observer_name().to_string(),
|
||||
|
@ -54,20 +54,20 @@ impl Ord for Earlier {
|
||||
|
||||
/// The mutational stage using power schedules
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ColorizationStage<EM, O, E, Z> {
|
||||
pub struct ColorizationStage<C, E, EM, O, Z> {
|
||||
map_observer_name: String,
|
||||
#[allow(clippy::type_complexity)]
|
||||
phantom: PhantomData<(E, EM, O, Z)>,
|
||||
phantom: PhantomData<(C, E, EM, O, E, Z)>,
|
||||
}
|
||||
|
||||
impl<EM, O, E, Z> UsesState for ColorizationStage<EM, O, E, Z>
|
||||
impl<C, E, EM, O, Z> UsesState for ColorizationStage<C, E, EM, O, Z>
|
||||
where
|
||||
E: UsesState,
|
||||
{
|
||||
type State = E::State;
|
||||
}
|
||||
|
||||
impl<EM, O, E, Z> Named for ColorizationStage<EM, O, E, Z>
|
||||
impl<C, E, EM, O, Z> Named for ColorizationStage<C, E, EM, O, Z>
|
||||
where
|
||||
E: UsesState,
|
||||
{
|
||||
@ -76,13 +76,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, EM, O, Z> Stage<E, EM, Z> for ColorizationStage<EM, O, E, Z>
|
||||
impl<C, E, EM, O, Z> Stage<E, EM, Z> for ColorizationStage<C, E, EM, O, Z>
|
||||
where
|
||||
EM: UsesState<State = E::State> + EventFirer,
|
||||
E: HasObservers + Executor<EM, Z>,
|
||||
E::State: HasCorpus + HasMetadata + HasRand + HasNamedMetadata,
|
||||
E::Input: HasBytesVec,
|
||||
O: MapObserver,
|
||||
C: AsRef<O> + Named,
|
||||
Z: UsesState<State = E::State>,
|
||||
{
|
||||
#[inline]
|
||||
@ -150,10 +151,11 @@ impl TaintMetadata {
|
||||
|
||||
libafl_bolts::impl_serdeany!(TaintMetadata);
|
||||
|
||||
impl<EM, O, E, Z> ColorizationStage<EM, O, E, Z>
|
||||
impl<C, E, EM, O, Z> ColorizationStage<C, E, EM, O, Z>
|
||||
where
|
||||
EM: UsesState<State = E::State> + EventFirer,
|
||||
O: MapObserver,
|
||||
C: AsRef<O> + Named,
|
||||
E: HasObservers + Executor<EM, Z>,
|
||||
E::State: HasCorpus + HasMetadata + HasRand,
|
||||
E::Input: HasBytesVec,
|
||||
@ -297,9 +299,9 @@ where
|
||||
|
||||
#[must_use]
|
||||
/// Creates a new [`ColorizationStage`]
|
||||
pub fn new(map_observer_name: &O) -> Self {
|
||||
pub fn new(map_observer: &C) -> Self {
|
||||
Self {
|
||||
map_observer_name: map_observer_name.name().to_string(),
|
||||
map_observer_name: map_observer.name().to_string(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -319,8 +321,9 @@ where
|
||||
|
||||
let observer = executor
|
||||
.observers()
|
||||
.match_name::<O>(name)
|
||||
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?;
|
||||
.match_name::<C>(name)
|
||||
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
|
||||
.as_ref();
|
||||
|
||||
let hash = observer.hash() as usize;
|
||||
|
||||
|
@ -14,7 +14,8 @@ use crate::{
|
||||
feedbacks::map::MapNoveltiesMetadata,
|
||||
inputs::{BytesInput, GeneralizedInputMetadata, GeneralizedItem, HasBytesVec, UsesInput},
|
||||
mark_feature_time,
|
||||
observers::{MapObserver, ObserversTuple},
|
||||
observers::{CanTrack, MapObserver, ObserversTuple},
|
||||
require_novelties_tracking,
|
||||
stages::{RetryRestartHelper, Stage},
|
||||
start_timer,
|
||||
state::{HasCorpus, HasExecutions, UsesState},
|
||||
@ -41,19 +42,19 @@ fn find_next_char(list: &[Option<u8>], mut idx: usize, ch: u8) -> usize {
|
||||
|
||||
/// A stage that runs a tracer executor
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GeneralizationStage<EM, O, OT, Z> {
|
||||
pub struct GeneralizationStage<C, EM, O, OT, Z> {
|
||||
map_observer_name: String,
|
||||
#[allow(clippy::type_complexity)]
|
||||
phantom: PhantomData<(EM, O, OT, Z)>,
|
||||
phantom: PhantomData<(C, EM, O, OT, Z)>,
|
||||
}
|
||||
|
||||
impl<EM, O, OT, Z> Named for GeneralizationStage<EM, O, OT, Z> {
|
||||
impl<C, EM, O, OT, Z> Named for GeneralizationStage<C, EM, O, OT, Z> {
|
||||
fn name(&self) -> &str {
|
||||
"GeneralizationStage"
|
||||
}
|
||||
}
|
||||
|
||||
impl<EM, O, OT, Z> UsesState for GeneralizationStage<EM, O, OT, Z>
|
||||
impl<C, EM, O, OT, Z> UsesState for GeneralizationStage<C, EM, O, OT, Z>
|
||||
where
|
||||
EM: UsesState,
|
||||
EM::State: UsesInput<Input = BytesInput>,
|
||||
@ -61,9 +62,10 @@ where
|
||||
type State = EM::State;
|
||||
}
|
||||
|
||||
impl<E, EM, O, Z> Stage<E, EM, Z> for GeneralizationStage<EM, O, E::Observers, Z>
|
||||
impl<C, E, EM, O, Z> Stage<E, EM, Z> for GeneralizationStage<C, EM, O, E::Observers, Z>
|
||||
where
|
||||
O: MapObserver,
|
||||
C: CanTrack + AsRef<O>,
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
E::Observers: ObserversTuple<E::State>,
|
||||
E::State:
|
||||
@ -331,18 +333,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<EM, O, OT, Z> GeneralizationStage<EM, O, OT, Z>
|
||||
impl<C, EM, O, OT, Z> GeneralizationStage<C, EM, O, OT, Z>
|
||||
where
|
||||
EM: UsesState,
|
||||
O: MapObserver,
|
||||
C: CanTrack + AsRef<O>,
|
||||
OT: ObserversTuple<EM::State>,
|
||||
EM::State: UsesInput<Input = BytesInput> + HasExecutions + HasMetadata + HasCorpus,
|
||||
{
|
||||
/// Create a new [`GeneralizationStage`].
|
||||
#[must_use]
|
||||
pub fn new(map_observer: &O) -> Self {
|
||||
pub fn new(map_observer: &C) -> Self {
|
||||
require_novelties_tracking!("GeneralizationStage", C);
|
||||
Self {
|
||||
map_observer_name: map_observer.name().to_string(),
|
||||
map_observer_name: map_observer.as_ref().name().to_string(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -387,8 +391,9 @@ where
|
||||
|
||||
let cnt = executor
|
||||
.observers()
|
||||
.match_name::<O>(&self.map_observer_name)
|
||||
.match_name::<C>(&self.map_observer_name)
|
||||
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
|
||||
.as_ref()
|
||||
.how_many_set(novelties);
|
||||
|
||||
Ok(cnt == novelties.len())
|
||||
|
@ -239,7 +239,7 @@ impl SyncFromBrokerMetadata {
|
||||
|
||||
/// A stage that loads testcases from disk to sync with other fuzzers such as AFL++
|
||||
#[derive(Debug)]
|
||||
pub struct SyncFromBrokerStage<IC, ICB, DI, S, SP>
|
||||
pub struct SyncFromBrokerStage<DI, IC, ICB, S, SP>
|
||||
where
|
||||
SP: ShMemProvider + 'static,
|
||||
S: UsesInput,
|
||||
@ -247,10 +247,10 @@ where
|
||||
ICB: InputConverter<From = DI, To = S::Input>,
|
||||
DI: Input,
|
||||
{
|
||||
client: LlmpEventConverter<IC, ICB, DI, S, SP>,
|
||||
client: LlmpEventConverter<DI, IC, ICB, S, SP>,
|
||||
}
|
||||
|
||||
impl<IC, ICB, DI, S, SP> UsesState for SyncFromBrokerStage<IC, ICB, DI, S, SP>
|
||||
impl<DI, IC, ICB, S, SP> UsesState for SyncFromBrokerStage<DI, IC, ICB, S, SP>
|
||||
where
|
||||
SP: ShMemProvider + 'static,
|
||||
S: State,
|
||||
@ -261,7 +261,7 @@ where
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<E, EM, IC, ICB, DI, S, SP, Z> Stage<E, EM, Z> for SyncFromBrokerStage<IC, ICB, DI, S, SP>
|
||||
impl<E, EM, IC, ICB, DI, S, SP, Z> Stage<E, EM, Z> for SyncFromBrokerStage<DI, IC, ICB, S, SP>
|
||||
where
|
||||
EM: UsesState<State = S> + EventFirer,
|
||||
S: State + HasExecutions + HasCorpus + HasRand + HasMetadata + HasTestcase,
|
||||
@ -343,7 +343,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<IC, ICB, DI, S, SP> SyncFromBrokerStage<IC, ICB, DI, S, SP>
|
||||
impl<DI, IC, ICB, S, SP> SyncFromBrokerStage<DI, IC, ICB, S, SP>
|
||||
where
|
||||
SP: ShMemProvider + 'static,
|
||||
S: UsesInput,
|
||||
@ -353,7 +353,7 @@ where
|
||||
{
|
||||
/// Creates a new [`SyncFromBrokerStage`]
|
||||
#[must_use]
|
||||
pub fn new(client: LlmpEventConverter<IC, ICB, DI, S, SP>) -> Self {
|
||||
pub fn new(client: LlmpEventConverter<DI, IC, ICB, S, SP>) -> Self {
|
||||
Self { client }
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ For bugs, feel free to open issues or contact us directly. Thank you for your su
|
||||
|
||||
Even though we will gladly assist you in finishing up your PR, try to
|
||||
- keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/build.rs#L26))
|
||||
- run `cargo fmt` on your code before pushing
|
||||
- run `cargo nightly fmt` on your code before pushing
|
||||
- check the output of `cargo clippy --all` or `./clippy.sh`
|
||||
- run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code.
|
||||
|
||||
|
@ -189,9 +189,7 @@ where
|
||||
match self._get(id, &self.mapping.enabled) {
|
||||
Ok(input) => Ok(input),
|
||||
Err(Error::KeyNotFound(..)) => return self._get(id, &self.mapping.disabled),
|
||||
Err(e) => {
|
||||
Err(e)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
fn current(&self) -> &Option<CorpusId> {
|
||||
|
@ -171,4 +171,4 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub type ShrinkMapFeedback<O, S, T> = MinMapFeedback<MappedEdgeMapObserver<O, T>, S, usize>;
|
||||
pub type ShrinkMapFeedback<C, O, S, T> = MinMapFeedback<C, MappedEdgeMapObserver<O, T>, S, usize>;
|
||||
|
@ -168,7 +168,7 @@ macro_rules! fuzz_with {
|
||||
I2SRandReplace, StdScheduledMutator, StringCategoryRandMutator, StringSubcategoryRandMutator,
|
||||
StringCategoryTokenReplaceMutator, StringSubcategoryTokenReplaceMutator, Tokens, tokens_mutations
|
||||
},
|
||||
observers::{stacktrace::BacktraceObserver, TimeObserver},
|
||||
observers::{stacktrace::BacktraceObserver, TimeObserver, CanTrack},
|
||||
schedulers::{
|
||||
IndexesLenTimeMinimizerScheduler, powersched::PowerSchedule, PowerQueueScheduler,
|
||||
},
|
||||
@ -198,7 +198,7 @@ macro_rules! fuzz_with {
|
||||
let grimoire_metadata = should_use_grimoire(&mut state, &$options, &mutator_status)?;
|
||||
let grimoire = grimoire_metadata.should();
|
||||
|
||||
let edges_observer = edge_maker();
|
||||
let edges_observer = edge_maker().track_indices().track_novelties();
|
||||
let size_edges_observer = MappedEdgeMapObserver::new(edge_maker(), SizeValueObserver::default());
|
||||
|
||||
let keep_observer = LibfuzzerKeepFeedback::new();
|
||||
@ -220,8 +220,8 @@ macro_rules! fuzz_with {
|
||||
);
|
||||
|
||||
// New maximization map feedback linked to the edges observer
|
||||
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, true);
|
||||
let shrinking_map_feedback = ShrinkMapFeedback::tracking(&size_edges_observer, false, false);
|
||||
let map_feedback = MaxMapFeedback::new(&edges_observer);
|
||||
let shrinking_map_feedback = ShrinkMapFeedback::new(&size_edges_observer);
|
||||
|
||||
// Set up a generalization stage for grimoire
|
||||
let generalization = GeneralizationStage::new(&edges_observer);
|
||||
@ -412,7 +412,7 @@ macro_rules! fuzz_with {
|
||||
let grimoire = IfStage::new(|_, _, _, _| Ok(grimoire.into()), (StdMutationalStage::transforming(grimoire_mutator), ()));
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST));
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST));
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -105,7 +105,7 @@ pub fn merge(
|
||||
let edges_observer =
|
||||
MappedEdgeMapObserver::new(edges_observer, SizeTimeValueObserver::new(time));
|
||||
|
||||
let map_feedback = MinMapFeedback::tracking(&edges_observer, false, true);
|
||||
let map_feedback = MinMapFeedback::new(&edges_observer);
|
||||
|
||||
// Create an OOM observer to monitor if an OOM has occurred
|
||||
let oom_observer = OomObserver::new(options.rss_limit(), options.malloc_limit());
|
||||
|
@ -55,6 +55,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, O> AsRef<Self> for MappedEdgeMapObserver<M, O> {
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, O> AsMut<Self> for MappedEdgeMapObserver<M, O> {
|
||||
fn as_mut(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, O> HasLen for MappedEdgeMapObserver<M, O>
|
||||
where
|
||||
M: HasLen,
|
||||
|
@ -15,7 +15,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::Tokens,
|
||||
},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::StdMutationalStage,
|
||||
state::{HasCorpus, StdState},
|
||||
@ -126,8 +126,10 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
|
||||
std::env::set_var("AFL_MAP_SIZE", format!("{MAP_SIZE}"));
|
||||
|
||||
// Create an observation channel using the coverage map
|
||||
let edges_observer =
|
||||
unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_map)) };
|
||||
let edges_observer = unsafe {
|
||||
HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_map))
|
||||
.track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -136,7 +138,7 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -164,7 +166,8 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
|
||||
let mut tokens = Tokens::new();
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -18,7 +18,7 @@ use libafl::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||
token_mutations::{I2SRandReplace, Tokens},
|
||||
},
|
||||
observers::{HitcountsMapObserver, TimeObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::{ShadowTracingStage, StdMutationalStage},
|
||||
state::{HasCorpus, StdState},
|
||||
@ -143,7 +143,8 @@ where
|
||||
_core_id| {
|
||||
// Create an observation channel using the coverage map
|
||||
let edges_observer =
|
||||
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") });
|
||||
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") })
|
||||
.track_indices();
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
@ -154,7 +155,7 @@ where
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -186,7 +187,8 @@ where
|
||||
}
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -21,7 +21,7 @@ use libafl::{
|
||||
token_mutations::Tokens,
|
||||
I2SRandReplace,
|
||||
},
|
||||
observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::{ShadowTracingStage, StdMutationalStage},
|
||||
state::{HasCorpus, StdState},
|
||||
@ -156,6 +156,7 @@ where
|
||||
edges_map_mut_slice(),
|
||||
addr_of_mut!(edges::MAX_EDGES_NUM),
|
||||
))
|
||||
.track_indices()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
@ -168,7 +169,7 @@ where
|
||||
// This one is composed by two Feedbacks in OR
|
||||
let mut feedback = feedback_or!(
|
||||
// New maximization map feedback linked to the edges observer and the feedback state
|
||||
MaxMapFeedback::tracking(&edges_observer, true, false),
|
||||
MaxMapFeedback::new(&edges_observer),
|
||||
// Time feedback, this one does not need a feedback state
|
||||
TimeFeedback::with_observer(&time_observer)
|
||||
);
|
||||
@ -200,7 +201,8 @@ where
|
||||
}
|
||||
|
||||
// A minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||
let scheduler =
|
||||
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
@ -159,6 +159,18 @@ mod observers {
|
||||
}
|
||||
}
|
||||
|
||||
impl<const DIFFERENTIAL: bool> AsRef<Self> for CountersMultiMapObserver<DIFFERENTIAL> {
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<const DIFFERENTIAL: bool> AsMut<Self> for CountersMultiMapObserver<DIFFERENTIAL> {
|
||||
fn as_mut(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<const DIFFERENTIAL: bool> MapObserver for CountersMultiMapObserver<DIFFERENTIAL> {
|
||||
type Entry = u8;
|
||||
|
||||
|
70
scripts/build_all_fuzzers.sh
Executable file
70
scripts/build_all_fuzzers.sh
Executable file
@ -0,0 +1,70 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
cd "$SCRIPT_DIR/.." || exit 1
|
||||
# TODO: This should be rewritten in rust, a Makefile, or some platform-independent language
|
||||
|
||||
if [[ -z "${RUN_ON_CI}" ]]; then
|
||||
fuzzers=$(find ./fuzzers -mindepth 1 -maxdepth 1 -type d)
|
||||
backtrace_fuzzers=$(find ./fuzzers/backtrace_baby_fuzzers -mindepth 1 -maxdepth 1 -type d)
|
||||
else
|
||||
cargo build -p build_and_test_fuzzers
|
||||
fuzzers=$(cargo run -p build_and_test_fuzzers -- "remotes/origin/main" "HEAD^")
|
||||
backtrace_fuzzers=""
|
||||
export PROFILE=dev
|
||||
export PROFILE_DIR=debug
|
||||
fi
|
||||
|
||||
fuzzers=$(echo "$fuzzers" | tr ' ' '\n')
|
||||
backtrace_fuzzers=$(echo "$backtrace_fuzzers" | tr ' ' '\n')
|
||||
|
||||
libafl=$(pwd)
|
||||
|
||||
# build with a shared target dir for all fuzzers. this should speed up
|
||||
# compilation a bit, and allows for easier artifact management (caching and
|
||||
# cargo clean).
|
||||
export CARGO_TARGET_DIR="$libafl/target"
|
||||
mkdir -p "$CARGO_TARGET_DIR"
|
||||
|
||||
git submodule init && git submodule update
|
||||
|
||||
# override default profile settings for speed
|
||||
# export RUSTFLAGS="-C prefer-dynamic"
|
||||
for profile in DEV RELEASE; # loop for all profiles
|
||||
do
|
||||
export CARGO_PROFILE_"$profile"_OPT_LEVEL=z # optimize for size
|
||||
# runs into shared target dir bug:
|
||||
# [pid 351769] openat(AT_FDCWD, "LibAFL/target/release/deps/libc-dbff77a14da5d893.libc.5deb7d4a-cgu.0.rcgu.dwo", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
|
||||
# error: failed to build archive: No such file or directory
|
||||
# export CARGO_PROFILE_"$profile"_SPLIT_DEBUGINFO=unpacked # minimize debug info
|
||||
# export CARGO_PROFILE_"$profile"_PANIC=abort
|
||||
# export CARGO_PROFILE_"$profile"_INCREMENTAL=true
|
||||
done
|
||||
|
||||
# shellcheck disable=SC2116
|
||||
for fuzzer in $(echo "$fuzzers" "$backtrace_fuzzers");
|
||||
do
|
||||
# skip nyx test on non-linux platforms
|
||||
if [[ $fuzzer == *"nyx_"* ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
cd "$fuzzer" || exit 1
|
||||
# Clippy checks
|
||||
echo "[*] Checking fmt for $fuzzer"
|
||||
cargo +nightly fmt --all || exit 1
|
||||
|
||||
if [ -e ./Makefile.toml ]; then
|
||||
echo "[*] Building $fuzzer"
|
||||
cargo make build || exit 1
|
||||
echo "[+] Done building $fuzzer"
|
||||
else
|
||||
echo "[*] Building $fuzzer"
|
||||
cargo build || exit 1
|
||||
echo "[+] Done building $fuzzer"
|
||||
fi
|
||||
|
||||
# no cleaning -- this is a local test, we want to cache here
|
||||
cd "$libafl" || exit 1
|
||||
echo ""
|
||||
done
|
Loading…
x
Reference in New Issue
Block a user