stats as trait

This commit is contained in:
Andrea Fioraldi 2020-12-15 12:19:44 +01:00
parent a739b91e2a
commit 08a60aa950
2 changed files with 145 additions and 100 deletions

View File

@ -410,7 +410,7 @@ mod tests {
use crate::corpus::{Corpus, InMemoryCorpus, Testcase}; use crate::corpus::{Corpus, InMemoryCorpus, Testcase};
use crate::engines::{Engine, Fuzzer, State, StdFuzzer}; use crate::engines::{Engine, Fuzzer, State, StdFuzzer};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::events::LoggerEventManager; use crate::events::{LoggerEventManager, SimpleStats};
use crate::executors::inmemory::InMemoryExecutor; use crate::executors::inmemory::InMemoryExecutor;
use crate::executors::{Executor, ExitKind}; use crate::executors::{Executor, ExitKind};
use crate::inputs::bytes::BytesInput; use crate::inputs::bytes::BytesInput;
@ -434,7 +434,7 @@ mod tests {
let executor = InMemoryExecutor::<BytesInput, _>::new("main", harness, tuple_list!()); let executor = InMemoryExecutor::<BytesInput, _>::new("main", harness, tuple_list!());
let mut state = State::new(tuple_list!()); let mut state = State::new(tuple_list!());
let mut events_manager = LoggerEventManager::new(stderr()); let mut events_manager = LoggerEventManager::new(SimpleStats::new(|s| { println!("{}", s); }));
let mut engine = Engine::new(executor); let mut engine = Engine::new(executor);
let mut mutator = StdScheduledMutator::new(); let mut mutator = StdScheduledMutator::new();
mutator.add_mutation(mutation_bitflip); mutator.add_mutation(mutation_bitflip);

View File

@ -42,60 +42,21 @@ pub struct ClientStats {
executions: u64, executions: u64,
} }
/* // TODO Stats as a trait in order to implement logging in an abstract way
/// A custom event, for own messages, with own handler. // Something like stats.show() that will render the AFL status screen
pub trait CustomEvent<I>: SerdeAny
where
I: Input,
{
/// Returns the name of this event
fn name(&self) -> &str;
/// This method will be called in the broker
fn handle_in_broker(&self) -> Result<BrokerEventResult, AflError>;
/// This method will be called in the clients after handle_in_broker (unless BrokerEventResult::Handled) was returned in handle_in_broker
fn handle_in_client(&self) -> Result<(), AflError>;
}
*/
/// Events sent around in the library pub trait Stats {
pub trait Event<I> /// the client stats (mut)
where fn client_stats_mut(&mut self) -> &mut Vec<ClientStats>;
I: Input,
{
/// Returns the name of this event
fn name(&self) -> &str;
/// This method will be called in the broker
fn handle_in_broker(&self, stats: &mut Stats) -> Result<BrokerEventResult, AflError>;
/// This method will be called in the clients after handle_in_broker (unless BrokerEventResult::Handled) was returned in handle_in_broker
fn handle_in_client<C, OT, FT, R>(
self,
state: &mut State<I, R, FT, OT>,
corpus: &mut C,
) -> Result<(), AflError>
where
C: Corpus<I, R>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
R: Rand;
}
#[derive(Debug, Clone, Default)]
pub struct Stats {
start_time: Duration,
corpus_size: usize,
client_stats: Vec<ClientStats>,
}
impl Stats {
/// the client stats, mutable
fn client_stats_mut(&mut self) -> &mut Vec<ClientStats> {
&mut self.client_stats
}
/// the client stats /// the client stats
fn client_stats(&self) -> &[ClientStats] { fn client_stats(&self) -> &[ClientStats];
&self.client_stats
} /// 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) /// Amount of elements in the corpus (combined for all children)
fn corpus_size(&self) -> u64 { fn corpus_size(&self) -> u64 {
@ -104,11 +65,6 @@ impl Stats {
.fold(0u64, |acc, x| acc + x.corpus_size) .fold(0u64, |acc, x| acc + x.corpus_size)
} }
/// Time this fuzzing run stated
fn start_time(&mut self) -> time::Duration {
self.start_time
}
/// Total executions /// Total executions
#[inline] #[inline]
fn total_execs(&mut self) -> u64 { fn total_execs(&mut self) -> u64 {
@ -140,6 +96,102 @@ impl Stats {
} }
} }
#[derive(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!("[{}] corpus: {}, executions: {}, exec/sec: {}", event_msg, 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: utils::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![]
}
}
}
/*
/// A custom event, for own messages, with own handler.
pub trait CustomEvent<I>: SerdeAny
where
I: Input,
{
/// Returns the name of this event
fn name(&self) -> &str;
/// This method will be called in the broker
fn handle_in_broker(&self) -> Result<BrokerEventResult, AflError>;
/// This method will be called in the clients after handle_in_broker (unless BrokerEventResult::Handled) was returned in handle_in_broker
fn handle_in_client(&self) -> Result<(), AflError>;
}
*/
/// Events sent around in the library
pub trait Event<I>
where
I: Input,
{
/// Returns the name of this event
fn name(&self) -> &str;
/// This method will be called in the broker
fn handle_in_broker<ST>(&self, stats: &mut ST) -> Result<BrokerEventResult, AflError> where ST: Stats;
/// This method will be called in the clients after handle_in_broker (unless BrokerEventResult::Handled) was returned in handle_in_broker
fn handle_in_client<C, OT, FT, R>(
self,
state: &mut State<I, R, FT, OT>,
corpus: &mut C,
) -> Result<(), AflError>
where
C: Corpus<I, R>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
R: Rand;
}
pub trait EventManager<C, E, OT, FT, I, R> pub trait EventManager<C, E, OT, FT, I, R>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
@ -258,7 +310,7 @@ where
/// Broker fun /// Broker fun
#[inline] #[inline]
fn handle_in_broker(&self, stats: &mut Stats) -> Result<BrokerEventResult, AflError> { fn handle_in_broker<ST>(&self, stats: &mut ST) -> Result<BrokerEventResult, AflError> where ST: Stats {
match self { match self {
LoggerEvent::NewTestcase { LoggerEvent::NewTestcase {
corpus_size, corpus_size,
@ -321,7 +373,7 @@ where
} }
} }
pub struct LoggerEventManager<C, E, OT, FT, I, R, W> pub struct LoggerEventManager<C, E, OT, FT, I, R, ST>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
E: Executor<I>, E: Executor<I>,
@ -329,19 +381,17 @@ where
FT: FeedbacksTuple<I>, FT: FeedbacksTuple<I>,
I: Input, I: Input,
R: Rand, R: Rand,
W: Write, ST: Stats,
//CE: CustomEvent<I, OT>, //CE: CustomEvent<I, OT>,
{ {
writer: W, stats: ST,
stats: Stats,
events: Vec<LoggerEvent<I>>, events: Vec<LoggerEvent<I>>,
// stats (maybe we need a separated struct?) // stats (maybe we need a separated struct?)
phantom: PhantomData<(C, E, I, R, OT, FT)>, phantom: PhantomData<(C, E, I, R, OT, FT)>,
} }
impl<C, E, OT, FT, I, R, W> EventManager<C, E, OT, FT, I, R> impl<C, E, OT, FT, I, R, ST> EventManager<C, E, OT, FT, I, R>
for LoggerEventManager<C, E, OT, FT, I, R, W> for LoggerEventManager<C, E, OT, FT, I, R, ST>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
E: Executor<I>, E: Executor<I>,
@ -349,7 +399,7 @@ where
FT: FeedbacksTuple<I>, FT: FeedbacksTuple<I>,
I: Input, I: Input,
R: Rand, R: Rand,
W: Write, ST: Stats,
//CE: CustomEvent<I, OT>, //CE: CustomEvent<I, OT>,
{ {
fn process( fn process(
@ -431,7 +481,7 @@ where
} }
} }
impl<C, E, OT, FT, I, R, W> LoggerEventManager<C, E, OT, FT, I, R, W> impl<C, E, OT, FT, I, R, ST> LoggerEventManager<C, E, OT, FT, I, R, ST>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
I: Input, I: Input,
@ -439,16 +489,12 @@ where
OT: ObserversTuple, OT: ObserversTuple,
FT: FeedbacksTuple<I>, FT: FeedbacksTuple<I>,
R: Rand, R: Rand,
W: Write, ST: Stats,
//TODO CE: CustomEvent, //TODO CE: CustomEvent,
{ {
pub fn new(writer: W) -> Self { pub fn new(stats: ST) -> Self {
Self { Self {
stats: Stats { stats: stats,
start_time: utils::current_time(),
..Default::default()
},
writer: writer,
phantom: PhantomData, phantom: PhantomData,
events: vec![], events: vec![],
} }
@ -534,7 +580,7 @@ where
/// Broker fun /// Broker fun
#[inline] #[inline]
fn handle_in_broker(&self, stats: &mut Stats) -> Result<BrokerEventResult, AflError> { fn handle_in_broker<ST>(&self, stats: &mut ST) -> Result<BrokerEventResult, AflError> where ST: Stats {
match &self.kind { match &self.kind {
LLMPEventKind::NewTestcase { LLMPEventKind::NewTestcase {
input: _, input: _,
@ -633,20 +679,7 @@ const _LLMP_TAG_EVENT_TO_BROKER: llmp::Tag = 0x2B80438;
const LLMP_TAG_EVENT_TO_BOTH: llmp::Tag = 0x2B0741; const LLMP_TAG_EVENT_TO_BOTH: llmp::Tag = 0x2B0741;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub struct LlmpEventManager<C, E, OT, FT, I, R, W> pub struct LlmpEventManager<C, E, OT, FT, I, R, ST>
where
W: Write,
//CE: CustomEvent<I>,
{
writer: W,
// stats (maybe we need a separated struct?)
llmp: llmp::LlmpConnection,
stats: Stats,
phantom: PhantomData<(C, E, OT, FT, I, R)>,
}
impl<C, E, OT, FT, I, R, W> LlmpEventManager<C, E, OT, FT, I, R, W>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
E: Executor<I>, E: Executor<I>,
@ -654,20 +687,32 @@ where
FT: FeedbacksTuple<I>, FT: FeedbacksTuple<I>,
I: Input, I: Input,
R: Rand, R: Rand,
W: Write, ST: Stats,
//CE: CustomEvent<I>,
{
llmp: llmp::LlmpConnection,
stats: ST,
phantom: PhantomData<(C, E, OT, FT, I, R)>,
}
impl<C, E, OT, FT, I, R, ST> LlmpEventManager<C, E, OT, FT, I, R, ST>
where
C: Corpus<I, R>,
E: Executor<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
I: Input,
R: Rand,
ST: Stats,
{ {
/// Create llmp on a port /// Create llmp on a port
/// If the port is not yet bound, it will act as broker /// If the port is not yet bound, it will act as broker
/// Else, it will act as client. /// Else, it will act as client.
pub fn new_on_port(port: u16, writer: W) -> Result<Self, AflError> { pub fn new_on_port(port: u16, stats: ST) -> Result<Self, AflError> {
let mgr = Self { let mgr = Self {
llmp: llmp::LlmpConnection::on_port(port)?, llmp: llmp::LlmpConnection::on_port(port)?,
stats: Stats { stats: stats,
start_time: utils::current_time(),
..Default::default()
},
phantom: PhantomData, phantom: PhantomData,
writer,
}; };
Ok(mgr) Ok(mgr)
} }
@ -723,8 +768,8 @@ where
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<C, E, OT, FT, I, R, W> EventManager<C, E, OT, FT, I, R> impl<C, E, OT, FT, I, R, ST> EventManager<C, E, OT, FT, I, R>
for LlmpEventManager<C, E, OT, FT, I, R, W> for LlmpEventManager<C, E, OT, FT, I, R, ST>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
E: Executor<I>, E: Executor<I>,
@ -732,7 +777,7 @@ where
OT: ObserversTuple, OT: ObserversTuple,
I: Input, I: Input,
R: Rand, R: Rand,
W: Write, ST: Stats,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
fn process( fn process(