event manager

This commit is contained in:
Dominik Maier 2020-11-25 21:34:28 +01:00
parent bc73984bd2
commit 68a72f583c
3 changed files with 187 additions and 169 deletions

View File

@ -9,7 +9,7 @@ use core::marker::PhantomData;
use hashbrown::HashMap; use hashbrown::HashMap;
use crate::corpus::{Corpus, Testcase}; use crate::corpus::{Corpus, Testcase};
use crate::events::{EventManager, LoadInitialEvent, UpdateStatsEvent}; use crate::events::{EventManager, Event};
use crate::executors::Executor; use crate::executors::Executor;
use crate::feedbacks::Feedback; use crate::feedbacks::Feedback;
use crate::generators::Generator; use crate::generators::Generator;
@ -17,7 +17,7 @@ use crate::inputs::Input;
use crate::observers::Observer; use crate::observers::Observer;
use crate::stages::Stage; use crate::stages::Stage;
use crate::utils::{current_milliseconds, Rand}; use crate::utils::{current_milliseconds, Rand};
use crate::{fire_event, AflError}; use crate::AflError;
// TODO FeedbackMetadata to store histroy_map // TODO FeedbackMetadata to store histroy_map
@ -177,9 +177,10 @@ where
for _ in 0..num { for _ in 0..num {
let input = generator.generate(rand)?; let input = generator.generate(rand)?;
state.add_input(corpus, input)?; state.add_input(corpus, input)?;
fire_event!(events, LoadInitialEvent)?; let event = Event::LoadInitial {sender_id: 0, _marker: PhantomData};
events.fire(event)?;
} }
events.process(state)?; events.process(state, corpus)?;
Ok(()) Ok(())
} }
@ -314,7 +315,7 @@ where
stage.perform(rand, state, corpus, events, &input)?; stage.perform(rand, state, corpus, events, &input)?;
} }
events.process(state)?; events.process(state, corpus)?;
Ok(idx) Ok(idx)
} }
@ -331,7 +332,7 @@ where
let cur = current_milliseconds(); let cur = current_milliseconds();
if cur - last > 60 * 100 { if cur - last > 60 * 100 {
last = cur; last = cur;
fire_event!(events, UpdateStatsEvent)?; events.fire(Event::UpdateStats {sender_id: 0, new_execs: 1, _marker: PhantomData})?; // TODO self.new_execs});
} }
} }
} }

View File

