diff --git a/docs/src/core_concepts/mutator.md b/docs/src/core_concepts/mutator.md index 1956befd7c..8406de7918 100644 --- a/docs/src/core_concepts/mutator.md +++ b/docs/src/core_concepts/mutator.md @@ -6,6 +6,6 @@ Mutators can be composed, and they are generally linked to a specific Input type There can be, for instance, a Mutator that applies more than a single type of mutation to the input. Consider a generic Mutator for a byte stream, bit flip is just one of the possible mutations but not the only one, there is also, for instance, the random replacement of a byte of the copy of a chunk. -There are also mutators that always produce valid inputs, say a mutator that generates valid JSON or code, but these grammar based mutators need a grammar to work. +There are also mutators that always produce valid inputs, say a mutator that generates valid Json or code, but these grammar based mutators need a grammar to work. In LibAFL, [`Mutator`](https://docs.rs/libafl/latest/libafl/mutators/trait.Mutator.html) is a trait. diff --git a/fuzzers/baby_fuzzer_multi/src/main.rs b/fuzzers/baby_fuzzer_multi/src/main.rs index 8956f8c1ac..6e7d9ae14d 100644 --- a/fuzzers/baby_fuzzer_multi/src/main.rs +++ b/fuzzers/baby_fuzzer_multi/src/main.rs @@ -3,7 +3,7 @@ use std::ptr::write_volatile; use std::{path::PathBuf, ptr::write}; #[cfg(feature = "tui")] -use libafl::monitors::tui::{ui::TuiUI, TuiMonitor}; +use libafl::monitors::tui::TuiMonitor; #[cfg(not(feature = "tui"))] use libafl::monitors::SimpleMonitor; use libafl::{ @@ -118,9 +118,10 @@ pub fn main() { #[cfg(not(feature = "tui"))] let mon = SimpleMonitor::new(|s| println!("{s}")); #[cfg(feature = "tui")] - let ui = TuiUI::with_version(String::from("Baby Fuzzer"), String::from("0.0.1"), false); - #[cfg(feature = "tui")] - let mon = TuiMonitor::new(ui); + let mon = TuiMonitor::builder() + .title("Baby Fuzzer") + .enhanced_graphics(false) + .build(); // The event manager handle the various events generated during the fuzzing loop // such as the notification of the addition of a new item to the corpus diff --git a/fuzzers/baby_fuzzer_swap_differential/src/main.rs b/fuzzers/baby_fuzzer_swap_differential/src/main.rs index 39edae9895..dd8b47e642 100644 --- a/fuzzers/baby_fuzzer_swap_differential/src/main.rs +++ b/fuzzers/baby_fuzzer_swap_differential/src/main.rs @@ -6,7 +6,7 @@ use std::{ }; #[cfg(feature = "tui")] -use libafl::monitors::tui::{ui::TuiUI, TuiMonitor}; +use libafl::monitors::tui::TuiMonitor; #[cfg(not(feature = "tui"))] use libafl::monitors::SimpleMonitor; use libafl::{ @@ -204,9 +204,10 @@ pub fn main() { #[cfg(not(feature = "tui"))] let mon = SimpleMonitor::with_user_monitor(|s| println!("{s}")); #[cfg(feature = "tui")] - let ui = TuiUI::new(String::from("Baby Fuzzer"), false); - #[cfg(feature = "tui")] - let mon = TuiMonitor::new(ui); + let mon = TuiMonitor::builder() + .title("Baby Fuzzer") + .enhanced_graphics(false) + .build(); // The event manager handle the various events generated during the fuzzing loop // such as the notification of the addition of a new item to the corpus diff --git a/fuzzers/baby_fuzzer_unicode/src/main.rs b/fuzzers/baby_fuzzer_unicode/src/main.rs index dfc3ac56ab..844ea35638 100644 --- a/fuzzers/baby_fuzzer_unicode/src/main.rs +++ b/fuzzers/baby_fuzzer_unicode/src/main.rs @@ -3,7 +3,7 @@ use std::ptr::write_volatile; use std::{path::PathBuf, ptr::write}; #[cfg(feature = "tui")] -use libafl::monitors::tui::{ui::TuiUI, TuiMonitor}; +use libafl::monitors::tui::TuiMonitor; #[cfg(not(feature = "tui"))] use libafl::monitors::SimpleMonitor; use libafl::{ @@ -85,9 +85,11 @@ pub fn main() { #[cfg(not(feature = "tui"))] let mon = SimpleMonitor::new(|s| println!("{s}")); #[cfg(feature = "tui")] - let ui = TuiUI::with_version(String::from("Baby Fuzzer"), String::from("0.0.1"), false); - #[cfg(feature = "tui")] - let mon = TuiMonitor::new(ui); + let mon = TuiMonitor::builder() + .title("Baby Fuzzer") + .version("0.0.1") + .enhanced_graphics(false) + .build(); // The event manager handle the various events generated during the fuzzing loop // such as the notification of the addition of a new item to the corpus diff --git a/fuzzers/dynamic_analysis/concatenator.py b/fuzzers/dynamic_analysis/concatenator.py index 72f09f56c6..0948167628 100755 --- a/fuzzers/dynamic_analysis/concatenator.py +++ b/fuzzers/dynamic_analysis/concatenator.py @@ -25,7 +25,7 @@ def concatenate_json_files(input_dir): with open(output_file, 'w') as file: json.dump([data], file) - print(f"JSON files concatenated successfully! Output file: {output_file}") + print(f"Json files concatenated successfully! Output file: {output_file}") if __name__ == '__main__': if len(sys.argv) != 2: diff --git a/fuzzers/frida_libpng/harness_win.cpp b/fuzzers/frida_libpng/harness_win.cpp index 5ccc0c104f..bfc42d3074 100644 --- a/fuzzers/frida_libpng/harness_win.cpp +++ b/fuzzers/frida_libpng/harness_win.cpp @@ -4,7 +4,7 @@ #include extern "C" __declspec(dllexport) size_t - LLVMFuzzerTestOneInput(const char *data, unsigned int len) { +LLVMFuzzerTestOneInput(const char *data, unsigned int len) { if (data[0] == 'b') { if (data[1] == 'a') { if (data[2] == 'd') { diff --git a/fuzzers/libfuzzer_libpng_aflpp_ui/src/lib.rs b/fuzzers/libfuzzer_libpng_aflpp_ui/src/lib.rs index 340e71b1fb..c4d80c7adf 100644 --- a/fuzzers/libfuzzer_libpng_aflpp_ui/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_aflpp_ui/src/lib.rs @@ -13,7 +13,7 @@ use libafl::{ feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, - monitors::tui::{ui::TuiUI, TuiMonitor}, + monitors::tui::TuiMonitor, mutators::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, @@ -70,12 +70,12 @@ fn fuzz( // let monitor = MultiMonitor::new(|s| println!("{s}")); //Setup an Monitor with AFL-Style UI to display the stats - let ui = TuiUI::with_version( - String::from("Libfuzzer For Libpng"), - String::from("0.0.1"), - false, - ); - let monitor = TuiMonitor::new(ui); + #[cfg(feature = "tui")] + let monitor = TuiMonitor::builder() + .title("Libfuzzer in LibAFL") + .version("0.0.1") + .enhanced_graphics(true) + .build(); // The restarting state will spawn the same process again as child, then restarted it each time it crashes. let (state, mut restarting_mgr) = diff --git a/fuzzers/libfuzzer_libpng_launcher/src/lib.rs b/fuzzers/libfuzzer_libpng_launcher/src/lib.rs index e9def09841..870fc02e9a 100644 --- a/fuzzers/libfuzzer_libpng_launcher/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_launcher/src/lib.rs @@ -14,7 +14,7 @@ use libafl::{ feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, - monitors::{MultiMonitor, OnDiskTOMLMonitor}, + monitors::{MultiMonitor, OnDiskTomlMonitor}, mutators::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, @@ -131,7 +131,7 @@ pub extern "C" fn libafl_main() { let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory"); - let monitor = OnDiskTOMLMonitor::new( + let monitor = OnDiskTomlMonitor::new( "./fuzzer_stats.toml", MultiMonitor::new(|s| println!("{s}")), ); diff --git a/fuzzers/libfuzzer_libpng_norestart/src/lib.rs b/fuzzers/libfuzzer_libpng_norestart/src/lib.rs index a792467aaf..9c4d7ebf94 100644 --- a/fuzzers/libfuzzer_libpng_norestart/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_norestart/src/lib.rs @@ -18,7 +18,7 @@ use libafl::{ feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, - monitors::{MultiMonitor, OnDiskTOMLMonitor}, + monitors::{MultiMonitor, OnDiskTomlMonitor}, mutators::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, @@ -154,7 +154,7 @@ pub extern "C" fn libafl_main() { let shmem_provider = MmapShMemProvider::new().expect("Failed to init shared memory"); - let monitor = OnDiskTOMLMonitor::new( + let monitor = OnDiskTomlMonitor::new( "./fuzzer_stats.toml", MultiMonitor::new(|s| println!("{s}")), ); diff --git a/fuzzers/nyx_libxml2_standalone/src/main.rs b/fuzzers/nyx_libxml2_standalone/src/main.rs index 3ba9e02d39..bd9bc00f38 100644 --- a/fuzzers/nyx_libxml2_standalone/src/main.rs +++ b/fuzzers/nyx_libxml2_standalone/src/main.rs @@ -5,7 +5,7 @@ use libafl::{ events::SimpleEventManager, feedbacks::{CrashFeedback, MaxMapFeedback}, inputs::BytesInput, - monitors::tui::{ui::TuiUI, TuiMonitor}, + monitors::tui::TuiMonitor, mutators::{havoc_mutations, StdScheduledMutator}, observers::StdMapObserver, schedulers::RandScheduler, @@ -40,8 +40,7 @@ fn main() { // switch monitor if you want // let monitor = SimpleMonitor::new(|x|-> () {println!("{}",x)}); - let ui = TuiUI::new(String::from("test_fuzz"), true); - let monitor = TuiMonitor::new(ui); + let monitor = TuiMonitor::builder().title("test_fuzz").build(); let mut mgr = SimpleEventManager::new(monitor); let mut executor = NyxExecutor::builder().build(helper, tuple_list!(observer)); diff --git a/fuzzers/qemu_launcher/src/fuzzer.rs b/fuzzers/qemu_launcher/src/fuzzer.rs index fe088f9f9e..c414400a1d 100644 --- a/fuzzers/qemu_launcher/src/fuzzer.rs +++ b/fuzzers/qemu_launcher/src/fuzzer.rs @@ -10,10 +10,7 @@ use libafl::events::SimpleEventManager; #[cfg(not(feature = "simplemgr"))] use libafl::events::{EventConfig, Launcher, MonitorTypedEventManager}; use libafl::{ - monitors::{ - tui::{ui::TuiUI, TuiMonitor}, - Monitor, MultiMonitor, - }, + monitors::{tui::TuiMonitor, Monitor, MultiMonitor}, Error, }; #[cfg(feature = "simplemgr")] @@ -42,9 +39,11 @@ impl Fuzzer { pub fn fuzz(&self) -> Result<(), Error> { if self.options.tui { - let ui = - TuiUI::with_version(String::from("QEMU Launcher"), String::from("0.10.1"), true); - let monitor = TuiMonitor::new(ui); + let monitor = TuiMonitor::builder() + .title("QEMU Launcher") + .version("0.13.1") + .enhanced_graphics(true) + .build(); self.launch(monitor) } else { let log = self.options.log.as_ref().and_then(|l| { diff --git a/libafl/src/corpus/ondisk.rs b/libafl/src/corpus/ondisk.rs index 273700d2ed..221d218411 100644 --- a/libafl/src/corpus/ondisk.rs +++ b/libafl/src/corpus/ondisk.rs @@ -24,9 +24,9 @@ use crate::{ pub enum OnDiskMetadataFormat { /// A binary-encoded postcard Postcard, - /// JSON + /// Json Json, - /// JSON formatted for readability + /// Json formatted for readability #[default] JsonPretty, /// The same as [`OnDiskMetadataFormat::JsonPretty`], but compressed diff --git a/libafl/src/monitors/disk.rs b/libafl/src/monitors/disk.rs index 754700ccaa..baaeb4d30b 100644 --- a/libafl/src/monitors/disk.rs +++ b/libafl/src/monitors/disk.rs @@ -1,4 +1,4 @@ -//! Monitors that wrap a base one and log on disk +//! Monitors that wrap a base monitor and also log to disk using different formats. use alloc::{string::String, vec::Vec}; use core::time::Duration; @@ -13,9 +13,9 @@ use serde_json::json; use crate::monitors::{ClientStats, Monitor, NopMonitor}; -/// Wrap a monitor and log the current state of the monitor into a TOML file. +/// Wrap a monitor and log the current state of the monitor into a Toml file. #[derive(Debug, Clone)] -pub struct OnDiskTOMLMonitor +pub struct OnDiskTomlMonitor where M: Monitor, { @@ -25,7 +25,7 @@ where update_interval: Duration, } -impl Monitor for OnDiskTOMLMonitor +impl Monitor for OnDiskTomlMonitor where M: Monitor, { @@ -59,10 +59,10 @@ where if cur_time - self.last_update >= self.update_interval { self.last_update = cur_time; - let mut file = File::create(&self.filename).expect("Failed to open the TOML file"); + let mut file = File::create(&self.filename).expect("Failed to open the Toml file"); write!( &mut file, - "# This TOML is generated using the OnDiskMonitor component of LibAFL + "# This Toml is generated using the OnDiskMonitor component of LibAFL [global] run_time = \"{}\" @@ -79,7 +79,7 @@ exec_sec = {} self.total_execs(), self.execs_per_sec() ) - .expect("Failed to write to the TOML file"); + .expect("Failed to write to the Toml file"); for (i, client) in self.client_stats_mut().iter_mut().enumerate() { let exec_sec = client.execs_per_sec(cur_time); @@ -95,7 +95,7 @@ exec_sec = {} ", i, client.corpus_size, client.objective_size, client.executions, exec_sec ) - .expect("Failed to write to the TOML file"); + .expect("Failed to write to the Toml file"); for (key, val) in &client.user_monitor { let k: String = key @@ -104,7 +104,7 @@ exec_sec = {} .filter(|c| c.is_alphanumeric() || *c == '_') .collect(); writeln!(&mut file, "{k} = \"{val}\"") - .expect("Failed to write to the TOML file"); + .expect("Failed to write to the Toml file"); } } @@ -115,11 +115,11 @@ exec_sec = {} } } -impl OnDiskTOMLMonitor +impl OnDiskTomlMonitor where M: Monitor, { - /// Create new [`OnDiskTOMLMonitor`] + /// Create new [`OnDiskTomlMonitor`] #[must_use] pub fn new

(filename: P, base: M) -> Self where @@ -128,7 +128,7 @@ where Self::with_update_interval(filename, base, Duration::from_secs(60)) } - /// Create new [`OnDiskTOMLMonitor`] with custom update interval + /// Create new [`OnDiskTomlMonitor`] with custom update interval #[must_use] pub fn with_update_interval

