From a739b91e2a1d5d9b49093e7ad96d15858258f86b Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 15 Dec 2020 11:28:15 +0100 Subject: [PATCH] Event as trait --- afl/src/engines/mod.rs | 15 +- afl/src/events/mod.rs | 759 +++++++++++++++++++++++------------ afl/src/stages/mutational.rs | 5 +- 3 files changed, 502 insertions(+), 277 deletions(-) diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index b656132489..dc9b44e7f3 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -6,7 +6,7 @@ use core::marker::PhantomData; use hashbrown::HashMap; use crate::corpus::{Corpus, Testcase}; -use crate::events::{Event, EventManager}; +use crate::events::EventManager; use crate::executors::{Executor, ExecutorsTuple, HasObservers}; use crate::feedbacks::FeedbacksTuple; use crate::generators::Generator; @@ -211,15 +211,11 @@ where if !self.add_if_interesting(corpus, input, fitness)?.is_none() { added += 1; } - manager.fire(Event::LoadInitial { - sender_id: 0, - phantom: PhantomData, - })?; } - manager.fire(Event::log( + manager.log( 0, format!("Loaded {} over {} initial testcases", added, num), - ))?; + )?; manager.process(self, corpus)?; Ok(()) } @@ -339,10 +335,7 @@ where let cur = current_milliseconds(); if cur - last > 60 * 100 { last = cur; - manager.fire(Event::update_stats( - state.executions(), - state.executions_over_seconds(), - ))?; + manager.update_stats(state.executions(), state.executions_over_seconds())?; } } } diff --git a/afl/src/events/mod.rs b/afl/src/events/mod.rs index fd18a0651f..cfed5e27a5 100644 --- a/afl/src/events/mod.rs +++ b/afl/src/events/mod.rs @@ -19,7 +19,7 @@ use crate::executors::Executor; use crate::feedbacks::FeedbacksTuple; use crate::inputs::Input; use crate::observers::ObserversTuple; -use crate::serde_anymap::SerdeAny; +use crate::serde_anymap::Ptr; use crate::utils::Rand; use crate::AflError; use crate::{engines::State, utils}; @@ -42,8 +42,9 @@ pub struct ClientStats { executions: u64, } +/* /// A custom event, for own messages, with own handler. -pub trait CustomEvent: SerdeAny + Serialize +pub trait CustomEvent: SerdeAny where I: Input, { @@ -54,135 +55,32 @@ where /// 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 -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(bound = "I: serde::de::DeserializeOwned")] -pub enum Event +pub trait Event where I: Input, { - LoadInitial { - sender_id: u64, - phantom: PhantomData, - }, - NewTestcase { - sender_id: u64, - input: I, - observers_buf: Vec, - client_config: String, - }, - UpdateStats { - sender_id: u64, - executions: usize, - execs_over_sec: u64, - phantom: PhantomData, - }, - Crash { - sender_id: u64, - input: I, - phantom: PhantomData, - }, - Timeout { - sender_id: u64, - input: I, - phantom: PhantomData, - }, - Log { - sender_id: u64, - severity_level: u8, - message: String, - phantom: PhantomData, - }, - None { - phantom: PhantomData, - }, - Custom { - sender_id: u64, - // TODO: Allow custom events - // custom_event: Box>, - }, -} - -impl Event -where - I: Input, -{ - pub fn name(&self) -> &str { - match self { - Event::LoadInitial { - sender_id: _, - phantom: _, - } => "Initial", - Event::NewTestcase { - sender_id: _, - input: _, - client_config: _, - observers_buf: _, - } => "New Testcase", - Event::UpdateStats { - sender_id: _, - executions: _, - execs_over_sec: _, - phantom: _, - } => "Stats", - Event::Crash { - sender_id: _, - input: _, - phantom: _, - } => "Crash", - Event::Timeout { - sender_id: _, - input: _, - phantom: _, - } => "Timeout", - Event::Log { - sender_id: _, - severity_level: _, - message: _, - phantom: _, - } => "Log", - Event::None { phantom: _ } => "None", - Event::Custom { - sender_id: _, /*custom_event} => custom_event.name()*/ - } => "todo", - } - } - - pub fn log(severity_level: u8, message: String) -> Self { - Event::Log { - sender_id: 0, - severity_level: severity_level, - message: message, - phantom: PhantomData, - } - } - - pub fn new_testcase(config: String, input: I, observers: &OT) -> Result + /// 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; + /// 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, + state: &mut State, + corpus: &mut C, + ) -> Result<(), AflError> where + C: Corpus, OT: ObserversTuple, - { - let observers_buf = postcard::to_allocvec(observers)?; - Ok(Self::NewTestcase { - sender_id: 0, - input: input, - client_config: config, - observers_buf: observers_buf, - }) - } - - pub fn update_stats(executions: usize, execs_over_sec: u64) -> Self { - Event::UpdateStats { - sender_id: 0, - executions: executions, - execs_over_sec: execs_over_sec, - phantom: PhantomData, - } - } + FT: FeedbacksTuple, + R: Rand; } #[derive(Debug, Clone, Default)] -struct Stats { +pub struct Stats { start_time: Duration, corpus_size: usize, client_stats: Vec, @@ -240,114 +138,6 @@ impl Stats { } &mut self.client_stats_mut()[client_id as usize] } - - /// Broker fun - #[inline] - fn handle_in_broker(&mut self, event: &Event) -> Result - where - I: Input, - { - match event { - Event::LoadInitial { - sender_id, - phantom: _, - } => { - let client = self.client_stats_mut_for(*sender_id); - client.corpus_size += 1; - Ok(BrokerEventResult::Handled) - } - Event::NewTestcase { - sender_id, - input: _, - observers_buf: _, - client_config: _, - } => { - let client = self.client_stats_mut_for(*sender_id); - client.corpus_size += 1; - println!("[NEW] client {}: corpus: {}", sender_id, self.corpus_size(),); - Ok(BrokerEventResult::Forward) - } - Event::UpdateStats { - sender_id, - executions, - execs_over_sec: _, - phantom: _, - } => { - // TODO: The stats buffer should be added on client add. - let client = self.client_stats_mut_for(*sender_id); - client.executions += *executions as u64; - println!( - "[UPDATE] from client {}, corpus: {} execs: {} execs/s: {}", - sender_id, - self.corpus_size(), - self.total_execs(), - self.execs_per_sec() - ); - Ok(BrokerEventResult::Handled) - } - Event::Crash { - sender_id: _, - input: _, - phantom: _, - } => { - panic!("LoggerEventManager cannot handle Event::Crash"); - } - Event::Timeout { - sender_id: _, - input: _, - phantom: _, - } => { - panic!("LoggerEventManager cannot handle Event::Timeout"); - } - Event::Log { - sender_id: _, - severity_level, - message, - phantom: _, - } => { - println!("[LOG {}]: {}", severity_level, message); - Ok(BrokerEventResult::Handled) - } - _ => Ok(BrokerEventResult::Forward), - } - } -} - -/// Client fun -#[inline] -fn handle_in_client( - event: Event, - state: &mut State, - corpus: &mut C, -) -> Result<(), AflError> -where - C: Corpus, - OT: ObserversTuple, - FT: FeedbacksTuple, - I: Input, - R: Rand, -{ - match event { - Event::NewTestcase { - sender_id: _, - input, - observers_buf, - client_config: _, - } => { - // TODO: here u should match client_config, if equal to the current one do not re-execute - // we need to pass engine to process() too, TODO - #[cfg(feature = "std")] - println!("Received new Testcase"); - let observers = postcard::from_bytes(&observers_buf)?; - let interestingness = state.is_interesting(&input, &observers)?; - state.add_if_interesting(corpus, input, interestingness)?; - Ok(()) - } - _ => Err(AflError::Unknown(format!( - "Received illegal message that message should not have arrived: {:?}.", - event - ))), - } } pub trait EventManager @@ -360,7 +150,7 @@ where R: Rand, { /// Fire an Event - fn fire<'a>(&mut self, event: Event) -> Result<(), AflError>; + //fn fire<'a>(&mut self, event: Event) -> Result<(), AflError>; /// Lookup for incoming events and process them. /// Return the number of processes events or an error @@ -377,9 +167,160 @@ where fn deserialize_observers(&mut self, observers_buf: &[u8]) -> Result { Ok(postcard::from_bytes(observers_buf)?) } + + fn new_testcase( + &mut self, + _input: &I, + _observers: &OT, + _corpus_size: usize, + _config: String, + ) -> Result<(), AflError> { + Ok(()) + } + + fn update_stats(&mut self, _executions: usize, _execs_over_sec: u64) -> Result<(), AflError> { + Ok(()) + } + + fn crash(&mut self, _input: &I) -> Result<(), AflError> { + Ok(()) + } + + fn timeout(&mut self, _input: &I) -> Result<(), AflError> { + Ok(()) + } + + fn log(&mut self, _severity_level: u8, _message: String) -> Result<(), AflError> { + Ok(()) + } + + // TODO Custom event fire (dyn CustomEvent or similar) +} + +#[derive(Debug)] +pub enum LoggerEvent +where + I: Input, +{ + NewTestcase { + corpus_size: usize, + phantom: PhantomData, + }, + UpdateStats { + executions: usize, + execs_over_sec: u64, + phantom: PhantomData, + }, + Crash { + input: I, + }, + Timeout { + input: I, + }, + Log { + severity_level: u8, + message: String, + phantom: PhantomData, + }, + /*Custom { + // TODO: Allow custom events + // custom_event: Box>, + },*/ +} + +impl Event for LoggerEvent +where + I: Input, +{ + #[inline] + fn name(&self) -> &str { + match self { + LoggerEvent::NewTestcase { + corpus_size: _, + phantom: _, + } => "New Testcase", + LoggerEvent::UpdateStats { + executions: _, + execs_over_sec: _, + phantom: _, + } => "Stats", + LoggerEvent::Crash { input: _ } => "Crash", + LoggerEvent::Timeout { input: _ } => "Timeout", + LoggerEvent::Log { + severity_level: _, + message: _, + phantom: _, + } => "Log", + /*Event::Custom => custom_event.name() + } => "todo",*/ + } + } + + /// Broker fun + #[inline] + fn handle_in_broker(&self, stats: &mut Stats) -> Result { + match self { + LoggerEvent::NewTestcase { + corpus_size, + phantom: _, + } => { + stats.client_stats_mut()[0].corpus_size = *corpus_size as u64; + println!("[NEW] corpus: {}", stats.corpus_size()); + Ok(BrokerEventResult::Handled) + } + LoggerEvent::UpdateStats { + executions, + execs_over_sec: _, + phantom: _, + } => { + // TODO: The stats buffer should be added on client add. + stats.client_stats_mut()[0].executions = *executions as u64; + println!( + "[UPDATE] corpus: {} execs: {} execs/s: {}", + stats.corpus_size(), + stats.total_execs(), + stats.execs_per_sec() + ); + Ok(BrokerEventResult::Handled) + } + LoggerEvent::Crash { input: _ } => { + panic!("LoggerEventManager cannot handle Event::Crash"); + } + LoggerEvent::Timeout { input: _ } => { + panic!("LoggerEventManager cannot handle Event::Timeout"); + } + LoggerEvent::Log { + severity_level, + message, + phantom: _, + } => { + println!("[LOG {}]: {}", severity_level, message); + Ok(BrokerEventResult::Handled) + } //_ => Ok(BrokerEventResult::Forward), + } + } + + #[inline] + fn handle_in_client( + self, + _state: &mut State, + _corpus: &mut C, + ) -> Result<(), AflError> + where + C: Corpus, + OT: ObserversTuple, + FT: FeedbacksTuple, + R: Rand, + { + match self { + _ => Err(AflError::Unknown(format!( + "Received illegal message that message should not have arrived: {:?}.", + self + ))), + } + } } -#[cfg(feature = "std")] pub struct LoggerEventManager where C: Corpus, @@ -394,12 +335,11 @@ where writer: W, stats: Stats, - events: Vec>, + events: Vec>, // stats (maybe we need a separated struct?) phantom: PhantomData<(C, E, I, R, OT, FT)>, } -#[cfg(feature = "std")] impl EventManager for LoggerEventManager where @@ -412,16 +352,6 @@ where W: Write, //CE: CustomEvent, { - #[inline] - fn fire<'a>(&mut self, event: Event) -> Result<(), AflError> { - match self.stats.handle_in_broker(&event)? { - BrokerEventResult::Forward => self.events.push(event), - // Ignore broker-only events - BrokerEventResult::Handled => (), - } - Ok(()) - } - fn process( &mut self, state: &mut State, @@ -430,12 +360,77 @@ where let count = self.events.len(); self.events .drain(..) - .try_for_each(|event| handle_in_client(event, state, corpus))?; + .try_for_each(|event| event.handle_in_client(state, corpus))?; Ok(count) } + + fn new_testcase( + &mut self, + _input: &I, + _observers: &OT, + corpus_size: usize, + _config: String, + ) -> Result<(), AflError> { + let event = LoggerEvent::NewTestcase { + corpus_size: corpus_size, + phantom: PhantomData, + }; + match event.handle_in_broker(&mut self.stats)? { + BrokerEventResult::Forward => self.events.push(event), + _ => (), + }; + Ok(()) + } + + fn update_stats(&mut self, executions: usize, execs_over_sec: u64) -> Result<(), AflError> { + let event = LoggerEvent::UpdateStats { + executions: executions, + execs_over_sec: execs_over_sec, + phantom: PhantomData, + }; + match event.handle_in_broker(&mut self.stats)? { + BrokerEventResult::Forward => self.events.push(event), + _ => (), + }; + Ok(()) + } + + fn crash(&mut self, input: &I) -> Result<(), AflError> { + let event = LoggerEvent::Crash { + input: input.clone(), + }; + match event.handle_in_broker(&mut self.stats)? { + BrokerEventResult::Forward => self.events.push(event), + _ => (), + }; + Ok(()) + } + + fn timeout(&mut self, input: &I) -> Result<(), AflError> { + let event = LoggerEvent::Timeout { + input: input.clone(), + }; + match event.handle_in_broker(&mut self.stats)? { + BrokerEventResult::Forward => self.events.push(event), + _ => (), + }; + Ok(()) + } + + fn log(&mut self, severity_level: u8, message: String) -> Result<(), AflError> { + let event = LoggerEvent::Log { + severity_level: severity_level, + message: message, + phantom: PhantomData, + }; + match event.handle_in_broker(&mut self.stats)? { + BrokerEventResult::Forward => self.events.push(event), + _ => (), + }; + Ok(()) + } } -#[cfg(feature = "std")] impl LoggerEventManager where C: Corpus, @@ -460,6 +455,173 @@ where } } +#[cfg(feature = "std")] +#[derive(Serialize, Deserialize)] +#[serde(bound = "I: serde::de::DeserializeOwned")] +pub enum LLMPEventKind<'a, I> +where + I: Input, +{ + NewTestcase { + input: Ptr<'a, I>, + observers_buf: Vec, + corpus_size: usize, + client_config: String, + }, + UpdateStats { + executions: usize, + execs_over_sec: u64, + phantom: PhantomData<&'a I>, + }, + Crash { + input: I, + }, + Timeout { + input: I, + }, + Log { + severity_level: u8, + message: String, + phantom: PhantomData, + }, + /*Custom { + // TODO: Allow custom events + // custom_event: Box>, + },*/ +} + +#[cfg(feature = "std")] +#[derive(Serialize, Deserialize)] +#[serde(bound = "I: serde::de::DeserializeOwned")] +pub struct LLMPEvent<'a, I> +where + I: Input, +{ + sender_id: u64, + kind: LLMPEventKind<'a, I>, +} + +#[cfg(feature = "std")] +impl<'a, I> Event for LLMPEvent<'a, I> +where + I: Input, +{ + fn name(&self) -> &str { + match self.kind { + LLMPEventKind::NewTestcase { + input: _, + client_config: _, + corpus_size: _, + observers_buf: _, + } => "New Testcase", + LLMPEventKind::UpdateStats { + executions: _, + execs_over_sec: _, + phantom: _, + } => "Stats", + LLMPEventKind::Crash { input: _ } => "Crash", + LLMPEventKind::Timeout { input: _ } => "Timeout", + LLMPEventKind::Log { + severity_level: _, + message: _, + phantom: _, + } => "Log", + /*Event::Custom { + sender_id: _, /*custom_event} => custom_event.name()*/ + } => "todo",*/ + } + } + + /// Broker fun + #[inline] + fn handle_in_broker(&self, stats: &mut Stats) -> Result { + match &self.kind { + LLMPEventKind::NewTestcase { + input: _, + client_config: _, + corpus_size, + observers_buf: _, + } => { + let client = stats.client_stats_mut_for(self.sender_id); + client.corpus_size = *corpus_size as u64; + println!("[NEW] corpus: {}", stats.corpus_size()); + Ok(BrokerEventResult::Handled) + } + LLMPEventKind::UpdateStats { + executions, + execs_over_sec: _, + phantom: _, + } => { + // TODO: The stats buffer should be added on client add. + let client = stats.client_stats_mut_for(self.sender_id); + client.executions = *executions as u64; + println!( + "[UPDATE] corpus: {} execs: {} execs/s: {}", + stats.corpus_size(), + stats.total_execs(), + stats.execs_per_sec() + ); + Ok(BrokerEventResult::Handled) + } + LLMPEventKind::Crash { input: _ } => { + panic!("LoggerEventManager cannot handle Event::Crash"); + } + LLMPEventKind::Timeout { input: _ } => { + panic!("LoggerEventManager cannot handle Event::Timeout"); + } + LLMPEventKind::Log { + severity_level, + message, + phantom: _, + } => { + println!("[LOG {}]: {}", severity_level, message); + Ok(BrokerEventResult::Handled) + } + _ => Ok(BrokerEventResult::Forward), + } + } + + #[inline] + fn handle_in_client( + self, + state: &mut State, + corpus: &mut C, + ) -> Result<(), AflError> + where + C: Corpus, + OT: ObserversTuple, + FT: FeedbacksTuple, + R: Rand, + { + match self.kind { + LLMPEventKind::NewTestcase { + input, + client_config: _, + corpus_size: _, + observers_buf, + } => { + // TODO: here u should match client_config, if equal to the current one do not re-execute + // we need to pass engine to process() too, TODO + #[cfg(feature = "std")] + println!("Received new Testcase"); + let observers = postcard::from_bytes(&observers_buf)?; + let interestingness = state.is_interesting(input.as_ref(), &observers)?; + match input { + Ptr::Owned(b) => { + state.add_if_interesting(corpus, *b, interestingness)?; + } + _ => {} + }; + Ok(()) + } + _ => Err(AflError::Unknown(format!( + "Received illegal message that message should not have arrived: {:?}.", + self.name() + ))), + } + } +} + #[cfg(feature = "std")] /// Forward this to the client const _LLMP_TAG_EVENT_TO_CLIENT: llmp::Tag = 0x2C11E471; @@ -532,8 +694,8 @@ where broker.loop_forever( &mut |_client_id: u32, tag: Tag, msg: &[u8]| { if tag == LLMP_TAG_EVENT_TO_BOTH { - let event = postcard::from_bytes(msg)?; - match stats.handle_in_broker::(&event)? { + let event: LLMPEvent = postcard::from_bytes(msg)?; + match event.handle_in_broker(stats)? { BrokerEventResult::Forward => { Ok(llmp::LlmpMsgHookResult::ForwardToClients) } @@ -551,6 +713,13 @@ where )), } } + + #[inline] + fn llmp_send<'a>(&mut self, event: LLMPEvent<'a, I>) -> Result<(), AflError> { + let serialized = postcard::to_allocvec(&event)?; + self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; + Ok(()) + } } #[cfg(feature = "std")] @@ -566,13 +735,6 @@ where W: Write, //CE: CustomEvent, { - #[inline] - fn fire<'a>(&mut self, event: Event) -> Result<(), AflError> { - let serialized = postcard::to_allocvec(&event)?; - self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; - Ok(()) - } - fn process( &mut self, state: &mut State, @@ -588,8 +750,8 @@ where if tag == _LLMP_TAG_EVENT_TO_BROKER { continue; } - let event: Event = postcard::from_bytes(event_buf)?; - handle_in_client(event, state, corpus)?; + let event: LLMPEvent = postcard::from_bytes(event_buf)?; + event.handle_in_client(state, corpus)?; count += 1; } None => break count, @@ -602,16 +764,81 @@ where } }) } + + fn new_testcase( + &mut self, + input: &I, + observers: &OT, + corpus_size: usize, + config: String, + ) -> Result<(), AflError> { + let event = LLMPEvent { + sender_id: 0, + kind: LLMPEventKind::NewTestcase { + input: Ptr::Ref(input), + observers_buf: postcard::to_allocvec(observers)?, + corpus_size: corpus_size, + client_config: config, + }, + }; + self.llmp_send(event) + } + + fn update_stats(&mut self, executions: usize, execs_over_sec: u64) -> Result<(), AflError> { + let event = LLMPEvent { + sender_id: 0, + kind: LLMPEventKind::UpdateStats { + executions: executions, + execs_over_sec: execs_over_sec, + phantom: PhantomData, + }, + }; + self.llmp_send(event) + } + + fn crash(&mut self, input: &I) -> Result<(), AflError> { + let event = LLMPEvent { + sender_id: 0, + kind: LLMPEventKind::Crash { + input: input.clone(), + }, + }; + self.llmp_send(event) + } + + fn timeout(&mut self, input: &I) -> Result<(), AflError> { + let event = LLMPEvent { + sender_id: 0, + kind: LLMPEventKind::Timeout { + input: input.clone(), + }, + }; + self.llmp_send(event) + } + + fn log(&mut self, severity_level: u8, message: String) -> Result<(), AflError> { + let event = LLMPEvent { + sender_id: 0, + kind: LLMPEventKind::Log { + severity_level: severity_level, + message: message, + phantom: PhantomData, + }, + }; + self.llmp_send(event) + } } #[cfg(feature = "std")] #[cfg(test)] mod tests { + use crate::events::{LLMPEvent, LLMPEventKind}; use crate::inputs::bytes::BytesInput; + use crate::observers::ObserversTuple; use crate::observers::StdMapObserver; + use crate::serde_anymap::Ptr; use crate::tuples::{tuple_list, MatchNameAndType, Named}; - use crate::{events::Event, observers::ObserversTuple}; static mut MAP: [u32; 4] = [0; 4]; #[test] @@ -622,20 +849,24 @@ mod tests { // test_event_mgr.serialize_observers(&map).unwrap(); let i = BytesInput::new(vec![0]); - let e = Event::NewTestcase { + let e = LLMPEvent { sender_id: 0, - input: i, - observers_buf, - client_config: "conf".into(), + kind: LLMPEventKind::NewTestcase { + input: Ptr::Ref(&i), + observers_buf, + corpus_size: 123, + client_config: "conf".into(), + }, }; let serialized = postcard::to_allocvec(&e).unwrap(); - match postcard::from_bytes::>(&serialized).unwrap() { - Event::NewTestcase { - sender_id: _, + let d = postcard::from_bytes::>(&serialized).unwrap(); + match d.kind { + LLMPEventKind::NewTestcase { input: _, observers_buf, + corpus_size: _, client_config: _, } => { let o = map.deserialize(&observers_buf).unwrap(); diff --git a/afl/src/stages/mutational.rs b/afl/src/stages/mutational.rs index 501dc66dee..4b3d620d6f 100644 --- a/afl/src/stages/mutational.rs +++ b/afl/src/stages/mutational.rs @@ -1,5 +1,6 @@ use core::marker::PhantomData; +use crate::engines::State; use crate::events::EventManager; use crate::executors::{Executor, ExecutorsTuple, HasObservers}; use crate::feedbacks::FeedbacksTuple; @@ -10,7 +11,6 @@ use crate::stages::Corpus; use crate::stages::{Engine, Stage}; use crate::utils::Rand; use crate::AflError; -use crate::{engines::State, events::Event}; // TODO multi mutators stage @@ -73,7 +73,8 @@ where // if needed by particular cases if fitness > 0 { // TODO decouple events manager and engine - manager.fire(Event::new_testcase("test".into(), input_mut, observers)?)?; + manager.new_testcase(&input_mut, observers, corpus.count() + 1, "test".into())?; + state.add_if_interesting(corpus, input_mut, fitness)?; // let _ = corpus.add(testcase); } else { state.discard_input(&input_mut)?;