@ -8,9 +8,8 @@ pub mod shmem_translated;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use crate::events::llmp::LLMP; pub use crate::events::llmp::LLMP;
use core::fmt::Formatter;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::io::Write; use std::{marker::PhantomData, io::Write};
use crate::corpus::{Corpus, Testcase}; use crate::corpus::{Corpus, Testcase};
use crate::engines::State; use crate::engines::State;
@ -18,19 +17,18 @@ use crate::executors::Executor;
use crate::inputs::Input; use crate::inputs::Input;
use crate::utils::Rand; use crate::utils::Rand;
use crate::AflError; use crate::AflError;
/// Indicate if an event worked or not
pub enum EventDestination { enum BrokerEventResult {
Main, /// The broker haneled this. No need to pass it on.
Broker, Handled,
Clients, /// Pass this message along to the clients.
Forward,
} }
pub trait Event { /*
fn name() -> &'static str;
fn destination() -> EventDestination; /// A custom event, in case a user wants to extend the features (at compile time)
pub trait CustomEvent<S, C, E, I, R>
fn log<S, C, E, I, R>(&self, formatter: &mut Formatter, _state: &S) -> Result<(), AflError>
where where
S: State<C, E, I, R>, S: State<C, E, I, R>,
C: Corpus<I, R>, C: Corpus<I, R>,
@ -38,13 +36,16 @@ pub trait Event {
I: Input, I: Input,
R: Rand, R: Rand,
{ {
match write!(formatter, "[{}]", Self::name()) { /// Returns the name of this event
Ok(_) => Ok(()), fn name(&self) -> &str;
Err(_) => Err(AflError::Unknown("write error".into())), /// This method will be called in the broker
} fn handle_in_broker(&self, broker: &dyn EventManager<S, C, E, I, R, Self>, state: &mut S, corpus: &mut C) -> 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, client: &dyn EventManager<S, C, E, I, R, Self>, state: &mut S, corpus: &mut C) -> Result<(), AflError>;
} }
fn on_recv<S, C, E, I, R>(&self, _state: &mut S) -> Result<(), AflError> struct UnusedCustomEvent {}
impl<S, C, E, I, R> CustomEvent<S, C, E, I, R> for UnusedCustomEvent<S, C, E, I, R>
where where
S: State<C, E, I, R>, S: State<C, E, I, R>,
C: Corpus<I, R>, C: Corpus<I, R>,
@ -52,8 +53,92 @@ pub trait Event {
I: Input, I: Input,
R: Rand, R: Rand,
{ {
fn name(&self) -> &str {"No custom events"}
fn handle_in_broker(&self, broker: &dyn EventManager<S, C, E, I, R, Self>, state: &mut S, corpus: &mut C) {Ok(BrokerEventResult::Handled)}
fn handle_in_client(&self, client: &dyn EventManager<S, C, E, I, R, Self>, state: &mut S, corpus: &mut C) {Ok(())}
}
*/
/// Events sent around in the library
pub enum Event<S, C, E, I, R>
where
S: State<C, E, I, R>,
C: Corpus<I, R>,
E: Executor<I>,
I: Input,
R: Rand,
// CE: CustomEvent<S, C, E, I, R>,
{
LoadInitial {sender_id: u64, _marker: PhantomData<(S, C, E, I, R)>},
NewTestcase {sender_id: u64, input: I, fitness: u32, _marker: PhantomData<(S, C, E, I, R)>},
UpdateStats {sender_id: u64, new_execs: usize, _marker: PhantomData<(S, C, E, I, R)>},
Crash {sender_id: u64, input: I, _marker: PhantomData<(S, C, E, I, R)>},
Timeout {sender_id: u64, input: I, _marker: PhantomData<(S, C, E, I, R)>},
Log {sender_id: u64, severity_level: u8, message: String, _marker: PhantomData<(S, C, E, I, R)>},
//Custom {sender_id: u64, custom_event: CE},
}
impl<S, C, E, I, R> Event<S, C, E, I, R>
where
S: State<C, E, I, R>,
C: Corpus<I, R>,
E: Executor<I>,
I: Input,
R: Rand,
//CE: CustomEvent<S, C, E, I, R>,
{
fn name(&self) -> &str {
match self {
Event::LoadInitial {sender_id, _marker} => "Initial",
Event::NewTestcase {sender_id, input, fitness, _marker} => "New Testcase",
Event::UpdateStats {sender_id, new_execs, _marker} => "Stats",
Event::Crash {sender_id, input, _marker} => "Crash",
Event::Timeout {sender_id, input, _marker} => "Timeout",
Event::Log {sender_id, severity_level, message, _marker} => "Log",
//Event::Custom {sender_id, custom_event} => custom_event.name(),
}
}
fn handle_in_broker(&self, /*broker: &dyn EventManager<S, C, E, I, R>,*/ state: &mut S, corpus: &mut C) -> Result<BrokerEventResult, AflError> {
match self {
Event::LoadInitial {sender_id, _marker} => {
Ok(BrokerEventResult::Handled)
}
Event::NewTestcase {sender_id, input, fitness, _marker} => {
Ok(BrokerEventResult::Forward)
}
Event::UpdateStats {sender_id, new_execs, _marker} => {
// TODO
Ok(BrokerEventResult::Handled)
}
Event::Crash {sender_id, input, _marker} => {
Ok(BrokerEventResult::Handled)
}
Event::Timeout {sender_id, input, _marker} => {
// TODO
Ok(BrokerEventResult::Handled)
},
Event::Log {sender_id, severity_level, message, _marker} => {
//TODO: broker.log()
println!("{}[{}]: {}", sender_id, severity_level, message);
Ok(BrokerEventResult::Handled)
},
//Event::Custom {sender_id, custom_event} => custom_event.handle_in_broker(state, corpus),
_ => Ok(BrokerEventResult::Forward)
}
}
fn handle_in_client(&self, /*client: &dyn EventManager<S, C, E, I, R>,*/ state: &mut S, corpus: &mut C) -> Result<(), AflError> {
match self {
Event::NewTestcase {sender_id, input, fitness, _marker} => {
let mut testcase = Testcase::new(input.to_owned());
testcase.set_fitness(*fitness);
corpus.add(testcase);
Ok(()) Ok(())
} }
_ => Err(AflError::Unknown("Received illegal message that message should not have arrived.".into()))
}
}
// TODO serialize and deserialize, defaults to serde // TODO serialize and deserialize, defaults to serde
} }
@ -65,138 +150,56 @@ where
E: Executor<I>, E: Executor<I>,
I: Input, I: Input,
R: Rand, R: Rand,
//CE: CustomEvent<S, C, E, I, R>,
{ {
/// Check if this EventaManager support a given Event type /// Check if this EventaManager support a given Event type
/// To compare events, use Event::name().as_ptr() /// To compare events, use Event::name().as_ptr()
fn enabled<T>(&self) -> bool fn enabled(&self) -> bool;
where
T: Event;
/// Fire an Event /// Fire an Event
fn fire<T>(&mut self, event: T) -> Result<(), AflError> fn fire(&mut self, event: Event<S, C, E, I, R>) -> Result<(), AflError>;
where
T: Event;
/// Lookup for incoming events and process them. /// Lookup for incoming events and process them.
/// Return the number of processes events or an error /// Return the number of processes events or an error
fn process(&mut self, state: &mut S) -> Result<usize, AflError>; fn process(&mut self, state: &mut S, corpus: &mut C) -> Result<usize, AflError>;
}
// e.g. fire_event!(manager, MyEvent, myparam1, ...)
#[macro_export] fn on_recv(&self, _state: &mut S, corpus: &mut C) -> Result<(), AflError> {
macro_rules! fire_event { // TODO: Better way to move out of testcase, or get ref
($manager:expr, $event:ty, $( $x:expr ),+ ) => { //Ok(corpus.add(self.testcase.take().unwrap()))
{
if $manager.enabled::<$event>() {
$manager.fire(<$event>::new($( $x ),*))
} else {
Ok(()) Ok(())
} }
} }
};
($manager:expr, $event:ty) => { /*TODO
{ fn on_recv(&self, state: &mut S, _corpus: &mut C) -> Result<(), AflError> {
if $manager.enabled::<$event>() { println!(
$manager.fire(<$event>::new()) "#{}\t exec/s: {}",
} else { state.executions(),
//TODO: Count corpus.entries().len(),
state.executions_over_seconds()
);
Ok(()) Ok(())
} }
} */
};
}
pub struct LoadInitialEvent {}
impl Event for LoadInitialEvent {
fn name() -> &'static str {
"LOAD"
}
fn destination() -> EventDestination {
EventDestination::Broker
}
}
impl LoadInitialEvent {
pub fn new() -> Self {
LoadInitialEvent {}
}
}
pub struct NewTestcaseEvent<I>
where
I: Input,
{
testcase: Testcase<I>,
}
impl<I> Event for NewTestcaseEvent<I>
where
I: Input,
{
fn name() -> &'static str {
"NEW"
}
fn destination() -> EventDestination {
EventDestination::Clients
}
}
impl<I> NewTestcaseEvent<I>
where
I: Input,
{
pub fn new(testcase: Testcase<I>) -> Self {
NewTestcaseEvent { testcase: testcase }
}
pub fn testcase(&self) -> &Testcase<I> {
&self.testcase
}
}
pub struct UpdateStatsEvent {}
impl Event for UpdateStatsEvent {
fn name() -> &'static str {
"STATS"
}
fn destination() -> EventDestination {
EventDestination::Broker
}
}
impl UpdateStatsEvent {
pub fn new() -> Self {
UpdateStatsEvent {}
}
}
pub struct CrashEvent {}
impl Event for CrashEvent {
fn name() -> &'static str {
"CRASH"
}
fn destination() -> EventDestination {
EventDestination::Broker
}
}
impl CrashEvent {
pub fn new() -> Self {
CrashEvent {}
}
}
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub struct LoggerEventManager<W> pub struct LoggerEventManager<S, C, E, I, R, W>
where where
S: State<C, E, I, R>,
C: Corpus<I, R>,
I: Input,
E: Executor<I>,
R: Rand,
W: Write, W: Write,
//CE: CustomEvent<S, C, E, I, R>,
{ {
events: Vec<String>, events: Vec<Event<S, C, E, I, R>>,
writer: W, writer: W,
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<S, C, E, I, R, W> EventManager<S, C, E, I, R> for LoggerEventManager<W> impl<S, C, E, I, R, W> EventManager<S, C, E, I, R> for LoggerEventManager<S, C, E, I, R, W>
where where
S: State<C, E, I, R>, S: State<C, E, I, R>,
C: Corpus<I, R>, C: Corpus<I, R>,
@ -204,43 +207,58 @@ where
I: Input, I: Input,
R: Rand, R: Rand,
W: Write, W: Write,
//CE: CustomEvent<S, C, E, I, R>,
{ {
fn enabled<T>(&self) -> bool fn enabled(&self) -> bool
where
T: Event,
{ {
true true
} }
fn fire<T>(&mut self, _event: T) -> Result<(), AflError> fn fire(&mut self, event: Event<S, C, E, I, R>) -> Result<(), AflError>
where
T: Event,
{ {
self.events.push(T::name().to_string()); self.events.push(event);
Ok(()) Ok(())
} }
fn process(&mut self, state: &mut S) -> Result<usize, AflError> { fn process(&mut self, state: &mut S, corpus: &mut C) -> Result<usize, AflError> {
let num = self.events.len(); // TODO: iterators
for event in &self.events { let mut handled = vec!();
writeln!( for x in self.events.iter() {
&mut self.writer, handled.push(x.handle_in_broker(state, corpus)?);
"#{}\t[{}] exec/s: {}",
state.executions(),
event,
//TODO: Count corpus.entries().len(),
state.executions_over_seconds()
)?;
} }
handled.iter().zip(self.events.iter()).map(|(x, event)| match x {
BrokerEventResult::Forward => {
event.handle_in_client(state, corpus)
},
// Ignore broker-only events
BrokerEventResult::Handled => Ok(()),
}
).collect::<Result<(), AflError>>();
let count = self.events.len();
dbg!("Handled {} events", count);
self.events.clear(); self.events.clear();
Ok(num)
/*
let num = self.events.len();
for event in &self.events {}
self.events.clear();
*/
Ok(count)
} }
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<W> LoggerEventManager<W> impl<S, C, E, I, R, W> LoggerEventManager<S, C, E, I, R, W>
where where
S: State<C, E, I, R>,
C: Corpus<I, R>,
I: Input,
E: Executor<I>,
R: Rand,
W: Write, W: Write,
//TODO CE: CustomEvent,
{ {
pub fn new(writer: W) -> Self { pub fn new(writer: W) -> Self {
LoggerEventManager { LoggerEventManager {

View File

@ -1,6 +1,6 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::engines::State; use crate::{events::Event, engines::State};
use crate::events::EventManager; use crate::events::EventManager;
use crate::executors::Executor; use crate::executors::Executor;
use crate::inputs::Input; use crate::inputs::Input;
@ -9,7 +9,6 @@ use crate::stages::Corpus;
use crate::stages::Stage; use crate::stages::Stage;
use crate::utils::Rand; use crate::utils::Rand;
use crate::AflError; use crate::AflError;
use crate::{events::NewTestcaseEvent, fire_event};
// TODO multi mutators stage // TODO multi mutators stage
@ -56,8 +55,8 @@ where
.post_exec(interesting, &input_mut, i as i32)?; .post_exec(interesting, &input_mut, i as i32)?;
if interesting > 0 { if interesting > 0 {
let new_testcase = state.input_to_testcase(input_mut, interesting)?; //let new_testcase = state.input_to_testcase(input_mut, interesting)?;
fire_event!(events, NewTestcaseEvent<I>, new_testcase)?; events.fire(Event::NewTestcase { sender_id: 0, input: input_mut, fitness: interesting , _marker: PhantomData})?;
//state.corpus_mut().add(new_testcase); // TODO: Probably no longer needed, once events work //state.corpus_mut().add(new_testcase); // TODO: Probably no longer needed, once events work
} else { } else {
state.discard_input(&input_mut)?; state.discard_input(&input_mut)?;