Skip to content

Commit a2eb6ec

Browse files
authored
Add missing mode to LibAFL (#3708)
* Add support for AFL_PIZZA_MODE * Fix titles
1 parent 703c855 commit a2eb6ec

File tree

4 files changed

+456
-104
lines changed

4 files changed

+456
-104
lines changed

crates/libafl/src/monitors/mod.rs

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,49 @@ use core::{
3636
fmt::{Debug, Write},
3737
time::Duration,
3838
};
39+
#[cfg(feature = "std")]
40+
use std::sync::OnceLock;
3941

4042
use libafl_bolts::ClientId;
4143
#[cfg(feature = "prometheus_monitor")]
4244
pub use prometheus::PrometheusMonitor;
4345
#[cfg(feature = "statsd_monitor")]
4446
pub use statsd::StatsdMonitor;
4547

48+
/// Returns if we're cooking.
49+
#[cfg(feature = "std")]
50+
#[must_use]
51+
pub(crate) fn pizza_is_served() -> bool {
52+
static PIZZA_IS_SERVED: OnceLock<bool> = OnceLock::new();
53+
*PIZZA_IS_SERVED.get_or_init(|| {
54+
std::env::var("AFL_PIZZA_MODE").map_or(false, |v| v != "0") || {
55+
#[cfg(unix)]
56+
// SAFETY: `localtime` and `time` are standard libc functions. `t` is initialized.
57+
unsafe {
58+
let mut t = 0;
59+
libc::time(&raw mut t);
60+
let tm = libc::localtime(&raw const t);
61+
!tm.is_null() && (*tm).tm_mon == 3 && (*tm).tm_mday == 1
62+
}
63+
#[cfg(windows)]
64+
// SAFETY: `GetLocalTime` is a standard Win32 API.
65+
unsafe {
66+
let lt = windows::Win32::System::SystemInformation::GetLocalTime();
67+
lt.wMonth == 4 && lt.wDay == 1
68+
}
69+
#[cfg(not(any(unix, windows)))]
70+
false
71+
}
72+
})
73+
}
74+
75+
#[cfg(not(feature = "std"))]
76+
/// Returns `true` if it is currently pizza mode.
77+
#[must_use]
78+
pub fn pizza_is_served() -> bool {
79+
false
80+
}
81+
4682
use crate::monitors::stats::ClientStatsManager;
4783

4884
/// The monitor trait keeps track of all the client's monitor, and offers methods to display them.
@@ -117,15 +153,40 @@ impl Monitor for SimplePrintingMonitor {
117153
.collect::<Vec<_>>();
118154
userstats.sort();
119155
let global_stats = client_stats_manager.global_stats();
156+
let (run, customers, corpus, objectives, executions, speed) = if pizza_is_served() {
157+
(
158+
"time to bake",
159+
"customers",
160+
"pizzas",
161+
"deliveries",
162+
"doughs",
163+
"p/s",
164+
)
165+
} else {
166+
(
167+
"run time",
168+
"clients",
169+
"corpus",
170+
"objectives",
171+
"executions",
172+
"exec/sec",
173+
)
174+
};
120175
println!(
121-
"[{} #{}] run time: {}, clients: {}, corpus: {}, objectives: {}, executions: {}, exec/sec: {}, {}",
176+
"[{} #{}] {}: {}, {}: {}, {}: {}, {}: {}, {}: {}, {}: {}, {}",
122177
event_msg,
123178
sender_id.0,
179+
run,
124180
global_stats.run_time_pretty,
181+
customers,
125182
global_stats.client_stats_count,
183+
corpus,
126184
global_stats.corpus_size,
185+
objectives,
127186
global_stats.objective_size,
187+
executions,
128188
global_stats.total_execs,
189+
speed,
129190
global_stats.execs_per_sec_pretty,
130191
userstats.join(", ")
131192
);
@@ -175,15 +236,40 @@ where
175236
sender_id: ClientId,
176237
) -> Result<(), Error> {
177238
let global_stats = client_stats_manager.global_stats();
239+
let (run, customers, corpus, objectives, executions, speed) = if pizza_is_served() {
240+
(
241+
"time to bake",
242+
"customers",
243+
"pizzas",
244+
"deliveries",
245+
"doughs",
246+
"p/s",
247+
)
248+
} else {
249+
(
250+
"run time",
251+
"clients",
252+
"corpus",
253+
"objectives",
254+
"executions",
255+
"exec/sec",
256+
)
257+
};
178258
let mut fmt = format!(
179-
"[{} #{}] run time: {}, clients: {}, corpus: {}, objectives: {}, executions: {}, exec/sec: {}",
259+
"[{} #{}] {}: {}, {}: {}, {}: {}, {}: {}, {}: {}, {}: {}",
180260
event_msg,
181261
sender_id.0,
262+
run,
182263
global_stats.run_time_pretty,
264+
customers,
183265
global_stats.client_stats_count,
266+
corpus,
184267
global_stats.corpus_size,
268+
objectives,
185269
global_stats.objective_size,
270+
executions,
186271
global_stats.total_execs,
272+
speed,
187273
global_stats.execs_per_sec_pretty
188274
);
189275

@@ -309,4 +395,18 @@ mod test {
309395
);
310396
let _ = mgr_list.display(&mut client_stats, "test", ClientId(0));
311397
}
398+
399+
#[test]
400+
#[cfg(feature = "std")]
401+
fn test_pizza_mode() {
402+
let _ = super::pizza_is_served();
403+
}
404+
405+
#[test]
406+
#[cfg(feature = "std")]
407+
fn test_multi_monitor_pizza_mode() {
408+
use std::{cell::RefCell, string::String};
409+
let output = RefCell::new(String::new());
410+
let _monitor = super::MultiMonitor::new(|s| output.borrow_mut().push_str(s));
411+
}
312412
}