(filename: P, base: M, update_interval: Duration) -> Self where @@ -143,8 +143,8 @@ where } } -impl OnDiskTOMLMonitor { - /// Create new [`OnDiskTOMLMonitor`] without a base +impl OnDiskTomlMonitor { + /// Create new [`OnDiskTomlMonitor`] without a base #[must_use] pub fn nop

(filename: P) -> Self where @@ -155,8 +155,8 @@ impl OnDiskTOMLMonitor { } #[derive(Debug, Clone)] -/// Wraps a base monitor and continuously appends the current statistics to a JSON lines file. -pub struct OnDiskJSONMonitor +/// Wraps a base monitor and continuously appends the current statistics to a Json lines file. +pub struct OnDiskJsonMonitor where F: FnMut(&mut M) -> bool, M: Monitor, @@ -167,12 +167,12 @@ where log_record: F, } -impl OnDiskJSONMonitor +impl OnDiskJsonMonitor where F: FnMut(&mut M) -> bool, M: Monitor, { - /// Create a new [`OnDiskJSONMonitor`] + /// Create a new [`OnDiskJsonMonitor`] pub fn new

(filename: P, base: M, log_record: F) -> Self where P: Into, @@ -187,7 +187,7 @@ where } } -impl Monitor for OnDiskJSONMonitor +impl Monitor for OnDiskJsonMonitor where F: FnMut(&mut M) -> bool, M: Monitor, @@ -225,7 +225,7 @@ where "exec_sec": self.base.execs_per_sec(), "client_stats": self.client_stats(), }); - writeln!(&file, "{line}").expect("Unable to write JSON to file"); + writeln!(&file, "{line}").expect("Unable to write Json to file"); } self.base.display(event_msg, sender_id); } diff --git a/libafl/src/monitors/mod.rs b/libafl/src/monitors/mod.rs index 57fb6b501e..5800539463 100644 --- a/libafl/src/monitors/mod.rs +++ b/libafl/src/monitors/mod.rs @@ -4,7 +4,6 @@ pub mod multi; pub use multi::MultiMonitor; #[cfg(all(feature = "tui_monitor", feature = "std"))] -#[allow(missing_docs)] pub mod tui; #[cfg(all(feature = "prometheus_monitor", feature = "std"))] @@ -20,7 +19,7 @@ use alloc::{borrow::Cow, fmt::Debug, string::String, vec::Vec}; use core::{fmt, fmt::Write, time::Duration}; #[cfg(feature = "std")] -pub use disk::{OnDiskJSONMonitor, OnDiskTOMLMonitor}; +pub use disk::{OnDiskJsonMonitor, OnDiskTomlMonitor}; use hashbrown::HashMap; use libafl_bolts::{current_time, format_duration_hms, ClientId}; use serde::{Deserialize, Serialize}; diff --git a/libafl/src/monitors/prometheus.rs b/libafl/src/monitors/prometheus.rs index 2ef8227b9b..4eaf567209 100644 --- a/libafl/src/monitors/prometheus.rs +++ b/libafl/src/monitors/prometheus.rs @@ -1,26 +1,31 @@ -// ===== overview for prommon ===== -// The client (i.e., the fuzzer) sets up an HTTP endpoint (/metrics). -// The endpoint contains metrics such as execution rate. - -// A prometheus server (can use a precompiled binary or docker) then scrapes \ -// the endpoint at regular intervals (configurable via prometheus.yml file). -// ==================== -// -// == how to use it === -// This monitor should plug into any fuzzer similar to other monitors. -// In your fuzzer, include: -// ```rust,ignore -// use libafl::monitors::PrometheusMonitor; -// ``` -// as well as: -// ```rust,ignore -// let listener = "127.0.0.1:8080".to_string(); // point prometheus to scrape here in your prometheus.yml -// let mon = PrometheusMonitor::new(listener, |s| log::info!("{s}")); -// and then like with any other monitor, pass it into the event manager like so: -// let mut mgr = SimpleEventManager::new(mon); -// ``` -// When using docker, you may need to point prometheus.yml to the docker0 interface or host.docker.internal -// ==================== +//! Prometheus Monitor to log to a prometheus endpoint. +//! +//! ## Overview +//! +//! The client (i.e., the fuzzer) sets up an HTTP endpoint (/metrics). +//! The endpoint contains metrics such as execution rate. +//! +//! A prometheus server (can use a precompiled binary or docker) then scrapes \ +//! the endpoint at regular intervals (configurable via prometheus.yml file). +//! +//! ## How to use it +//! +//! This monitor should plug into any fuzzer similar to other monitors. +//! In your fuzzer: +//! +//! ```rust +//! // First, include: +//! use libafl::monitors::PrometheusMonitor; +//! +//! // Then, create the monitor: +//! let listener = "127.0.0.1:8080".to_string(); // point prometheus to scrape here in your prometheus.yml +//! let mon = PrometheusMonitor::new(listener, |s| log::info!("{s}")); +//! +//! // and finally, like with any other monitor, pass it into the event manager like so: +//! // let mgr = SimpleEventManager::new(mon); +//! ``` +//! +//! When using docker, you may need to point `prometheus.yml` to the `docker0` interface or `host.docker.internal` use alloc::{borrow::Cow, fmt::Debug, string::String, vec::Vec}; use core::{fmt, time::Duration}; diff --git a/libafl/src/monitors/tui/mod.rs b/libafl/src/monitors/tui/mod.rs index 149760aa69..6e5944f322 100644 --- a/libafl/src/monitors/tui/mod.rs +++ b/libafl/src/monitors/tui/mod.rs @@ -1,4 +1,4 @@ -//! Monitor based on ratatui +//! Fancy-looking terminal UI monitor, similar to AFL, based on [ratatui](https://ratatui.rs/) use alloc::{borrow::Cow, boxed::Box, string::ToString}; use core::cmp; @@ -24,30 +24,60 @@ use hashbrown::HashMap; use libafl_bolts::{current_time, format_duration_hms, ClientId}; use ratatui::{backend::CrosstermBackend, Terminal}; use serde_json::Value; +use typed_builder::TypedBuilder; #[cfg(feature = "introspection")] use super::{ClientPerfMonitor, PerfFeature}; use crate::monitors::{Aggregator, AggregatorOps, ClientStats, Monitor, UserStats, UserStatsValue}; +#[allow(missing_docs)] pub mod ui; -use ui::TuiUI; +use ui::TuiUi; const DEFAULT_TIME_WINDOW: u64 = 60 * 10; // 10 min const DEFAULT_LOGS_NUMBER: usize = 128; +#[derive(Debug, Clone, TypedBuilder)] +#[builder(build_method(into = TuiMonitor), builder_method(vis = "pub(crate)", + doc = "Build the [`TuiMonitor`] from the set values"))] +/// Settings to create a new [`TuiMonitor`]. +/// Use `TuiMonitor::builder()` or create this config and call `.into()` to create a new [`TuiMonitor`]. +pub struct TuiMonitorConfig { + /// The title to show + #[builder(default_code = r#""LibAFL Fuzzer".to_string()"#, setter(into))] + pub title: String, + /// A version string to show for this (optional) + #[builder(default_code = r#""default".to_string()"#, setter(into))] + pub version: String, + /// Creates the monitor with an explicit `start_time`. + /// If nothings was set, this will use [`current_time`] instead. + #[builder(default_code = "current_time()")] + pub start_time: Duration, + /// Enables unicode TUI graphics, Looks better but may interfere with old terminals. + #[builder(default = true)] + pub enhanced_graphics: bool, +} + +/// A single status entry for timings #[derive(Debug, Copy, Clone)] pub struct TimedStat { + /// The time pub time: Duration, + /// The item pub item: u64, } +/// Stats for timings #[derive(Debug, Clone)] pub struct TimedStats { + /// Series of [`TimedStat`] entries pub series: VecDeque, + /// The time window to keep track of pub window: Duration, } impl TimedStats { + /// Create a new [`TimedStats`] struct #[must_use] pub fn new(window: Duration) -> Self { Self { @@ -56,6 +86,7 @@ impl TimedStats { } } + /// Add a stat datapoint pub fn add(&mut self, time: Duration, item: u64) { if self.series.is_empty() || self.series.back().unwrap().item != item { if self.series.front().is_some() @@ -67,6 +98,7 @@ impl TimedStats { } } + /// Add a stat datapoint for the `current_time` pub fn add_now(&mut self, item: u64) { if self.series.is_empty() || self.series[self.series.len() - 1].item != item { let time = current_time(); @@ -79,6 +111,7 @@ impl TimedStats { } } + /// Change the window duration pub fn update_window(&mut self, window: Duration) { self.window = window; while !self.series.is_empty() @@ -89,6 +122,7 @@ impl TimedStats { } } +/// The context to show performance metrics #[cfg(feature = "introspection")] #[derive(Debug, Default, Clone)] pub struct PerfTuiContext { @@ -101,6 +135,7 @@ pub struct PerfTuiContext { #[cfg(feature = "introspection")] impl PerfTuiContext { + /// Get the data for performance metrics #[allow(clippy::cast_precision_loss)] pub fn grab_data(&mut self, m: &ClientPerfMonitor) { // Calculate the elapsed time from the monitor @@ -164,15 +199,21 @@ impl PerfTuiContext { } } +/// Data struct to process timings #[derive(Debug, Default, Clone)] pub struct ProcessTiming { + /// The start time pub client_start_time: Duration, + /// The executions speed pub exec_speed: String, + /// Timing of the last new corpus entry pub last_new_entry: Duration, + /// Timing of the last new solution pub last_saved_solution: Duration, } impl ProcessTiming { + /// Create a new [`ProcessTiming`] struct fn new() -> Self { Self { exec_speed: "0".to_string(), @@ -181,6 +222,8 @@ impl ProcessTiming { } } +/// The geometry of a single data point +#[allow(missing_docs)] #[derive(Debug, Default, Clone)] pub struct ItemGeometry { pub pending: u64, @@ -199,6 +242,8 @@ impl ItemGeometry { } } +/// The context for a single client tracked in this [`TuiMonitor`] +#[allow(missing_docs)] #[derive(Debug, Default, Clone)] pub struct ClientTuiContext { pub corpus: u64, @@ -215,6 +260,7 @@ pub struct ClientTuiContext { } impl ClientTuiContext { + /// Grab data for a single client pub fn grab_data(&mut self, client: &ClientStats, exec_sec: String) { self.corpus = client.corpus_size; self.objectives = client.objective_size; @@ -267,6 +313,8 @@ impl ClientTuiContext { } } +/// The [`TuiContext`] for this [`TuiMonitor`] +#[allow(missing_docs)] #[derive(Debug, Clone)] pub struct TuiContext { pub graphs: Vec, @@ -326,7 +374,7 @@ impl TuiContext { } } -/// Tracking monitor during fuzzing and display with ratatui +/// Tracking monitor during fuzzing and display with [`ratatui`](https://ratatui.rs/) #[derive(Debug, Clone)] pub struct TuiMonitor { pub(crate) context: Arc>, @@ -336,6 +384,16 @@ pub struct TuiMonitor { aggregator: Aggregator, } +impl From for TuiMonitor { + #[allow(deprecated)] + fn from(builder: TuiMonitorConfig) -> Self { + Self::with_time( + TuiUi::with_version(builder.title, builder.version, builder.enhanced_graphics), + builder.start_time, + ) + } +} + impl Monitor for TuiMonitor { /// The client monitor, mutable /// This also includes disabled "padding" clients. @@ -443,15 +501,35 @@ impl Monitor for TuiMonitor { } impl TuiMonitor { - /// Creates the monitor + /// Create a builder for [`TuiMonitor`] + pub fn builder() -> TuiMonitorConfigBuilder { + TuiMonitorConfig::builder() + } + + /// Creates the monitor. + /// + /// # Deprecation Note + /// Use `TuiMonitor::builder()` instead. + #[deprecated( + since = "0.13.2", + note = "Please use TuiMonitor::builder() instead of creating TuiUi directly." + )] #[must_use] - pub fn new(tui_ui: TuiUI) -> Self { + #[allow(deprecated)] + pub fn new(tui_ui: TuiUi) -> Self { Self::with_time(tui_ui, current_time()) } /// Creates the monitor with a given `start_time`. + /// + /// # Deprecation Note + /// Use `TuiMonitor::builder()` instead. + #[deprecated( + since = "0.13.2", + note = "Please use TuiMonitor::builder() instead of creating TuiUi directly." + )] #[must_use] - pub fn with_time(tui_ui: TuiUI, start_time: Duration) -> Self { + pub fn with_time(tui_ui: TuiUi, start_time: Duration) -> Self { let context = Arc::new(RwLock::new(TuiContext::new(start_time))); enable_raw_mode().unwrap(); @@ -565,7 +643,7 @@ impl TuiMonitor { fn run_tui_thread( context: Arc>, tick_rate: Duration, - tui_ui: TuiUI, + tui_ui: TuiUi, stdout_provider: impl Send + Sync + 'static + Fn() -> W, ) { thread::spawn(move || -> io::Result<()> { diff --git a/libafl/src/monitors/tui/ui.rs b/libafl/src/monitors/tui/ui.rs index 976a681433..403f9bc56f 100644 --- a/libafl/src/monitors/tui/ui.rs +++ b/libafl/src/monitors/tui/ui.rs @@ -21,7 +21,7 @@ use super::{ }; #[derive(Default, Debug)] -pub struct TuiUI { +pub struct TuiUi { title: String, version: String, enhanced_graphics: bool, @@ -34,13 +34,13 @@ pub struct TuiUI { pub should_quit: bool, } -impl TuiUI { +impl TuiUi { #[must_use] pub fn new(title: String, enhanced_graphics: bool) -> Self { Self::with_version(title, String::from("default"), enhanced_graphics) } - // create the TuiUI with a given `version`. + // create the TuiUi with a given `version`. #[must_use] pub fn with_version(title: String, version: String, enhanced_graphics: bool) -> Self { Self { @@ -49,7 +49,7 @@ impl TuiUI { enhanced_graphics, show_logs: true, clients_idx: 1, - ..TuiUI::default() + ..TuiUi::default() } } pub fn on_key(&mut self, c: char) { diff --git a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/fuzz.rs b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/fuzz.rs index 8639c72401..95cccbb1cc 100644 --- a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/fuzz.rs +++ b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/fuzz.rs @@ -18,10 +18,7 @@ use libafl::{ }, executors::ExitKind, inputs::UsesInput, - monitors::{ - tui::{ui::TuiUI, TuiMonitor}, - Monitor, MultiMonitor, - }, + monitors::{tui::TuiMonitor, Monitor, MultiMonitor}, stages::{HasCurrentStage, StagesTuple}, state::{HasExecutions, HasLastReportTime, HasSolutions, Stoppable, UsesState}, Error, Fuzzer, HasMetadata, @@ -208,7 +205,10 @@ pub fn fuzz( if let Some(forks) = options.forks() { let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory"); if options.tui() { - let monitor = TuiMonitor::new(TuiUI::new(options.fuzzer_name().to_string(), true)); + let monitor = TuiMonitor::builder() + .title(options.fuzzer_name()) + .enhanced_graphics(true) + .build(); fuzz_many_forking(options, harness, shmem_provider, forks, monitor) } else if forks == 1 { let monitor = MultiMonitor::with_time( @@ -227,7 +227,10 @@ pub fn fuzz( // if the user specifies TUI, we assume they want to fork; it would not be possible to use // TUI safely otherwise let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory"); - let monitor = TuiMonitor::new(TuiUI::new(options.fuzzer_name().to_string(), true)); + let monitor = TuiMonitor::builder() + .title(options.fuzzer_name()) + .enhanced_graphics(true) + .build(); fuzz_many_forking(options, harness, shmem_provider, 1, monitor) } else { destroy_output_fds(options); diff --git a/scripts/parallellize_cargo_check.py b/scripts/parallellize_cargo_check.py index c70473e97c..e1cebe1511 100755 --- a/scripts/parallellize_cargo_check.py +++ b/scripts/parallellize_cargo_check.py @@ -35,6 +35,8 @@ for task in output[ print(os.environ) if "libafl_frida" in task: # DOCS_RS is needed for libafl_frida to build without auto-download feature - cargo_check = subprocess.check_output(task, shell=True, text=True, env=dict(os.environ, DOCS_RS="1")) + cargo_check = subprocess.check_output( + task, shell=True, text=True, env=dict(os.environ, DOCS_RS="1") + ) else: - cargo_check = subprocess.check_output(task, shell=True, text=True) \ No newline at end of file + cargo_check = subprocess.check_output(task, shell=True, text=True)