Match by Ref fix (#2105)

* match by ref fix

* impl Named for Reference

* rename

* magic indexing

* whoops

* docs, clippy

* some additional CI complaints

* other libafl_qemu fixes

* missed an alloc feature

* a smattering of fixes

* use from not direct construction

* tinyinst fix

* horrible double-mutability things

* fixup nyx

* from not new

* forkserver_simple fixes

* dogfood: forkserver

* mmmm yummy dogfood

* round one CI fixes

* clippy appeasement

* deref generic impl to simplify usage

* adaptive serialization (ouch)

* remaining clippy items

* I am tired

* new not with

* fixup: aflpp tracing was not actually constructable

* fix tmin

* reduce complexity of map feedback now that we do not need to constrain

* frida fixes

* fix concolic

* type_ref => reference
This commit is contained in:
Addison Crump 2024-04-27 18:08:09 +02:00 committed by GitHub
parent 084b9b5878
commit 28c43b332f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
85 changed files with 1279 additions and 847 deletions

View File

@ -36,7 +36,7 @@ pub fn main() -> Result<(), Error> {
// Create an observation channel using the signals map // 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()) };
let factory = MapEqualityFactory::with_observer(&observer); let factory = MapEqualityFactory::new(&observer);
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
let mut feedback = MaxMapFeedback::new(&observer); let mut feedback = MaxMapFeedback::new(&observer);

View File

@ -116,7 +116,7 @@ pub fn main() {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
@ -167,7 +167,7 @@ pub fn main() {
// Create the executor for the forkserver // Create the executor for the forkserver
let args = opt.arguments; let args = opt.arguments;
let observer_ref = edges_observer.type_ref(); let observer_ref = edges_observer.reference();
let mut tokens = Tokens::new(); let mut tokens = Tokens::new();
let mut executor = ForkserverExecutor::builder() let mut executor = ForkserverExecutor::builder()
@ -183,10 +183,7 @@ pub fn main() {
.unwrap(); .unwrap();
if let Some(dynamic_map_size) = executor.coverage_map_size() { if let Some(dynamic_map_size) = executor.coverage_map_size() {
executor executor.observers_mut()[&observer_ref]
.observers_mut()
.match_by_ref_mut(observer_ref)
.unwrap()
.as_mut() .as_mut()
.truncate(dynamic_map_size); .truncate(dynamic_map_size);
} }

View File

@ -12,7 +12,7 @@ use libafl::{
inputs::BytesInput, inputs::BytesInput,
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens}, mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
observers::{CanTrack, ExplicitTracking, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -22,7 +22,7 @@ use libafl_bolts::{
current_nanos, current_nanos,
rands::StdRand, rands::StdRand,
shmem::{ShMem, ShMemProvider, UnixShMemProvider}, shmem::{ShMem, ShMemProvider, UnixShMemProvider},
tuples::{tuple_list, MatchName, Merge}, tuples::{tuple_list, Merge, Referenceable},
AsSliceMut, Truncate, AsSliceMut, Truncate,
}; };
use nix::sys::signal::Signal; use nix::sys::signal::Signal;
@ -114,7 +114,7 @@ pub fn main() {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
@ -163,6 +163,8 @@ pub fn main() {
// Create the executor for the forkserver // Create the executor for the forkserver
let args = opt.arguments; let args = opt.arguments;
let observer_ref = edges_observer.reference();
let mut tokens = Tokens::new(); let mut tokens = Tokens::new();
let mut executor = ForkserverExecutor::builder() let mut executor = ForkserverExecutor::builder()
.program(opt.executable) .program(opt.executable)
@ -177,10 +179,7 @@ pub fn main() {
.unwrap(); .unwrap();
if let Some(dynamic_map_size) = executor.coverage_map_size() { if let Some(dynamic_map_size) = executor.coverage_map_size() {
executor executor.observers_mut()[&observer_ref]
.observers_mut()
.match_name_mut::<ExplicitTracking<HitcountsMapObserver<StdMapObserver<'_, u8, false>>, true, false>>("shared_mem")
.unwrap()
.as_mut() .as_mut()
.truncate(dynamic_map_size); .truncate(dynamic_map_size);
} }

View File

@ -35,7 +35,7 @@ use libafl_bolts::{
#[cfg(unix)] #[cfg(unix)]
use libafl_frida::asan::{ use libafl_frida::asan::{
asan_rt::AsanRuntime, asan_rt::AsanRuntime,
errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS}, errors::{AsanErrorsFeedback, AsanErrorsObserver},
}; };
use libafl_frida::{ use libafl_frida::{
cmplog_rt::CmpLogRuntime, cmplog_rt::CmpLogRuntime,
@ -123,6 +123,8 @@ unsafe fn fuzz(
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
@ -130,7 +132,7 @@ unsafe fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// Feedbacks to recognize an input as solution // Feedbacks to recognize an input as solution
@ -139,7 +141,10 @@ unsafe fn fuzz(
CrashFeedback::new(), CrashFeedback::new(),
TimeoutFeedback::new(), TimeoutFeedback::new(),
// true enables the AsanErrorFeedback // true enables the AsanErrorFeedback
feedback_and_fast!(ConstFeedback::from(true), AsanErrorsFeedback::new()) feedback_and_fast!(
ConstFeedback::from(true),
AsanErrorsFeedback::new(&asan_observer)
)
); );
#[cfg(windows)] #[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -185,9 +190,7 @@ unsafe fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)] #[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe { let observers = tuple_list!(edges_observer, time_observer, asan_observer);
AsanErrorsObserver::from_static_asan_errors()
});
#[cfg(windows)] #[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer); let observers = tuple_list!(edges_observer, time_observer);
@ -240,6 +243,8 @@ unsafe fn fuzz(
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
@ -247,14 +252,17 @@ unsafe fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
#[cfg(unix)] #[cfg(unix)]
let mut objective = feedback_or_fast!( let mut objective = feedback_or_fast!(
CrashFeedback::new(), CrashFeedback::new(),
TimeoutFeedback::new(), TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new()) feedback_and_fast!(
ConstFeedback::from(false),
AsanErrorsFeedback::new(&asan_observer)
)
); );
#[cfg(windows)] #[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -300,11 +308,9 @@ unsafe fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)] #[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe { let observers = tuple_list!(edges_observer, time_observer, asan_observer);
AsanErrorsObserver::from_static_asan_errors()
});
#[cfg(windows)] #[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,); let observers = tuple_list!(edges_observer, time_observer);
// Create the executor for an in-process function with just one observer for edge coverage // Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new( let mut executor = FridaInProcessExecutor::new(
@ -370,6 +376,8 @@ unsafe fn fuzz(
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
@ -377,14 +385,17 @@ unsafe fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
#[cfg(unix)] #[cfg(unix)]
let mut objective = feedback_or_fast!( let mut objective = feedback_or_fast!(
CrashFeedback::new(), CrashFeedback::new(),
TimeoutFeedback::new(), TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new()) feedback_and_fast!(
ConstFeedback::from(false),
AsanErrorsFeedback::new(&asan_observer)
)
); );
#[cfg(windows)] #[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -430,11 +441,9 @@ unsafe fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)] #[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe { let observers = tuple_list!(edges_observer, time_observer, asan_observer);
AsanErrorsObserver::from_static_asan_errors()
});
#[cfg(windows)] #[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,); let observers = tuple_list!(edges_observer, time_observer);
// Create the executor for an in-process function with just one observer for edge coverage // Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new( let mut executor = FridaInProcessExecutor::new(

View File

@ -99,7 +99,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let coverage = CoverageRuntime::new(); let coverage = CoverageRuntime::new();
#[cfg(unix)] #[cfg(unix)]
let asan = AsanRuntime::new(&options); let asan = AsanRuntime::new(options);
#[cfg(unix)] #[cfg(unix)]
let mut frida_helper = let mut frida_helper =
@ -119,13 +119,16 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// Feedbacks to recognize an input as solution // Feedbacks to recognize an input as solution
@ -134,7 +137,10 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
CrashFeedback::new(), CrashFeedback::new(),
TimeoutFeedback::new(), TimeoutFeedback::new(),
// true enables the AsanErrorFeedback // true enables the AsanErrorFeedback
feedback_and_fast!(ConstFeedback::from(true), AsanErrorsFeedback::new()) feedback_and_fast!(
ConstFeedback::from(true),
AsanErrorsFeedback::new(&asan_observer)
)
); );
#[cfg(windows)] #[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -179,9 +185,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)] #[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe { let observers = tuple_list!(edges_observer, time_observer, asan_observer);
AsanErrorsObserver::from_static_asan_errors()
});
#[cfg(windows)] #[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer); let observers = tuple_list!(edges_observer, time_observer);
@ -234,6 +238,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
@ -241,14 +247,17 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
#[cfg(unix)] #[cfg(unix)]
let mut objective = feedback_or_fast!( let mut objective = feedback_or_fast!(
CrashFeedback::new(), CrashFeedback::new(),
TimeoutFeedback::new(), TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new()) feedback_and_fast!(
ConstFeedback::from(false),
AsanErrorsFeedback::new(&asan_observer)
)
); );
#[cfg(windows)] #[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -294,9 +303,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)] #[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe { let observers = tuple_list!(edges_observer, time_observer, asan_observer);
AsanErrorsObserver::from_static_asan_errors()
});
#[cfg(windows)] #[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,); let observers = tuple_list!(edges_observer, time_observer,);
@ -366,20 +373,26 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
#[cfg(unix)] #[cfg(unix)]
let mut objective = feedback_or_fast!( let mut objective = feedback_or_fast!(
CrashFeedback::new(), CrashFeedback::new(),
TimeoutFeedback::new(), TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new()) feedback_and_fast!(
ConstFeedback::from(false),
AsanErrorsFeedback::new(&asan_observer)
)
); );
#[cfg(windows)] #[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -425,11 +438,9 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)] #[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe { let observers = tuple_list!(edges_observer, time_observer, asan_observer);
AsanErrorsObserver::from_static_asan_errors()
});
#[cfg(windows)] #[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,); let observers = tuple_list!(edges_observer, time_observer);
// Create the executor for an in-process function with just one observer for edge coverage // Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new( let mut executor = FridaInProcessExecutor::new(

View File

@ -35,7 +35,7 @@ use libafl_bolts::{
#[cfg(unix)] #[cfg(unix)]
use libafl_frida::asan::{ use libafl_frida::asan::{
asan_rt::AsanRuntime, asan_rt::AsanRuntime,
errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS}, errors::{AsanErrorsFeedback, AsanErrorsObserver},
}; };
use libafl_frida::{ use libafl_frida::{
cmplog_rt::CmpLogRuntime, cmplog_rt::CmpLogRuntime,
@ -113,6 +113,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
@ -120,7 +122,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// Feedbacks to recognize an input as solution // Feedbacks to recognize an input as solution
@ -129,7 +131,10 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
CrashFeedback::new(), CrashFeedback::new(),
TimeoutFeedback::new(), TimeoutFeedback::new(),
// true enables the AsanErrorFeedback // true enables the AsanErrorFeedback
feedback_and_fast!(ConstFeedback::from(true), AsanErrorsFeedback::new()) feedback_and_fast!(
ConstFeedback::from(true),
AsanErrorsFeedback::new(&asan_observer)
)
); );
#[cfg(windows)] #[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -175,9 +180,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)] #[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe { let observers = tuple_list!(edges_observer, time_observer, asan_observer);
AsanErrorsObserver::from_static_asan_errors()
});
#[cfg(windows)] #[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer); let observers = tuple_list!(edges_observer, time_observer);
@ -231,6 +234,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
@ -238,14 +243,17 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
#[cfg(unix)] #[cfg(unix)]
let mut objective = feedback_or_fast!( let mut objective = feedback_or_fast!(
CrashFeedback::new(), CrashFeedback::new(),
TimeoutFeedback::new(), TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new()) feedback_and_fast!(
ConstFeedback::from(false),
AsanErrorsFeedback::new(&asan_observer)
)
); );
#[cfg(windows)] #[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -291,11 +299,9 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)] #[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe { let observers = tuple_list!(edges_observer, time_observer, asan_observer);
AsanErrorsObserver::from_static_asan_errors()
});
#[cfg(windows)] #[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,); let observers = tuple_list!(edges_observer, time_observer);
// Create the executor for an in-process function with just one observer for edge coverage // Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new( let mut executor = FridaInProcessExecutor::new(
@ -361,6 +367,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
@ -368,14 +376,17 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
#[cfg(unix)] #[cfg(unix)]
let mut objective = feedback_or_fast!( let mut objective = feedback_or_fast!(
CrashFeedback::new(), CrashFeedback::new(),
TimeoutFeedback::new(), TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new()) feedback_and_fast!(
ConstFeedback::from(false),
AsanErrorsFeedback::new(&asan_observer)
)
); );
#[cfg(windows)] #[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -421,13 +432,9 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)] #[cfg(unix)]
let observers = tuple_list!( let observers = tuple_list!(edges_observer, time_observer, asan_observer);
edges_observer,
time_observer,
AsanErrorsObserver::from_static_asan_errors()
);
#[cfg(windows)] #[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,); let observers = tuple_list!(edges_observer, time_observer);
// Create the executor for an in-process function with just one observer for edge coverage // Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new( let mut executor = FridaInProcessExecutor::new(

View File

