trident_fuzz/fuzz_stats.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
#![allow(dead_code)]
use prettytable::{row, Table};
use std::collections::HashMap;
/// Represents fuzzing statistics, specifically tracking the number of times
/// an instruction was invoked and successfully executed.
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct IterationStats {
pub invoked: u64,
pub successful: u64,
pub failed: u64,
pub failed_check: u64,
}
/// Manages and aggregates statistics for fuzzing instructions.
#[derive(Debug, Default)]
pub struct FuzzingStatistics {
pub instructions: HashMap<String, IterationStats>,
}
impl FuzzingStatistics {
/// Constructs a new, empty `FuzzingStatistics`.
pub fn new() -> Self {
let empty_instructions = HashMap::<String, IterationStats>::default();
Self {
instructions: empty_instructions,
}
}
/// Outputs the statistics as a serialized JSON string.
pub fn output_serialized(&self) {
let serialized = serde_json::to_string(&self.instructions).unwrap();
println!("{}", serialized);
}
/// Increments the invocation count for a given instruction.
/// # Arguments
/// * `instruction` - The instruction to increment the count for.
pub fn increase_invoked(&mut self, instruction: String) {
self.instructions
.entry(instruction)
.and_modify(|iterations_stats| iterations_stats.invoked += 1)
.or_insert(IterationStats {
invoked: 1,
successful: 0,
failed: 0,
failed_check: 0,
});
}
/// Increments the successful invocation count for a given instruction.
/// # Arguments
/// * `instruction` - The instruction to increment the successful count for.
pub fn increase_successful(&mut self, instruction: String) {
self.instructions
.entry(instruction)
.and_modify(|iterations_stats| iterations_stats.successful += 1)
.or_insert(
// this should not occure as instruction has to be invoked
// and then successfully_invoked
IterationStats {
invoked: 1,
successful: 1,
failed: 0,
failed_check: 0,
},
);
}
pub fn increase_failed(&mut self, instruction: String) {
self.instructions
.entry(instruction)
.and_modify(|iterations_stats| iterations_stats.failed += 1)
.or_insert(
// this should not occure as instruction has to be invoked
// and then unsuccessfully_invoked
IterationStats {
invoked: 1,
successful: 0,
failed: 1,
failed_check: 0,
},
);
}
pub fn increase_failed_check(&mut self, instruction: String) {
self.instructions
.entry(instruction)
.and_modify(|iterations_stats| iterations_stats.failed_check += 1)
.or_insert(
// this should not occure as instruction has to be invoked
// and then unsuccessfully_invoked
IterationStats {
invoked: 1,
successful: 1,
failed: 0,
failed_check: 1,
},
);
}
/// Inserts or updates instructions with statistics provided in a serialized string.
/// # Arguments
/// * `serialized_iteration` - The serialized statistics to insert or update.
pub fn insert_serialized(&mut self, serialized_iteration: &str) {
let result = serde_json::from_str::<HashMap<String, IterationStats>>(serialized_iteration);
if let Ok(deserialized_instruction) = result {
for (key, value) in deserialized_instruction {
self.instructions
.entry(key)
.and_modify(|instruction_stats| {
instruction_stats.invoked += value.invoked;
instruction_stats.successful += value.successful;
instruction_stats.failed += value.failed;
instruction_stats.failed_check += value.failed_check;
})
.or_insert_with(|| IterationStats {
invoked: value.invoked,
successful: value.successful,
failed: value.failed,
failed_check: value.failed_check,
});
}
}
}
/// Displays the collected statistics in a formatted table.
pub fn show_table(&self) {
let mut table = Table::new();
table.add_row(row![
"Instruction",
"Invoked Total",
"Ix Success",
"Check Failed",
"Ix Failed"
]);
for (instruction, stats) in &self.instructions {
table.add_row(row![
instruction,
stats.invoked,
stats.successful,
stats.failed_check,
stats.failed,
]);
}
table.printstd();
println!("Note that unhandled panics are currently logged only as crashes and are not displayed in the table above.")
}
}