Skip to content

Commit 9dff7a4

Browse files
authored
Add client stats to Events (#3116)
* add stats alongside Event over the wire
1 parent 184b69b commit 9dff7a4

File tree

20 files changed

+463
-340
lines changed

20 files changed

+463
-340
lines changed

fuzzers/forkserver/libafl-fuzz/src/hooks.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use libafl::{
2-
events::{Event, EventManagerHook},
2+
events::{Event, EventManagerHook, EventWithStats},
33
state::Stoppable,
44
Error,
55
};
@@ -18,9 +18,9 @@ where
1818
&mut self,
1919
state: &mut S,
2020
_client_id: ClientId,
21-
event: &Event<I>,
21+
event: &EventWithStats<I>,
2222
) -> Result<bool, Error> {
23-
if self.exit_on_solution && matches!(event, Event::Objective { .. }) {
23+
if self.exit_on_solution && matches!(event.event(), Event::Objective { .. }) {
2424
// TODO: dump state
2525
state.request_stop();
2626
}

libafl/src/corpus/minimizer.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use core::{hash::Hash, marker::PhantomData};
66

77
use hashbrown::{HashMap, HashSet};
88
use libafl_bolts::{
9-
AsIter, Named, current_time,
9+
AsIter, Named,
1010
tuples::{Handle, Handled},
1111
};
1212
use num_traits::ToPrimitive;
@@ -15,7 +15,7 @@ use z3::{Config, Context, Optimize, ast::Bool};
1515
use crate::{
1616
Error, HasMetadata, HasScheduler,
1717
corpus::Corpus,
18-
events::{Event, EventFirer, LogSeverity},
18+
events::{Event, EventFirer, EventWithStats, LogSeverity},
1919
executors::{Executor, HasObservers},
2020
inputs::Input,
2121
monitors::stats::{AggregatorOps, UserStats, UserStatsValue},
@@ -123,20 +123,17 @@ where
123123

124124
manager.fire(
125125
state,
126-
Event::UpdateUserStats {
127-
name: Cow::from("minimisation exec pass"),
128-
value: UserStats::new(UserStatsValue::Ratio(curr, total), AggregatorOps::None),
129-
phantom: PhantomData,
130-
},
131-
)?;
132-
133-
manager.fire(
134-
state,
135-
Event::UpdateExecStats {
136-
time: current_time(),
137-
phantom: PhantomData,
126+
EventWithStats::with_current_time(
127+
Event::UpdateUserStats {
128+
name: Cow::from("minimisation exec pass"),
129+
value: UserStats::new(
130+
UserStatsValue::Ratio(curr, total),
131+
AggregatorOps::None,
132+
),
133+
phantom: PhantomData,
134+
},
138135
executions,
139-
},
136+
),
140137
)?;
141138

142139
let seed_expr = Bool::fresh_const(&ctx, "seed");

libafl/src/events/broker_hooks/centralized.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use serde::de::DeserializeOwned;
1111

1212
#[cfg(feature = "llmp_compression")]
1313
use crate::events::COMPRESS_THRESHOLD;
14-
use crate::events::{_LLMP_TAG_TO_MAIN, BrokerEventResult, Event};
14+
use crate::events::{_LLMP_TAG_TO_MAIN, BrokerEventResult, Event, EventWithStats};
1515

1616
/// An LLMP-backed event manager for scalable multi-processed fuzzing
1717
pub struct CentralizedLlmpHook<I> {
@@ -47,7 +47,7 @@ where
4747
} else {
4848
&*msg
4949
};
50-
let event: Event<I> = postcard::from_bytes(event_bytes)?;
50+
let event: EventWithStats<I> = postcard::from_bytes(event_bytes)?;
5151
match Self::handle_in_broker(client_id, &event)? {
5252
BrokerEventResult::Forward => Ok(LlmpMsgHookResult::ForwardToClients),
5353
BrokerEventResult::Handled => Ok(LlmpMsgHookResult::Handled),
@@ -85,9 +85,9 @@ impl<I> CentralizedLlmpHook<I> {
8585
#[expect(clippy::unnecessary_wraps)]
8686
fn handle_in_broker(
8787
_client_id: ClientId,
88-
event: &Event<I>,
88+
event: &EventWithStats<I>,
8989
) -> Result<BrokerEventResult, Error> {
90-
match &event {
90+
match event.event() {
9191
Event::NewTestcase { .. } | Event::Stop => Ok(BrokerEventResult::Forward),
9292
_ => Ok(BrokerEventResult::Handled),
9393
}

libafl/src/events/broker_hooks/centralized_multi_machine.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use tokio::{
2222

2323
use crate::{
2424
events::{
25-
Event,
25+
EventWithStats,
2626
centralized::_LLMP_TAG_TO_MAIN,
2727
multi_machine::{MultiMachineMsg, TcpMultiMachineState},
2828
},
@@ -128,7 +128,7 @@ where
128128
#[cfg(feature = "llmp_compression")]
129129
fn try_compress(
130130
state_lock: &mut RwLockWriteGuard<TcpMultiMachineState<A>>,
131-
event: &Event<I>,
131+
event: &EventWithStats<I>,
132132
) -> Result<(Flags, Vec<u8>), Error> {
133133
let serialized = postcard::to_allocvec(&event)?;
134134

@@ -141,7 +141,7 @@ where
141141
#[cfg(not(feature = "llmp_compression"))]
142142
fn try_compress(
143143
_state_lock: &mut RwLockWriteGuard<TcpMultiMachineState<A>>,
144-
event: &Event<I>,
144+
event: &EventWithStats<I>,
145145
) -> Result<(Flags, Vec<u8>), Error> {
146146
Ok((Flags(0), postcard::to_allocvec(&event)?))
147147
}

libafl/src/events/broker_hooks/mod.rs

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub mod centralized_multi_machine;
3030
#[cfg(all(unix, feature = "multi_machine"))]
3131
pub use centralized_multi_machine::*;
3232

33+
use super::EventWithStats;
34+
3335
/// An LLMP-backed event hook for scalable multi-processed fuzzing
3436
#[derive(Debug)]
3537
pub struct StdLlmpEventHook<I, MT> {
@@ -71,7 +73,7 @@ where
7173
} else {
7274
&*msg
7375
};
74-
let event: Event<I> = postcard::from_bytes(event_bytes)?;
76+
let event: EventWithStats<I> = postcard::from_bytes(event_bytes)?;
7577
match Self::handle_in_broker(
7678
monitor,
7779
&mut self.client_stats_manager,
@@ -117,8 +119,16 @@ where
117119
monitor: &mut MT,
118120
client_stats_manager: &mut ClientStatsManager,
119121
client_id: ClientId,
120-
event: &Event<I>,
122+
event: &EventWithStats<I>,
121123
) -> Result<BrokerEventResult, Error> {
124+
let stats = event.stats();
125+
126+
client_stats_manager.client_stats_insert(ClientId(0));
127+
client_stats_manager.update_client_stats_for(ClientId(0), |client_stat| {
128+
client_stat.update_executions(stats.executions, stats.time);
129+
});
130+
131+
let event = event.event();
122132
match &event {
123133
Event::NewTestcase {
124134
corpus_size,
@@ -138,19 +148,7 @@ where
138148
monitor.display(client_stats_manager, event.name(), id);
139149
Ok(BrokerEventResult::Forward)
140150
}
141-
Event::UpdateExecStats {
142-
time,
143-
executions,
144-
phantom: _,
145-
} => {
146-
// TODO: The monitor buffer should be added on client add.
147-
client_stats_manager.client_stats_insert(client_id);
148-
client_stats_manager.update_client_stats_for(client_id, |client_stat| {
149-
client_stat.update_executions(*executions, *time);
150-
});
151-
monitor.display(client_stats_manager, event.name(), client_id);
152-
Ok(BrokerEventResult::Handled)
153-
}
151+
Event::Heartbeat => Ok(BrokerEventResult::Handled),
154152
Event::UpdateUserStats { name, value, .. } => {
155153
client_stats_manager.client_stats_insert(client_id);
156154
client_stats_manager.update_client_stats_for(client_id, |client_stat| {
@@ -162,8 +160,6 @@ where
162160
}
163161
#[cfg(feature = "introspection")]
164162
Event::UpdatePerfMonitor {
165-
time,
166-
executions,
167163
introspection_stats,
168164
phantom: _,
169165
} => {
@@ -172,8 +168,6 @@ where
172168
// Get the client for the staterestorer ID
173169
client_stats_manager.client_stats_insert(client_id);
174170
client_stats_manager.update_client_stats_for(client_id, |client_stat| {
175-
// Update the normal monitor for this client
176-
client_stat.update_executions(*executions, *time);
177171
// Update the performance monitor for this client
178172
client_stat.update_introspection_stats((**introspection_stats).clone());
179173
});

libafl/src/events/centralized.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use libafl_bolts::{
2222
llmp::{LLMP_FLAG_COMPRESSED, LLMP_FLAG_INITIALIZED},
2323
};
2424

25-
use super::AwaitRestartSafe;
25+
use super::{AwaitRestartSafe, EventWithStats};
2626
#[cfg(feature = "llmp_compression")]
2727
use crate::events::llmp::COMPRESS_THRESHOLD;
2828
use crate::{
@@ -166,18 +166,18 @@ where
166166
}
167167

168168
#[expect(clippy::match_same_arms)]
169-
fn fire(&mut self, state: &mut S, mut event: Event<I>) -> Result<(), Error> {
169+
fn fire(&mut self, state: &mut S, mut event: EventWithStats<I>) -> Result<(), Error> {
170170
if !self.is_main {
171171
// secondary node
172172
let mut is_tc = false;
173173
// Forward to main only if new tc, heartbeat, or optionally, a new objective
174-
let should_be_forwarded = match &mut event {
174+
let should_be_forwarded = match event.event_mut() {
175175
Event::NewTestcase { forward_id, .. } => {
176176
*forward_id = Some(ClientId(self.inner.mgr_id().0 as u32));
177177
is_tc = true;
178178
true
179179
}
180-
Event::UpdateExecStats { .. } => true, // send UpdateExecStats but this guy won't be handled. the only purpose is to keep this client alive else the broker thinks it is dead and will dc it
180+
Event::Heartbeat => true, // the only purpose is to keep this client alive else the broker thinks it is dead and will dc it
181181
Event::Objective { .. } => true,
182182
Event::Stop => true,
183183
_ => false,
@@ -201,7 +201,10 @@ where
201201
state: &mut S,
202202
severity_level: LogSeverity,
203203
message: String,
204-
) -> Result<(), Error> {
204+
) -> Result<(), Error>
205+
where
206+
S: HasExecutions,
207+
{
205208
self.inner.log(state, severity_level, message)
206209
}
207210

@@ -261,7 +264,7 @@ where
261264
SHM: ShMem,
262265
SP: ShMemProvider<ShMem = SHM>,
263266
{
264-
fn try_receive(&mut self, state: &mut S) -> Result<Option<(Event<I>, bool)>, Error> {
267+
fn try_receive(&mut self, state: &mut S) -> Result<Option<(EventWithStats<I>, bool)>, Error> {
265268
if self.is_main {
266269
// main node
267270
self.receive_from_secondary(state)
@@ -272,7 +275,7 @@ where
272275
}
273276
}
274277

275-
fn on_interesting(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error> {
278+
fn on_interesting(&mut self, state: &mut S, event: EventWithStats<I>) -> Result<(), Error> {
276279
self.inner.fire(state, event)
277280
}
278281
}
@@ -343,7 +346,7 @@ where
343346
SP: ShMemProvider<ShMem = SHM>,
344347
{
345348
#[cfg(feature = "llmp_compression")]
346-
fn forward_to_main(&mut self, event: &Event<I>) -> Result<(), Error> {
349+
fn forward_to_main(&mut self, event: &EventWithStats<I>) -> Result<(), Error> {
347350
let serialized = postcard::to_allocvec(event)?;
348351
let flags = LLMP_FLAG_INITIALIZED;
349352

@@ -363,13 +366,16 @@ where
363366
}
364367

365368
#[cfg(not(feature = "llmp_compression"))]
366-
fn forward_to_main(&mut self, event: &Event<I>) -> Result<(), Error> {
369+
fn forward_to_main(&mut self, event: &EventWithStats<I>) -> Result<(), Error> {
367370
let serialized = postcard::to_allocvec(event)?;
368371
self.client.send_buf(_LLMP_TAG_TO_MAIN, &serialized)?;
369372
Ok(())
370373
}
371374

372-
fn receive_from_secondary(&mut self, state: &mut S) -> Result<Option<(Event<I>, bool)>, Error> {
375+
fn receive_from_secondary(
376+
&mut self,
377+
state: &mut S,
378+
) -> Result<Option<(EventWithStats<I>, bool)>, Error> {
373379
// TODO: Get around local event copy by moving handle_in_client
374380
let self_id = self.client.sender().id();
375381
while let Some((client_id, tag, _flags, msg)) = self.client.recv_buf_with_flags()? {
@@ -392,15 +398,18 @@ where
392398
} else {
393399
msg
394400
};
395-
let event: Event<I> = postcard::from_bytes(event_bytes)?;
396-
log::debug!("Processor received message {}", event.name_detailed());
401+
let event: EventWithStats<I> = postcard::from_bytes(event_bytes)?;
402+
log::debug!(
403+
"Processor received message {}",
404+
event.event().name_detailed()
405+
);
397406

398-
let event_name = event.name_detailed();
407+
let event_name = event.event().name_detailed();
399408

400-
match event {
409+
match event.event() {
401410
Event::NewTestcase {
402411
client_config,
403-
ref observers_buf,
412+
observers_buf,
404413
forward_id,
405414
..
406415
} => {
@@ -425,7 +434,7 @@ where
425434
_ => {
426435
return Err(Error::illegal_state(format!(
427436
"Received illegal message that message should not have arrived: {:?}.",
428-
event.name()
437+
event.event().name()
429438
)));
430439
}
431440
}

libafl/src/events/events_hooks/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//! other clients
55
use libafl_bolts::ClientId;
66

7-
use crate::{Error, events::Event};
7+
use crate::{Error, events::EventWithStats};
88

99
/// The `broker_hooks` that are run before and after the event manager calls `try_receive`
1010
pub trait EventManagerHook<I, S> {
@@ -14,7 +14,7 @@ pub trait EventManagerHook<I, S> {
1414
&mut self,
1515
state: &mut S,
1616
client_id: ClientId,
17-
event: &Event<I>,
17+
event: &EventWithStats<I>,
1818
) -> Result<bool, Error>;
1919
}
2020

@@ -25,7 +25,7 @@ pub trait EventManagerHooksTuple<I, S> {
2525
&mut self,
2626
state: &mut S,
2727
client_id: ClientId,
28-
event: &Event<I>,
28+
event: &EventWithStats<I>,
2929
) -> Result<bool, Error>;
3030
}
3131

@@ -35,7 +35,7 @@ impl<I, S> EventManagerHooksTuple<I, S> for () {
3535
&mut self,
3636
_state: &mut S,
3737
_client_id: ClientId,
38-
_event: &Event<I>,
38+
_event: &EventWithStats<I>,
3939
) -> Result<bool, Error> {
4040
Ok(true)
4141
}
@@ -51,7 +51,7 @@ where
5151
&mut self,
5252
state: &mut S,
5353
client_id: ClientId,
54-
event: &Event<I>,
54+
event: &EventWithStats<I>,
5555
) -> Result<bool, Error> {
5656
let first = self.0.pre_receive(state, client_id, event)?;
5757
let second = self.1.pre_receive_all(state, client_id, event)?;

0 commit comments

Comments
 (0)