@ -260,7 +260,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -270,7 +270,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -258,7 +258,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -267,7 +267,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -37,7 +37,7 @@ use libafl_bolts::{
ownedref::OwnedRefMut, ownedref::OwnedRefMut,
rands::StdRand, rands::StdRand,
shmem::{ShMem, ShMemProvider, UnixShMemProvider}, shmem::{ShMem, ShMemProvider, UnixShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge, Referenceable},
AsSliceMut, AsSliceMut,
}; };
use libafl_targets::{ use libafl_targets::{
@ -268,7 +268,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
@ -355,6 +355,7 @@ fn fuzz(
let cmpmap = unsafe { OwnedRefMut::from_shmem(&mut cmplog_shmem) }; let cmpmap = unsafe { OwnedRefMut::from_shmem(&mut cmplog_shmem) };
let cmplog_observer = AFLppCmpLogObserver::new("cmplog", cmpmap, true); let cmplog_observer = AFLppCmpLogObserver::new("cmplog", cmpmap, true);
let cmplog_ref = cmplog_observer.reference();
let cmplog_executor = ForkserverExecutor::builder() let cmplog_executor = ForkserverExecutor::builder()
.program(exec) .program(exec)
@ -367,7 +368,7 @@ fn fuzz(
.build(tuple_list!(cmplog_observer)) .build(tuple_list!(cmplog_observer))
.unwrap(); .unwrap();
let tracing = AFLppCmplogTracingStage::with_cmplog_observer_name(cmplog_executor, "cmplog"); let tracing = AFLppCmplogTracingStage::with_cmplog_observer(cmplog_executor, cmplog_ref);
// Setup a randomic Input2State stage // Setup a randomic Input2State stage
let rq = MultiMutationalStage::new(AFLppRedQueen::with_cmplog_options(true, true)); let rq = MultiMutationalStage::new(AFLppRedQueen::with_cmplog_options(true, true));

View File

@ -279,7 +279,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -328,7 +328,7 @@ fn fuzz_binary(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let mut objective = CrashFeedback::new(); let mut objective = CrashFeedback::new();
@ -539,7 +539,7 @@ fn fuzz_text(
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -151,7 +151,7 @@ pub extern "C" fn LLVMFuzzerRunDriver(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -101,7 +101,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -152,7 +152,7 @@ pub extern "C" fn libafl_main() {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -115,7 +115,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -150,7 +150,7 @@ pub extern "C" fn libafl_main() {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -100,7 +100,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -151,7 +151,7 @@ pub extern "C" fn libafl_main() {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -176,7 +176,7 @@ pub extern "C" fn libafl_main() {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -99,7 +99,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -81,7 +81,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -42,8 +42,8 @@ use libafl_bolts::{
current_nanos, current_nanos,
rands::StdRand, rands::StdRand,
shmem::{ShMem, ShMemProvider, StdShMemProvider}, shmem::{ShMem, ShMemProvider, StdShMemProvider},
tuples::tuple_list, tuples::{tuple_list, Referenceable},
AsSliceMut, AsSlice, Named, AsSliceMut, AsSlice
}; };
use libafl_targets::{ use libafl_targets::{
libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer, CmpLogObserver, libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer, CmpLogObserver,
@ -119,7 +119,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
@ -207,8 +207,7 @@ fn fuzz(
// The concolic observer observers the concolic shared memory map. // The concolic observer observers the concolic shared memory map.
let concolic_observer = ConcolicObserver::new("concolic", concolic_shmem.as_slice_mut()); let concolic_observer = ConcolicObserver::new("concolic", concolic_shmem.as_slice_mut());
let concolic_ref = concolic_observer.reference();
let concolic_observer_name = concolic_observer.name().to_string();
// The order of the stages matter! // The order of the stages matter!
let mut stages = tuple_list!( let mut stages = tuple_list!(
@ -217,7 +216,7 @@ fn fuzz(
TracingStage::new( TracingStage::new(
MyCommandConfigurator.into_executor(tuple_list!(concolic_observer)) MyCommandConfigurator.into_executor(tuple_list!(concolic_observer))
), ),
concolic_observer_name, concolic_ref,
), ),
// Use the concolic trace for z3-based solving // Use the concolic trace for z3-based solving
SimpleConcolicMutationalStage::default(), SimpleConcolicMutationalStage::default(),

View File

@ -77,7 +77,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -97,7 +97,7 @@ impl<'a, M: Monitor> Instance<'a, M> {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -169,7 +169,7 @@ pub fn fuzz() {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -176,7 +176,7 @@ pub fn fuzz() {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -110,7 +110,7 @@ pub fn fuzz() {
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not

View File

@ -97,7 +97,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
map_feedback, map_feedback,
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer), TimeFeedback::new(&time_observer),
PacketLenFeedback::new() PacketLenFeedback::new()
); );

View File

@ -1,15 +1,15 @@
//! Whole corpus minimizers, for reducing the number of samples/the total size/the average runtime //! Whole corpus minimizers, for reducing the number of samples/the total size/the average runtime
//! of your corpus. //! of your corpus.
use alloc::{ use alloc::{borrow::Cow, string::ToString, vec::Vec};
borrow::Cow,
string::{String, ToString},
vec::Vec,
};
use core::{hash::Hash, marker::PhantomData}; use core::{hash::Hash, marker::PhantomData};
use hashbrown::{HashMap, HashSet}; use hashbrown::{HashMap, HashSet};
use libafl_bolts::{current_time, tuples::MatchName, AsIter, Named}; use libafl_bolts::{
current_time,
tuples::{Reference, Referenceable},
AsIter, Named,
};
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use z3::{ast::Bool, Config, Context, Optimize}; use z3::{ast::Bool, Config, Context, Optimize};
@ -51,8 +51,8 @@ where
/// Algorithm based on WMOPT: <https://hexhive.epfl.ch/publications/files/21ISSTA2.pdf> /// Algorithm based on WMOPT: <https://hexhive.epfl.ch/publications/files/21ISSTA2.pdf>
#[derive(Debug)] #[derive(Debug)]
pub struct MapCorpusMinimizer<C, E, O, T, TS> { pub struct MapCorpusMinimizer<C, E, O, T, TS> {
obs_name: String, obs_ref: Reference<C>,
phantom: PhantomData<(C, E, O, T, TS)>, phantom: PhantomData<(E, O, T, TS)>,
} }
/// Standard corpus minimizer, which weights inputs by length and time. /// Standard corpus minimizer, which weights inputs by length and time.
@ -70,7 +70,7 @@ where
/// in the future to get observed maps from an executed input. /// in the future to get observed maps from an executed input.
pub fn new(obs: &C) -> Self { pub fn new(obs: &C) -> Self {
Self { Self {
obs_name: obs.name().to_string(), obs_ref: obs.reference(),
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -160,11 +160,8 @@ where
)?; )?;
let seed_expr = Bool::fresh_const(&ctx, "seed"); let seed_expr = Bool::fresh_const(&ctx, "seed");
let obs = executor let observers = executor.observers();
.observers() let obs = observers[&self.obs_ref].as_ref();
.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 // Store coverage, mapping coverage map indices to hit counts (if present) and the
// associated seeds for the map indices with those hit counts. // associated seeds for the map indices with those hit counts.

View File

@ -10,6 +10,8 @@
use alloc::{boxed::Box, string::String, vec::Vec}; use alloc::{boxed::Box, string::String, vec::Vec};
use core::{marker::PhantomData, num::NonZeroUsize, time::Duration}; use core::{marker::PhantomData, num::NonZeroUsize, time::Duration};
#[cfg(feature = "adaptive_serialization")]
use libafl_bolts::tuples::{Reference, Referenceable};
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
use libafl_bolts::{ use libafl_bolts::{
compress::GzipCompressor, compress::GzipCompressor,
@ -24,6 +26,8 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
use crate::events::llmp::COMPRESS_THRESHOLD; use crate::events::llmp::COMPRESS_THRESHOLD;
#[cfg(feature = "adaptive_serialization")]
use crate::observers::TimeObserver;
#[cfg(feature = "scalability_introspection")] #[cfg(feature = "scalability_introspection")]
use crate::state::HasScalabilityMonitor; use crate::state::HasScalabilityMonitor;
use crate::{ use crate::{
@ -221,6 +225,8 @@ where
client: LlmpClient<SP>, client: LlmpClient<SP>,
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor, compressor: GzipCompressor,
#[cfg(feature = "adaptive_serialization")]
time_ref: Reference<TimeObserver>,
is_main: bool, is_main: bool,
} }
@ -263,6 +269,10 @@ where
fn should_serialize_cnt_mut(&mut self) -> &mut usize { fn should_serialize_cnt_mut(&mut self) -> &mut usize {
self.inner.should_serialize_cnt_mut() self.inner.should_serialize_cnt_mut()
} }
fn time_ref(&self) -> &Reference<TimeObserver> {
&self.time_ref
}
} }
#[cfg(not(feature = "adaptive_serialization"))] #[cfg(not(feature = "adaptive_serialization"))]
@ -275,7 +285,7 @@ where
impl<EM, SP> EventFirer for CentralizedEventManager<EM, SP> impl<EM, SP> EventFirer for CentralizedEventManager<EM, SP>
where where
EM: AdaptiveSerializer + EventFirer + HasEventManagerId + AdaptiveSerializer, EM: AdaptiveSerializer + EventFirer + HasEventManagerId,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
{ {
fn fire( fn fire(
@ -459,6 +469,7 @@ where
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
{ {
/// Creates a new [`CentralizedEventManager`]. /// Creates a new [`CentralizedEventManager`].
#[cfg(not(feature = "adaptive_serialization"))]
pub fn new(inner: EM, client: LlmpClient<SP>, is_main: bool) -> Result<Self, Error> { pub fn new(inner: EM, client: LlmpClient<SP>, is_main: bool) -> Result<Self, Error> {
Ok(Self { Ok(Self {
inner, inner,
@ -469,25 +480,66 @@ where
}) })
} }
/// Creates a new [`CentralizedEventManager`].
#[cfg(feature = "adaptive_serialization")]
pub fn new(
inner: EM,
client: LlmpClient<SP>,
is_main: bool,
time_obs: &TimeObserver,
) -> Result<Self, Error> {
Ok(Self {
inner,
client,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
time_ref: time_obs.reference(),
is_main,
})
}
/// Create a centralized event manager on a port
///
/// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client.
#[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
pub fn on_port(inner: EM, shmem_provider: SP, port: u16, is_main: bool) -> Result<Self, Error> {
let client = LlmpClient::create_attach_to_tcp(shmem_provider, port)?;
Ok(Self {
inner,
client,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
is_main,
})
}
/// Create a centralized event manager on a port /// Create a centralized event manager on a port
/// ///
/// If the port is not yet bound, it will act as a broker; otherwise, it /// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client. /// will act as a client.
#[cfg(feature = "std")] #[cfg(all(feature = "std", feature = "adaptive_serialization"))]
pub fn on_port(inner: EM, shmem_provider: SP, port: u16, is_main: bool) -> Result<Self, Error> { pub fn on_port(
inner: EM,
shmem_provider: SP,
port: u16,
is_main: bool,
time_obs: &TimeObserver,
) -> Result<Self, Error> {
let client = LlmpClient::create_attach_to_tcp(shmem_provider, port)?; let client = LlmpClient::create_attach_to_tcp(shmem_provider, port)?;
Ok(Self { Ok(Self {
inner, inner,
client, client,
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD), compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
time_ref: time_obs.reference(),
is_main, is_main,
}) })
} }
/// If a client respawns, it may reuse the existing connection, previously /// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`]. /// stored by [`LlmpClient::to_env()`].
#[cfg(feature = "std")] #[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
pub fn existing_client_from_env( pub fn existing_client_from_env(
inner: EM, inner: EM,
shmem_provider: SP, shmem_provider: SP,
@ -503,12 +555,28 @@ where
}) })
} }
/// Describe the client event manager's LLMP parts in a restorable fashion /// If a client respawns, it may reuse the existing connection, previously
pub fn describe(&self) -> Result<LlmpClientDescription, Error> { /// stored by [`LlmpClient::to_env()`].
self.client.describe() #[cfg(all(feature = "std", feature = "adaptive_serialization"))]
pub fn existing_client_from_env(
inner: EM,
shmem_provider: SP,
env_name: &str,
is_main: bool,
time_obs: &TimeObserver,
) -> Result<Self, Error> {
Ok(Self {
inner,
client: LlmpClient::on_existing_from_env(shmem_provider, env_name)?,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
time_ref: time_obs.reference(),
is_main,
})
} }
/// Create an existing client from description /// Create an existing client from description
#[cfg(not(feature = "adaptive_serialization"))]
pub fn existing_client_from_description( pub fn existing_client_from_description(
inner: EM, inner: EM,
shmem_provider: SP, shmem_provider: SP,
@ -524,6 +592,30 @@ where
}) })
} }
/// Create an existing client from description
#[cfg(feature = "adaptive_serialization")]
pub fn existing_client_from_description(
inner: EM,
shmem_provider: SP,
description: &LlmpClientDescription,
is_main: bool,
time_obs: &TimeObserver,
) -> Result<Self, Error> {
Ok(Self {
inner,
client: LlmpClient::existing_client_from_description(shmem_provider, description)?,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
time_ref: time_obs.reference(),
is_main,
})
}
/// Describe the client event manager's LLMP parts in a restorable fashion
pub fn describe(&self) -> Result<LlmpClientDescription, Error> {
self.client.describe()
}
/// Write the config for a client [`EventManager`] to env vars, a new /// Write the config for a client [`EventManager`] to env vars, a new
/// client can reattach using [`CentralizedEventManager::existing_client_from_env()`]. /// client can reattach using [`CentralizedEventManager::existing_client_from_env()`].
#[cfg(feature = "std")] #[cfg(feature = "std")]

View File

@ -30,6 +30,8 @@ use std::{fs::File, os::unix::io::AsRawFd};
#[cfg(all(feature = "std", any(windows, not(feature = "fork"))))] #[cfg(all(feature = "std", any(windows, not(feature = "fork"))))]
use libafl_bolts::os::startable_self; use libafl_bolts::os::startable_self;
#[cfg(feature = "adaptive_serialization")]
use libafl_bolts::tuples::{Reference, Referenceable};
#[cfg(all(unix, feature = "std", feature = "fork"))] #[cfg(all(unix, feature = "std", feature = "fork"))]
use libafl_bolts::{ use libafl_bolts::{
core_affinity::get_core_ids, core_affinity::get_core_ids,
@ -46,6 +48,8 @@ use typed_builder::TypedBuilder;
use super::hooks::EventManagerHooksTuple; use super::hooks::EventManagerHooksTuple;
#[cfg(all(unix, feature = "std", feature = "fork"))] #[cfg(all(unix, feature = "std", feature = "fork"))]
use crate::events::{CentralizedEventManager, CentralizedLlmpEventBroker}; use crate::events::{CentralizedEventManager, CentralizedLlmpEventBroker};
#[cfg(feature = "adaptive_serialization")]
use crate::observers::TimeObserver;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::{ use crate::{
events::{ events::{
@ -116,6 +120,8 @@ where
/// clusters. /// clusters.
#[builder(default = None)] #[builder(default = None)]
remote_broker_addr: Option<SocketAddr>, remote_broker_addr: Option<SocketAddr>,
#[cfg(feature = "adaptive_serialization")]
time_ref: Reference<TimeObserver>,
/// If this launcher should spawn a new `broker` on `[Self::broker_port]` (default). /// If this launcher should spawn a new `broker` on `[Self::broker_port]` (default).
/// The reason you may not want this is, if you already have a [`Launcher`] /// The reason you may not want this is, if you already have a [`Launcher`]
/// with a different configuration (for the same target) running on this machine. /// with a different configuration (for the same target) running on this machine.
@ -250,7 +256,7 @@ where
} }
// Fuzzer client. keeps retrying the connection to broker till the broker starts // Fuzzer client. keeps retrying the connection to broker till the broker starts
let (state, mgr) = RestartingMgr::<EMH, MT, S, SP>::builder() let builder = RestartingMgr::<EMH, MT, S, SP>::builder()
.shmem_provider(self.shmem_provider.clone()) .shmem_provider(self.shmem_provider.clone())
.broker_port(self.broker_port) .broker_port(self.broker_port)
.kind(ManagerKind::Client { .kind(ManagerKind::Client {
@ -258,9 +264,10 @@ where
}) })
.configuration(self.configuration) .configuration(self.configuration)
.serialize_state(self.serialize_state) .serialize_state(self.serialize_state)
.hooks(hooks) .hooks(hooks);
.build() #[cfg(feature = "adaptive_serialization")]
.launch()?; let builder = builder.time_ref(self.time_ref.clone());
let (state, mgr) = builder.build().launch()?;
return (self.run_client.take().unwrap())(state, mgr, *bind_to); return (self.run_client.take().unwrap())(state, mgr, *bind_to);
} }
@ -273,7 +280,7 @@ where
log::info!("I am broker!!."); log::info!("I am broker!!.");
// TODO we don't want always a broker here, think about using different laucher process to spawn different configurations // TODO we don't want always a broker here, think about using different laucher process to spawn different configurations
RestartingMgr::<EMH, MT, S, SP>::builder() let builder = RestartingMgr::<EMH, MT, S, SP>::builder()
.shmem_provider(self.shmem_provider.clone()) .shmem_provider(self.shmem_provider.clone())
.monitor(Some(self.monitor.clone())) .monitor(Some(self.monitor.clone()))
.broker_port(self.broker_port) .broker_port(self.broker_port)
@ -282,9 +289,12 @@ where
.exit_cleanly_after(Some(NonZeroUsize::try_from(self.cores.ids.len()).unwrap())) .exit_cleanly_after(Some(NonZeroUsize::try_from(self.cores.ids.len()).unwrap()))
.configuration(self.configuration) .configuration(self.configuration)
.serialize_state(self.serialize_state) .serialize_state(self.serialize_state)
.hooks(hooks) .hooks(hooks);
.build()
.launch()?; #[cfg(feature = "adaptive_serialization")]
let builder = builder.time_ref(self.time_ref.clone());
builder.build().launch()?;
// Broker exited. kill all clients. // Broker exited. kill all clients.
for handle in &handles { for handle in &handles {
@ -457,6 +467,9 @@ where
/// The centralized broker port to use (or to attach to, in case [`Self::spawn_broker`] is `false`) /// The centralized broker port to use (or to attach to, in case [`Self::spawn_broker`] is `false`)
#[builder(default = 1338_u16)] #[builder(default = 1338_u16)]
centralized_broker_port: u16, centralized_broker_port: u16,
/// The time observer by which to adaptively serialize
#[cfg(feature = "adaptive_serialization")]
time_obs: &'a TimeObserver,
/// The list of cores to run on /// The list of cores to run on
cores: &'a Cores, cores: &'a Cores,
/// A file name to write all client output to /// A file name to write all client output to
@ -617,7 +630,7 @@ where
} }
// Fuzzer client. keeps retrying the connection to broker till the broker starts // Fuzzer client. keeps retrying the connection to broker till the broker starts
let (state, mgr) = RestartingMgr::<(), MT, S, SP>::builder() let builder = RestartingMgr::<(), MT, S, SP>::builder()
.shmem_provider(self.shmem_provider.clone()) .shmem_provider(self.shmem_provider.clone())
.broker_port(self.broker_port) .broker_port(self.broker_port)
.kind(ManagerKind::Client { .kind(ManagerKind::Client {
@ -625,16 +638,26 @@ where
}) })
.configuration(self.configuration) .configuration(self.configuration)
.serialize_state(self.serialize_state) .serialize_state(self.serialize_state)
.hooks(tuple_list!()) .hooks(tuple_list!());
.build() #[cfg(feature = "adaptive_serialization")]
.launch()?; let builder = builder.time_ref(self.time_obs.reference());
let (state, mgr) = builder.build().launch()?;
#[cfg(not(feature = "adaptive_serialization"))]
let c_mgr = CentralizedEventManager::on_port( let c_mgr = CentralizedEventManager::on_port(
mgr, mgr,
self.shmem_provider.clone(), self.shmem_provider.clone(),
self.centralized_broker_port, self.centralized_broker_port,
index == 1, index == 1,
)?; )?;
#[cfg(feature = "adaptive_serialization")]
let c_mgr = CentralizedEventManager::on_port(
mgr,
self.shmem_provider.clone(),
self.centralized_broker_port,
index == 1,
self.time_obs,
)?;
return (self.run_client.take().unwrap())(state, c_mgr, *bind_to); return (self.run_client.take().unwrap())(state, c_mgr, *bind_to);
} }
@ -646,7 +669,7 @@ where
log::info!("I am broker!!."); log::info!("I am broker!!.");
// TODO we don't want always a broker here, think about using different laucher process to spawn different configurations // TODO we don't want always a broker here, think about using different laucher process to spawn different configurations
RestartingMgr::<(), MT, S, SP>::builder() let builder = RestartingMgr::<(), MT, S, SP>::builder()
.shmem_provider(self.shmem_provider.clone()) .shmem_provider(self.shmem_provider.clone())
.monitor(Some(self.monitor.clone())) .monitor(Some(self.monitor.clone()))
.broker_port(self.broker_port) .broker_port(self.broker_port)
@ -655,9 +678,12 @@ where
.exit_cleanly_after(Some(NonZeroUsize::try_from(self.cores.ids.len()).unwrap())) .exit_cleanly_after(Some(NonZeroUsize::try_from(self.cores.ids.len()).unwrap()))
.configuration(self.configuration) .configuration(self.configuration)
.serialize_state(self.serialize_state) .serialize_state(self.serialize_state)
.hooks(tuple_list!()) .hooks(tuple_list!());
.build()
.launch()?; #[cfg(feature = "adaptive_serialization")]
let builder = builder.time_ref(self.time_obs.reference());
builder.build().launch()?;
// Broker exited. kill all clients. // Broker exited. kill all clients.
for handle in &handles { for handle in &handles {

View File

@ -13,8 +13,6 @@ use std::net::TcpStream;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::net::{SocketAddr, ToSocketAddrs}; use std::net::{SocketAddr, ToSocketAddrs};
#[cfg(feature = "adaptive_serialization")]
use libafl_bolts::current_time;
#[cfg(all(feature = "std", any(windows, not(feature = "fork"))))] #[cfg(all(feature = "std", any(windows, not(feature = "fork"))))]
use libafl_bolts::os::startable_self; use libafl_bolts::os::startable_self;
#[cfg(all(unix, feature = "std", not(miri)))] #[cfg(all(unix, feature = "std", not(miri)))]
@ -32,6 +30,11 @@ use libafl_bolts::{
llmp::{recv_tcp_msg, send_tcp_msg, TcpRequest, TcpResponse}, llmp::{recv_tcp_msg, send_tcp_msg, TcpRequest, TcpResponse},
IP_LOCALHOST, IP_LOCALHOST,
}; };
#[cfg(feature = "adaptive_serialization")]
use libafl_bolts::{
current_time,
tuples::{Reference, Referenceable},
};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use libafl_bolts::{llmp::LlmpConnection, shmem::StdShMemProvider, staterestore::StateRestorer}; use libafl_bolts::{llmp::LlmpConnection, shmem::StdShMemProvider, staterestore::StateRestorer};
use libafl_bolts::{ use libafl_bolts::{
@ -49,6 +52,8 @@ use super::{hooks::EventManagerHooksTuple, CustomBufEventResult, CustomBufHandle
use crate::events::AdaptiveSerializer; use crate::events::AdaptiveSerializer;
#[cfg(all(unix, feature = "std"))] #[cfg(all(unix, feature = "std"))]
use crate::events::EVENTMGR_SIGHANDLER_STATE; use crate::events::EVENTMGR_SIGHANDLER_STATE;
#[cfg(feature = "adaptive_serialization")]
use crate::observers::TimeObserver;
use crate::{ use crate::{
events::{ events::{
BrokerEventResult, Event, EventConfig, EventFirer, EventManager, EventManagerId, BrokerEventResult, Event, EventConfig, EventFirer, EventManager, EventManagerId,
@ -336,7 +341,7 @@ where
} }
/// An [`EventManager`] that forwards all events to other attached fuzzers on shared maps or via tcp, /// An [`EventManager`] that forwards all events to other attached fuzzers on shared maps or via tcp,
/// using low-level message passing, [`libafl_bolts::llmp`]. /// using low-level message passing, [`llmp`].
pub struct LlmpEventManager<EMH, S, SP> pub struct LlmpEventManager<EMH, S, SP>
where where
S: State, S: State,
@ -361,6 +366,8 @@ where
serializations_cnt: usize, serializations_cnt: usize,
#[cfg(feature = "adaptive_serialization")] #[cfg(feature = "adaptive_serialization")]
should_serialize_cnt: usize, should_serialize_cnt: usize,
#[cfg(feature = "adaptive_serialization")]
time_ref: Reference<TimeObserver>,
phantom: PhantomData<S>, phantom: PhantomData<S>,
} }
@ -395,6 +402,10 @@ where
fn should_serialize_cnt_mut(&mut self) -> &mut usize { fn should_serialize_cnt_mut(&mut self) -> &mut usize {
&mut self.should_serialize_cnt &mut self.should_serialize_cnt
} }
fn time_ref(&self) -> &Reference<TimeObserver> {
&self.time_ref
}
} }
impl<EMH, S, SP> core::fmt::Debug for LlmpEventManager<EMH, S, SP> impl<EMH, S, SP> core::fmt::Debug for LlmpEventManager<EMH, S, SP>
@ -432,6 +443,7 @@ where
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
{ {
/// Create a manager from a raw LLMP client /// Create a manager from a raw LLMP client
#[cfg(not(feature = "adaptive_serialization"))]
pub fn new(llmp: LlmpClient<SP>, configuration: EventConfig) -> Result<Self, Error> { pub fn new(llmp: LlmpClient<SP>, configuration: EventConfig) -> Result<Self, Error> {
Ok(LlmpEventManager { Ok(LlmpEventManager {
hooks: tuple_list!(), hooks: tuple_list!(),
@ -439,14 +451,6 @@ where
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD), compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration, configuration,
#[cfg(feature = "adaptive_serialization")]
serialization_time: Duration::ZERO,
#[cfg(feature = "adaptive_serialization")]
deserialization_time: Duration::ZERO,
#[cfg(feature = "adaptive_serialization")]
serializations_cnt: 0,
#[cfg(feature = "adaptive_serialization")]
should_serialize_cnt: 0,
phantom: PhantomData, phantom: PhantomData,
custom_buf_handlers: vec![], custom_buf_handlers: vec![],
}) })
@ -456,7 +460,7 @@ where
/// ///
/// If the port is not yet bound, it will act as a broker; otherwise, it /// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client. /// will act as a client.
#[cfg(feature = "std")] #[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
pub fn on_port( pub fn on_port(
shmem_provider: SP, shmem_provider: SP,
port: u16, port: u16,
@ -468,7 +472,7 @@ where
/// If a client respawns, it may reuse the existing connection, previously /// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`]. /// stored by [`LlmpClient::to_env()`].
#[cfg(feature = "std")] #[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
pub fn existing_client_from_env( pub fn existing_client_from_env(
shmem_provider: SP, shmem_provider: SP,
env_name: &str, env_name: &str,
@ -479,6 +483,7 @@ where
} }
/// Create an existing client from description /// Create an existing client from description
#[cfg(not(feature = "adaptive_serialization"))]
pub fn existing_client_from_description( pub fn existing_client_from_description(
shmem_provider: SP, shmem_provider: SP,
description: &LlmpClientDescription, description: &LlmpClientDescription,
@ -487,6 +492,69 @@ where
let llmp = LlmpClient::existing_client_from_description(shmem_provider, description)?; let llmp = LlmpClient::existing_client_from_description(shmem_provider, description)?;
Self::new(llmp, configuration) Self::new(llmp, configuration)
} }
/// Create a manager from a raw LLMP client
#[cfg(feature = "adaptive_serialization")]
pub fn new(
llmp: LlmpClient<SP>,
configuration: EventConfig,
time_ref: Reference<TimeObserver>,
) -> Result<Self, Error> {
Ok(LlmpEventManager {
hooks: tuple_list!(),
llmp,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration,
serialization_time: Duration::ZERO,
deserialization_time: Duration::ZERO,
serializations_cnt: 0,
should_serialize_cnt: 0,
time_ref,
phantom: PhantomData,
custom_buf_handlers: vec![],
})
}
/// Create an LLMP event manager on a port
///
/// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client.
#[cfg(all(feature = "std", feature = "adaptive_serialization"))]
pub fn on_port(
shmem_provider: SP,
port: u16,
configuration: EventConfig,
time_ref: Reference<TimeObserver>,
) -> Result<LlmpEventManager<(), S, SP>, Error> {
let llmp = LlmpClient::create_attach_to_tcp(shmem_provider, port)?;
Self::new(llmp, configuration, time_ref)
}
/// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`].
#[cfg(all(feature = "std", feature = "adaptive_serialization"))]
pub fn existing_client_from_env(
shmem_provider: SP,
env_name: &str,
configuration: EventConfig,
time_ref: Reference<TimeObserver>,
) -> Result<LlmpEventManager<(), S, SP>, Error> {
let llmp = LlmpClient::on_existing_from_env(shmem_provider, env_name)?;
Self::new(llmp, configuration, time_ref)
}
/// Create an existing client from description
#[cfg(feature = "adaptive_serialization")]
pub fn existing_client_from_description(
shmem_provider: SP,
description: &LlmpClientDescription,
configuration: EventConfig,
time_ref: Reference<TimeObserver>,
) -> Result<LlmpEventManager<(), S, SP>, Error> {
let llmp = LlmpClient::existing_client_from_description(shmem_provider, description)?;
Self::new(llmp, configuration, time_ref)
}
} }
impl<EMH, S, SP> LlmpEventManager<EMH, S, SP> impl<EMH, S, SP> LlmpEventManager<EMH, S, SP>
@ -494,6 +562,135 @@ where
S: State, S: State,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
{ {
/// Create a manager from a raw LLMP client with hooks
#[cfg(not(feature = "adaptive_serialization"))]
pub fn with_hooks(
llmp: LlmpClient<SP>,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
Ok(Self {
hooks,
llmp,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration,
phantom: PhantomData,
custom_buf_handlers: vec![],
})
}
/// Create an LLMP event manager on a port with hook
///
/// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client.
/// This will make a new connection to the broker so will return its new [`ClientId`], too
#[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
pub fn on_port_with_hooks(
shmem_provider: SP,
port: u16,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
let llmp = LlmpClient::create_attach_to_tcp(shmem_provider, port)?;
Self::with_hooks(llmp, configuration, hooks)
}
/// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`].
/// create a event manager from env with hooks
#[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
pub fn existing_client_from_env_with_hooks(
shmem_provider: SP,
env_name: &str,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
let llmp = LlmpClient::on_existing_from_env(shmem_provider, env_name)?;
Self::with_hooks(llmp, configuration, hooks)
}
/// Create an existing client from description
#[cfg(not(feature = "adaptive_serialization"))]
pub fn existing_client_from_description_with_hooks(
shmem_provider: SP,
description: &LlmpClientDescription,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
let llmp = LlmpClient::existing_client_from_description(shmem_provider, description)?;
Self::with_hooks(llmp, configuration, hooks)
}
/// Create a manager from a raw LLMP client with hooks
#[cfg(feature = "adaptive_serialization")]
pub fn with_hooks(
llmp: LlmpClient<SP>,
configuration: EventConfig,
hooks: EMH,
time_ref: Reference<TimeObserver>,
) -> Result<Self, Error> {
Ok(Self {
hooks,
llmp,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration,
serialization_time: Duration::ZERO,
deserialization_time: Duration::ZERO,
serializations_cnt: 0,
should_serialize_cnt: 0,
time_ref,
phantom: PhantomData,
custom_buf_handlers: vec![],
})
}
/// Create an LLMP event manager on a port with hook
///
/// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client.
/// This will make a new connection to the broker so will return its new [`ClientId`], too
#[cfg(all(feature = "std", feature = "adaptive_serialization"))]
pub fn on_port_with_hooks(
shmem_provider: SP,
port: u16,
configuration: EventConfig,
hooks: EMH,
time_ref: Reference<TimeObserver>,
) -> Result<Self, Error> {
let llmp = LlmpClient::create_attach_to_tcp(shmem_provider, port)?;
Self::with_hooks(llmp, configuration, hooks, time_ref)
}
/// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`].
/// create a event manager from env with hooks
#[cfg(all(feature = "std", feature = "adaptive_serialization"))]
pub fn existing_client_from_env_with_hooks(
shmem_provider: SP,
env_name: &str,
configuration: EventConfig,
hooks: EMH,
time_ref: Reference<TimeObserver>,
) -> Result<Self, Error> {
let llmp = LlmpClient::on_existing_from_env(shmem_provider, env_name)?;
Self::with_hooks(llmp, configuration, hooks, time_ref)
}
/// Create an existing client from description
#[cfg(feature = "adaptive_serialization")]
pub fn existing_client_from_description_with_hooks(
shmem_provider: SP,
description: &LlmpClientDescription,
configuration: EventConfig,
hooks: EMH,
time_ref: Reference<TimeObserver>,
) -> Result<Self, Error> {
let llmp = LlmpClient::existing_client_from_description(shmem_provider, description)?;
Self::with_hooks(llmp, configuration, hooks, time_ref)
}
/// Calling this function will tell the llmp broker that this client is exiting /// Calling this function will tell the llmp broker that this client is exiting
/// This should be called from the restarter not from the actual fuzzer client /// This should be called from the restarter not from the actual fuzzer client
/// This function serves the same roll as the `LlmpClient.send_exiting()` /// This function serves the same roll as the `LlmpClient.send_exiting()`
@ -526,77 +723,12 @@ where
log::info!("Asking he broker to be disconnected"); log::info!("Asking he broker to be disconnected");
Ok(()) Ok(())
} }
/// Create a manager from a raw LLMP client with hooks
pub fn with_hooks(
llmp: LlmpClient<SP>,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
Ok(Self {
hooks,
llmp,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration,
#[cfg(feature = "adaptive_serialization")]
serialization_time: Duration::ZERO,
#[cfg(feature = "adaptive_serialization")]
deserialization_time: Duration::ZERO,
#[cfg(feature = "adaptive_serialization")]
serializations_cnt: 0,
#[cfg(feature = "adaptive_serialization")]
should_serialize_cnt: 0,
phantom: PhantomData,
custom_buf_handlers: vec![],
})
}
/// Create an LLMP event manager on a port with hook
///
/// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client.
/// This will make a new connection to the broker so will return its new [`ClientId`], too
#[cfg(feature = "std")]
pub fn on_port_with_hooks(
shmem_provider: SP,
port: u16,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
let llmp = LlmpClient::create_attach_to_tcp(shmem_provider, port)?;
Self::with_hooks(llmp, configuration, hooks)
}
/// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`].
/// create a event manager from env with hooks
#[cfg(feature = "std")]
pub fn existing_client_from_env_with_hooks(
shmem_provider: SP,
env_name: &str,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
let llmp = LlmpClient::on_existing_from_env(shmem_provider, env_name)?;
Self::with_hooks(llmp, configuration, hooks)
}
/// Describe the client event manager's LLMP parts in a restorable fashion /// Describe the client event manager's LLMP parts in a restorable fashion
pub fn describe(&self) -> Result<LlmpClientDescription, Error> { pub fn describe(&self) -> Result<LlmpClientDescription, Error> {
self.llmp.describe() self.llmp.describe()
} }
/// Create an existing client from description
pub fn existing_client_from_description_with_hooks(
shmem_provider: SP,
description: &LlmpClientDescription,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
let llmp = LlmpClient::existing_client_from_description(shmem_provider, description)?;
Self::with_hooks(llmp, configuration, hooks)
}
/// Write the config for a client [`EventManager`] to env vars, a new /// Write the config for a client [`EventManager`] to env vars, a new
/// client can reattach using [`LlmpEventManager::existing_client_from_env()`]. /// client can reattach using [`LlmpEventManager::existing_client_from_env()`].
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -958,6 +1090,10 @@ where
fn should_serialize_cnt_mut(&mut self) -> &mut usize { fn should_serialize_cnt_mut(&mut self) -> &mut usize {
self.llmp_mgr.should_serialize_cnt_mut() self.llmp_mgr.should_serialize_cnt_mut()
} }
fn time_ref(&self) -> &Reference<TimeObserver> {
&self.llmp_mgr.time_ref
}
} }
#[cfg(all(feature = "std", not(feature = "adaptive_serialization")))] #[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
@ -1172,7 +1308,7 @@ pub enum ManagerKind {
/// Sets up a restarting fuzzer, using the [`StdShMemProvider`], and standard features. /// Sets up a restarting fuzzer, using the [`StdShMemProvider`], and standard features.
/// The restarting mgr is a combination of restarter and runner, that can be used on systems with and without `fork` support. /// The restarting mgr is a combination of restarter and runner, that can be used on systems with and without `fork` support.
/// The restarter will spawn a new process each time the child crashes or timeouts. /// The restarter will spawn a new process each time the child crashes or timeouts.
#[cfg(feature = "std")] #[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn setup_restarting_mgr_std<MT, S>( pub fn setup_restarting_mgr_std<MT, S>(
monitor: MT, monitor: MT,
@ -1199,6 +1335,38 @@ where
.launch() .launch()
} }
/// Sets up a restarting fuzzer, using the [`StdShMemProvider`], and standard features.
/// The restarting mgr is a combination of restarter and runner, that can be used on systems with and without `fork` support.
/// The restarter will spawn a new process each time the child crashes or timeouts.
#[cfg(all(feature = "std", feature = "adaptive_serialization"))]
#[allow(clippy::type_complexity)]
pub fn setup_restarting_mgr_std<MT, S>(
monitor: MT,
broker_port: u16,
configuration: EventConfig,
time_obs: &TimeObserver,
) -> Result<
(
Option<S>,
LlmpRestartingEventManager<(), S, StdShMemProvider>,
),
Error,
>
where
MT: Monitor + Clone,
S: State + HasExecutions,
{
RestartingMgr::builder()
.shmem_provider(StdShMemProvider::new()?)
.monitor(Some(monitor))
.broker_port(broker_port)
.configuration(configuration)
.hooks(tuple_list!())
.time_ref(time_obs.reference())
.build()
.launch()
}
/// Provides a `builder` which can be used to build a [`RestartingMgr`], which is a combination of a /// Provides a `builder` which can be used to build a [`RestartingMgr`], which is a combination of a
/// `restarter` and `runner`, that can be used on systems both with and without `fork` support. The /// `restarter` and `runner`, that can be used on systems both with and without `fork` support. The
/// `restarter` will start a new process each time the child crashes or times out. /// `restarter` will start a new process each time the child crashes or times out.
@ -1243,6 +1411,8 @@ where
serialize_state: LlmpShouldSaveState, serialize_state: LlmpShouldSaveState,
/// The hooks passed to event manager: /// The hooks passed to event manager:
hooks: EMH, hooks: EMH,
#[cfg(feature = "adaptive_serialization")]
time_ref: Reference<TimeObserver>,
#[builder(setter(skip), default = PhantomData)] #[builder(setter(skip), default = PhantomData)]
phantom_data: PhantomData<(EMH, S)>, phantom_data: PhantomData<(EMH, S)>,
} }
@ -1310,11 +1480,19 @@ where
return Err(Error::shutting_down()); return Err(Error::shutting_down());
} }
LlmpConnection::IsClient { client } => { LlmpConnection::IsClient { client } => {
#[cfg(not(feature = "adaptive_serialization"))]
let mgr = LlmpEventManager::<EMH, S, SP>::with_hooks( let mgr = LlmpEventManager::<EMH, S, SP>::with_hooks(
client, client,
self.configuration, self.configuration,
self.hooks, self.hooks,
)?; )?;
#[cfg(feature = "adaptive_serialization")]
let mgr = LlmpEventManager::<EMH, S, SP>::with_hooks(
client,
self.configuration,
self.hooks,
self.time_ref.clone(),
)?;
(mgr, None) (mgr, None)
} }
} }
@ -1331,12 +1509,21 @@ where
} }
ManagerKind::Client { cpu_core } => { ManagerKind::Client { cpu_core } => {
// We are a client // We are a client
#[cfg(not(feature = "adaptive_serialization"))]
let mgr = LlmpEventManager::<EMH, S, SP>::on_port_with_hooks( let mgr = LlmpEventManager::<EMH, S, SP>::on_port_with_hooks(
self.shmem_provider.clone(), self.shmem_provider.clone(),
self.broker_port, self.broker_port,
self.configuration, self.configuration,
self.hooks, self.hooks,
)?; )?;
#[cfg(feature = "adaptive_serialization")]
let mgr = LlmpEventManager::<EMH, S, SP>::on_port_with_hooks(
self.shmem_provider.clone(),
self.broker_port,
self.configuration,
self.hooks,
self.time_ref.clone(),
)?;
(mgr, cpu_core) (mgr, cpu_core)
} }
@ -1449,15 +1636,25 @@ where
// If we're restarting, deserialize the old state. // If we're restarting, deserialize the old state.
let (state, mut mgr) = let (state, mut mgr) =
if let Some((state_opt, mgr_description)) = staterestorer.restore()? { if let Some((state_opt, mgr_description)) = staterestorer.restore()? {
#[cfg(not(feature = "adaptive_serialization"))]
let llmp_mgr = LlmpEventManager::existing_client_from_description_with_hooks(
new_shmem_provider,
&mgr_description,
self.configuration,
self.hooks,
)?;
#[cfg(feature = "adaptive_serialization")]
let llmp_mgr = LlmpEventManager::existing_client_from_description_with_hooks(
new_shmem_provider,
&mgr_description,
self.configuration,
self.hooks,
self.time_ref.clone(),
)?;
( (
state_opt, state_opt,
LlmpRestartingEventManager::with_save_state( LlmpRestartingEventManager::with_save_state(
LlmpEventManager::existing_client_from_description_with_hooks( llmp_mgr,
new_shmem_provider,
&mgr_description,
self.configuration,
self.hooks,
)?,
staterestorer, staterestorer,
self.serialize_state, self.serialize_state,
), ),
@ -1465,12 +1662,21 @@ where
} else { } else {
log::info!("First run. Let's set it all up"); log::info!("First run. Let's set it all up");
// Mgr to send and receive msgs from/to all other fuzzer instances // Mgr to send and receive msgs from/to all other fuzzer instances
#[cfg(not(feature = "adaptive_serialization"))]
let mgr = LlmpEventManager::<EMH, S, SP>::existing_client_from_env_with_hooks( let mgr = LlmpEventManager::<EMH, S, SP>::existing_client_from_env_with_hooks(
new_shmem_provider, new_shmem_provider,
_ENV_FUZZER_BROKER_CLIENT_INITIAL, _ENV_FUZZER_BROKER_CLIENT_INITIAL,
self.configuration, self.configuration,
self.hooks, self.hooks,
)?; )?;
#[cfg(feature = "adaptive_serialization")]
let mgr = LlmpEventManager::<EMH, S, SP>::existing_client_from_env_with_hooks(
new_shmem_provider,
_ENV_FUZZER_BROKER_CLIENT_INITIAL,
self.configuration,
self.hooks,
self.time_ref.clone(),
)?;
( (
None, None,
@ -1854,6 +2060,8 @@ where
mod tests { mod tests {
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
#[cfg(feature = "adaptive_serialization")]
use libafl_bolts::tuples::Referenceable;
use libafl_bolts::{ use libafl_bolts::{
llmp::{LlmpClient, LlmpSharedMap}, llmp::{LlmpClient, LlmpSharedMap},
rands::StdRand, rands::StdRand,
@ -1872,6 +2080,7 @@ mod tests {
fuzzer::Fuzzer, fuzzer::Fuzzer,
inputs::BytesInput, inputs::BytesInput,
mutators::BitFlipMutator, mutators::BitFlipMutator,
observers::TimeObserver,
schedulers::RandScheduler, schedulers::RandScheduler,
stages::StdMutationalStage, stages::StdMutationalStage,
state::StdState, state::StdState,
@ -1884,6 +2093,10 @@ mod tests {
fn test_mgr_state_restore() { fn test_mgr_state_restore() {
let rand = StdRand::with_seed(0); let rand = StdRand::with_seed(0);
let time = TimeObserver::new("time");
#[cfg(feature = "adaptive_serialization")]
let time_ref = time.reference();
let mut corpus = InMemoryCorpus::<BytesInput>::new(); let mut corpus = InMemoryCorpus::<BytesInput>::new();
let testcase = Testcase::new(vec![0; 4].into()); let testcase = Testcase::new(vec![0; 4].into());
corpus.add(testcase).unwrap(); corpus.add(testcase).unwrap();
@ -1910,7 +2123,11 @@ mod tests {
llmp_client.mark_safe_to_unmap(); llmp_client.mark_safe_to_unmap();
} }
#[cfg(not(feature = "adaptive_serialization"))]
let mut llmp_mgr = LlmpEventManager::new(llmp_client, "fuzzer".into()).unwrap(); let mut llmp_mgr = LlmpEventManager::new(llmp_client, "fuzzer".into()).unwrap();
#[cfg(feature = "adaptive_serialization")]
let mut llmp_mgr =
LlmpEventManager::new(llmp_client, "fuzzer".into(), time_ref.clone()).unwrap();
let scheduler = RandScheduler::new(); let scheduler = RandScheduler::new();
@ -1922,7 +2139,7 @@ mod tests {
let mut harness = |_buf: &BytesInput| ExitKind::Ok; let mut harness = |_buf: &BytesInput| ExitKind::Ok;
let mut executor = InProcessExecutor::new( let mut executor = InProcessExecutor::new(
&mut harness, &mut harness,
tuple_list!(), tuple_list!(time),
&mut fuzzer, &mut fuzzer,
&mut state, &mut state,
&mut llmp_mgr, &mut llmp_mgr,
@ -1952,22 +2169,29 @@ mod tests {
assert!(sc_cpy.has_content()); assert!(sc_cpy.has_content());
let (mut state_clone, mgr_description) = staterestorer.restore().unwrap().unwrap(); let (mut state_clone, mgr_description) = staterestorer.restore().unwrap().unwrap();
#[cfg(not(feature = "adaptive_serialization"))]
let mut llmp_clone = LlmpEventManager::existing_client_from_description( let mut llmp_clone = LlmpEventManager::existing_client_from_description(
shmem_provider, shmem_provider,
&mgr_description, &mgr_description,
"fuzzer".into(), "fuzzer".into(),
) )
.unwrap(); .unwrap();
#[cfg(feature = "adaptive_serialization")]
let mut llmp_clone = LlmpEventManager::existing_client_from_description(
shmem_provider,
&mgr_description,
"fuzzer".into(),
time_ref,
)
.unwrap();
if false { fuzzer
fuzzer .fuzz_one(
.fuzz_one( &mut stages,
&mut stages, &mut executor,
&mut executor, &mut state_clone,
&mut state_clone, &mut llmp_clone,
&mut llmp_clone, )
) .unwrap();
.unwrap();
}
} }
} }

View File

@ -32,6 +32,8 @@ use ahash::RandomState;
pub use launcher::*; pub use launcher::*;
#[cfg(all(unix, feature = "std"))] #[cfg(all(unix, feature = "std"))]
use libafl_bolts::os::unix_signals::{siginfo_t, ucontext_t, Handler, Signal}; use libafl_bolts::os::unix_signals::{siginfo_t, ucontext_t, Handler, Signal};
#[cfg(feature = "adaptive_serialization")]
use libafl_bolts::tuples::{MatchNameRef, Reference};
use libafl_bolts::{current_time, ClientId}; use libafl_bolts::{current_time, ClientId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -119,7 +121,7 @@ impl Handler for ShutdownSignalData {
} }
/// A per-fuzzer unique `ID`, usually starting with `0` and increasing /// A per-fuzzer unique `ID`, usually starting with `0` and increasing
/// by `1` in multiprocessed [`EventManager`]s, such as [`self::llmp::LlmpEventManager`]. /// by `1` in multiprocessed [`EventManager`]s, such as [`LlmpEventManager`].
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)] #[repr(transparent)]
pub struct EventManagerId( pub struct EventManagerId(
@ -129,6 +131,8 @@ pub struct EventManagerId(
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
use crate::monitors::ClientPerfMonitor; use crate::monitors::ClientPerfMonitor;
#[cfg(feature = "adaptive_serialization")]
use crate::observers::TimeObserver;
use crate::{inputs::UsesInput, stages::HasCurrentStage, state::UsesState}; use crate::{inputs::UsesInput, stages::HasCurrentStage, state::UsesState};
/// The log event severity /// The log event severity
@ -415,7 +419,7 @@ where
pub trait EventFirer: UsesState { pub trait EventFirer: UsesState {
/// Send off an [`Event`] to the broker /// Send off an [`Event`] to the broker
/// ///
/// For multi-processed managers, such as [`llmp::LlmpEventManager`], /// For multi-processed managers, such as [`LlmpEventManager`],
/// this serializes the [`Event`] and commits it to the [`llmp`] page. /// this serializes the [`Event`] and commits it to the [`llmp`] page.
/// In this case, if you `fire` faster than the broker can consume /// In this case, if you `fire` faster than the broker can consume
/// (for example for each [`Input`], on multiple cores) /// (for example for each [`Input`], on multiple cores)
@ -466,7 +470,7 @@ where
{ {
/// Given the last time, if `monitor_timeout` seconds passed, send off an info/monitor/heartbeat message to the broker. /// Given the last time, if `monitor_timeout` seconds passed, send off an info/monitor/heartbeat message to the broker.
/// Returns the new `last` time (so the old one, unless `monitor_timeout` time has passed and monitor have been sent) /// Returns the new `last` time (so the old one, unless `monitor_timeout` time has passed and monitor have been sent)
/// Will return an [`crate::Error`], if the stats could not be sent. /// Will return an [`Error`], if the stats could not be sent.
fn maybe_report_progress( fn maybe_report_progress(
&mut self, &mut self,
state: &mut Self::State, state: &mut Self::State,
@ -487,7 +491,7 @@ where
} }
/// Send off an info/monitor/heartbeat message to the broker. /// Send off an info/monitor/heartbeat message to the broker.
/// Will return an [`crate::Error`], if the stats could not be sent. /// Will return an [`Error`], if the stats could not be sent.
fn report_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { fn report_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
let executions = *state.executions(); let executions = *state.executions();
let cur = current_time(); let cur = current_time();
@ -875,6 +879,9 @@ pub trait AdaptiveSerializer {
/// How many times shoukd have been serialized an observer (mut) /// How many times shoukd have been serialized an observer (mut)
fn should_serialize_cnt_mut(&mut self) -> &mut usize; fn should_serialize_cnt_mut(&mut self) -> &mut usize;
/// A [`Reference`] to the time observer to determine the `time_factor`
fn time_ref(&self) -> &Reference<TimeObserver>;
/// Serialize the observer using the `time_factor` and `percentage_threshold`. /// Serialize the observer using the `time_factor` and `percentage_threshold`.
/// These parameters are unique to each of the different types of `EventManager` /// These parameters are unique to each of the different types of `EventManager`
fn serialize_observers_adaptive<S, OT>( fn serialize_observers_adaptive<S, OT>(
@ -888,7 +895,7 @@ pub trait AdaptiveSerializer {
S: UsesInput, S: UsesInput,
{ {
let exec_time = observers let exec_time = observers
.match_name::<crate::observers::TimeObserver>("time") .get(self.time_ref())
.map(|o| o.last_runtime().unwrap_or(Duration::ZERO)) .map(|o| o.last_runtime().unwrap_or(Duration::ZERO))
.unwrap(); .unwrap();

View File

@ -3,6 +3,8 @@
use core::fmt::Debug; use core::fmt::Debug;
use libafl_bolts::tuples::RefIndexable;
use crate::{ use crate::{
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
observers::UsesObservers, observers::UsesObservers,
@ -80,12 +82,12 @@ where
A: HasObservers, A: HasObservers,
{ {
#[inline] #[inline]
fn observers(&self) -> &Self::Observers { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.primary.observers() self.primary.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut Self::Observers { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.primary.observers_mut() self.primary.observers_mut()
} }
} }

View File

@ -18,7 +18,7 @@ use std::{
use libafl_bolts::{ use libafl_bolts::{
fs::{get_unique_std_input_file, InputFile}, fs::{get_unique_std_input_file, InputFile},
tuples::MatchName, tuples::{MatchName, RefIndexable},
AsSlice, AsSlice,
}; };
@ -397,12 +397,12 @@ where
T: Debug, T: Debug,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
{ {
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
&self.observers RefIndexable::from(&self.observers)
} }
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
&mut self.observers RefIndexable::from(&mut self.observers)
} }
} }

View File

@ -4,7 +4,10 @@
//! //!
use core::{cell::UnsafeCell, fmt::Debug, ptr}; use core::{cell::UnsafeCell, fmt::Debug, ptr};
use libafl_bolts::{ownedref::OwnedMutPtr, tuples::MatchName}; use libafl_bolts::{
ownedref::OwnedMutPtr,
tuples::{MatchName, RefIndexable},
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -183,6 +186,7 @@ where
B: MatchName, B: MatchName,
DOT: MatchName, DOT: MatchName,
{ {
#[allow(deprecated)]
fn match_name<T>(&self, name: &str) -> Option<&T> { fn match_name<T>(&self, name: &str) -> Option<&T> {
if let Some(t) = self.primary.as_ref().match_name::<T>(name) { if let Some(t) = self.primary.as_ref().match_name::<T>(name) {
Some(t) Some(t)
@ -192,6 +196,8 @@ where
self.differential.match_name::<T>(name) self.differential.match_name::<T>(name)
} }
} }
#[allow(deprecated)]
fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T> { fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T> {
if let Some(t) = self.primary.as_mut().match_name_mut::<T>(name) { if let Some(t) = self.primary.as_mut().match_name_mut::<T>(name) {
Some(t) Some(t)
@ -238,26 +244,25 @@ where
DOT: DifferentialObserversTuple<OTA, OTB, A::State>, DOT: DifferentialObserversTuple<OTA, OTB, A::State>,
{ {
#[inline] #[inline]
fn observers(&self) -> &ProxyObserversTuple<OTA, OTB, DOT> { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
unsafe { unsafe {
self.observers self.observers
.get() .get()
.as_mut() .as_mut()
.unwrap() .unwrap()
.set(self.primary.observers(), self.secondary.observers()); .set(&*self.primary.observers(), &*self.secondary.observers());
self.observers.get().as_ref().unwrap() RefIndexable::from(self.observers.get().as_ref().unwrap())
} }
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut ProxyObserversTuple<OTA, OTB, DOT> { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
unsafe { unsafe {
self.observers self.observers.get().as_mut().unwrap().set(
.get() &*self.primary.observers_mut(),
.as_mut() &*self.secondary.observers_mut(),
.unwrap() );
.set(self.primary.observers(), self.secondary.observers()); RefIndexable::from(self.observers.get().as_mut().unwrap())
self.observers.get().as_mut().unwrap()
} }
} }
} }

View File

@ -22,7 +22,7 @@ use libafl_bolts::{
fs::{get_unique_std_input_file, InputFile}, fs::{get_unique_std_input_file, InputFile},
os::{dup2, pipes::Pipe}, os::{dup2, pipes::Pipe},
shmem::{ShMem, ShMemProvider, UnixShMemProvider}, shmem::{ShMem, ShMemProvider, UnixShMemProvider},
tuples::Prepend, tuples::{MatchNameRef, Prepend, RefIndexable, Reference, Referenceable},
AsSlice, AsSliceMut, Truncate, AsSlice, AsSliceMut, Truncate,
}; };
use nix::{ use nix::{
@ -497,6 +497,8 @@ where
map: Option<SP::ShMem>, map: Option<SP::ShMem>,
phantom: PhantomData<S>, phantom: PhantomData<S>,
map_size: Option<usize>, map_size: Option<usize>,
#[cfg(feature = "regex")]
asan_obs: Reference<AsanBacktraceObserver>,
timeout: TimeSpec, timeout: TimeSpec,
crash_exitcode: Option<i8>, crash_exitcode: Option<i8>,
} }
@ -584,6 +586,8 @@ pub struct ForkserverExecutorBuilder<'a, SP> {
real_map_size: i32, real_map_size: i32,
kill_signal: Option<Signal>, kill_signal: Option<Signal>,
timeout: Option<Duration>, timeout: Option<Duration>,
#[cfg(feature = "regex")]
asan_obs: Option<Reference<AsanBacktraceObserver>>,
crash_exitcode: Option<i8>, crash_exitcode: Option<i8>,
} }
@ -633,6 +637,10 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
phantom: PhantomData, phantom: PhantomData,
map_size: self.map_size, map_size: self.map_size,
timeout, timeout,
asan_obs: self
.asan_obs
.clone()
.unwrap_or(AsanBacktraceObserver::default().reference()),
crash_exitcode: self.crash_exitcode, crash_exitcode: self.crash_exitcode,
}) })
} }
@ -691,6 +699,10 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
phantom: PhantomData, phantom: PhantomData,
map_size: self.map_size, map_size: self.map_size,
timeout, timeout,
asan_obs: self
.asan_obs
.clone()
.unwrap_or(AsanBacktraceObserver::default().reference()),
crash_exitcode: self.crash_exitcode, crash_exitcode: self.crash_exitcode,
}) })
} }
@ -1058,6 +1070,7 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
max_input_size: MAX_INPUT_SIZE_DEFAULT, max_input_size: MAX_INPUT_SIZE_DEFAULT,
kill_signal: None, kill_signal: None,
timeout: None, timeout: None,
asan_obs: None,
crash_exitcode: None, crash_exitcode: None,
} }
} }
@ -1084,6 +1097,7 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
max_input_size: MAX_INPUT_SIZE_DEFAULT, max_input_size: MAX_INPUT_SIZE_DEFAULT,
kill_signal: None, kill_signal: None,
timeout: None, timeout: None,
asan_obs: None,
crash_exitcode: None, crash_exitcode: None,
} }
} }
@ -1178,10 +1192,7 @@ where
if libc::WIFSIGNALED(self.forkserver().status()) || exitcode_is_crash { if libc::WIFSIGNALED(self.forkserver().status()) || exitcode_is_crash {
exit_kind = ExitKind::Crash; exit_kind = ExitKind::Crash;
#[cfg(feature = "regex")] #[cfg(feature = "regex")]
if let Some(asan_observer) = self if let Some(asan_observer) = self.observers.get_mut(&self.asan_obs) {
.observers_mut()
.match_name_mut::<AsanBacktraceObserver>("AsanBacktraceObserver")
{
asan_observer.parse_asan_output_from_asan_log_file(pid)?; asan_observer.parse_asan_output_from_asan_log_file(pid)?;
} }
} }
@ -1229,13 +1240,13 @@ where
SP: ShMemProvider, SP: ShMemProvider,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
&self.observers RefIndexable::from(&self.observers)
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
&mut self.observers RefIndexable::from(&mut self.observers)
} }
} }

View File

@ -7,7 +7,7 @@ use core::{
time::Duration, time::Duration,
}; };
use libafl_bolts::tuples::{tuple_list, Merge}; use libafl_bolts::tuples::{tuple_list, Merge, RefIndexable};
#[cfg(windows)] #[cfg(windows)]
use windows::Win32::System::Threading::SetThreadStackGuarantee; use windows::Win32::System::Threading::SetThreadStackGuarantee;
@ -85,13 +85,13 @@ where
S: State, S: State,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
&self.observers RefIndexable::from(&self.observers)
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
&mut self.observers RefIndexable::from(&mut self.observers)
} }
} }

View File

@ -16,7 +16,7 @@ use core::{
time::Duration, time::Duration,
}; };
use libafl_bolts::tuples::tuple_list; use libafl_bolts::tuples::{tuple_list, RefIndexable};
#[cfg(any(unix, feature = "std"))] #[cfg(any(unix, feature = "std"))]
use crate::executors::hooks::inprocess::GLOBAL_STATE; use crate::executors::hooks::inprocess::GLOBAL_STATE;
@ -151,12 +151,12 @@ where
S: State, S: State,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers() self.inner.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut() self.inner.observers_mut()
} }
} }
@ -438,7 +438,7 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
E::State: HasExecutions + HasSolutions + HasCorpus, E::State: HasExecutions + HasSolutions + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
let observers = executor.observers_mut(); let mut observers = executor.observers_mut();
observers observers
.post_exec_all(state, input, &exitkind) .post_exec_all(state, input, &exitkind)
@ -446,7 +446,7 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
let interesting = fuzzer let interesting = fuzzer
.objective_mut() .objective_mut()
.is_interesting(state, event_mgr, input, observers, &exitkind) .is_interesting(state, event_mgr, input, &*observers, &exitkind)
.expect("In run_observers_and_save_state objective failure."); .expect("In run_observers_and_save_state objective failure.");
if interesting { if interesting {
@ -456,7 +456,7 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
new_testcase.set_parent_id_optional(*state.corpus().current()); new_testcase.set_parent_id_optional(*state.corpus().current());
fuzzer fuzzer
.objective_mut() .objective_mut()
.append_metadata(state, event_mgr, observers, &mut new_testcase) .append_metadata(state, event_mgr, &*observers, &mut new_testcase)
.expect("Failed adding metadata"); .expect("Failed adding metadata");
state state
.solutions_mut() .solutions_mut()

View File

@ -8,7 +8,7 @@ use core::{
time::Duration, time::Duration,
}; };
use libafl_bolts::tuples::tuple_list; use libafl_bolts::tuples::{tuple_list, RefIndexable};
use crate::{ use crate::{
events::{EventFirer, EventRestarter}, events::{EventFirer, EventRestarter},
@ -142,12 +142,12 @@ where
S: State, S: State,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers() self.inner.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut() self.inner.observers_mut()
} }
} }

View File

@ -10,7 +10,7 @@ use core::{
use libafl_bolts::{ use libafl_bolts::{
os::unix_signals::Signal, os::unix_signals::Signal,
shmem::ShMemProvider, shmem::ShMemProvider,
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge, RefIndexable},
}; };
use nix::{ use nix::{
sys::wait::{waitpid, WaitStatus}, sys::wait::{waitpid, WaitStatus},
@ -339,12 +339,12 @@ where
Z: UsesState<State = S>, Z: UsesState<State = S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
&self.observers RefIndexable::from(&self.observers)
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
&mut self.observers RefIndexable::from(&mut self.observers)
} }
} }