crates/libafl/src/monitors/multi.rs

Lines changed: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
//! The [`MultiMonitor`] displays both cumulative and per-client stats.
22
33
use alloc::string::String;
4-
use core::{
5-
fmt::{Debug, Formatter, Write},
6-
time::Duration,
7-
};
4+
use core::fmt::{Debug, Formatter, Write};
85

96
use libafl_bolts::{ClientId, Error, current_time};
107

@@ -17,6 +14,7 @@ where
1714
F: FnMut(&str),
1815
{
1916
print_fn: F,
17+
pizza_mode: bool,
2018
}
2119

2220
impl<F> Debug for MultiMonitor<F>
@@ -46,16 +44,29 @@ where
4644
};
4745
let head = format!("{event_msg}{pad} {sender}");
4846
let global_stats = client_stats_manager.global_stats();
49-
let mut global_fmt = format!(
50-
"[{}] (GLOBAL) run time: {}, clients: {}, corpus: {}, objectives: {}, executions: {}, exec/sec: {}",
51-
head,
52-
global_stats.run_time_pretty,
53-
global_stats.client_stats_count,
54-
global_stats.corpus_size,
55-
global_stats.objective_size,
56-
global_stats.total_execs,
57-
global_stats.execs_per_sec_pretty
58-
);
47+
let mut global_fmt = if self.pizza_mode {
48+
format!(
49+
"[{}] (GLOBAL) time to bake: {}, customers: {}, pizzas: {}, deliveries: {}, doughs: {}, p/s: {}, Pineapple pizzas: 0",
50+
head,
51+
global_stats.run_time_pretty,
52+
global_stats.client_stats_count,
53+
global_stats.corpus_size,
54+
global_stats.objective_size,
55+
global_stats.total_execs,
56+
global_stats.execs_per_sec_pretty
57+
)
58+
} else {
59+
format!(
60+
"[{}] (GLOBAL) run time: {}, clients: {}, corpus: {}, objectives: {}, executions: {}, exec/sec: {}",
61+
head,
62+
global_stats.run_time_pretty,
63+
global_stats.client_stats_count,
64+
global_stats.corpus_size,
65+
global_stats.objective_size,
66+
global_stats.total_execs,
67+
global_stats.execs_per_sec_pretty
68+
)
69+
};
5970
for (key, val) in client_stats_manager.aggregated() {
6071
write!(global_fmt, ", {key}: {val}").unwrap();
6172
}
@@ -64,19 +75,29 @@ where
6475

