new eventmanager structure

This commit is contained in:
Andrea Fioraldi 2021-02-08 16:13:55 +01:00
parent 419a4aef86
commit f97418d311
7 changed files with 542 additions and 677 deletions

File diff suppressed because it is too large Load Diff

161
afl/src/events/stats.rs Normal file
View File

@ -0,0 +1,161 @@
use core::{time, time::Duration};
use crate::utils::current_time;
const CLIENT_STATS_TIME_WINDOW_SECS: u64 = 5; // 5 seconds
/// A simple struct to keep track of client stats
#[derive(Debug, Clone, Default)]
pub struct ClientStats {
// stats (maybe we need a separated struct?)
/// The corpus size for this client
pub corpus_size: u64,
/// The total executions for this client
pub executions: u64,
/// The last reported executions for this client
pub last_window_executions: u64,
/// The last time we got this information
pub last_window_time: time::Duration,
/// The last executions per sec
pub last_execs_per_sec: u64,
}
impl ClientStats {
pub fn update_executions(&mut self, executions: u64, cur_time: time::Duration) {
self.executions = executions;
if (cur_time - self.last_window_time).as_secs() > CLIENT_STATS_TIME_WINDOW_SECS {
self.last_execs_per_sec = self.execs_per_sec(cur_time);
self.last_window_time = cur_time;
self.last_window_executions = executions;
}
}
pub fn execs_per_sec(&self, cur_time: time::Duration) -> u64 {
if self.executions == 0 {
return 0;
}
let secs = (cur_time - self.last_window_time).as_secs();
if secs == 0 {
self.last_execs_per_sec
} else {
let diff = self.executions - self.last_window_executions;
diff / secs
}
}
}
pub trait Stats {
/// the client stats (mut)
fn client_stats_mut(&mut self) -> &mut Vec<ClientStats>;
/// the client stats
fn client_stats(&self) -> &[ClientStats];
/// creation time
fn start_time(&mut self) -> time::Duration;
/// show the stats to the user
fn show(&mut self, event_msg: String);
/// Amount of elements in the corpus (combined for all children)
fn corpus_size(&self) -> u64 {
self.client_stats()
.iter()
.fold(0u64, |acc, x| acc + x.corpus_size)
}
/// Total executions
#[inline]
fn total_execs(&mut self) -> u64 {
self.client_stats()
.iter()
.fold(0u64, |acc, x| acc + x.executions)
}
/// Executions per second
#[inline]
fn execs_per_sec(&mut self) -> u64 {
let cur_time = current_time();
self.client_stats()
.iter()
.fold(0u64, |acc, x| acc + x.execs_per_sec(cur_time))
}
/// The client stats for a specific id, creating new if it doesn't exist
fn client_stats_mut_for(&mut self, client_id: u32) -> &mut ClientStats {
let client_stat_count = self.client_stats().len();
for _ in client_stat_count..(client_id + 1) as usize {
self.client_stats_mut().push(ClientStats {
last_window_time: current_time(),
..Default::default()
})
}
&mut self.client_stats_mut()[client_id as usize]
}
}
#[derive(Clone, Debug)]
pub struct SimpleStats<F>
where
F: FnMut(String),
{
print_fn: F,
start_time: Duration,
corpus_size: usize,
client_stats: Vec<ClientStats>,
}
impl<F> Stats for SimpleStats<F>
where
F: FnMut(String),
{
/// the client stats, mutable
fn client_stats_mut(&mut self) -> &mut Vec<ClientStats> {
&mut self.client_stats
}
/// the client stats
fn client_stats(&self) -> &[ClientStats] {
&self.client_stats
}
/// Time this fuzzing run stated
fn start_time(&mut self) -> time::Duration {
self.start_time
}
fn show(&mut self, event_msg: String) {
let fmt = format!(
"[{}] clients: {}, corpus: {}, executions: {}, exec/sec: {}",
event_msg,
self.client_stats().len(),
self.corpus_size(),
self.total_execs(),
self.execs_per_sec()
);
(self.print_fn)(fmt);
}
}
impl<F> SimpleStats<F>
where
F: FnMut(String),
{
pub fn new(print_fn: F) -> Self {
Self {
print_fn: print_fn,
start_time: current_time(),
corpus_size: 0,
client_stats: vec![],
}
}
pub fn with_time(print_fn: F, start_time: time::Duration) -> Self {
Self {
print_fn: print_fn,
start_time: start_time,
corpus_size: 0,
client_stats: vec![],
}
}
}