View File

@ -7,7 +7,7 @@ use core::{
use libafl_bolts::{ use libafl_bolts::{
os::unix_signals::{ucontext_t, Signal}, os::unix_signals::{ucontext_t, Signal},
shmem::ShMemProvider, shmem::ShMemProvider,
tuples::tuple_list, tuples::{tuple_list, RefIndexable},
}; };
use libc::siginfo_t; use libc::siginfo_t;
use nix::unistd::{fork, ForkResult}; use nix::unistd::{fork, ForkResult};
@ -255,12 +255,12 @@ where
Z: UsesState<State = S>, Z: UsesState<State = S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers() self.inner.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut() self.inner.observers_mut()
} }
} }
@ -295,7 +295,7 @@ pub mod child_signal_handlers {
let data = addr_of_mut!(FORK_EXECUTOR_GLOBAL_DATA); let data = addr_of_mut!(FORK_EXECUTOR_GLOBAL_DATA);
if !data.is_null() && (*data).is_valid() { if !data.is_null() && (*data).is_valid() {
let executor = (*data).executor_mut::<E>(); let executor = (*data).executor_mut::<E>();
let observers = executor.observers_mut(); let mut observers = executor.observers_mut();
let state = (*data).state_mut::<E::State>(); let state = (*data).state_mut::<E::State>();
// Invalidate data to not execute again the observer hooks in the crash handler // Invalidate data to not execute again the observer hooks in the crash handler
let input = (*data).take_current_input::<<E::State as UsesInput>::Input>(); let input = (*data).take_current_input::<<E::State as UsesInput>::Input>();
@ -326,7 +326,7 @@ pub mod child_signal_handlers {
{ {
if data.is_valid() { if data.is_valid() {
let executor = data.executor_mut::<E>(); let executor = data.executor_mut::<E>();
let observers = executor.observers_mut(); let mut observers = executor.observers_mut();
let state = data.state_mut::<E::State>(); let state = data.state_mut::<E::State>();
let input = data.take_current_input::<<E::State as UsesInput>::Input>(); let input = data.take_current_input::<<E::State as UsesInput>::Input>();
observers observers
@ -349,7 +349,7 @@ pub mod child_signal_handlers {
{ {
if data.is_valid() { if data.is_valid() {
let executor = data.executor_mut::<E>(); let executor = data.executor_mut::<E>();
let observers = executor.observers_mut(); let mut observers = executor.observers_mut();
let state = data.state_mut::<E::State>(); let state = data.state_mut::<E::State>();
let input = data.take_current_input::<<E::State as UsesInput>::Input>(); let input = data.take_current_input::<<E::State as UsesInput>::Input>();
observers observers

View File

@ -5,7 +5,10 @@ use core::{
time::Duration, time::Duration,
}; };
use libafl_bolts::{shmem::ShMemProvider, tuples::tuple_list}; use libafl_bolts::{
shmem::ShMemProvider,
tuples::{tuple_list, RefIndexable},
};
use nix::unistd::{fork, ForkResult}; use nix::unistd::{fork, ForkResult};
use super::super::hooks::ExecutorHooksTuple; use super::super::hooks::ExecutorHooksTuple;
@ -245,12 +248,12 @@ where
Z: UsesState<State = S>, Z: UsesState<State = S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers() self.inner.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut() self.inner.observers_mut()
} }
} }

View File

@ -15,6 +15,7 @@ pub use inprocess::InProcessExecutor;
pub use inprocess_fork::InProcessForkExecutor; pub use inprocess_fork::InProcessForkExecutor;
#[cfg(unix)] #[cfg(unix)]
use libafl_bolts::os::unix_signals::Signal; use libafl_bolts::os::unix_signals::Signal;
use libafl_bolts::tuples::RefIndexable;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub use shadow::ShadowExecutor; pub use shadow::ShadowExecutor;
pub use with_observers::WithObservers; pub use with_observers::WithObservers;
@ -110,10 +111,10 @@ libafl_bolts::impl_serdeany!(DiffExitKind);
/// Holds a tuple of Observers /// Holds a tuple of Observers
pub trait HasObservers: UsesObservers { pub trait HasObservers: UsesObservers {
/// Get the linked observers /// Get the linked observers
fn observers(&self) -> &Self::Observers; fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers>;
/// Get the linked observers (mutable) /// Get the linked observers (mutable)
fn observers_mut(&mut self) -> &mut Self::Observers; fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers>;
} }
/// An executor takes the given inputs, and runs the harness/target. /// An executor takes the given inputs, and runs the harness/target.

View File

@ -2,6 +2,8 @@
use core::fmt::{self, Debug, Formatter}; use core::fmt::{self, Debug, Formatter};
use libafl_bolts::tuples::RefIndexable;
use crate::{ use crate::{
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
observers::{ObserversTuple, UsesObservers}, observers::{ObserversTuple, UsesObservers},
@ -45,14 +47,14 @@ where
/// The shadow observers are not considered by the feedbacks and the manager, mutable /// The shadow observers are not considered by the feedbacks and the manager, mutable
#[inline] #[inline]
pub fn shadow_observers(&self) -> &SOT { pub fn shadow_observers(&self) -> RefIndexable<&SOT, SOT> {
&self.shadow_observers RefIndexable::from(&self.shadow_observers)
} }
/// The shadow observers are not considered by the feedbacks and the manager, mutable /// The shadow observers are not considered by the feedbacks and the manager, mutable
#[inline] #[inline]
pub fn shadow_observers_mut(&mut self) -> &mut SOT { pub fn shadow_observers_mut(&mut self) -> RefIndexable<&mut SOT, SOT> {
&mut self.shadow_observers RefIndexable::from(&mut self.shadow_observers)
} }
} }
@ -94,12 +96,12 @@ where
SOT: ObserversTuple<E::State>, SOT: ObserversTuple<E::State>,
{ {
#[inline] #[inline]
fn observers(&self) -> &Self::Observers { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.executor.observers() self.executor.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut Self::Observers { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.executor.observers_mut() self.executor.observers_mut()
} }
} }

View File

@ -2,6 +2,8 @@
use core::fmt::Debug; use core::fmt::Debug;
use libafl_bolts::tuples::RefIndexable;
use crate::{ use crate::{
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
observers::{ObserversTuple, UsesObservers}, observers::{ObserversTuple, UsesObservers},
@ -53,12 +55,12 @@ where
E: UsesState, E: UsesState,
OT: ObserversTuple<E::State>, OT: ObserversTuple<E::State>,
{ {
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
&self.observers RefIndexable::from(&self.observers)
} }
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
&mut self.observers RefIndexable::from(&mut self.observers)
} }
} }

View File

@ -6,7 +6,10 @@
use alloc::borrow::Cow; use alloc::borrow::Cow;
use core::{fmt::Debug, marker::PhantomData}; use core::{fmt::Debug, marker::PhantomData};
use libafl_bolts::Named; use libafl_bolts::{
tuples::{MatchNameRef, Reference, Referenceable},
Named,
};
use crate::{ use crate::{
corpus::Testcase, corpus::Testcase,
@ -24,30 +27,30 @@ use crate::{
/// to be not interesting. /// to be not interesting.
/// Requires a [`ConcolicObserver`] to observe the concolic trace. /// Requires a [`ConcolicObserver`] to observe the concolic trace.
#[derive(Debug)] #[derive(Debug)]
pub struct ConcolicFeedback<S> { pub struct ConcolicFeedback<'map, S> {
name: Cow<'static, str>, obs_ref: Reference<ConcolicObserver<'map>>,
phantom: PhantomData<S>, phantom: PhantomData<S>,
} }
impl<S> ConcolicFeedback<S> { impl<'map, S> ConcolicFeedback<'map, S> {
/// Creates a concolic feedback from an observer /// Creates a concolic feedback from an observer
#[allow(unused)] #[allow(unused)]
#[must_use] #[must_use]
pub fn from_observer(observer: &ConcolicObserver) -> Self { pub fn from_observer(observer: &ConcolicObserver<'map>) -> Self {
Self { Self {
name: observer.name().clone(), obs_ref: observer.reference(),
phantom: PhantomData, phantom: PhantomData,
} }
} }
} }
impl<S> Named for ConcolicFeedback<S> { impl<S> Named for ConcolicFeedback<'_, S> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name self.obs_ref.name()
} }
} }
impl<S> Feedback<S> for ConcolicFeedback<S> impl<S> Feedback<S> for ConcolicFeedback<'_, S>
where where
S: State, S: State,
{ {
@ -79,7 +82,7 @@ where
EM: EventFirer<State = S>, EM: EventFirer<State = S>,
{ {
if let Some(metadata) = observers if let Some(metadata) = observers
.match_name::<ConcolicObserver>(&self.name) .get(&self.obs_ref)
.map(ConcolicObserver::create_metadata_from_current_map) .map(ConcolicObserver::create_metadata_from_current_map)
{ {
testcase.metadata_map_mut().insert(metadata); testcase.metadata_map_mut().insert(metadata);

View File

@ -7,7 +7,10 @@ use core::{
marker::PhantomData, marker::PhantomData,
}; };
use libafl_bolts::{tuples::MatchName, Named}; use libafl_bolts::{
tuples::{MatchName, MatchNameRef, Reference, Referenceable},
Named,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -55,12 +58,12 @@ where
/// This feedback's name /// This feedback's name
name: Cow<'static, str>, name: Cow<'static, str>,
/// The first observer to compare against /// The first observer to compare against
o1_name: Cow<'static, str>, o1_ref: Reference<O1>,
/// The second observer to compare against /// The second observer to compare against
o2_name: Cow<'static, str>, o2_ref: Reference<O2>,
/// The function used to compare the two observers /// The function used to compare the two observers
compare_fn: F, compare_fn: F,
phantomm: PhantomData<(O1, O2, I, S)>, phantomm: PhantomData<(I, S)>,
} }
impl<F, I, O1, O2, S> DiffFeedback<F, I, O1, O2, S> impl<F, I, O1, O2, S> DiffFeedback<F, I, O1, O2, S>
@ -71,16 +74,17 @@ where
{ {
/// Create a new [`DiffFeedback`] using two observers and a test function. /// Create a new [`DiffFeedback`] using two observers and a test function.
pub fn new(name: &'static str, o1: &O1, o2: &O2, compare_fn: F) -> Result<Self, Error> { pub fn new(name: &'static str, o1: &O1, o2: &O2, compare_fn: F) -> Result<Self, Error> {
let o1_name = o1.name().clone(); let o1_ref = o1.reference();
let o2_name = o2.name().clone(); let o2_ref = o2.reference();
if o1_name == o2_name { if o1_ref.name() == o2_ref.name() {
Err(Error::illegal_argument(format!( Err(Error::illegal_argument(format!(
"DiffFeedback: observer names must be different (both were {o1_name})" "DiffFeedback: observer names must be different (both were {})",
o1_ref.name()
))) )))
} else { } else {
Ok(Self { Ok(Self {
o1_name, o1_ref,
o2_name, o2_ref,
name: Cow::from(name), name: Cow::from(name),
compare_fn, compare_fn,
phantomm: PhantomData, phantomm: PhantomData,
@ -101,8 +105,8 @@ where
fn create_feedback(&self, _ctx: &T) -> DiffFeedback<F, I, O1, O2, S> { fn create_feedback(&self, _ctx: &T) -> DiffFeedback<F, I, O1, O2, S> {
Self { Self {
name: self.name.clone(), name: self.name.clone(),
o1_name: self.o1_name.clone(), o1_ref: self.o1_ref.clone(),
o2_name: self.o2_name.clone(), o2_ref: self.o2_ref.clone(),
compare_fn: self.compare_fn.clone(), compare_fn: self.compare_fn.clone(),
phantomm: self.phantomm, phantomm: self.phantomm,
} }
@ -127,11 +131,11 @@ where
O2: Named, O2: Named,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!( f.debug_struct("DiffFeedback")
f, .field("name", self.name())
"DiffFeedback {{ name: {}, o1: {}, o2: {} }}", .field("o1", &self.o1_ref)
self.name, self.o1_name, self.o2_name .field("o2", &self.o2_ref)
) .finish_non_exhaustive()
} }
} }
@ -160,11 +164,11 @@ where
Error::illegal_argument(format!("DiffFeedback: observer {name} not found")) Error::illegal_argument(format!("DiffFeedback: observer {name} not found"))
} }
let o1: &O1 = observers let o1: &O1 = observers
.match_name(&self.o1_name) .get(&self.o1_ref)
.ok_or_else(|| err(&self.o1_name))?; .ok_or_else(|| err(self.o1_ref.name()))?;
let o2: &O2 = observers let o2: &O2 = observers
.match_name(&self.o2_name) .get(&self.o2_ref)
.ok_or_else(|| err(&self.o2_name))?; .ok_or_else(|| err(self.o2_ref.name()))?;
Ok((self.compare_fn)(o1, o2) == DiffResult::Diff) Ok((self.compare_fn)(o1, o2) == DiffResult::Diff)
} }

View File

@ -1,8 +1,11 @@
use alloc::borrow::Cow; use alloc::borrow::Cow;
use core::{fmt::Debug, hash::Hash, marker::PhantomData}; use core::{fmt::Debug, hash::Hash};
use hashbrown::HashSet; use hashbrown::HashSet;
use libafl_bolts::{Error, HasRefCnt, Named}; use libafl_bolts::{
tuples::{MatchNameRef, Reference, Referenceable},
Error, HasRefCnt, Named,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::{ use crate::{
@ -70,10 +73,8 @@ pub struct ListFeedback<T>
where where
T: Hash + Eq, T: Hash + Eq,
{ {
name: Cow<'static, str>, obs_ref: Reference<ListObserver<T>>,
observer_name: Cow<'static, str>,
novelty: HashSet<T>, novelty: HashSet<T>,
phantom: PhantomData<T>,
} }
libafl_bolts::impl_serdeany!( libafl_bolts::impl_serdeany!(
@ -88,7 +89,7 @@ where
{ {
fn init_state(&mut self, state: &mut S) -> Result<(), Error> { fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
// eprintln!("self.name {:#?}", &self.name); // eprintln!("self.name {:#?}", &self.name);
state.add_named_metadata(&self.name, ListFeedbackMetadata::<T>::default()); state.add_named_metadata(self.name(), ListFeedbackMetadata::<T>::default());
Ok(()) Ok(())
} }
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
@ -105,15 +106,13 @@ where
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
{ {
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
let observer = observers let observer = observers.get(&self.obs_ref).unwrap();
.match_name::<ListObserver<T>>(&self.observer_name)
.unwrap();
// TODO register the list content in a testcase metadata // TODO register the list content in a testcase metadata
self.novelty.clear(); self.novelty.clear();
// can't fail // can't fail
let history_set = state let history_set = state
.named_metadata_map_mut() .named_metadata_map_mut()
.get_mut::<ListFeedbackMetadata<T>>(&self.name) .get_mut::<ListFeedbackMetadata<T>>(self.name())
.unwrap(); .unwrap();
for v in observer.list() { for v in observer.list() {
if !history_set.set.contains(v) { if !history_set.set.contains(v) {
@ -136,7 +135,7 @@ where
{ {
let history_set = state let history_set = state
.named_metadata_map_mut() .named_metadata_map_mut()
.get_mut::<ListFeedbackMetadata<T>>(&self.name) .get_mut::<ListFeedbackMetadata<T>>(self.name())
.unwrap(); .unwrap();
for v in &self.novelty { for v in &self.novelty {
@ -152,7 +151,7 @@ where
{ {
#[inline] #[inline]
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name self.obs_ref.name()
} }
} }
@ -164,10 +163,8 @@ where
#[must_use] #[must_use]
pub fn new(observer: &ListObserver<T>) -> Self { pub fn new(observer: &ListObserver<T>) -> Self {
Self { Self {
name: observer.name().clone(), obs_ref: observer.reference(),
observer_name: observer.name().clone(),
novelty: HashSet::<T>::new(), novelty: HashSet::<T>::new(),
phantom: PhantomData,
} }
} }
} }

View File

@ -9,7 +9,10 @@ use core::{
ops::{BitAnd, BitOr}, ops::{BitAnd, BitOr},
}; };
use libafl_bolts::{AsIter, AsSlice, AsSliceMut, HasRefCnt, Named}; use libafl_bolts::{
tuples::{MatchNameRef, Reference, Referenceable},
AsIter, AsSlice, AsSliceMut, HasRefCnt, Named,
};
use num_traits::PrimInt; use num_traits::PrimInt;
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
@ -17,32 +20,31 @@ use crate::{
corpus::Testcase, corpus::Testcase,
events::{Event, EventFirer}, events::{Event, EventFirer},
executors::ExitKind, executors::ExitKind,
feedbacks::{Feedback, HasObserverName}, feedbacks::{Feedback, HasObserverReference},
inputs::UsesInput, inputs::UsesInput,
monitors::{AggregatorOps, UserStats, UserStatsValue}, monitors::{AggregatorOps, UserStats, UserStatsValue},
observers::{CanTrack, MapObserver, Observer, ObserversTuple, UsesObserver}, observers::{CanTrack, MapObserver, Observer, ObserversTuple},
state::State, state::State,
Error, HasMetadata, HasNamedMetadata, 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`)[`crate::observers::HitcountsMapObserver`]. /// 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>; pub type AflMapFeedback<C, O, T> = MapFeedback<C, DifferentIsNovel, O, OrReducer, T>;
/// A [`MapFeedback`] that strives to maximize the map contents. /// A [`MapFeedback`] that strives to maximize the map contents.
pub type MaxMapFeedback<C, O, S, T> = MapFeedback<C, DifferentIsNovel, O, MaxReducer, S, T>; pub type MaxMapFeedback<C, O, T> = MapFeedback<C, DifferentIsNovel, O, MaxReducer, T>;
/// A [`MapFeedback`] that strives to minimize the map contents. /// A [`MapFeedback`] that strives to minimize the map contents.
pub type MinMapFeedback<C, O, S, T> = MapFeedback<C, DifferentIsNovel, O, MinReducer, S, T>; pub type MinMapFeedback<C, O, T> = MapFeedback<C, DifferentIsNovel, O, MinReducer, T>;
/// A [`MapFeedback`] that always returns `true` for `is_interesting`. Useful for tracing all executions. /// A [`MapFeedback`] that always returns `true` for `is_interesting`. Useful for tracing all executions.
pub type AlwaysInterestingMapFeedback<C, O, S, T> = MapFeedback<C, AllIsNovel, O, NopReducer, S, T>; pub type AlwaysInterestingMapFeedback<C, O, T> = MapFeedback<C, AllIsNovel, O, NopReducer, T>;
/// A [`MapFeedback`] that strives to maximize the map contents, /// A [`MapFeedback`] that strives to maximize the map contents,
/// but only, if a value is larger than `pow2` of the previous. /// but only, if a value is larger than `pow2` of the previous.
pub type MaxMapPow2Feedback<C, O, S, T> = MapFeedback<C, NextPow2IsNovel, O, MaxReducer, S, T>; pub type MaxMapPow2Feedback<C, O, T> = MapFeedback<C, NextPow2IsNovel, O, MaxReducer, T>;
/// A [`MapFeedback`] that strives to maximize the map contents, /// A [`MapFeedback`] that strives to maximize the map contents,
/// but only, if a value is larger than `pow2` of the previous. /// but only, if a value is larger than `pow2` of the previous.
pub type MaxMapOneOrFilledFeedback<C, O, S, T> = pub type MaxMapOneOrFilledFeedback<C, O, T> = MapFeedback<C, OneOrFilledIsNovel, O, MaxReducer, T>;
MapFeedback<C, OneOrFilledIsNovel, O, MaxReducer, S, T>;
/// A `Reducer` function is used to aggregate values for the novelty search /// A `Reducer` function is used to aggregate values for the novelty search
pub trait Reducer<T>: 'static pub trait Reducer<T>: 'static
@ -380,35 +382,27 @@ where
/// The most common AFL-like feedback type /// The most common AFL-like feedback type
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MapFeedback<C, N, O, R, S, T> { pub struct MapFeedback<C, N, O, R, T> {
/// New indexes observed in the last observation /// New indexes observed in the last observation
novelties: Option<Vec<usize>>, novelties: Option<Vec<usize>>,
/// Name identifier of this instance /// Name identifier of this instance
name: Cow<'static, str>, name: Cow<'static, str>,
/// Name identifier of the observer /// Name identifier of the observer
observer_name: Cow<'static, str>, map_ref: Reference<C>,
/// Name of the feedback as shown in the `UserStats` /// Name of the feedback as shown in the `UserStats`
stats_name: Cow<'static, str>, stats_name: Cow<'static, str>,
/// Phantom Data of Reducer /// Phantom Data of Reducer
phantom: PhantomData<(C, N, O, R, S, T)>, phantom: PhantomData<(C, N, O, R, T)>,
} }
impl<C, N, O, R, S, T> UsesObserver<S> for MapFeedback<C, N, O, R, S, T> impl<C, N, O, R, S, T> Feedback<S> for MapFeedback<C, N, O, R, T>
where
S: UsesInput,
C: AsRef<O> + Observer<S>,
{
type Observer = C;
}
impl<C, N, O, R, S, T> Feedback<S> for MapFeedback<C, N, O, R, S, T>
where where
N: IsNovel<T>, N: IsNovel<T>,
O: MapObserver<Entry = T> + for<'it> AsIter<'it, Item = T>, O: MapObserver<Entry = T> + for<'it> AsIter<'it, Item = T>,
R: Reducer<T>, R: Reducer<T>,
S: State + HasNamedMetadata, S: State + HasNamedMetadata,
T: Default + Copy + Serialize + for<'de> Deserialize<'de> + PartialEq + Debug + 'static, T: Default + Copy + Serialize + for<'de> Deserialize<'de> + PartialEq + Debug + 'static,
C: CanTrack + AsRef<O>, C: CanTrack + AsRef<O> + Observer<S>,
{ {
fn init_state(&mut self, state: &mut S) -> Result<(), Error> { fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
// Initialize `MapFeedbackMetadata` with an empty vector and add it to the state. // Initialize `MapFeedbackMetadata` with an empty vector and add it to the state.
@ -464,10 +458,7 @@ where
let meta = MapNoveltiesMetadata::new(novelties); let meta = MapNoveltiesMetadata::new(novelties);
testcase.add_metadata(meta); testcase.add_metadata(meta);
} }
let observer = observers let observer = observers.get(&self.map_ref).unwrap().as_ref();
.match_name::<C>(&self.observer_name)
.unwrap()
.as_ref();
let initial = observer.initial(); let initial = observer.initial();
let map_state = state let map_state = state
.named_metadata_map_mut() .named_metadata_map_mut()
@ -546,12 +537,12 @@ where
/// Specialize for the common coverage map size, maximization of u8s /// Specialize for the common coverage map size, maximization of u8s
#[rustversion::nightly] #[rustversion::nightly]
impl<C, O, S> Feedback<S> for MapFeedback<C, DifferentIsNovel, O, MaxReducer, S, u8> impl<C, O, S> Feedback<S> for MapFeedback<C, DifferentIsNovel, O, MaxReducer, u8>
where where
O: MapObserver<Entry = u8> + AsSlice<Entry = u8>, O: MapObserver<Entry = u8> + AsSlice<Entry = u8>,
for<'it> O: AsIter<'it, Item = u8>, for<'it> O: AsIter<'it, Item = u8>,
S: State + HasNamedMetadata, S: State + HasNamedMetadata,
C: CanTrack + AsRef<O>, C: CanTrack + AsRef<O> + Observer<S>,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
#[allow(clippy::needless_range_loop)] #[allow(clippy::needless_range_loop)]
@ -572,10 +563,7 @@ where
let mut interesting = false; let mut interesting = false;
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
let observer = observers let observer = observers.get(&self.map_ref).unwrap().as_ref();
.match_name::<C>(&self.observer_name)
.unwrap()
.as_ref();
let map_state = state let map_state = state
.named_metadata_map_mut() .named_metadata_map_mut()
@ -666,21 +654,23 @@ where
} }
} }
impl<C, N, O, R, S, T> Named for MapFeedback<C, N, O, R, S, T> { impl<C, N, O, R, T> Named for MapFeedback<C, N, O, R, T> {
#[inline] #[inline]
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
} }
impl<C, N, O, R, S, T> HasObserverName for MapFeedback<C, N, O, R, S, T> impl<C, N, O, R, T> HasObserverReference for MapFeedback<C, N, O, R, T>
where where
O: Named, O: Named,
C: AsRef<O>, C: AsRef<O>,
{ {
type Observer = C;
#[inline] #[inline]
fn observer_name(&self) -> &Cow<'static, str> { fn observer_ref(&self) -> &Reference<C> {
&self.observer_name &self.map_ref
} }
} }
@ -693,24 +683,22 @@ fn create_stats_name(name: &Cow<'static, str>) -> Cow<'static, str> {
} }
} }
impl<C, N, O, R, S, T> MapFeedback<C, N, O, R, S, T> impl<C, N, O, R, T> MapFeedback<C, N, O, R, T>
where where
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
R: Reducer<T>, R: Reducer<T>,
O: MapObserver<Entry = T>, O: MapObserver<Entry = T>,
for<'it> O: AsIter<'it, Item = T>, for<'it> O: AsIter<'it, Item = T>,
N: IsNovel<T>, N: IsNovel<T>,
S: UsesInput + HasNamedMetadata, C: CanTrack + AsRef<O> + Named,
C: CanTrack + AsRef<O>,
{ {
/// Create new `MapFeedback` /// Create new `MapFeedback`
#[must_use] #[must_use]
pub fn new(map_observer: &C) -> Self { pub fn new(map_observer: &C) -> Self {
let map_observer = map_observer.as_ref();
Self { Self {
novelties: if C::NOVELTIES { Some(vec![]) } else { None }, novelties: if C::NOVELTIES { Some(vec![]) } else { None },
name: map_observer.name().clone(), name: map_observer.name().clone(),
observer_name: map_observer.name().clone(), map_ref: map_observer.reference(),
stats_name: create_stats_name(map_observer.name()), stats_name: create_stats_name(map_observer.name()),
phantom: PhantomData, phantom: PhantomData,
} }
@ -722,10 +710,9 @@ where
#[must_use] #[must_use]
pub fn with_name(name: &'static str, map_observer: &C) -> Self { pub fn with_name(name: &'static str, map_observer: &C) -> Self {
let name = Cow::from(name); let name = Cow::from(name);
let map_observer = map_observer.as_ref();
Self { Self {
novelties: if C::NOVELTIES { Some(vec![]) } else { None }, novelties: if C::NOVELTIES { Some(vec![]) } else { None },
observer_name: map_observer.name().clone(), map_ref: map_observer.reference(),
stats_name: create_stats_name(&name), stats_name: create_stats_name(&name),
name, name,
phantom: PhantomData, phantom: PhantomData,
@ -735,7 +722,7 @@ where
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
#[allow(clippy::needless_range_loop)] #[allow(clippy::needless_range_loop)]
#[allow(clippy::trivially_copy_pass_by_ref)] #[allow(clippy::trivially_copy_pass_by_ref)]
fn is_interesting_default<EM, OT>( fn is_interesting_default<EM, S, OT>(
&mut self, &mut self,
state: &mut S, state: &mut S,
_manager: &mut EM, _manager: &mut EM,
@ -746,13 +733,11 @@ where
where where
EM: EventFirer<State = S>, EM: EventFirer<State = S>,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
S: UsesInput + HasNamedMetadata,
{ {
let mut interesting = false; let mut interesting = false;
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
let observer = observers let observer = observers.get(&self.map_ref).unwrap().as_ref();
.match_name::<C>(&self.observer_name)
.unwrap()
.as_ref();
let map_state = state let map_state = state
.named_metadata_map_mut() .named_metadata_map_mut()

View File

@ -4,43 +4,27 @@
// TODO: make S of Feedback<S> an associated type when specialisation + AT is stable // TODO: make S of Feedback<S> an associated type when specialisation + AT is stable
pub mod map;
use alloc::borrow::Cow; use alloc::borrow::Cow;
pub use map::*;
pub mod differential;
pub use differential::DiffFeedback;
#[cfg(feature = "std")]
pub mod concolic;
#[cfg(feature = "std")]
pub use concolic::ConcolicFeedback;
#[cfg(feature = "std")]
pub mod new_hash_feedback;
#[cfg(feature = "std")]
pub use new_hash_feedback::NewHashFeedback;
#[cfg(feature = "std")]
pub use new_hash_feedback::NewHashFeedbackMetadata;
#[cfg(feature = "nautilus")]
pub mod nautilus;
#[cfg(feature = "std")]
pub mod stdio;
pub mod transferred;
/// The module for list feedback
pub mod list;
use core::{ use core::{
fmt::{self, Debug, Formatter}, fmt::{self, Debug, Formatter},
marker::PhantomData, marker::PhantomData,
}; };
use libafl_bolts::Named; #[cfg(feature = "std")]
pub use concolic::ConcolicFeedback;
pub use differential::DiffFeedback;
use libafl_bolts::{
tuples::{MatchNameRef, Reference, Referenceable},
Named,
};
pub use list::*; pub use list::*;
pub use map::*;
#[cfg(feature = "nautilus")] #[cfg(feature = "nautilus")]
pub use nautilus::*; pub use nautilus::*;
#[cfg(feature = "std")]
pub use new_hash_feedback::NewHashFeedback;
#[cfg(feature = "std")]
pub use new_hash_feedback::NewHashFeedbackMetadata;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -52,6 +36,22 @@ use crate::{
Error, Error,
}; };
pub mod map;
#[cfg(feature = "std")]
pub mod concolic;
pub mod differential;
#[cfg(feature = "nautilus")]
pub mod nautilus;
#[cfg(feature = "std")]
pub mod new_hash_feedback;
#[cfg(feature = "std")]
pub mod stdio;
pub mod transferred;
/// The module for list feedback
pub mod list;
/// Feedbacks evaluate the observers. /// Feedbacks evaluate the observers.
/// Basically, they reduce the information provided by an observer to a value, /// Basically, they reduce the information provided by an observer to a value,
/// indicating the "interestingness" of the last run. /// indicating the "interestingness" of the last run.
@ -138,9 +138,12 @@ where
} }
/// Has an associated observer name (mostly used to retrieve the observer with `MatchName` from an `ObserverTuple`) /// Has an associated observer name (mostly used to retrieve the observer with `MatchName` from an `ObserverTuple`)
pub trait HasObserverName { pub trait HasObserverReference {
/// The observer for which we hold a reference
type Observer: ?Sized;
/// The name associated with the observer /// The name associated with the observer
fn observer_name(&self) -> &Cow<'static, str>; fn observer_ref(&self) -> &Reference<Self::Observer>;
} }
/// A combined feedback consisting of multiple [`Feedback`]s /// A combined feedback consisting of multiple [`Feedback`]s
@ -931,7 +934,7 @@ pub type TimeoutFeedbackFactory = DefaultFeedbackFactory<TimeoutFeedback>;
/// It decides, if the given [`TimeObserver`] value of a run is interesting. /// It decides, if the given [`TimeObserver`] value of a run is interesting.
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TimeFeedback { pub struct TimeFeedback {
name: Cow<'static, str>, obs_ref: Reference<TimeObserver>,
} }
impl<S> Feedback<S> for TimeFeedback impl<S> Feedback<S> for TimeFeedback
@ -968,7 +971,7 @@ where
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
EM: EventFirer<State = S>, EM: EventFirer<State = S>,
{ {
let observer = observers.match_name::<TimeObserver>(self.name()).unwrap(); let observer = observers.get(&self.obs_ref).unwrap();
*testcase.exec_time_mut() = *observer.last_runtime(); *testcase.exec_time_mut() = *observer.last_runtime();
Ok(()) Ok(())
} }
@ -983,24 +986,16 @@ where
impl Named for TimeFeedback { impl Named for TimeFeedback {
#[inline] #[inline]
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name self.obs_ref.name()
} }
} }
impl TimeFeedback { impl TimeFeedback {
/// Creates a new [`TimeFeedback`], deciding if the value of a [`TimeObserver`] with the given `name` of a run is interesting.
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
name: Cow::from(name),
}
}
/// Creates a new [`TimeFeedback`], deciding if the given [`TimeObserver`] value of a run is interesting. /// Creates a new [`TimeFeedback`], deciding if the given [`TimeObserver`] value of a run is interesting.
#[must_use] #[must_use]
pub fn with_observer(observer: &TimeObserver) -> Self { pub fn new(observer: &TimeObserver) -> Self {
Self { Self {
name: observer.name().clone(), obs_ref: observer.reference(),
} }
} }
} }

View File

@ -4,13 +4,16 @@ use alloc::{borrow::Cow, string::ToString};
use std::{fmt::Debug, marker::PhantomData}; use std::{fmt::Debug, marker::PhantomData};
use hashbrown::HashSet; use hashbrown::HashSet;
use libafl_bolts::Named; use libafl_bolts::{
tuples::{MatchNameRef, Reference, Referenceable},
Named,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
events::EventFirer, events::EventFirer,
executors::ExitKind, executors::ExitKind,
feedbacks::{Feedback, HasObserverName}, feedbacks::{Feedback, HasObserverReference},
inputs::UsesInput, inputs::UsesInput,
observers::{ObserverWithHashField, ObserversTuple}, observers::{ObserverWithHashField, ObserversTuple},
state::State, state::State,
@ -79,10 +82,10 @@ impl HashSetState<u64> for NewHashFeedbackMetadata {
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct NewHashFeedback<O, S> { pub struct NewHashFeedback<O, S> {
name: Cow<'static, str>, name: Cow<'static, str>,
observer_name: Cow<'static, str>, o_ref: Reference<O>,
/// Initial capacity of hash set /// Initial capacity of hash set
capacity: usize, capacity: usize,
o_type: PhantomData<(O, S)>, phantom: PhantomData<S>,
} }
impl<O, S> Feedback<S> for NewHashFeedback<O, S> impl<O, S> Feedback<S> for NewHashFeedback<O, S>
@ -112,7 +115,7 @@ where
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
{ {
let observer = observers let observer = observers
.match_name::<O>(&self.observer_name) .get(&self.o_ref)
.expect("A NewHashFeedback needs a BacktraceObserver"); .expect("A NewHashFeedback needs a BacktraceObserver");
let backtrace_state = state let backtrace_state = state
@ -142,10 +145,12 @@ impl<O, S> Named for NewHashFeedback<O, S> {
} }
} }
impl<O, S> HasObserverName for NewHashFeedback<O, S> { impl<O, S> HasObserverReference for NewHashFeedback<O, S> {
type Observer = O;
#[inline] #[inline]
fn observer_name(&self) -> &Cow<'static, str> { fn observer_ref(&self) -> &Reference<O> {
&self.observer_name &self.o_ref
} }
} }
@ -171,9 +176,9 @@ where
pub fn with_capacity(observer: &O, capacity: usize) -> Self { pub fn with_capacity(observer: &O, capacity: usize) -> Self {
Self { Self {
name: Cow::from(NEWHASHFEEDBACK_PREFIX.to_string() + observer.name()), name: Cow::from(NEWHASHFEEDBACK_PREFIX.to_string() + observer.name()),
observer_name: observer.name().clone(), o_ref: observer.reference(),
capacity, capacity,
o_type: PhantomData, phantom: PhantomData,
} }
} }
} }

View File

@ -2,7 +2,11 @@
use alloc::{borrow::Cow, string::String}; use alloc::{borrow::Cow, string::String};
use libafl_bolts::{impl_serdeany, Named}; use libafl_bolts::{
impl_serdeany,
tuples::{MatchNameRef, Reference, Referenceable},
Named,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -28,7 +32,7 @@ impl_serdeany!(StdOutMetadata);
/// is never interesting (use with an OR). /// is never interesting (use with an OR).
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct StdOutToMetadataFeedback { pub struct StdOutToMetadataFeedback {
name: Cow<'static, str>, o_ref: Reference<StdOutObserver>,
} }
impl<S> Feedback<S> for StdOutToMetadataFeedback impl<S> Feedback<S> for StdOutToMetadataFeedback
@ -66,7 +70,7 @@ where
EM: EventFirer<State = S>, EM: EventFirer<State = S>,
{ {
let observer = observers let observer = observers
.match_name::<StdOutObserver>(self.name()) .get(&self.o_ref)
.ok_or(Error::illegal_state("StdOutObserver is missing"))?; .ok_or(Error::illegal_state("StdOutObserver is missing"))?;
let buffer = observer let buffer = observer
.stdout .stdout
@ -91,25 +95,16 @@ where
impl Named for StdOutToMetadataFeedback { impl Named for StdOutToMetadataFeedback {
#[inline] #[inline]
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name self.o_ref.name()
} }
} }
impl StdOutToMetadataFeedback { impl StdOutToMetadataFeedback {
/// Creates a new [`StdOutToMetadataFeedback`]. The provided `name` is
/// used to look up the observer.
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
name: Cow::from(name),
}
}
/// Creates a new [`StdOutToMetadataFeedback`]. /// Creates a new [`StdOutToMetadataFeedback`].
#[must_use] #[must_use]
pub fn with_observer(observer: &StdOutObserver) -> Self { pub fn new(observer: &StdOutObserver) -> Self {
Self { Self {
name: observer.name().clone(), o_ref: observer.reference(),
} }
} }
} }
@ -127,7 +122,7 @@ impl_serdeany!(StdErrMetadata);
/// is never interesting (use with an OR). /// is never interesting (use with an OR).
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct StdErrToMetadataFeedback { pub struct StdErrToMetadataFeedback {
name: Cow<'static, str>, o_ref: Reference<StdErrObserver>,
} }
impl<S> Feedback<S> for StdErrToMetadataFeedback impl<S> Feedback<S> for StdErrToMetadataFeedback
@ -165,7 +160,7 @@ where
EM: EventFirer<State = S>, EM: EventFirer<State = S>,
{ {
let observer = observers let observer = observers
.match_name::<StdErrObserver>(self.name()) .get(&self.o_ref)
.ok_or(Error::illegal_state("StdErrObserver is missing"))?; .ok_or(Error::illegal_state("StdErrObserver is missing"))?;
let buffer = observer let buffer = observer
.stderr .stderr
@ -190,25 +185,16 @@ where
impl Named for StdErrToMetadataFeedback { impl Named for StdErrToMetadataFeedback {
#[inline] #[inline]
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name self.o_ref.name()
} }
} }
impl StdErrToMetadataFeedback { impl StdErrToMetadataFeedback {
/// Creates a new [`StdErrToMetadataFeedback`]. The provided `name` is
/// used to look up the observer.
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
name: Cow::from(name),
}
}
/// Creates a new [`StdErrToMetadataFeedback`]. /// Creates a new [`StdErrToMetadataFeedback`].
#[must_use] #[must_use]
pub fn with_observer(observer: &StdErrObserver) -> Self { pub fn new(observer: &StdErrObserver) -> Self {
Self { Self {
name: observer.name().clone(), o_ref: observer.reference(),
} }
} }
} }

View File

@ -541,9 +541,9 @@ where
let exit_kind = self.execute_input(state, executor, manager, &input)?; let exit_kind = self.execute_input(state, executor, manager, &input)?;
let observers = executor.observers(); let observers = executor.observers();
self.scheduler.on_evaluation(state, &input, observers)?; self.scheduler.on_evaluation(state, &input, &*observers)?;
self.execute_and_process(state, manager, input, observers, &exit_kind, send_events) self.execute_and_process(state, manager, input, &*observers, &exit_kind, send_events)
} }
} }
@ -595,18 +595,22 @@ where
// Maybe a solution // Maybe a solution
#[cfg(not(feature = "introspection"))] #[cfg(not(feature = "introspection"))]
let is_solution = self let is_solution =
.objective_mut() self.objective_mut()
.is_interesting(state, manager, &input, observers, &exit_kind)?; .is_interesting(state, manager, &input, &*observers, &exit_kind)?;
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
let is_solution = self let is_solution = self.objective_mut().is_interesting_introspection(
.objective_mut() state,
.is_interesting_introspection(state, manager, &input, observers, &exit_kind)?; manager,
&input,
&*observers,
&exit_kind,
)?;
if is_solution { if is_solution {
self.objective_mut() self.objective_mut()
.append_metadata(state, manager, observers, &mut testcase)?; .append_metadata(state, manager, &*observers, &mut testcase)?;
let idx = state.solutions_mut().add(testcase)?; let idx = state.solutions_mut().add(testcase)?;
let executions = *state.executions(); let executions = *state.executions();
@ -627,25 +631,29 @@ where
// several is_interesting implementations collect some data about the run, later used in // several is_interesting implementations collect some data about the run, later used in
// append_metadata; we *must* invoke is_interesting here to collect it // append_metadata; we *must* invoke is_interesting here to collect it
#[cfg(not(feature = "introspection"))] #[cfg(not(feature = "introspection"))]
let _corpus_worthy = self let _corpus_worthy =
.feedback_mut() self.feedback_mut()
.is_interesting(state, manager, &input, observers, &exit_kind)?; .is_interesting(state, manager, &input, &*observers, &exit_kind)?;
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
let _corpus_worthy = self let _corpus_worthy = self.feedback_mut().is_interesting_introspection(
.feedback_mut() state,
.is_interesting_introspection(state, manager, &input, observers, &exit_kind)?; manager,
&input,
&*observers,
&exit_kind,
)?;
// Add the input to the main corpus // Add the input to the main corpus
self.feedback_mut() self.feedback_mut()
.append_metadata(state, manager, observers, &mut testcase)?; .append_metadata(state, manager, &*observers, &mut testcase)?;
let idx = state.corpus_mut().add(testcase)?; let idx = state.corpus_mut().add(testcase)?;
self.scheduler_mut().on_add(state, idx)?; self.scheduler_mut().on_add(state, idx)?;
let observers_buf = if manager.configuration() == EventConfig::AlwaysUnique { let observers_buf = if manager.configuration() == EventConfig::AlwaysUnique {
None None
} else { } else {
manager.serialize_observers::<OT>(observers)? manager.serialize_observers::<OT>(&*observers)?
}; };
manager.fire( manager.fire(
state, state,

View File

@ -8,12 +8,9 @@ use crate::{inputs::UsesInput, observers::Observer};
/// A simple observer with a list of things. /// A simple observer with a list of things.
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")] #[serde(bound = "T: serde::de::DeserializeOwned + serde::Serialize")]
#[allow(clippy::unsafe_derive_deserialize)] #[allow(clippy::unsafe_derive_deserialize)]
pub struct ListObserver<T> pub struct ListObserver<T> {
where
T: Debug + Serialize,
{
name: Cow<'static, str>, name: Cow<'static, str>,
/// The list /// The list
list: OwnedMutPtr<Vec<T>>, list: OwnedMutPtr<Vec<T>>,

View File

@ -38,15 +38,6 @@ pub use value::*;
use crate::{executors::ExitKind, inputs::UsesInput, state::UsesState, Error}; use crate::{executors::ExitKind, inputs::UsesInput, state::UsesState, Error};
/// Something that uses observer like mapfeedbacks
pub trait UsesObserver<S>
where
S: UsesInput,
{
/// The observer type used
type Observer: Observer<S>;
}
/// Observers observe different information about the target. /// Observers observe different information about the target.
/// They can then be used by various sorts of feedback. /// They can then be used by various sorts of feedback.
pub trait Observer<S>: Named pub trait Observer<S>: Named

View File

@ -27,7 +27,10 @@ pub mod weighted;
pub use weighted::{StdWeightedScheduler, WeightedScheduler}; pub use weighted::{StdWeightedScheduler, WeightedScheduler};
pub mod tuneable; pub mod tuneable;
use libafl_bolts::rands::Rand; use libafl_bolts::{
rands::Rand,
tuples::{MatchNameRef, Reference},
};
pub use tuneable::*; pub use tuneable::*;
use crate::{ use crate::{
@ -79,7 +82,7 @@ where
fn set_last_hash(&mut self, value: usize); fn set_last_hash(&mut self, value: usize);
/// Get the observer map observer name /// Get the observer map observer name
fn map_observer_name(&self) -> &str; fn map_observer_ref(&self) -> &Reference<C>;
/// Called when a [`Testcase`] is added to the corpus /// Called when a [`Testcase`] is added to the corpus
fn on_add_metadata(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> { fn on_add_metadata(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
@ -118,7 +121,7 @@ where
OT: ObserversTuple<Self::State>, OT: ObserversTuple<Self::State>,
{ {
let observer = observers let observer = observers
.match_name::<C>(self.map_observer_name()) .get(self.map_observer_ref())
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))? .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref(); .as_ref();

View File

@ -1,12 +1,12 @@
//! The queue corpus scheduler for power schedules. //! The queue corpus scheduler for power schedules.
use alloc::{ use alloc::vec::Vec;
string::{String, ToString},
vec::Vec,
};
use core::{marker::PhantomData, time::Duration}; use core::{marker::PhantomData, time::Duration};
use libafl_bolts::Named; use libafl_bolts::{
tuples::{Reference, Referenceable},
Named,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -173,9 +173,9 @@ pub enum PowerSchedule {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PowerQueueScheduler<C, O, S> { pub struct PowerQueueScheduler<C, O, S> {
strat: PowerSchedule, strat: PowerSchedule,
map_observer_name: String, map_observer_ref: Reference<C>,
last_hash: usize, last_hash: usize,
phantom: PhantomData<(C, O, S)>, phantom: PhantomData<(O, S)>,
} }
impl<C, O, S> UsesState for PowerQueueScheduler<C, O, S> impl<C, O, S> UsesState for PowerQueueScheduler<C, O, S>
@ -226,8 +226,8 @@ where
self.last_hash = hash; self.last_hash = hash;
} }
fn map_observer_name(&self) -> &str { fn map_observer_ref(&self) -> &Reference<C> {
&self.map_observer_name &self.map_observer_ref
} }
} }
@ -256,9 +256,9 @@ where
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> { fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
Err(Error::empty(String::from( Err(Error::empty(
"No entries in corpus. This often implies the target is not properly instrumented.", "No entries in corpus. This often implies the target is not properly instrumented.",
))) ))
} else { } else {
let id = match state.corpus().current() { let id = match state.corpus().current() {
Some(cur) => { Some(cur) => {
@ -305,7 +305,7 @@ where
} }
PowerQueueScheduler { PowerQueueScheduler {
strat, strat,
map_observer_name: map_observer.name().to_string(), map_observer_ref: map_observer.reference(),
last_hash: 0, last_hash: 0,
phantom: PhantomData, phantom: PhantomData,
} }

View File

@ -1,11 +1,14 @@
//! The queue corpus scheduler with weighted queue item selection [from AFL++](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. //! This queue corpus scheduler needs calibration stage.
use alloc::string::{String, ToString};
use core::marker::PhantomData; use core::marker::PhantomData;
use hashbrown::HashMap; use hashbrown::HashMap;
use libafl_bolts::{rands::Rand, Named}; use libafl_bolts::{
rands::Rand,
tuples::{Reference, Referenceable},
Named,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -95,9 +98,9 @@ libafl_bolts::impl_serdeany!(WeightedScheduleMetadata);
pub struct WeightedScheduler<C, F, O, S> { pub struct WeightedScheduler<C, F, O, S> {
table_invalidated: bool, table_invalidated: bool,
strat: Option<PowerSchedule>, strat: Option<PowerSchedule>,
map_observer_name: String, map_observer_ref: Reference<C>,
last_hash: usize, last_hash: usize,
phantom: PhantomData<(C, F, O, S)>, phantom: PhantomData<(F, O, S)>,
} }
impl<C, F, O, S> WeightedScheduler<C, F, O, S> impl<C, F, O, S> WeightedScheduler<C, F, O, S>
@ -121,7 +124,7 @@ where
Self { Self {
strat, strat,
map_observer_name: map_observer.name().to_string(), map_observer_ref: map_observer.reference(),
last_hash: 0, last_hash: 0,
table_invalidated: true, table_invalidated: true,
phantom: PhantomData, phantom: PhantomData,
@ -271,8 +274,8 @@ where
self.last_hash = hash; self.last_hash = hash;
} }
fn map_observer_name(&self) -> &str { fn map_observer_ref(&self) -> &Reference<C> {
&self.map_observer_name &self.map_observer_ref
} }
} }
@ -310,9 +313,9 @@ where
} }
let corpus_counts = state.corpus().count(); let corpus_counts = state.corpus().count();
if corpus_counts == 0 { if corpus_counts == 0 {
Err(Error::empty(String::from( Err(Error::empty(
"No entries in corpus. This often implies the target is not properly instrumented.", "No entries in corpus. This often implies the target is not properly instrumented.",
))) ))
} else { } else {
let s = random_corpus_id!(state.corpus(), state.rand_mut()); let s = random_corpus_id!(state.corpus(), state.rand_mut());

View File

@ -1,14 +1,10 @@
//! The calibration stage. The fuzzer measures the average exec time and the bitmap size. //! The calibration stage. The fuzzer measures the average exec time and the bitmap size.
use alloc::{ use alloc::{borrow::Cow, vec::Vec};
borrow::Cow,
string::{String, ToString},
vec::Vec,
};
use core::{fmt::Debug, marker::PhantomData, time::Duration}; use core::{fmt::Debug, marker::PhantomData, time::Duration};
use hashbrown::HashSet; use hashbrown::HashSet;
use libafl_bolts::{current_time, impl_serdeany, AsIter, Named}; use libafl_bolts::{current_time, impl_serdeany, tuples::Reference, AsIter, Named};
use num_traits::Bounded; use num_traits::Bounded;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -16,10 +12,11 @@ use crate::{
corpus::{Corpus, SchedulerTestcaseMetadata}, corpus::{Corpus, SchedulerTestcaseMetadata},
events::{Event, EventFirer, LogSeverity}, events::{Event, EventFirer, LogSeverity},
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
feedbacks::{map::MapFeedbackMetadata, HasObserverName}, feedbacks::{map::MapFeedbackMetadata, HasObserverReference},
fuzzer::Evaluator, fuzzer::Evaluator,
inputs::UsesInput,
monitors::{AggregatorOps, UserStats, UserStatsValue}, monitors::{AggregatorOps, UserStats, UserStatsValue},
observers::{MapObserver, ObserversTuple, UsesObserver}, observers::{MapObserver, ObserversTuple},
schedulers::powersched::SchedulerMetadata, schedulers::powersched::SchedulerMetadata,
stages::{ExecutionCountRestartHelper, Stage}, stages::{ExecutionCountRestartHelper, Stage},
state::{HasCorpus, HasCurrentTestcase, HasExecutions, State, UsesState}, state::{HasCorpus, HasCurrentTestcase, HasExecutions, State, UsesState},
@ -66,13 +63,13 @@ impl UnstableEntriesMetadata {
/// The calibration stage will measure the average exec time and the target's stability for this input. /// The calibration stage will measure the average exec time and the target's stability for this input.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct CalibrationStage<C, O, OT, S> { pub struct CalibrationStage<C, O, OT, S> {
map_observer_name: String, map_observer_ref: Reference<C>,
map_name: String, map_name: Cow<'static, str>,
stage_max: usize, stage_max: usize,
/// If we should track stability /// If we should track stability
track_stability: bool, track_stability: bool,
restart_helper: ExecutionCountRestartHelper, restart_helper: ExecutionCountRestartHelper,
phantom: PhantomData<(C, O, OT, S)>, phantom: PhantomData<(O, OT, S)>,
} }
const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1 const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1
@ -147,10 +144,7 @@ where
.observers_mut() .observers_mut()
.post_exec_all(state, &input, &exit_kind)?; .post_exec_all(state, &input, &exit_kind)?;
let map_first = &executor let map_first = &executor.observers()[&self.map_observer_ref]
.observers()
.match_name::<C>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref() .as_ref()
.to_vec(); .to_vec();
@ -191,10 +185,7 @@ where
.post_exec_all(state, &input, &exit_kind)?; .post_exec_all(state, &input, &exit_kind)?;
if self.track_stability { if self.track_stability {
let map = &executor let map = &executor.observers()[&self.map_observer_ref]
.observers()
.match_name::<C>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref() .as_ref()
.to_vec(); .to_vec();
@ -248,11 +239,8 @@ where
// If weighted scheduler or powerscheduler is used, update it // If weighted scheduler or powerscheduler is used, update it
if state.has_metadata::<SchedulerMetadata>() { if state.has_metadata::<SchedulerMetadata>() {
let map = executor let observers = executor.observers();
.observers() let map = observers[&self.map_observer_ref].as_ref();
.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(); let mut bitmap_size = map.count_bytes();
assert!(bitmap_size != 0); assert!(bitmap_size != 0);
@ -343,21 +331,20 @@ where
impl<C, O, OT, S> CalibrationStage<C, O, OT, S> impl<C, O, OT, S> CalibrationStage<C, O, OT, S>
where where
O: MapObserver, O: MapObserver,
for<'it> O: AsIter<'it, Item = O::Entry>,
C: AsRef<O>, C: AsRef<O>,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
S: HasCorpus + HasMetadata + HasNamedMetadata, S: UsesInput + HasNamedMetadata,
{ {
/// Create a new [`CalibrationStage`]. /// Create a new [`CalibrationStage`].
#[must_use] #[must_use]
pub fn new<F>(map_feedback: &F) -> Self pub fn new<F>(map_feedback: &F) -> Self
where where
F: HasObserverName + Named + UsesObserver<S, Observer = C>, F: HasObserverReference<Observer = C> + Named,
for<'it> O: AsIter<'it, Item = O::Entry>,
C: AsRef<O>,
{ {
Self { Self {
map_observer_name: map_feedback.observer_name().to_string(), map_observer_ref: map_feedback.observer_ref().clone(),
map_name: map_feedback.name().to_string(), map_name: map_feedback.name().clone(),
stage_max: CAL_STAGE_START, stage_max: CAL_STAGE_START,
track_stability: true, track_stability: true,
restart_helper: ExecutionCountRestartHelper::default(), restart_helper: ExecutionCountRestartHelper::default(),
@ -369,13 +356,11 @@ where
#[must_use] #[must_use]
pub fn ignore_stability<F>(map_feedback: &F) -> Self pub fn ignore_stability<F>(map_feedback: &F) -> Self
where where
F: HasObserverName + Named + UsesObserver<S, Observer = C>, F: HasObserverReference<Observer = C> + Named,
for<'it> O: AsIter<'it, Item = O::Entry>,
C: AsRef<O>,
{ {
Self { Self {
map_observer_name: map_feedback.observer_name().to_string(), map_observer_ref: map_feedback.observer_ref().clone(),
map_name: map_feedback.name().to_string(), map_name: map_feedback.name().clone(),
stage_max: CAL_STAGE_START, stage_max: CAL_STAGE_START,
track_stability: false, track_stability: false,
restart_helper: ExecutionCountRestartHelper::default(), restart_helper: ExecutionCountRestartHelper::default(),

View File

@ -1,8 +1,12 @@
//! The colorization stage from `colorization()` in afl++ //! The colorization stage from `colorization()` in afl++
use alloc::{borrow::Cow, collections::binary_heap::BinaryHeap, string::ToString, vec::Vec}; use alloc::{borrow::Cow, collections::binary_heap::BinaryHeap, vec::Vec};
use core::{cmp::Ordering, fmt::Debug, marker::PhantomData, ops::Range}; use core::{cmp::Ordering, fmt::Debug, marker::PhantomData, ops::Range};
use libafl_bolts::{rands::Rand, tuples::MatchName, Named}; use libafl_bolts::{
rands::Rand,
tuples::{Reference, Referenceable},
Named,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -51,9 +55,9 @@ impl Ord for Earlier {
/// The mutational stage using power schedules /// The mutational stage using power schedules
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ColorizationStage<C, E, EM, O, Z> { pub struct ColorizationStage<C, E, EM, O, Z> {
map_observer_name: Cow<'static, str>, map_observer_ref: Reference<C>,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(C, E, EM, O, E, Z)>, phantom: PhantomData<(E, EM, O, E, Z)>,
} }
impl<C, E, EM, O, Z> UsesState for ColorizationStage<C, E, EM, O, Z> impl<C, E, EM, O, Z> UsesState for ColorizationStage<C, E, EM, O, Z>
@ -68,7 +72,7 @@ where
E: UsesState, E: UsesState,
{ {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.map_observer_name self.map_observer_ref.name()
} }
} }
@ -92,7 +96,7 @@ where
manager: &mut EM, manager: &mut EM,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Run with the mutated input // Run with the mutated input
Self::colorize(fuzzer, executor, state, manager, &self.map_observer_name)?; Self::colorize(fuzzer, executor, state, manager, &self.map_observer_ref)?;
Ok(()) Ok(())
} }
@ -164,7 +168,7 @@ where
executor: &mut E, executor: &mut E,
state: &mut E::State, state: &mut E::State,
manager: &mut EM, manager: &mut EM,
name: &str, obs_ref: &Reference<C>,
) -> Result<E::Input, Error> { ) -> Result<E::Input, Error> {
let mut input = state.current_input_cloned()?; let mut input = state.current_input_cloned()?;
// The backup of the input // The backup of the input
@ -179,7 +183,7 @@ where
// Idea: No need to do this every time // Idea: No need to do this every time
let orig_hash = let orig_hash =
Self::get_raw_map_hash_run(fuzzer, executor, state, manager, consumed_input, name)?; Self::get_raw_map_hash_run(fuzzer, executor, state, manager, consumed_input, obs_ref)?;
let changed_bytes = changed.bytes_mut(); let changed_bytes = changed.bytes_mut();
let input_len = changed_bytes.len(); let input_len = changed_bytes.len();
@ -224,7 +228,7 @@ where
state, state,
manager, manager,
consumed_input, consumed_input,
name, obs_ref,
)?; )?;
if orig_hash == changed_hash { if orig_hash == changed_hash {
@ -297,7 +301,7 @@ where
/// Creates a new [`ColorizationStage`] /// Creates a new [`ColorizationStage`]
pub fn new(map_observer: &C) -> Self { pub fn new(map_observer: &C) -> Self {
Self { Self {
map_observer_name: map_observer.name().clone(), map_observer_ref: map_observer.reference(),
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -309,17 +313,14 @@ where
state: &mut E::State, state: &mut E::State,
manager: &mut EM, manager: &mut EM,
input: E::Input, input: E::Input,
name: &str, obs_ref: &Reference<C>,
) -> Result<usize, Error> { ) -> Result<usize, Error> {
executor.observers_mut().pre_exec_all(state, &input)?; executor.observers_mut().pre_exec_all(state, &input)?;
let exit_kind = executor.run_target(fuzzer, state, manager, &input)?; let exit_kind = executor.run_target(fuzzer, state, manager, &input)?;
let observer = executor let observers = executor.observers();
.observers() let observer = observers[obs_ref].as_ref();
.match_name::<C>(name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref();
let hash = observer.hash_simple() as usize; let hash = observer.hash_simple() as usize;

View File

@ -2,13 +2,16 @@
//! and use the results for fuzzer input and mutations. //! and use the results for fuzzer input and mutations.
//! //!
use alloc::{borrow::Cow, string::String}; use alloc::borrow::Cow;
#[cfg(feature = "concolic_mutation")] #[cfg(feature = "concolic_mutation")]
use alloc::{string::ToString, vec::Vec}; use alloc::{string::ToString, vec::Vec};
#[cfg(feature = "concolic_mutation")] #[cfg(feature = "concolic_mutation")]
use core::marker::PhantomData; use core::marker::PhantomData;
use libafl_bolts::{tuples::MatchName, Named}; use libafl_bolts::{
tuples::{MatchNameRef, Reference},
Named,
};
#[cfg(all(feature = "concolic_mutation", feature = "introspection"))] #[cfg(all(feature = "concolic_mutation", feature = "introspection"))]
use crate::monitors::PerfFeature; use crate::monitors::PerfFeature;
@ -34,26 +37,26 @@ use crate::{
/// Wraps a [`TracingStage`] to add concolic observing. /// Wraps a [`TracingStage`] to add concolic observing.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ConcolicTracingStage<EM, TE, Z> { pub struct ConcolicTracingStage<'a, EM, TE, Z> {
inner: TracingStage<EM, TE, Z>, inner: TracingStage<EM, TE, Z>,
observer_name: String, obs_ref: Reference<ConcolicObserver<'a>>,
} }
impl<EM, TE, Z> UsesState for ConcolicTracingStage<EM, TE, Z> impl<EM, TE, Z> UsesState for ConcolicTracingStage<'_, EM, TE, Z>
where where
TE: UsesState, TE: UsesState,
{ {
type State = TE::State; type State = TE::State;
} }
impl<EM, TE, Z> Named for ConcolicTracingStage<EM, TE, Z> { impl<EM, TE, Z> Named for ConcolicTracingStage<'_, EM, TE, Z> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("ConcolicTracingStage"); static NAME: Cow<'static, str> = Cow::Borrowed("ConcolicTracingStage");
&NAME &NAME
} }
} }
impl<E, EM, TE, Z> Stage<E, EM, Z> for ConcolicTracingStage<EM, TE, Z> impl<E, EM, TE, Z> Stage<E, EM, Z> for ConcolicTracingStage<'_, EM, TE, Z>
where where
E: UsesState<State = TE::State>, E: UsesState<State = TE::State>,
EM: UsesState<State = TE::State>, EM: UsesState<State = TE::State>,
@ -70,12 +73,7 @@ where
manager: &mut EM, manager: &mut EM,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.inner.trace(fuzzer, state, manager)?; self.inner.trace(fuzzer, state, manager)?;
if let Some(observer) = self if let Some(observer) = self.inner.executor().observers().get(&self.obs_ref) {
.inner
.executor()
.observers()
.match_name::<ConcolicObserver>(&self.observer_name)
{
let metadata = observer.create_metadata_from_current_map(); let metadata = observer.create_metadata_from_current_map();
state state
.current_testcase_mut()? .current_testcase_mut()?
@ -94,14 +92,11 @@ where
} }
} }
impl<EM, TE, Z> ConcolicTracingStage<EM, TE, Z> { impl<'a, EM, TE, Z> ConcolicTracingStage<'a, EM, TE, Z> {
/// Creates a new default tracing stage using the given [`Executor`], observing traces from a /// Creates a new default tracing stage using the given [`Executor`], observing traces from a
/// [`ConcolicObserver`] with the given name. /// [`ConcolicObserver`] with the given name.
pub fn new(inner: TracingStage<EM, TE, Z>, observer_name: String) -> Self { pub fn new(inner: TracingStage<EM, TE, Z>, obs_ref: Reference<ConcolicObserver<'a>>) -> Self {
Self { Self { inner, obs_ref }
inner,
observer_name,
}
} }
} }

View File

@ -1,13 +1,12 @@
//! The tracing stage can trace the target and enrich a [`crate::corpus::Testcase`] with metadata, for example for `CmpLog`. //! The tracing stage can trace the target and enrich a [`crate::corpus::Testcase`] with metadata, for example for `CmpLog`.
use alloc::{ use alloc::{borrow::Cow, vec::Vec};
borrow::Cow,
string::{String, ToString},
vec::Vec,
};
use core::{fmt::Debug, marker::PhantomData}; use core::{fmt::Debug, marker::PhantomData};
use libafl_bolts::{AsSlice, Named}; use libafl_bolts::{
tuples::{Reference, Referenceable},
AsSlice, Named,
};
use crate::{ use crate::{
corpus::{Corpus, HasCurrentCorpusIdx}, corpus::{Corpus, HasCurrentCorpusIdx},
@ -44,9 +43,9 @@ fn find_next_char(list: &[Option<u8>], mut idx: usize, ch: u8) -> usize {
/// A stage that runs a tracer executor /// A stage that runs a tracer executor
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct GeneralizationStage<C, EM, O, OT, Z> { pub struct GeneralizationStage<C, EM, O, OT, Z> {
map_observer_name: String, map_observer_ref: Reference<C>,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(C, EM, O, OT, Z)>, phantom: PhantomData<(EM, O, OT, Z)>,
} }
impl<C, EM, O, OT, Z> Named for GeneralizationStage<C, EM, O, OT, Z> { impl<C, EM, O, OT, Z> Named for GeneralizationStage<C, EM, O, OT, Z> {
@ -67,7 +66,7 @@ where
impl<C, E, EM, O, Z> Stage<E, EM, Z> for GeneralizationStage<C, EM, O, E::Observers, Z> impl<C, E, EM, O, Z> Stage<E, EM, Z> for GeneralizationStage<C, EM, O, E::Observers, Z>
where where
O: MapObserver, O: MapObserver,
C: CanTrack + AsRef<O>, C: CanTrack + AsRef<O> + Named,
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
E::Observers: ObserversTuple<E::State>, E::Observers: ObserversTuple<E::State>,
E::State: E::State:
@ -339,7 +338,7 @@ impl<C, EM, O, OT, Z> GeneralizationStage<C, EM, O, OT, Z>
where where
EM: UsesState, EM: UsesState,
O: MapObserver, O: MapObserver,
C: CanTrack + AsRef<O>, C: CanTrack + AsRef<O> + Named,
OT: ObserversTuple<EM::State>, OT: ObserversTuple<EM::State>,
EM::State: UsesInput<Input = BytesInput> + HasExecutions + HasMetadata + HasCorpus, EM::State: UsesInput<Input = BytesInput> + HasExecutions + HasMetadata + HasCorpus,
{ {
@ -348,16 +347,7 @@ where
pub fn new(map_observer: &C) -> Self { pub fn new(map_observer: &C) -> Self {
require_novelties_tracking!("GeneralizationStage", C); require_novelties_tracking!("GeneralizationStage", C);
Self { Self {
map_observer_name: map_observer.as_ref().name().to_string(), map_observer_ref: map_observer.reference(),
phantom: PhantomData,
}
}
/// Create a new [`GeneralizationStage`] from name
#[must_use]
pub fn from_name(map_observer_name: &str) -> Self {
Self {
map_observer_name: map_observer_name.to_string(),
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -391,10 +381,7 @@ where
.post_exec_all(state, input, &exit_kind)?; .post_exec_all(state, input, &exit_kind)?;
mark_feature_time!(state, PerfFeature::PostExecObservers); mark_feature_time!(state, PerfFeature::PostExecObservers);
let cnt = executor let cnt = executor.observers()[&self.map_observer_ref]
.observers()
.match_name::<C>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref() .as_ref()
.how_many_set(novelties); .how_many_set(novelties);

View File

@ -429,11 +429,12 @@ where
push_stage.set_current_corpus_idx(corpus_idx); push_stage.set_current_corpus_idx(corpus_idx);
push_stage.init(fuzzer, state, event_mgr, executor.observers_mut())?; push_stage.init(fuzzer, state, event_mgr, &mut *executor.observers_mut())?;
loop { loop {
let input = let input =
match push_stage.pre_exec(fuzzer, state, event_mgr, executor.observers_mut()) { match push_stage.pre_exec(fuzzer, state, event_mgr, &mut *executor.observers_mut())
{
Some(Ok(next_input)) => next_input, Some(Ok(next_input)) => next_input,
Some(Err(err)) => return Err(err), Some(Err(err)) => return Err(err),
None => break, None => break,
@ -445,14 +446,14 @@ where
fuzzer, fuzzer,
state, state,
event_mgr, event_mgr,
executor.observers_mut(), &mut *executor.observers_mut(),
input, input,
exit_kind, exit_kind,
)?; )?;
} }
self.push_stage self.push_stage
.deinit(fuzzer, state, event_mgr, executor.observers_mut()) .deinit(fuzzer, state, event_mgr, &mut *executor.observers_mut())
} }
#[inline] #[inline]

View File

@ -4,13 +4,16 @@ use alloc::borrow::Cow;
use core::{borrow::BorrowMut, fmt::Debug, hash::Hash, marker::PhantomData}; use core::{borrow::BorrowMut, fmt::Debug, hash::Hash, marker::PhantomData};
use ahash::RandomState; use ahash::RandomState;
use libafl_bolts::{HasLen, Named}; use libafl_bolts::{
tuples::{MatchNameRef, Reference, Referenceable},
HasLen, Named,
};
use crate::{ use crate::{
corpus::{Corpus, HasCurrentCorpusIdx, Testcase}, corpus::{Corpus, HasCurrentCorpusIdx, Testcase},
events::EventFirer, events::EventFirer,
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
feedbacks::{Feedback, FeedbackFactory, HasObserverName}, feedbacks::{Feedback, FeedbackFactory, HasObserverReference},
inputs::UsesInput, inputs::UsesInput,
mark_feature_time, mark_feature_time,
mutators::{MutationResult, Mutator}, mutators::{MutationResult, Mutator},
@ -91,7 +94,7 @@ where
fuzzer.execute_input(state, executor, manager, &base)?; fuzzer.execute_input(state, executor, manager, &base)?;
let observers = executor.observers(); let observers = executor.observers();
let mut feedback = self.create_feedback(observers); let mut feedback = self.create_feedback(&*observers);
let mut i = 0; let mut i = 0;
loop { loop {
@ -130,7 +133,7 @@ where
state, state,
manager, manager,
input.clone(), input.clone(),
observers, &*observers,
&exit_kind, &exit_kind,
false, false,
)?; )?;
@ -139,7 +142,7 @@ where
&& state.solutions().count() == solution_count && state.solutions().count() == solution_count
{ {
// we do not care about interesting inputs! // we do not care about interesting inputs!
if feedback.is_interesting(state, manager, &input, observers, &exit_kind)? { if feedback.is_interesting(state, manager, &input, &*observers, &exit_kind)? {
// we found a reduced corpus entry! use the smaller base // we found a reduced corpus entry! use the smaller base
base = input; base = input;
base_post = Some(post.clone()); base_post = Some(post.clone());
@ -172,11 +175,11 @@ where
// marked as interesting above; similarly, it should not trigger objectives // marked as interesting above; similarly, it should not trigger objectives
fuzzer fuzzer
.feedback_mut() .feedback_mut()
.is_interesting(state, manager, &base, observers, &exit_kind)?; .is_interesting(state, manager, &base, &*observers, &exit_kind)?;
let mut testcase = Testcase::with_executions(base, *state.executions()); let mut testcase = Testcase::with_executions(base, *state.executions());
fuzzer fuzzer
.feedback_mut() .feedback_mut()
.append_metadata(state, manager, observers, &mut testcase)?; .append_metadata(state, manager, &*observers, &mut testcase)?;
let prev = state.corpus_mut().replace(base_corpus_idx, testcase)?; let prev = state.corpus_mut().replace(base_corpus_idx, testcase)?;
fuzzer fuzzer
.scheduler_mut() .scheduler_mut()
@ -245,6 +248,14 @@ where
IP: MutatedTransformPost<CS::State> + Clone, IP: MutatedTransformPost<CS::State> + Clone,
I: MutatedTransform<CS::Input, CS::State, Post = IP> + Clone, I: MutatedTransform<CS::Input, CS::State, Post = IP> + Clone,
{ {
fn restart_progress_should_run(&mut self, state: &mut Self::State) -> Result<bool, Error> {
self.restart_helper.restart_progress_should_run(state)
}
fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
self.restart_helper.clear_restart_progress(state)
}
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
@ -259,14 +270,6 @@ where
Ok(()) Ok(())
} }
fn restart_progress_should_run(&mut self, state: &mut Self::State) -> Result<bool, Error> {
self.restart_helper.restart_progress_should_run(state)
}
fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
self.restart_helper.clear_restart_progress(state)
}
} }
impl<CS, E, EM, F1, F2, FF, I, IP, M, OT, Z> FeedbackFactory<F2, Z::State, OT> impl<CS, E, EM, F1, F2, FF, I, IP, M, OT, Z> FeedbackFactory<F2, Z::State, OT>
@ -348,28 +351,31 @@ where
/// A feedback which checks if the hash of the currently observed map is equal to the original hash /// A feedback which checks if the hash of the currently observed map is equal to the original hash
/// provided /// provided
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MapEqualityFeedback<M, S> { pub struct MapEqualityFeedback<C, M, S> {
name: Cow<'static, str>, name: Cow<'static, str>,
obs_name: Cow<'static, str>, map_ref: Reference<C>,
orig_hash: u64, orig_hash: u64,
phantom: PhantomData<(M, S)>, phantom: PhantomData<(M, S)>,
} }
impl<M, S> Named for MapEqualityFeedback<M, S> { impl<C, M, S> Named for MapEqualityFeedback<C, M, S> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
} }
impl<M, S> HasObserverName for MapEqualityFeedback<M, S> { impl<C, M, S> HasObserverReference for MapEqualityFeedback<C, M, S> {
fn observer_name(&self) -> &Cow<'static, str> { type Observer = C;
&self.obs_name
fn observer_ref(&self) -> &Reference<Self::Observer> {
&self.map_ref
} }
} }
impl<M, S> Feedback<S> for MapEqualityFeedback<M, S> impl<C, M, S> Feedback<S> for MapEqualityFeedback<C, M, S>
where where
M: MapObserver, M: MapObserver,
C: AsRef<M>,
S: State, S: State,
{ {
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
@ -385,52 +391,57 @@ where
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
{ {
let obs = observers let obs = observers
.match_name::<M>(self.observer_name()) .get(self.observer_ref())
.expect("Should have been provided valid observer name."); .expect("Should have been provided valid observer name.");
Ok(obs.hash_simple() == self.orig_hash) Ok(obs.as_ref().hash_simple() == self.orig_hash)
} }
} }
/// A feedback factory for ensuring that the maps for minimized inputs are the same /// A feedback factory for ensuring that the maps for minimized inputs are the same
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct MapEqualityFactory<M, S> { pub struct MapEqualityFactory<C, M, S> {
obs_name: Cow<'static, str>, map_ref: Reference<C>,
phantom: PhantomData<(M, S)>, phantom: PhantomData<(C, M, S)>,
} }
impl<M, S> MapEqualityFactory<M, S> impl<C, M, S> MapEqualityFactory<C, M, S>
where where
M: MapObserver, M: MapObserver,
C: AsRef<M> + Referenceable,
{ {
/// Creates a new map equality feedback for the given observer /// Creates a new map equality feedback for the given observer
pub fn with_observer(obs: &M) -> Self { pub fn new(obs: &C) -> Self {
Self { Self {
obs_name: obs.name().clone(), map_ref: obs.reference(),
phantom: PhantomData, phantom: PhantomData,
} }
} }
} }
impl<M, S> HasObserverName for MapEqualityFactory<M, S> { impl<C, M, S> HasObserverReference for MapEqualityFactory<C, M, S> {
fn observer_name(&self) -> &Cow<'static, str> { type Observer = C;
&self.obs_name
fn observer_ref(&self) -> &Reference<C> {
&self.map_ref
} }
} }
impl<M, OT, S> FeedbackFactory<MapEqualityFeedback<M, S>, S, OT> for MapEqualityFactory<M, S> impl<C, M, OT, S> FeedbackFactory<MapEqualityFeedback<C, M, S>, S, OT>
for MapEqualityFactory<C, M, S>
where where
M: MapObserver, M: MapObserver,
C: AsRef<M> + Referenceable,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
S: State + Debug, S: State + Debug,
{ {
fn create_feedback(&self, observers: &OT) -> MapEqualityFeedback<M, S> { fn create_feedback(&self, observers: &OT) -> MapEqualityFeedback<C, M, S> {
let obs = observers let obs = observers
.match_name::<M>(self.observer_name()) .get(self.observer_ref())
.expect("Should have been provided valid observer name."); .expect("Should have been provided valid observer name.");
MapEqualityFeedback { MapEqualityFeedback {
name: Cow::from("MapEq"), name: Cow::from("MapEq"),
obs_name: self.obs_name.clone(), map_ref: obs.reference(),
orig_hash: obs.hash_simple(), orig_hash: obs.as_ref().hash_simple(),
phantom: PhantomData, phantom: PhantomData,
} }
} }

View File

@ -51,6 +51,7 @@ pub fn read_time_counter() -> u64 {
v v
} }
/// Read a timestamp for measurements
#[cfg(target_arch = "arm")] #[cfg(target_arch = "arm")]
#[must_use] #[must_use]
pub fn read_time_counter() -> u64 { pub fn read_time_counter() -> u64 {

View File

@ -2,15 +2,19 @@
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use alloc::{borrow::Cow, vec::Vec}; use alloc::{borrow::Cow, vec::Vec};
#[rustversion::not(nightly)] #[cfg(feature = "alloc")]
use core::any::type_name; use core::ops::{Deref, DerefMut};
use core::{ use core::{
any::TypeId, any::{type_name, TypeId},
fmt::{Debug, Formatter},
marker::PhantomData, marker::PhantomData,
mem::transmute, mem::transmute,
ops::{Index, IndexMut},
ptr::{addr_of, addr_of_mut}, ptr::{addr_of, addr_of_mut},
}; };
#[cfg(feature = "alloc")]
use serde::{Deserialize, Serialize};
pub use tuple_list::{tuple_list, tuple_list_type, TupleList}; pub use tuple_list::{tuple_list, tuple_list_type, TupleList};
#[cfg(any(feature = "xxh3", feature = "alloc"))] #[cfg(any(feature = "xxh3", feature = "alloc"))]
@ -219,9 +223,9 @@ where
/// Returns the first element with the given type /// Returns the first element with the given type
pub trait MatchFirstType { pub trait MatchFirstType {
/// Returns the first element with the given type as borrow, or [`Option::None`] /// Returns the first element with the given type as borrow, or [`None`]
fn match_first_type<T: 'static>(&self) -> Option<&T>; fn match_first_type<T: 'static>(&self) -> Option<&T>;
/// Returns the first element with the given type as mutable borrow, or [`Option::None`] /// Returns the first element with the given type as mutable borrow, or [`None`]
fn match_first_type_mut<T: 'static>(&mut self) -> Option<&mut T>; fn match_first_type_mut<T: 'static>(&mut self) -> Option<&mut T>;
} }
@ -258,7 +262,7 @@ where
/// Returns the first element with the given type (dereference mut version) /// Returns the first element with the given type (dereference mut version)
pub trait ExtractFirstRefType { pub trait ExtractFirstRefType {
/// Returns the first element with the given type as borrow, or [`Option::None`] /// Returns the first element with the given type as borrow, or [`None`]
fn take<'a, T: 'static>(self) -> (Option<&'a T>, Self); fn take<'a, T: 'static>(self) -> (Option<&'a T>, Self);
} }
@ -305,7 +309,7 @@ where
/// Returns the first element with the given type (dereference mut version) /// Returns the first element with the given type (dereference mut version)
pub trait ExtractFirstRefMutType { pub trait ExtractFirstRefMutType {
/// Returns the first element with the given type as borrow, or [`Option::None`] /// Returns the first element with the given type as borrow, or [`None`]
fn take<'a, T: 'static>(self) -> (Option<&'a mut T>, Self); fn take<'a, T: 'static>(self) -> (Option<&'a mut T>, Self);
} }
@ -456,8 +460,10 @@ where
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub trait MatchName { pub trait MatchName {
/// Match for a name and return the borrowed value /// Match for a name and return the borrowed value
#[deprecated = "Use `.reference` and either `.get` (fallible access) or `[]` (infallible access) instead"]
fn match_name<T>(&self, name: &str) -> Option<&T>; fn match_name<T>(&self, name: &str) -> Option<&T>;
/// Match for a name and return the mut borrowed value /// Match for a name and return the mut borrowed value
#[deprecated = "Use `.reference` and either `.get` (fallible access) or `[]` (infallible access) instead"]
fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T>; fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T>;
} }
@ -472,6 +478,7 @@ impl MatchName for () {
} }
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[allow(deprecated)]
impl<Head, Tail> MatchName for (Head, Tail) impl<Head, Tail> MatchName for (Head, Tail)
where where
Head: Named, Head: Named,
@ -494,56 +501,12 @@ where
} }
} }
/// Finds an element of a `type` by the given `name`.
#[cfg(feature = "alloc")]
pub trait MatchNameAndType {
/// Finds an element of a `type` by the given `name`, and returns a borrow, or [`Option::None`].
fn match_name_type<T: 'static>(&self, name: &str) -> Option<&T>;
/// Finds an element of a `type` by the given `name`, and returns a mut borrow, or [`Option::None`].
fn match_name_type_mut<T: 'static>(&mut self, name: &str) -> Option<&mut T>;
}
#[cfg(feature = "alloc")]
impl MatchNameAndType for () {
fn match_name_type<T: 'static>(&self, _name: &str) -> Option<&T> {
None
}
fn match_name_type_mut<T: 'static>(&mut self, _name: &str) -> Option<&mut T> {
None
}
}
#[cfg(feature = "alloc")]
impl<Head, Tail> MatchNameAndType for (Head, Tail)
where
Head: 'static + Named,
Tail: MatchNameAndType,
{
fn match_name_type<T: 'static>(&self, name: &str) -> Option<&T> {
// Switch this check to https://stackoverflow.com/a/60138532/7658998 when in stable and remove 'static
if TypeId::of::<T>() == TypeId::of::<Head>() && name == self.0.name() {
unsafe { (addr_of!(self.0) as *const T).as_ref() }
} else {
self.1.match_name_type::<T>(name)
}
}
fn match_name_type_mut<T: 'static>(&mut self, name: &str) -> Option<&mut T> {
// Switch this check to https://stackoverflow.com/a/60138532/7658998 when in stable and remove 'static
if TypeId::of::<T>() == TypeId::of::<Head>() && name == self.0.name() {
unsafe { (addr_of_mut!(self.0) as *mut T).as_mut() }
} else {
self.1.match_name_type_mut::<T>(name)
}
}
}
/// Structs that has `Reference ` /// Structs that has `Reference `
/// You should use this when you want to avoid specifying types using `match_name_type_mut` /// You should use this when you want to avoid specifying types using `match_name_type_mut`
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub trait Referenceable: Named { pub trait Referenceable: Named {
/// Return the `Reference ` /// Return the `Reference `
fn type_ref(&self) -> Reference<Self> { fn reference(&self) -> Reference<Self> {
Reference { Reference {
name: Named::name(self).clone(), name: Named::name(self).clone(),
phantom: PhantomData, phantom: PhantomData,
@ -554,38 +517,141 @@ pub trait Referenceable: Named {
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
impl<N> Referenceable for N where N: Named {} impl<N> Referenceable for N where N: Named {}
/// Empty object with the type T /// Object with the type T and the name associated with its concrete value
#[derive(Debug)] #[derive(Serialize, Deserialize)]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub struct Reference<T: ?Sized> { pub struct Reference<T: ?Sized> {
name: Cow<'static, str>, name: Cow<'static, str>,
#[serde(skip)]
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
#[cfg(feature = "alloc")]
impl<T: ?Sized> Reference<T> {
/// Fetch the name of the referenced instance.
///
/// We explicitly do *not* implement [`Named`], as this could potentially lead to confusion
/// where we make a [`Reference`] of a [`Reference`] as [`Named`] is blanket implemented.
#[must_use]
pub fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
#[cfg(feature = "alloc")]
impl<T> Clone for Reference<T> {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
phantom: PhantomData,
}
}
}
#[cfg(feature = "alloc")]
impl<T> Debug for Reference<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Reference")
.field("name", self.name())
.field("type", &type_name::<T>())
.finish()
}
}
/// Search using `Reference ` /// Search using `Reference `
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub trait MatchNameRef { pub trait MatchNameRef {
/// Search using name and `Reference ` /// Search using name and `Reference `
fn match_by_ref<T>(&self, rf: Reference<T>) -> Option<&T>; fn get<T>(&self, rf: &Reference<T>) -> Option<&T>;
/// Search using name and `Reference ` /// Search using name and `Reference `
fn match_by_ref_mut<T>(&mut self, rf: Reference<T>) -> Option<&mut T>; fn get_mut<T>(&mut self, rf: &Reference<T>) -> Option<&mut T>;
} }
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[allow(deprecated)]
impl<M> MatchNameRef for M impl<M> MatchNameRef for M
where where
M: MatchName, M: MatchName,
{ {
fn match_by_ref<T>(&self, rf: Reference<T>) -> Option<&T> { fn get<T>(&self, rf: &Reference<T>) -> Option<&T> {
self.match_name::<T>(&rf.name) self.match_name::<T>(&rf.name)
} }
fn match_by_ref_mut<T>(&mut self, rf: Reference<T>) -> Option<&mut T> { fn get_mut<T>(&mut self, rf: &Reference<T>) -> Option<&mut T> {
self.match_name_mut::<T>(&rf.name) self.match_name_mut::<T>(&rf.name)
} }
} }
/// A wrapper type to enable the indexing of [`MatchName`] implementors with `[]`.
#[cfg(feature = "alloc")]
#[derive(Copy, Clone, Debug)]
#[repr(transparent)]
pub struct RefIndexable<RM, M>(RM, PhantomData<M>);
#[cfg(feature = "alloc")]
impl<RM, M> From<RM> for RefIndexable<RM, M>
where
RM: Deref<Target = M>,
M: MatchName,
{
fn from(value: RM) -> Self {
RefIndexable(value, PhantomData)
}
}
#[cfg(feature = "alloc")]
impl<RM, M> Deref for RefIndexable<RM, M>
where
RM: Deref<Target = M>,
{
type Target = RM::Target;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "alloc")]
impl<RM, M> DerefMut for RefIndexable<RM, M>
where
RM: DerefMut<Target = M>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(feature = "alloc")]
impl<T, RM, M> Index<&Reference<T>> for RefIndexable<RM, M>
where
RM: Deref<Target = M>,
M: MatchName,
{
type Output = T;
fn index(&self, index: &Reference<T>) -> &Self::Output {
let Some(e) = self.get(index) else {
panic!("Could not find entry matching {index:?}")
};
e
}
}
#[cfg(feature = "alloc")]
impl<T, RM, M> IndexMut<&Reference<T>> for RefIndexable<RM, M>
where
RM: DerefMut<Target = M>,
M: MatchName,
{
fn index_mut(&mut self, index: &Reference<T>) -> &mut Self::Output {
let Some(e) = self.get_mut(index) else {
panic!("Could not find entry matching {index:?}")
};
e
}
}
/// Allows prepending of values to a tuple /// Allows prepending of values to a tuple
pub trait Prepend<T> { pub trait Prepend<T> {
/// The Resulting [`TupleList`], of an [`Prepend::prepend()`] call, /// The Resulting [`TupleList`], of an [`Prepend::prepend()`] call,

View File

@ -22,7 +22,11 @@ use libafl::{
state::State, state::State,
Error, HasMetadata, Error, HasMetadata,
}; };
use libafl_bolts::{ownedref::OwnedPtr, Named, SerdeAny}; use libafl_bolts::{
ownedref::OwnedPtr,
tuples::{MatchNameRef, Reference, Referenceable},
Named, SerdeAny,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use termcolor::{Color, ColorSpec, WriteColor}; use termcolor::{Color, ColorSpec, WriteColor};
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
@ -39,8 +43,6 @@ use crate::{
alloc::AllocationMetadata, asan::asan_rt::ASAN_SAVE_REGISTER_COUNT, utils::disas_count, alloc::AllocationMetadata, asan::asan_rt::ASAN_SAVE_REGISTER_COUNT, utils::disas_count,
}; };
static ASAN_ERRORS_NAME: Cow<'static, str> = Cow::Borrowed("AsanErrors");
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct AsanReadWriteError { pub(crate) struct AsanReadWriteError {
pub registers: [usize; ASAN_SAVE_REGISTER_COUNT], pub registers: [usize; ASAN_SAVE_REGISTER_COUNT],
@ -591,6 +593,7 @@ where
impl Named for AsanErrorsObserver { impl Named for AsanErrorsObserver {
#[inline] #[inline]
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
static ASAN_ERRORS_NAME: Cow<'static, str> = Cow::Borrowed("AsanErrors");
&ASAN_ERRORS_NAME &ASAN_ERRORS_NAME
} }
} }
@ -643,6 +646,7 @@ impl AsanErrorsObserver {
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct AsanErrorsFeedback<S> { pub struct AsanErrorsFeedback<S> {
errors: Option<AsanErrors>, errors: Option<AsanErrors>,
obs_ref: Reference<AsanErrorsObserver>,
phantom: PhantomData<S>, phantom: PhantomData<S>,
} }
@ -665,7 +669,7 @@ where
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
{ {
let observer = observers let observer = observers
.match_name::<AsanErrorsObserver>(&ASAN_ERRORS_NAME) .get(&self.obs_ref)
.expect("An AsanErrorsFeedback needs an AsanErrorsObserver"); .expect("An AsanErrorsFeedback needs an AsanErrorsObserver");
let errors = observer.errors(); let errors = observer.errors();
if errors.is_empty() { if errors.is_empty() {
@ -702,23 +706,18 @@ where
impl<S> Named for AsanErrorsFeedback<S> { impl<S> Named for AsanErrorsFeedback<S> {
#[inline] #[inline]
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&ASAN_ERRORS_NAME self.obs_ref.name()
} }
} }
impl<S> AsanErrorsFeedback<S> { impl<S> AsanErrorsFeedback<S> {
/// Create a new `AsanErrorsFeedback` /// Create a new `AsanErrorsFeedback`
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new(obs: &AsanErrorsObserver) -> Self {
Self { Self {
errors: None, errors: None,
obs_ref: obs.reference(),
phantom: PhantomData, phantom: PhantomData,
} }
} }
} }
impl<S> Default for AsanErrorsFeedback<S> {
fn default() -> Self {
Self::new()
}
}

View File

@ -19,6 +19,7 @@ use libafl::{
state::{HasExecutions, State, UsesState}, state::{HasExecutions, State, UsesState},
Error, Error,
}; };
use libafl_bolts::tuples::RefIndexable;
#[cfg(all(unix, not(test)))] #[cfg(all(unix, not(test)))]
use crate::asan::errors::AsanErrors; use crate::asan::errors::AsanErrors;
@ -145,12 +146,12 @@ where
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.base.observers() self.base.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.base.observers_mut() self.base.observers_mut()
} }
} }

View File

@ -416,10 +416,15 @@ mod tests {
let mut feedback = ConstFeedback::new(false); let mut feedback = ConstFeedback::new(false);
let asan_obs = AsanErrorsObserver::from_static_asan_errors();
// Feedbacks to recognize an input as solution // Feedbacks to recognize an input as solution
let mut objective = feedback_or_fast!( let mut objective = feedback_or_fast!(
// true enables the AsanErrorFeedback // true enables the AsanErrorFeedback
feedback_and_fast!(ConstFeedback::from(true), AsanErrorsFeedback::new()) feedback_and_fast!(
ConstFeedback::from(true),
AsanErrorsFeedback::new(&asan_obs)
)
); );
let mut state = StdState::new( let mut state = StdState::new(
@ -436,7 +441,7 @@ mod tests {
let mut fuzzer = StdFuzzer::new(StdScheduler::new(), feedback, objective); let mut fuzzer = StdFuzzer::new(StdScheduler::new(), feedback, objective);
let observers = tuple_list!( let observers = tuple_list!(
AsanErrorsObserver::from_static_asan_errors() //, asan_obs //,
); );
{ {

View File

@ -174,4 +174,4 @@ where
} }
} }
pub type ShrinkMapFeedback<C, O, S, T> = MinMapFeedback<C, MappedEdgeMapObserver<O, T>, S, usize>; pub type ShrinkMapFeedback<C, O, T> = MinMapFeedback<C, MappedEdgeMapObserver<O, T>, usize>;

View File

@ -244,7 +244,7 @@ macro_rules! fuzz_with {
map_feedback, map_feedback,
feedback_and_fast!(ConstFeedback::new($options.shrink()), shrinking_map_feedback), feedback_and_fast!(ConstFeedback::new($options.shrink()), shrinking_map_feedback),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
) )
); );

View File

@ -11,7 +11,7 @@ use libafl::{
state::{HasExecutions, State, UsesState}, state::{HasExecutions, State, UsesState},
Error, Error,
}; };
use libafl_bolts::AsSlice; use libafl_bolts::{tuples::RefIndexable, AsSlice};
use libnyx::NyxReturnValue; use libnyx::NyxReturnValue;
use crate::helper::NyxHelper; use crate::helper::NyxHelper;
@ -146,11 +146,11 @@ where
S: State, S: State,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
{ {
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
&self.observers RefIndexable::from(&self.observers)
} }
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
&mut self.observers RefIndexable::from(&mut self.observers)
} }
} }

View File

@ -22,9 +22,12 @@ use libafl::{
state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState}, state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState},
Error, HasMetadata, Error, HasMetadata,
}; };
use libafl_bolts::os::unix_signals::{siginfo_t, ucontext_t, Signal};
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
use libafl_bolts::shmem::ShMemProvider; use libafl_bolts::shmem::ShMemProvider;
use libafl_bolts::{
os::unix_signals::{siginfo_t, ucontext_t, Signal},
tuples::RefIndexable,
};
use crate::{helpers::QemuHelperTuple, hooks::QemuHooks, Qemu}; use crate::{helpers::QemuHelperTuple, hooks::QemuHooks, Qemu};
@ -308,7 +311,7 @@ where
self.state.post_exec::<Self, EM, OT, OF, Z>( self.state.post_exec::<Self, EM, OT, OF, Z>(
input, input,
qemu, qemu,
self.inner.observers_mut(), &mut *self.inner.observers_mut(),
&mut exit_kind, &mut exit_kind,
); );
Ok(exit_kind) Ok(exit_kind)
@ -343,12 +346,12 @@ where
QT: QemuHelperTuple<S>, QT: QemuHelperTuple<S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers() self.inner.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut() self.inner.observers_mut()
} }
} }
@ -480,7 +483,7 @@ where
self.state.hooks.helpers_mut().post_exec_all( self.state.hooks.helpers_mut().post_exec_all(
qemu, qemu,
input, input,
self.inner.observers_mut(), &mut *self.inner.observers_mut(),
&mut exit_kind, &mut exit_kind,
); );
Ok(exit_kind) Ok(exit_kind)
@ -527,12 +530,12 @@ where
Z: UsesState<State = S>, Z: UsesState<State = S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers() self.inner.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut() self.inner.observers_mut()
} }
} }

View File

@ -17,6 +17,7 @@ use libafl::{
state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState}, state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState},
Error, Error,
}; };
use libafl_bolts::tuples::RefIndexable;
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
use crate::executor::inproc_qemu_crash_handler; use crate::executor::inproc_qemu_crash_handler;
@ -164,7 +165,7 @@ where
.post_exec::<Self, EM, OT, OF, Z>( .post_exec::<Self, EM, OT, OF, Z>(
input, input,
qemu, qemu,
self.inner.inner.observers_mut(), &mut *self.inner.inner.observers_mut(),
&mut exit_kind, &mut exit_kind,
); );
Ok(exit_kind) Ok(exit_kind)
@ -199,12 +200,12 @@ where
QT: QemuHelperTuple<S>, QT: QemuHelperTuple<S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers() self.inner.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut() self.inner.observers_mut()
} }
} }

View File

@ -6,7 +6,7 @@ use libafl::{
inputs::{Input, UsesInput}, inputs::{Input, UsesInput},
observers::{stacktrace::BacktraceObserver, ObserversTuple}, observers::{stacktrace::BacktraceObserver, ObserversTuple},
}; };
use libafl_bolts::{tuples::MatchFirstType, Named}; use libafl_bolts::tuples::{MatchFirstType, MatchNameRef, Reference, Referenceable};
use libafl_qemu_sys::GuestAddr; use libafl_qemu_sys::GuestAddr;
use thread_local::ThreadLocal; use thread_local::ThreadLocal;
@ -21,7 +21,7 @@ use crate::{
Qemu, Qemu,
}; };
pub trait CallTraceCollector: 'static + Debug { pub trait CallTraceCollector: 'static {
fn on_call<QT, S>( fn on_call<QT, S>(
&mut self, &mut self,
hooks: &mut QemuHooks<QT, S>, hooks: &mut QemuHooks<QT, S>,
@ -62,7 +62,7 @@ pub trait CallTraceCollector: 'static + Debug {
} }
} }
pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug { pub trait CallTraceCollectorTuple: 'static + MatchFirstType {
fn on_call_all<QT, S>( fn on_call_all<QT, S>(
&mut self, &mut self,
hooks: &mut QemuHooks<QT, S>, hooks: &mut QemuHooks<QT, S>,
@ -402,7 +402,7 @@ where
impl<S, T> QemuHelper<S> for QemuCallTracerHelper<T> impl<S, T> QemuHelper<S> for QemuCallTracerHelper<T>
where where
S: UsesInput, S: UsesInput,
T: CallTraceCollectorTuple, T: CallTraceCollectorTuple + Debug,
{ {
fn init_hooks<QT>(&self, hooks: &QemuHooks<QT, S>) fn init_hooks<QT>(&self, hooks: &QemuHooks<QT, S>)
where where
@ -437,25 +437,17 @@ where
// TODO support multiple threads with thread local callstack // TODO support multiple threads with thread local callstack
#[derive(Debug)] #[derive(Debug)]
pub struct OnCrashBacktraceCollector { pub struct OnCrashBacktraceCollector<'a> {
callstack_hash: u64, callstack_hash: u64,
observer_name: String, obs_ref: Reference<BacktraceObserver<'a>>,
} }
impl OnCrashBacktraceCollector { impl<'a> OnCrashBacktraceCollector<'a> {
#[must_use] #[must_use]
pub fn new(observer: &BacktraceObserver<'_>) -> Self { pub fn new(observer: &BacktraceObserver<'a>) -> Self {
Self { Self {
callstack_hash: 0, callstack_hash: 0,
observer_name: observer.name().to_string(), obs_ref: observer.reference(),
}
}
#[must_use]
pub fn with_name(observer_name: String) -> Self {
Self {
callstack_hash: 0,
observer_name,
} }
} }
@ -469,7 +461,10 @@ impl OnCrashBacktraceCollector {
} }
} }
impl CallTraceCollector for OnCrashBacktraceCollector { impl<'a> CallTraceCollector for OnCrashBacktraceCollector<'a>
where
'a: 'static,
{
#[allow(clippy::unnecessary_cast)] #[allow(clippy::unnecessary_cast)]
fn on_call<QT, S>( fn on_call<QT, S>(
&mut self, &mut self,
@ -516,7 +511,7 @@ impl CallTraceCollector for OnCrashBacktraceCollector {
S: UsesInput, S: UsesInput,
{ {
let observer = observers let observer = observers
.match_name_mut::<BacktraceObserver<'_>>(&self.observer_name) .get_mut(&self.obs_ref)
.expect("A OnCrashBacktraceCollector needs a BacktraceObserver"); .expect("A OnCrashBacktraceCollector needs a BacktraceObserver");
observer.fill_external(self.callstack_hash, exit_kind); observer.fill_external(self.callstack_hash, exit_kind);
} }

View File

@ -33,7 +33,7 @@ hexagon = ["libafl_qemu/hexagon"] # build qemu for hexagon
pyo3-build-config = { version = "0.18", optional = true } pyo3-build-config = { version = "0.18", optional = true }
[dependencies] [dependencies]
libafl = { path = "../libafl", version = "0.12.0" } libafl = { path = "../libafl", version = "0.12.0", features = ["adaptive_serialization"] }
libafl_bolts = { path = "../libafl_bolts", version = "0.12.0" } libafl_bolts = { path = "../libafl_bolts", version = "0.12.0" }
libafl_targets = { path = "../libafl_targets", version = "0.12.0" } libafl_targets = { path = "../libafl_targets", version = "0.12.0" }

View File

@ -26,7 +26,7 @@ use libafl_bolts::{
current_nanos, current_nanos,
rands::StdRand, rands::StdRand,
shmem::{ShMem, ShMemProvider, UnixShMemProvider}, shmem::{ShMem, ShMemProvider, UnixShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge, Referenceable},
AsSliceMut, AsSliceMut,
}; };
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
@ -114,9 +114,15 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
let monitor = MultiMonitor::new(|s| log::info!("{s}")); let monitor = MultiMonitor::new(|s| log::info!("{s}"));
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
let time_ref = time_observer.reference();
let mut run_client = |state: Option<_>, let mut run_client = |state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>, mut mgr: LlmpRestartingEventManager<_, _, _>,
_core_id| { _core_id| {
let time_observer = time_observer.clone();
// Coverage map shared between target and fuzzer // Coverage map shared between target and fuzzer
let mut shmem = shmem_provider_client.new_shmem(MAP_SIZE).unwrap(); let mut shmem = shmem_provider_client.new_shmem(MAP_SIZE).unwrap();
shmem.write_to_env("__AFL_SHM_ID").unwrap(); shmem.write_to_env("__AFL_SHM_ID").unwrap();
@ -131,16 +137,13 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
.track_indices() .track_indices()
}; };
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
@ -292,7 +295,8 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
.run_client(&mut run_client) .run_client(&mut run_client)
.cores(self.cores) .cores(self.cores)
.broker_port(self.broker_port) .broker_port(self.broker_port)
.remote_broker_addr(self.remote_broker_addr); .remote_broker_addr(self.remote_broker_addr)
.time_ref(time_ref);
#[cfg(unix)] #[cfg(unix)]
let launcher = launcher.stdout_file(Some("/dev/null")); let launcher = launcher.stdout_file(Some("/dev/null"));
match launcher.build().launch() { match launcher.build().launch() {

View File

@ -29,7 +29,7 @@ use libafl_bolts::{
current_nanos, current_nanos,
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge, Referenceable},
AsSlice, AsSlice,
}; };
use libafl_targets::{std_edges_map_observer, CmpLogObserver}; use libafl_targets::{std_edges_map_observer, CmpLogObserver};
@ -138,17 +138,20 @@ where
let monitor = MultiMonitor::new(|s| println!("{s}")); let monitor = MultiMonitor::new(|s| println!("{s}"));
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
let time_ref = time_observer.reference();
let mut run_client = |state: Option<_>, let mut run_client = |state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>, mut mgr: LlmpRestartingEventManager<_, _, _>,
_core_id| { _core_id| {
let time_observer = time_observer.clone();
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = let edges_observer =
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }) HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") })
.track_indices(); .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 cmplog_observer = CmpLogObserver::new("cmplog", true);
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
@ -157,7 +160,7 @@ where
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
@ -340,7 +343,8 @@ where
.run_client(&mut run_client) .run_client(&mut run_client)
.cores(self.cores) .cores(self.cores)
.broker_port(self.broker_port) .broker_port(self.broker_port)
.remote_broker_addr(self.remote_broker_addr); .remote_broker_addr(self.remote_broker_addr)
.time_ref(time_ref);
#[cfg(unix)] #[cfg(unix)]
let launcher = launcher.stdout_file(Some("/dev/null")); let launcher = launcher.stdout_file(Some("/dev/null"));
match launcher.build().launch() { match launcher.build().launch() {

View File

@ -32,7 +32,7 @@ use libafl_bolts::{
current_nanos, current_nanos,
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge, Referenceable},
AsSlice, AsSlice,
}; };
pub use libafl_qemu::emu::Qemu; pub use libafl_qemu::emu::Qemu;
@ -146,9 +146,15 @@ where
let monitor = MultiMonitor::new(|s| log::info!("{s}")); let monitor = MultiMonitor::new(|s| log::info!("{s}"));
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
let time_ref = time_observer.reference();
let mut run_client = |state: Option<_>, let mut run_client = |state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>, mut mgr: LlmpRestartingEventManager<_, _, _>,
_core_id| { _core_id| {
let time_observer = time_observer.clone();
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = unsafe { let edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
@ -159,9 +165,6 @@ where
.track_indices() .track_indices()
}; };
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
// Keep tracks of CMPs // Keep tracks of CMPs
let cmplog_observer = CmpLogObserver::new("cmplog", true); let cmplog_observer = CmpLogObserver::new("cmplog", true);
@ -171,7 +174,7 @@ where
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::new(&time_observer)
); );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
@ -433,9 +436,11 @@ where
.run_client(&mut run_client) .run_client(&mut run_client)
.cores(self.cores) .cores(self.cores)
.broker_port(self.broker_port) .broker_port(self.broker_port)
.remote_broker_addr(self.remote_broker_addr); .remote_broker_addr(self.remote_broker_addr)
.time_ref(time_ref);
#[cfg(unix)] #[cfg(unix)]
let launcher = launcher.stdout_file(Some("/dev/null")); let launcher = launcher.stdout_file(Some("/dev/null"));
launcher.build().launch().expect("Launcher failed"); launcher.build().launch().expect("Launcher failed");
} }
} }

View File

@ -65,10 +65,7 @@ struct cmp_map {
/// A [`CmpObserver`] observer for AFL++ redqueen /// A [`CmpObserver`] observer for AFL++ redqueen
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct AFLppCmpLogObserver<'a, S> pub struct AFLppCmpLogObserver<'a, S> {
where
S: UsesInput + HasMetadata,
{
cmp_map: OwnedRefMut<'a, AFLppCmpLogMap>, cmp_map: OwnedRefMut<'a, AFLppCmpLogMap>,
size: Option<OwnedRefMut<'a, usize>>, size: Option<OwnedRefMut<'a, usize>>,
name: Cow<'static, str>, name: Cow<'static, str>,
@ -80,7 +77,7 @@ where
impl<'a, S> CmpObserver<'a, AFLppCmpLogMap, S, AFLppCmpValuesMetadata> impl<'a, S> CmpObserver<'a, AFLppCmpLogMap, S, AFLppCmpValuesMetadata>
for AFLppCmpLogObserver<'a, S> for AFLppCmpLogObserver<'a, S>
where where
S: UsesInput + Debug + HasMetadata, S: UsesInput + HasMetadata,
{ {
/// Get the number of usable cmps (all by default) /// Get the number of usable cmps (all by default)
fn usable_count(&self) -> usize { fn usable_count(&self) -> usize {
@ -142,7 +139,7 @@ where
impl<'a, S> Observer<S> for AFLppCmpLogObserver<'a, S> impl<'a, S> Observer<S> for AFLppCmpLogObserver<'a, S>
where where
S: UsesInput + Debug + HasMetadata, S: UsesInput + HasMetadata,
{ {
fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
#[cfg(feature = "cmplog_extended_instrumentation")] #[cfg(feature = "cmplog_extended_instrumentation")]
@ -176,19 +173,13 @@ where
} }
} }
impl<'a, S> Named for AFLppCmpLogObserver<'a, S> impl<'a, S> Named for AFLppCmpLogObserver<'a, S> {
where
S: UsesInput + HasMetadata,
{
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
} }
impl<'a, S> AFLppCmpLogObserver<'a, S> impl<'a, S> AFLppCmpLogObserver<'a, S> {
where
S: UsesInput + HasMetadata,
{
/// Creates a new [`AFLppCmpLogObserver`] with the given name and map. /// Creates a new [`AFLppCmpLogObserver`] with the given name and map.
#[must_use] #[must_use]
pub fn new( pub fn new(

View File

@ -1,7 +1,4 @@
use alloc::{ use alloc::borrow::Cow;
borrow::Cow,
string::{String, ToString},
};
use core::marker::PhantomData; use core::marker::PhantomData;
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
@ -14,34 +11,43 @@ use libafl::{
state::{HasCorpus, HasCurrentTestcase, HasExecutions, UsesState}, state::{HasCorpus, HasCurrentTestcase, HasExecutions, UsesState},
Error, HasMetadata, HasNamedMetadata, Error, HasMetadata, HasNamedMetadata,
}; };
use libafl_bolts::{tuples::MatchName, Named}; use libafl_bolts::{
tuples::{MatchNameRef, Reference},
Named,
};
use crate::cmps::observers::AFLppCmpLogObserver; use crate::cmps::observers::AFLppCmpLogObserver;
/// Trace with tainted input /// Trace with tainted input
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct AFLppCmplogTracingStage<EM, TE, Z> { pub struct AFLppCmplogTracingStage<'a, EM, TE, Z>
where
TE: UsesState,
{
tracer_executor: TE, tracer_executor: TE,
cmplog_observer_name: Option<String>, cmplog_observer_ref: Option<Reference<AFLppCmpLogObserver<'a, TE::State>>>,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(EM, TE, Z)>, phantom: PhantomData<(EM, TE, Z)>,
} }
impl<EM, TE, Z> UsesState for AFLppCmplogTracingStage<EM, TE, Z> impl<EM, TE, Z> UsesState for AFLppCmplogTracingStage<'_, EM, TE, Z>
where where
TE: UsesState, TE: UsesState,
{ {
type State = TE::State; type State = TE::State;
} }
impl<EM, TE, Z> Named for AFLppCmplogTracingStage<EM, TE, Z> { impl<EM, TE, Z> Named for AFLppCmplogTracingStage<'_, EM, TE, Z>
where
TE: UsesState,
{
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("AFLppCmplogTracingStage"); static NAME: Cow<'static, str> = Cow::Borrowed("AFLppCmplogTracingStage");
&NAME &NAME
} }
} }
impl<E, EM, TE, Z> Stage<E, EM, Z> for AFLppCmplogTracingStage<EM, TE, Z> impl<E, EM, TE, Z> Stage<E, EM, Z> for AFLppCmplogTracingStage<'_, EM, TE, Z>
where where
E: UsesState<State = TE::State>, E: UsesState<State = TE::State>,
TE: Executor<EM, Z> + HasObservers, TE: Executor<EM, Z> + HasObservers,
@ -61,12 +67,8 @@ where
// First run with the un-mutated input // First run with the un-mutated input
let unmutated_input = state.current_input_cloned()?; let unmutated_input = state.current_input_cloned()?;
if let Some(name) = &self.cmplog_observer_name { if let Some(obs_ref) = &self.cmplog_observer_ref {
if let Some(ob) = self if let Some(ob) = self.tracer_executor.observers_mut().get_mut(obs_ref) {
.tracer_executor
.observers_mut()
.match_name_mut::<AFLppCmpLogObserver<TE::State>>(name)
{
// This is not the original input, // This is not the original input,
// Set it to false // Set it to false
ob.set_original(true); ob.set_original(true);
@ -95,12 +97,8 @@ where
None => return Err(Error::unknown("No metadata found")), None => return Err(Error::unknown("No metadata found")),
}; };
if let Some(name) = &self.cmplog_observer_name { if let Some(obs_ref) = &self.cmplog_observer_ref {
if let Some(ob) = self if let Some(ob) = self.tracer_executor.observers_mut().get_mut(obs_ref) {
.tracer_executor
.observers_mut()
.match_name_mut::<AFLppCmpLogObserver<TE::State>>(name)
{
// This is not the original input, // This is not the original input,
// Set it to false // Set it to false
ob.set_original(false); ob.set_original(false);
@ -137,20 +135,26 @@ where
} }
} }
impl<EM, TE, Z> AFLppCmplogTracingStage<EM, TE, Z> { impl<'a, EM, TE, Z> AFLppCmplogTracingStage<'a, EM, TE, Z>
where
TE: UsesState,
{
/// Creates a new default stage /// Creates a new default stage
pub fn new(tracer_executor: TE) -> Self { pub fn new(tracer_executor: TE) -> Self {
Self { Self {
cmplog_observer_name: None, cmplog_observer_ref: None,
tracer_executor, tracer_executor,
phantom: PhantomData, phantom: PhantomData,
} }
} }
/// With cmplog observer /// With cmplog observer
pub fn with_cmplog_observer_name(tracer_executor: TE, name: &'static str) -> Self { pub fn with_cmplog_observer(
tracer_executor: TE,
obs_ref: Reference<AFLppCmpLogObserver<'a, TE::State>>,
) -> Self {
Self { Self {
cmplog_observer_name: Some(name.to_string()), cmplog_observer_ref: Some(obs_ref),
tracer_executor, tracer_executor,
phantom: PhantomData, phantom: PhantomData,
} }

View File

@ -11,6 +11,7 @@ use libafl::{
use libafl_bolts::{ use libafl_bolts::{
fs::{InputFile, INPUTFILE_STD}, fs::{InputFile, INPUTFILE_STD},
shmem::{ShMem, ShMemProvider, StdShMemProvider}, shmem::{ShMem, ShMemProvider, StdShMemProvider},
tuples::RefIndexable,
AsSlice, AsSliceMut, AsSlice, AsSliceMut,
}; };
use tinyinst::tinyinst::{litecov::RunResult, TinyInst}; use tinyinst::tinyinst::{litecov::RunResult, TinyInst};
@ -300,12 +301,12 @@ where
SP: ShMemProvider, SP: ShMemProvider,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
{ {
fn observers(&self) -> &OT { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
&self.observers RefIndexable::from(&self.observers)
} }
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
&mut self.observers RefIndexable::from(&mut self.observers)
} }
} }
impl<'a, S, SP, OT> UsesState for TinyInstExecutor<'a, S, SP, OT> impl<'a, S, SP, OT> UsesState for TinyInstExecutor<'a, S, SP, OT>