6576
client_stats_manager.client_stats_insert(sender_id)?;
6677
let cur_time = current_time();
67-
let exec_sec = client_stats_manager
78+
let exec_sec_val = client_stats_manager
6879
.update_client_stats_for(sender_id, |client| client.execs_per_sec_pretty(cur_time))?;
6980
let client = client_stats_manager.client_stats_for(sender_id)?;
7081

71-
let pad = " ".repeat(head.len());
72-
let mut fmt = format!(
73-
" {} (CLIENT) corpus: {}, objectives: {}, executions: {}, exec/sec: {}",
74-
pad,
75-
client.corpus_size(),
76-
client.objective_size(),
77-
client.executions(),
78-
exec_sec
79-
);
82+
let mut fmt = if self.pizza_mode {
83+
format!(
84+
" {} (CUSTOMER) pizzas: {}, deliveries: {}, doughs: {}, p/s: {}",
85+
pad,
86+
client.corpus_size(),
87+
client.objective_size(),
88+
client.executions(),
89+
exec_sec_val
90+
)
91+
} else {
92+
format!(
93+
" {} (CLIENT) corpus: {}, objectives: {}, executions: {}, exec/sec: {}",
94+
pad,
95+
client.corpus_size(),
96+
client.objective_size(),
97+
client.executions(),
98+
exec_sec_val
99+
)
100+
};
80101
for (key, val) in client.user_stats() {
81102
write!(fmt, ", {key}: {val}").unwrap();
82103
}
@@ -87,12 +108,29 @@ where
87108
{
88109
// Print the client performance monitor. Skip clients with no introspection data
89110
// (e.g., broker that never fuzzes will have elapsed_cycles == 0)
111+
let client_header = if self.pizza_mode {
112+
"Customer"
113+
} else {
114+
"Client"
115+
};
116+
let cycles_label = if self.pizza_mode {
117+
"pizzas baked"
118+
} else {
119+
"cycles"
120+
};
90121
for (client_id, client) in client_stats_manager
91122
.client_stats()
92123
.iter()
93124
.filter(|(_, x)| x.enabled() && x.introspection_stats.elapsed_cycles() > 0)
94125
{
95-
let fmt = format!("Client {:03}:\n{}", client_id.0, client.introspection_stats);
126+
let fmt = format!(
127+
"{} {:03}:\n{} {}: {}",
128+
client_header,
129+
client_id.0,
130+
client.introspection_stats,
131+
cycles_label,
132+
client.executions()
133+
);
96134
(self.print_fn)(&fmt);
97135
}
98136

@@ -109,15 +147,14 @@ where
109147
{
110148
/// Creates the monitor, using the `current_time` as `start_time`.
111149
pub fn new(print_fn: F) -> Self {
112-
Self { print_fn }
150+
Self {
151+
print_fn,
152+
pizza_mode: crate::monitors::pizza_is_served(),
153+
}
113154
}
114155

115-
/// Creates the monitor with a given `start_time`.
116-
#[deprecated(
117-
since = "0.16.0",
118-
note = "Please use new to create. start_time is useless here."
119-
)]
120-
pub fn with_time(print_fn: F, _start_time: Duration) -> Self {
121-
Self::new(print_fn)
156+
/// Adds pineapple.
157+
pub fn add_pineapple(&mut self) {
158+
self.pizza_mode = false;
122159
}
123160
}

0 commit comments

Comments
 (0)