View File

@ -29,7 +29,7 @@ pub mod utils;
use alloc::string::String; use alloc::string::String;
use core::{fmt, marker::PhantomData}; use core::{fmt, marker::PhantomData};
use corpus::Corpus; use corpus::Corpus;
use events::EventManager; use events::{Event, EventManager};
use executors::{Executor, HasObservers}; use executors::{Executor, HasObservers};
use feedbacks::FeedbacksTuple; use feedbacks::FeedbacksTuple;
use inputs::Input; use inputs::Input;
@ -86,7 +86,11 @@ where
let cur = current_milliseconds(); let cur = current_milliseconds();
if cur - last > 60 * 100 { if cur - last > 60 * 100 {
last = cur; last = cur;
manager.update_stats(state.executions(), state.executions_over_seconds())?; manager.fire(Event::UpdateStats {
executions: state.executions(),
execs_over_sec: state.executions_over_seconds(),
phantom: PhantomData,
})?
} }
} }
} }
@ -265,9 +269,10 @@ mod tests {
let mut state = State::new(corpus, tuple_list!()); let mut state = State::new(corpus, tuple_list!());
let mut event_manager = LoggerEventManager::new(SimpleStats::new(|s| { let stats = SimpleStats::new(|s| {
println!("{}", s); println!("{}", s);
})); });
let mut event_manager = LoggerEventManager::new(stats);
let mut executor = InMemoryExecutor::new( let mut executor = InMemoryExecutor::new(
"main", "main",

View File

@ -208,7 +208,7 @@ where
let idx = self.scheduled.schedule(14, rand, input); let idx = self.scheduled.schedule(14, rand, input);
let mutation = match idx { let mutation = match idx {
0 => mutation_bitflip, 0 => mutation_bitflip,
1 => mutation_byteflip, /*1 => mutation_byteflip,
2 => mutation_byteinc, 2 => mutation_byteinc,
3 => mutation_bytedec, 3 => mutation_bytedec,
4 => mutation_byteneg, 4 => mutation_byteneg,
@ -219,7 +219,7 @@ where
8 => mutation_dwordadd, 8 => mutation_dwordadd,
9 => mutation_byteinteresting, 9 => mutation_byteinteresting,
10 => mutation_wordinteresting, 10 => mutation_wordinteresting,
11 => mutation_dwordinteresting, 11 => mutation_dwordinteresting,*/
_ => mutation_splice, _ => mutation_splice,
}; };
mutation(self, rand, state, input)?; mutation(self, rand, state, input)?;
@ -277,7 +277,7 @@ where
pub fn new_default() -> Self { pub fn new_default() -> Self {
let mut scheduled = StdScheduledMutator::<C, I, R, S>::new(); let mut scheduled = StdScheduledMutator::<C, I, R, S>::new();
scheduled.add_mutation(mutation_bitflip); scheduled.add_mutation(mutation_bitflip);
scheduled.add_mutation(mutation_byteflip); /*scheduled.add_mutation(mutation_byteflip);
scheduled.add_mutation(mutation_byteinc); scheduled.add_mutation(mutation_byteinc);
scheduled.add_mutation(mutation_bytedec); scheduled.add_mutation(mutation_bytedec);
scheduled.add_mutation(mutation_byteneg); scheduled.add_mutation(mutation_byteneg);
@ -301,7 +301,7 @@ where
scheduled.add_mutation(mutation_bytesset); scheduled.add_mutation(mutation_bytesset);
scheduled.add_mutation(mutation_bytesrandset); scheduled.add_mutation(mutation_bytesrandset);
scheduled.add_mutation(mutation_bytescopy); scheduled.add_mutation(mutation_bytescopy);
scheduled.add_mutation(mutation_bytesswap); scheduled.add_mutation(mutation_bytesswap);*/
/* TODO /* TODO
scheduled.add_mutation(mutation_tokeninsert); scheduled.add_mutation(mutation_tokeninsert);

View File

@ -1,7 +1,7 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::{ use crate::{
events::EventManager, events::{Event, EventManager},
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
feedbacks::FeedbacksTuple, feedbacks::FeedbacksTuple,
inputs::Input, inputs::Input,
@ -76,13 +76,15 @@ where
// So by default we shoudl trigger it in corpus.add, so that the user can override it and remove // So by default we shoudl trigger it in corpus.add, so that the user can override it and remove
// if needed by particular cases // if needed by particular cases
if fitness > 0 { if fitness > 0 {
let observers_buf = manager.serialize_observers(observers)?;
// TODO decouple events manager and engine // TODO decouple events manager and engine
manager.new_testcase( manager.fire(Event::NewTestcase {
&input_mut, input: input_mut.clone(),
observers, observers_buf,
state.corpus().count() + 1, corpus_size: state.corpus().count() + 1,
"test".into(), client_config: "TODO".into(),
)?; })?;
state.add_if_interesting(input_mut, fitness)?; state.add_if_interesting(input_mut, fitness)?;
// let _ = corpus.add(testcase); // let _ = corpus.add(testcase);
} else { } else {

View File

@ -10,7 +10,7 @@ use std::{
use crate::{ use crate::{
corpus::{Corpus, Testcase}, corpus::{Corpus, Testcase},
events::EventManager, events::{Event, EventManager, LogSeverity},
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
feedbacks::FeedbacksTuple, feedbacks::FeedbacksTuple,
generators::Generator, generators::Generator,
@ -143,10 +143,11 @@ where
for in_dir in in_dirs { for in_dir in in_dirs {
self.load_from_directory(executor, generator, manager, in_dir)?; self.load_from_directory(executor, generator, manager, in_dir)?;
} }
manager.log( manager.fire(Event::Log {
0, severity_level: LogSeverity::Debug,
format!("Loaded {} initial testcases.", self.corpus().count()), // get corpus count message: format!("Loaded {} initial testcases.", self.corpus().count()), // get corpus count
)?; phantom: PhantomData,
})?;
manager.process(self)?; manager.process(self)?;
Ok(()) Ok(())
} }
@ -350,10 +351,11 @@ where
added += 1; added += 1;
} }
} }
manager.log( manager.fire(Event::Log {
0, severity_level: LogSeverity::Debug,
format!("Loaded {} over {} initial testcases", added, num), message: format!("Loaded {} over {} initial testcases", added, num),
)?; phantom: PhantomData,
})?;
manager.process(self)?; manager.process(self)?;
Ok(()) Ok(())
} }

View File

@ -56,7 +56,6 @@ where
/// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)` /// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)`
pub fn deserialize_state_corpus_mgr<C, FT, I, R, SH, ST>( pub fn deserialize_state_corpus_mgr<C, FT, I, R, SH, ST>(
state_corpus_serialized: &[u8], state_corpus_serialized: &[u8],
stats: ST,
) -> Result<(State<C, I, R, FT>, LlmpEventManager<I, SH, ST>), AflError> ) -> Result<(State<C, I, R, FT>, LlmpEventManager<I, SH, ST>), AflError>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
@ -70,7 +69,7 @@ where
let client_description = postcard::from_bytes(&tuple.1)?; let client_description = postcard::from_bytes(&tuple.1)?;
Ok(( Ok((
postcard::from_bytes(&tuple.0)?, postcard::from_bytes(&tuple.0)?,
LlmpEventManager::existing_client_from_description(&client_description, stats)?, LlmpEventManager::existing_client_from_description(&client_description)?,
)) ))
} }