Improve introspection (#200)
* remove NUM_FEEDBACKS * working introspection * adust introspection stats * bugfixes, clippy * removed outdated define * more clippy; * no_std Co-authored-by: Dominik Maier <domenukk@gmail.com>
This commit is contained in:
parent
204b15a432
commit
44f6e4c389
@ -20,7 +20,7 @@ which = { version = "4.0.2" }
|
|||||||
num_cpus = "1.0"
|
num_cpus = "1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { path = "../../libafl/" }
|
libafl = { path = "../../libafl/", features = ["std", "anymap_debug", "derive", "llmp_compression", "introspection"] }
|
||||||
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer"] }
|
||||||
# TODO Include it only when building cc
|
# TODO Include it only when building cc
|
||||||
libafl_cc = { path = "../../libafl_cc/" }
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
|
@ -1012,7 +1012,7 @@ where
|
|||||||
let shm = self.out_maps.last().unwrap();
|
let shm = self.out_maps.last().unwrap();
|
||||||
println!(
|
println!(
|
||||||
"LLMP_DEBUG: End of page reached for map {} with len {}, sending EOP, bt: {:?}",
|
"LLMP_DEBUG: End of page reached for map {} with len {}, sending EOP, bt: {:?}",
|
||||||
shm.shmem.id().to_string(),
|
shm.shmem.id(),
|
||||||
shm.shmem.len(),
|
shm.shmem.len(),
|
||||||
bt
|
bt
|
||||||
);
|
);
|
||||||
@ -1369,7 +1369,7 @@ where
|
|||||||
#[cfg(all(feature = "llmp_debug", feature = "std"))]
|
#[cfg(all(feature = "llmp_debug", feature = "std"))]
|
||||||
println!(
|
println!(
|
||||||
"LLMP_DEBUG: Got a new recv map {} with len {:?}",
|
"LLMP_DEBUG: Got a new recv map {} with len {:?}",
|
||||||
self.current_recv_map.shmem.id().to_string(),
|
self.current_recv_map.shmem.id(),
|
||||||
self.current_recv_map.shmem.len()
|
self.current_recv_map.shmem.len()
|
||||||
);
|
);
|
||||||
// After we mapped the new page, return the next message, if available
|
// After we mapped the new page, return the next message, if available
|
||||||
@ -1500,7 +1500,7 @@ where
|
|||||||
#[cfg(all(feature = "llmp_debug", feature = "std"))]
|
#[cfg(all(feature = "llmp_debug", feature = "std"))]
|
||||||
println!(
|
println!(
|
||||||
"LLMP_DEBUG: Initializing map on {} with size {}",
|
"LLMP_DEBUG: Initializing map on {} with size {}",
|
||||||
new_map.id().to_string(),
|
new_map.id(),
|
||||||
new_map.len()
|
new_map.len()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1520,7 +1520,7 @@ where
|
|||||||
//let bt = "<n/a (release)>";
|
//let bt = "<n/a (release)>";
|
||||||
dbg!(
|
dbg!(
|
||||||
"LLMP_DEBUG: Using existing map {} with size {}",
|
"LLMP_DEBUG: Using existing map {} with size {}",
|
||||||
existing_map.id().to_string(),
|
existing_map.id(),
|
||||||
existing_map.len(),
|
existing_map.len(),
|
||||||
//bt
|
//bt
|
||||||
);
|
);
|
||||||
|
@ -94,8 +94,7 @@ impl ServedShMemProvider {
|
|||||||
.expect("Did not receive a response");
|
.expect("Did not receive a response");
|
||||||
|
|
||||||
let server_id = ShMemId::from_slice(&shm_slice);
|
let server_id = ShMemId::from_slice(&shm_slice);
|
||||||
let server_id_str = server_id.to_string();
|
let server_fd: i32 = server_id.into();
|
||||||
let server_fd: i32 = server_id_str.parse()?;
|
|
||||||
Ok((server_fd, fd_buf[0]))
|
Ok((server_fd, fd_buf[0]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,7 +138,7 @@ impl ShMemProvider for ServedShMemProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn from_id_and_size(&mut self, id: ShMemId, size: usize) -> Result<Self::Mem, Error> {
|
fn from_id_and_size(&mut self, id: ShMemId, size: usize) -> Result<Self::Mem, Error> {
|
||||||
let parts = id.to_string().split(':').collect::<Vec<&str>>();
|
let parts = id.as_str().split(':').collect::<Vec<&str>>();
|
||||||
let server_id_str = parts.get(0).unwrap();
|
let server_id_str = parts.get(0).unwrap();
|
||||||
let (server_fd, client_fd) = self.send_receive(AshmemRequest::ExistingMap(
|
let (server_fd, client_fd) = self.send_receive(AshmemRequest::ExistingMap(
|
||||||
ShMemDescription::from_string_and_size(server_id_str, size),
|
ShMemDescription::from_string_and_size(server_id_str, size),
|
||||||
@ -257,16 +256,17 @@ impl AshmemService {
|
|||||||
let description = new_map.description();
|
let description = new_map.description();
|
||||||
let new_rc = Rc::new(RefCell::new(new_map));
|
let new_rc = Rc::new(RefCell::new(new_map));
|
||||||
self.all_maps
|
self.all_maps
|
||||||
.insert(description.id.to_int(), Rc::downgrade(&new_rc));
|
.insert(description.id.into(), Rc::downgrade(&new_rc));
|
||||||
Ok(AshmemResponse::Mapping(new_rc))
|
Ok(AshmemResponse::Mapping(new_rc))
|
||||||
}
|
}
|
||||||
AshmemRequest::ExistingMap(description) => {
|
AshmemRequest::ExistingMap(description) => {
|
||||||
let client = self.clients.get_mut(&client_id).unwrap();
|
let client = self.clients.get_mut(&client_id).unwrap();
|
||||||
if client.maps.contains_key(&description.id.to_int()) {
|
let description_id: i32 = description.id.into();
|
||||||
|
if client.maps.contains_key(&description_id) {
|
||||||
Ok(AshmemResponse::Mapping(
|
Ok(AshmemResponse::Mapping(
|
||||||
client
|
client
|
||||||
.maps
|
.maps
|
||||||
.get_mut(&description.id.to_int())
|
.get_mut(&description_id)
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.first()
|
.first()
|
||||||
@ -277,7 +277,7 @@ impl AshmemService {
|
|||||||
} else {
|
} else {
|
||||||
Ok(AshmemResponse::Mapping(
|
Ok(AshmemResponse::Mapping(
|
||||||
self.all_maps
|
self.all_maps
|
||||||
.get_mut(&description.id.to_int())
|
.get_mut(&description_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone()
|
.clone()
|
||||||
.upgrade()
|
.upgrade()
|
||||||
|
@ -38,7 +38,11 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use alloc::{rc::Rc, string::ToString};
|
use alloc::{rc::Rc, string::ToString};
|
||||||
use core::{cell::RefCell, fmt::Debug, mem::ManuallyDrop};
|
use core::{
|
||||||
|
cell::RefCell,
|
||||||
|
fmt::{self, Debug, Display},
|
||||||
|
mem::ManuallyDrop,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "std"))]
|
#[cfg(all(unix, feature = "std"))]
|
||||||
use crate::bolts::os::pipes::Pipe;
|
use crate::bolts::os::pipes::Pipe;
|
||||||
@ -102,18 +106,28 @@ impl ShMemId {
|
|||||||
&self.id
|
&self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a string representation of this id
|
/// Returns the first null-byte in or the end of the buffer
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_string(&self) -> &str {
|
pub fn null_pos(&self) -> usize {
|
||||||
let eof_pos = self.id.iter().position(|&c| c == 0).unwrap();
|
self.id.iter().position(|&c| c == 0).unwrap()
|
||||||
alloc::str::from_utf8(&self.id[..eof_pos]).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an integer representation of this id
|
/// Returns a `str` representation of this [`ShMemId`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_int(&self) -> i32 {
|
pub fn as_str(&self) -> &str {
|
||||||
let id: i32 = self.to_string().parse().unwrap();
|
alloc::str::from_utf8(&self.id[..self.null_pos()]).unwrap()
|
||||||
id
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ShMemId> for i32 {
|
||||||
|
fn from(id: ShMemId) -> i32 {
|
||||||
|
id.as_str().parse().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ShMemId {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,7 +537,8 @@ pub mod unix_shmem {
|
|||||||
/// Get a [`UnixShMem`] of the existing shared memory mapping identified by id
|
/// Get a [`UnixShMem`] of the existing shared memory mapping identified by id
|
||||||
pub fn from_id_and_size(id: ShMemId, map_size: usize) -> Result<Self, Error> {
|
pub fn from_id_and_size(id: ShMemId, map_size: usize) -> Result<Self, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let map = shmat(id.to_int(), ptr::null(), 0) as *mut c_uchar;
|
let id_int: i32 = id.into();
|
||||||
|
let map = shmat(id_int, ptr::null(), 0) as *mut c_uchar;
|
||||||
|
|
||||||
if map == usize::MAX as *mut c_void as *mut c_uchar || map.is_null() {
|
if map == usize::MAX as *mut c_void as *mut c_uchar || map.is_null() {
|
||||||
return Err(Error::Unknown(
|
return Err(Error::Unknown(
|
||||||
@ -560,7 +575,8 @@ pub mod unix_shmem {
|
|||||||
impl Drop for CommonUnixShMem {
|
impl Drop for CommonUnixShMem {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
shmctl(self.id.to_int(), 0, ptr::null_mut());
|
let id_int: i32 = self.id.into();
|
||||||
|
shmctl(id_int, 0, ptr::null_mut());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ where
|
|||||||
client.update_executions(*executions as u64, *time);
|
client.update_executions(*executions as u64, *time);
|
||||||
|
|
||||||
// Update the performance stats for this client
|
// Update the performance stats for this client
|
||||||
client.update_introspection_stats(**introspection_stats);
|
client.update_introspection_stats((**introspection_stats).clone());
|
||||||
|
|
||||||
// Display the stats via `.display` only on core #1
|
// Display the stats via `.display` only on core #1
|
||||||
stats.display(event.name().to_string(), sender_id);
|
stats.display(event.name().to_string(), sender_id);
|
||||||
|
@ -176,7 +176,8 @@ where
|
|||||||
} => {
|
} => {
|
||||||
// TODO: The stats buffer should be added on client add.
|
// TODO: The stats buffer should be added on client add.
|
||||||
stats.client_stats_mut()[0].update_executions(*executions as u64, *time);
|
stats.client_stats_mut()[0].update_executions(*executions as u64, *time);
|
||||||
stats.client_stats_mut()[0].update_introspection_stats(**introspection_stats);
|
stats.client_stats_mut()[0]
|
||||||
|
.update_introspection_stats((**introspection_stats).clone());
|
||||||
stats.display(event.name().to_string(), 0);
|
stats.display(event.name().to_string(), 0);
|
||||||
Ok(BrokerEventResult::Handled)
|
Ok(BrokerEventResult::Handled)
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ use crate::{
|
|||||||
fuzzer::HasObjective,
|
fuzzer::HasObjective,
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
observers::ObserversTuple,
|
observers::ObserversTuple,
|
||||||
state::HasSolutions,
|
state::{HasClientPerfStats, HasSolutions},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -170,7 +170,7 @@ where
|
|||||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||||
OC: Corpus<I>,
|
OC: Corpus<I>,
|
||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
S: HasSolutions<OC, I>,
|
S: HasSolutions<OC, I> + HasClientPerfStats,
|
||||||
Z: HasObjective<I, OF, S>,
|
Z: HasObjective<I, OF, S>,
|
||||||
{
|
{
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@ -255,7 +255,7 @@ mod unix_signal_handler {
|
|||||||
fuzzer::HasObjective,
|
fuzzer::HasObjective,
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
observers::ObserversTuple,
|
observers::ObserversTuple,
|
||||||
state::HasSolutions,
|
state::{HasClientPerfStats, HasSolutions},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type HandlerFuncPtr =
|
pub type HandlerFuncPtr =
|
||||||
@ -343,7 +343,7 @@ mod unix_signal_handler {
|
|||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
OC: Corpus<I>,
|
OC: Corpus<I>,
|
||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
S: HasSolutions<OC, I>,
|
S: HasSolutions<OC, I> + HasClientPerfStats,
|
||||||
I: Input,
|
I: Input,
|
||||||
Z: HasObjective<I, OF, S>,
|
Z: HasObjective<I, OF, S>,
|
||||||
{
|
{
|
||||||
@ -417,7 +417,7 @@ mod unix_signal_handler {
|
|||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
OC: Corpus<I>,
|
OC: Corpus<I>,
|
||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
S: HasSolutions<OC, I>,
|
S: HasSolutions<OC, I> + HasClientPerfStats,
|
||||||
I: Input,
|
I: Input,
|
||||||
Z: HasObjective<I, OF, S>,
|
Z: HasObjective<I, OF, S>,
|
||||||
{
|
{
|
||||||
@ -562,7 +562,7 @@ mod windows_exception_handler {
|
|||||||
fuzzer::HasObjective,
|
fuzzer::HasObjective,
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
observers::ObserversTuple,
|
observers::ObserversTuple,
|
||||||
state::HasSolutions,
|
state::{HasClientPerfStats, HasSolutions},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type HandlerFuncPtr =
|
pub type HandlerFuncPtr =
|
||||||
@ -628,7 +628,7 @@ mod windows_exception_handler {
|
|||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
OC: Corpus<I>,
|
OC: Corpus<I>,
|
||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
S: HasSolutions<OC, I>,
|
S: HasSolutions<OC, I> + HasClientPerfStats,
|
||||||
I: Input,
|
I: Input,
|
||||||
Z: HasObjective<I, OF, S>,
|
Z: HasObjective<I, OF, S>,
|
||||||
{
|
{
|
||||||
|
@ -16,7 +16,7 @@ use crate::{
|
|||||||
feedbacks::{Feedback, FeedbackState, FeedbackStatesTuple},
|
feedbacks::{Feedback, FeedbackState, FeedbackStatesTuple},
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
observers::{MapObserver, ObserversTuple},
|
observers::{MapObserver, ObserversTuple},
|
||||||
state::{HasFeedbackStates, HasMetadata},
|
state::{HasClientPerfStats, HasFeedbackStates, HasMetadata},
|
||||||
stats::UserStats,
|
stats::UserStats,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -211,7 +211,7 @@ where
|
|||||||
R: Reducer<T>,
|
R: Reducer<T>,
|
||||||
O: MapObserver<T>,
|
O: MapObserver<T>,
|
||||||
I: Input,
|
I: Input,
|
||||||
S: HasFeedbackStates<FT>,
|
S: HasFeedbackStates<FT> + HasClientPerfStats,
|
||||||
FT: FeedbackStatesTuple,
|
FT: FeedbackStatesTuple,
|
||||||
{
|
{
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
@ -430,6 +430,7 @@ impl<I, O, S> Feedback<I, S> for ReachabilityFeedback<O>
|
|||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
O: MapObserver<usize>,
|
O: MapObserver<usize>,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -14,12 +14,10 @@ use crate::{
|
|||||||
executors::ExitKind,
|
executors::ExitKind,
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
observers::{ObserversTuple, TimeObserver},
|
observers::{ObserversTuple, TimeObserver},
|
||||||
|
state::HasClientPerfStats,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
|
||||||
use crate::stats::NUM_FEEDBACKS;
|
|
||||||
|
|
||||||
use core::{marker::PhantomData, time::Duration};
|
use core::{marker::PhantomData, time::Duration};
|
||||||
|
|
||||||
/// Feedbacks evaluate the observers.
|
/// Feedbacks evaluate the observers.
|
||||||
@ -28,6 +26,7 @@ use core::{marker::PhantomData, time::Duration};
|
|||||||
pub trait Feedback<I, S>: Named
|
pub trait Feedback<I, S>: Named
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
/// `is_interesting ` return if an input is worth the addition to the corpus
|
/// `is_interesting ` return if an input is worth the addition to the corpus
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
@ -44,15 +43,13 @@ where
|
|||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn is_interesting_with_perf<EM, OT>(
|
fn is_interesting_introspection<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: &I,
|
input: &I,
|
||||||
observers: &OT,
|
observers: &OT,
|
||||||
exit_kind: &ExitKind,
|
exit_kind: &ExitKind,
|
||||||
feedback_stats: &mut [u64; NUM_FEEDBACKS],
|
|
||||||
feedback_index: usize,
|
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<I, S>,
|
EM: EventFirer<I, S>,
|
||||||
@ -67,10 +64,10 @@ where
|
|||||||
// Get the elapsed time for checking this feedback
|
// Get the elapsed time for checking this feedback
|
||||||
let elapsed = crate::bolts::cpu::read_time_counter() - start_time;
|
let elapsed = crate::bolts::cpu::read_time_counter() - start_time;
|
||||||
|
|
||||||
// TODO: A more meaningful way to get perf for each feedback
|
|
||||||
|
|
||||||
// Add this stat to the feedback metrics
|
// Add this stat to the feedback metrics
|
||||||
feedback_stats[feedback_index] = elapsed;
|
state
|
||||||
|
.introspection_stats_mut()
|
||||||
|
.update_feedback(self.name(), elapsed);
|
||||||
|
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
@ -114,6 +111,7 @@ where
|
|||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
FL: FeedbackLogic<A, B, I, S>,
|
FL: FeedbackLogic<A, B, I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
pub first: A,
|
pub first: A,
|
||||||
pub second: B,
|
pub second: B,
|
||||||
@ -127,6 +125,7 @@ where
|
|||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
FL: FeedbackLogic<A, B, I, S>,
|
FL: FeedbackLogic<A, B, I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
self.name.as_ref()
|
self.name.as_ref()
|
||||||
@ -139,6 +138,7 @@ where
|
|||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
FL: FeedbackLogic<A, B, I, S>,
|
FL: FeedbackLogic<A, B, I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
pub fn new(first: A, second: B) -> Self {
|
pub fn new(first: A, second: B) -> Self {
|
||||||
let name = format!("{} ({},{})", FL::name(), first.name(), second.name());
|
let name = format!("{} ({},{})", FL::name(), first.name(), second.name());
|
||||||
@ -157,6 +157,7 @@ where
|
|||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
FL: FeedbackLogic<A, B, I, S>,
|
FL: FeedbackLogic<A, B, I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -182,21 +183,19 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
fn is_interesting_with_perf<EM, OT>(
|
fn is_interesting_introspection<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: &I,
|
input: &I,
|
||||||
observers: &OT,
|
observers: &OT,
|
||||||
exit_kind: &ExitKind,
|
exit_kind: &ExitKind,
|
||||||
feedback_stats: &mut [u64; NUM_FEEDBACKS],
|
|
||||||
feedback_index: usize,
|
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<I, S>,
|
EM: EventFirer<I, S>,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
{
|
{
|
||||||
FL::is_pair_interesting_with_perf(
|
FL::is_pair_interesting_introspection(
|
||||||
&mut self.first,
|
&mut self.first,
|
||||||
&mut self.second,
|
&mut self.second,
|
||||||
state,
|
state,
|
||||||
@ -204,8 +203,6 @@ where
|
|||||||
input,
|
input,
|
||||||
observers,
|
observers,
|
||||||
exit_kind,
|
exit_kind,
|
||||||
feedback_stats,
|
|
||||||
feedback_index,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,6 +224,7 @@ where
|
|||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn name() -> &'static str;
|
fn name() -> &'static str;
|
||||||
|
|
||||||
@ -245,7 +243,7 @@ where
|
|||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn is_pair_interesting_with_perf<EM, OT>(
|
fn is_pair_interesting_introspection<EM, OT>(
|
||||||
first: &mut A,
|
first: &mut A,
|
||||||
second: &mut B,
|
second: &mut B,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
@ -253,8 +251,6 @@ where
|
|||||||
input: &I,
|
input: &I,
|
||||||
observers: &OT,
|
observers: &OT,
|
||||||
exit_kind: &ExitKind,
|
exit_kind: &ExitKind,
|
||||||
feedback_stats: &mut [u64; NUM_FEEDBACKS],
|
|
||||||
feedback_index: usize,
|
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<I, S>,
|
EM: EventFirer<I, S>,
|
||||||
@ -271,6 +267,7 @@ where
|
|||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn name() -> &'static str {
|
fn name() -> &'static str {
|
||||||
"Eager OR"
|
"Eager OR"
|
||||||
@ -295,7 +292,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
fn is_pair_interesting_with_perf<EM, OT>(
|
fn is_pair_interesting_introspection<EM, OT>(
|
||||||
first: &mut A,
|
first: &mut A,
|
||||||
second: &mut B,
|
second: &mut B,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
@ -303,33 +300,15 @@ where
|
|||||||
input: &I,
|
input: &I,
|
||||||
observers: &OT,
|
observers: &OT,
|
||||||
exit_kind: &ExitKind,
|
exit_kind: &ExitKind,
|
||||||
feedback_stats: &mut [u64; NUM_FEEDBACKS],
|
|
||||||
feedback_index: usize,
|
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<I, S>,
|
EM: EventFirer<I, S>,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
{
|
{
|
||||||
// Execute this feedback
|
// Execute this feedback
|
||||||
let a = first.is_interesting_with_perf(
|
let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
|
||||||
state,
|
|
||||||
manager,
|
|
||||||
input,
|
|
||||||
observers,
|
|
||||||
exit_kind,
|
|
||||||
feedback_stats,
|
|
||||||
feedback_index,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let b = second.is_interesting_with_perf(
|
let b = second.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
|
||||||
state,
|
|
||||||
manager,
|
|
||||||
input,
|
|
||||||
observers,
|
|
||||||
exit_kind,
|
|
||||||
feedback_stats,
|
|
||||||
feedback_index + 1,
|
|
||||||
)?;
|
|
||||||
Ok(a || b)
|
Ok(a || b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -339,6 +318,7 @@ where
|
|||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn name() -> &'static str {
|
fn name() -> &'static str {
|
||||||
"Fast OR"
|
"Fast OR"
|
||||||
@ -366,7 +346,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
fn is_pair_interesting_with_perf<EM, OT>(
|
fn is_pair_interesting_introspection<EM, OT>(
|
||||||
first: &mut A,
|
first: &mut A,
|
||||||
second: &mut B,
|
second: &mut B,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
@ -374,37 +354,19 @@ where
|
|||||||
input: &I,
|
input: &I,
|
||||||
observers: &OT,
|
observers: &OT,
|
||||||
exit_kind: &ExitKind,
|
exit_kind: &ExitKind,
|
||||||
feedback_stats: &mut [u64; NUM_FEEDBACKS],
|
|
||||||
feedback_index: usize,
|
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<I, S>,
|
EM: EventFirer<I, S>,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
{
|
{
|
||||||
// Execute this feedback
|
// Execute this feedback
|
||||||
let a = first.is_interesting_with_perf(
|
let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
|
||||||
state,
|
|
||||||
manager,
|
|
||||||
input,
|
|
||||||
observers,
|
|
||||||
exit_kind,
|
|
||||||
feedback_stats,
|
|
||||||
feedback_index,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if a {
|
if a {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
second.is_interesting_with_perf(
|
second.is_interesting_introspection(state, manager, input, observers, exit_kind)
|
||||||
state,
|
|
||||||
manager,
|
|
||||||
input,
|
|
||||||
observers,
|
|
||||||
exit_kind,
|
|
||||||
feedback_stats,
|
|
||||||
feedback_index + 1,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,6 +375,7 @@ where
|
|||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn name() -> &'static str {
|
fn name() -> &'static str {
|
||||||
"Eager AND"
|
"Eager AND"
|
||||||
@ -437,7 +400,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
fn is_pair_interesting_with_perf<EM, OT>(
|
fn is_pair_interesting_introspection<EM, OT>(
|
||||||
first: &mut A,
|
first: &mut A,
|
||||||
second: &mut B,
|
second: &mut B,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
@ -445,33 +408,15 @@ where
|
|||||||
input: &I,
|
input: &I,
|
||||||
observers: &OT,
|
observers: &OT,
|
||||||
exit_kind: &ExitKind,
|
exit_kind: &ExitKind,
|
||||||
feedback_stats: &mut [u64; NUM_FEEDBACKS],
|
|
||||||
feedback_index: usize,
|
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<I, S>,
|
EM: EventFirer<I, S>,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
{
|
{
|
||||||
// Execute this feedback
|
// Execute this feedback
|
||||||
let a = first.is_interesting_with_perf(
|
let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
|
||||||
state,
|
|
||||||
manager,
|
|
||||||
input,
|
|
||||||
observers,
|
|
||||||
exit_kind,
|
|
||||||
feedback_stats,
|
|
||||||
feedback_index,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let b = second.is_interesting_with_perf(
|
let b = second.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
|
||||||
state,
|
|
||||||
manager,
|
|
||||||
input,
|
|
||||||
observers,
|
|
||||||
exit_kind,
|
|
||||||
feedback_stats,
|
|
||||||
feedback_index + 1,
|
|
||||||
)?;
|
|
||||||
Ok(a && b)
|
Ok(a && b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -481,6 +426,7 @@ where
|
|||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn name() -> &'static str {
|
fn name() -> &'static str {
|
||||||
"Fast AND"
|
"Fast AND"
|
||||||
@ -508,7 +454,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
fn is_pair_interesting_with_perf<EM, OT>(
|
fn is_pair_interesting_introspection<EM, OT>(
|
||||||
first: &mut A,
|
first: &mut A,
|
||||||
second: &mut B,
|
second: &mut B,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
@ -516,37 +462,19 @@ where
|
|||||||
input: &I,
|
input: &I,
|
||||||
observers: &OT,
|
observers: &OT,
|
||||||
exit_kind: &ExitKind,
|
exit_kind: &ExitKind,
|
||||||
feedback_stats: &mut [u64; NUM_FEEDBACKS],
|
|
||||||
feedback_index: usize,
|
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<I, S>,
|
EM: EventFirer<I, S>,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
{
|
{
|
||||||
// Execute this feedback
|
// Execute this feedback
|
||||||
let a = first.is_interesting_with_perf(
|
let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
|
||||||
state,
|
|
||||||
manager,
|
|
||||||
input,
|
|
||||||
observers,
|
|
||||||
exit_kind,
|
|
||||||
feedback_stats,
|
|
||||||
feedback_index,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if !a {
|
if !a {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
second.is_interesting_with_perf(
|
second.is_interesting_introspection(state, manager, input, observers, exit_kind)
|
||||||
state,
|
|
||||||
manager,
|
|
||||||
input,
|
|
||||||
observers,
|
|
||||||
exit_kind,
|
|
||||||
feedback_stats,
|
|
||||||
feedback_index + 1,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,6 +501,7 @@ pub struct NotFeedback<A, I, S>
|
|||||||
where
|
where
|
||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
/// The feedback to invert
|
/// The feedback to invert
|
||||||
pub first: A,
|
pub first: A,
|
||||||
@ -585,6 +514,7 @@ impl<A, I, S> Feedback<I, S> for NotFeedback<A, I, S>
|
|||||||
where
|
where
|
||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -618,6 +548,7 @@ impl<A, I, S> Named for NotFeedback<A, I, S>
|
|||||||
where
|
where
|
||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
@ -629,6 +560,7 @@ impl<A, I, S> NotFeedback<A, I, S>
|
|||||||
where
|
where
|
||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
/// Creates a new [`NotFeedback`].
|
/// Creates a new [`NotFeedback`].
|
||||||
pub fn new(first: A) -> Self {
|
pub fn new(first: A) -> Self {
|
||||||
@ -696,6 +628,7 @@ macro_rules! feedback_not {
|
|||||||
impl<I, S> Feedback<I, S> for ()
|
impl<I, S> Feedback<I, S> for ()
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -727,6 +660,7 @@ pub struct CrashFeedback {}
|
|||||||
impl<I, S> Feedback<I, S> for CrashFeedback
|
impl<I, S> Feedback<I, S> for CrashFeedback
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -776,6 +710,7 @@ pub struct TimeoutFeedback {}
|
|||||||
impl<I, S> Feedback<I, S> for TimeoutFeedback
|
impl<I, S> Feedback<I, S> for TimeoutFeedback
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -830,6 +765,7 @@ pub struct TimeFeedback {
|
|||||||
impl<I, S> Feedback<I, S> for TimeFeedback
|
impl<I, S> Feedback<I, S> for TimeFeedback
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -44,6 +44,7 @@ pub trait HasFeedback<F, I, S>
|
|||||||
where
|
where
|
||||||
F: Feedback<I, S>,
|
F: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
/// The feedback
|
/// The feedback
|
||||||
fn feedback(&self) -> &F;
|
fn feedback(&self) -> &F;
|
||||||
@ -57,6 +58,7 @@ pub trait HasObjective<I, OF, S>
|
|||||||
where
|
where
|
||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
/// The objective feedback
|
/// The objective feedback
|
||||||
fn objective(&self) -> &OF;
|
fn objective(&self) -> &OF;
|
||||||
@ -240,6 +242,7 @@ where
|
|||||||
F: Feedback<I, S>,
|
F: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
scheduler: CS,
|
scheduler: CS,
|
||||||
feedback: F,
|
feedback: F,
|
||||||
@ -254,6 +257,7 @@ where
|
|||||||
F: Feedback<I, S>,
|
F: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn scheduler(&self) -> &CS {
|
fn scheduler(&self) -> &CS {
|
||||||
&self.scheduler
|
&self.scheduler
|
||||||
@ -270,6 +274,7 @@ where
|
|||||||
F: Feedback<I, S>,
|
F: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn feedback(&self) -> &F {
|
fn feedback(&self) -> &F {
|
||||||
&self.feedback
|
&self.feedback
|
||||||
@ -286,6 +291,7 @@ where
|
|||||||
F: Feedback<I, S>,
|
F: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn objective(&self) -> &OF {
|
fn objective(&self) -> &OF {
|
||||||
&self.objective
|
&self.objective
|
||||||
@ -323,11 +329,15 @@ where
|
|||||||
{
|
{
|
||||||
let mut res = ExecuteInputResult::None;
|
let mut res = ExecuteInputResult::None;
|
||||||
|
|
||||||
start_timer!(state);
|
#[cfg(not(feature = "introspection"))]
|
||||||
let is_solution = self
|
let is_solution = self
|
||||||
.objective_mut()
|
.objective_mut()
|
||||||
.is_interesting(state, manager, &input, observers, &exit_kind)?;
|
.is_interesting(state, manager, &input, observers, &exit_kind)?;
|
||||||
mark_feature_time!(state, PerfFeature::GetObjectivesInterestingAll);
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
let is_solution = self
|
||||||
|
.objective_mut()
|
||||||
|
.is_interesting_introspection(state, manager, &input, observers, &exit_kind)?;
|
||||||
|
|
||||||
if is_solution {
|
if is_solution {
|
||||||
res = ExecuteInputResult::Solution;
|
res = ExecuteInputResult::Solution;
|
||||||
@ -338,31 +348,9 @@ where
|
|||||||
.is_interesting(state, manager, &input, observers, &exit_kind)?;
|
.is_interesting(state, manager, &input, observers, &exit_kind)?;
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
let is_corpus = {
|
let is_corpus = self
|
||||||
// Init temporary feedback stats here. We can't use the typical pattern above
|
.feedback_mut()
|
||||||
// since we need a `mut self` for `feedbacks_mut`, so we can't also hand a
|
.is_interesting_introspection(state, manager, &input, observers, &exit_kind)?;
|
||||||
// new `mut self` to `is_interesting_with_perf`. We use this stack
|
|
||||||
// variable to get the stats and then update the feedbacks directly
|
|
||||||
let mut feedback_stats = [0_u64; crate::stats::NUM_FEEDBACKS];
|
|
||||||
let feedback_index = 0;
|
|
||||||
let is_corpus = self.feedback_mut().is_interesting_with_perf(
|
|
||||||
state,
|
|
||||||
manager,
|
|
||||||
&input,
|
|
||||||
observers,
|
|
||||||
&exit_kind,
|
|
||||||
&mut feedback_stats,
|
|
||||||
feedback_index,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Update the feedback stats
|
|
||||||
state
|
|
||||||
.introspection_stats_mut()
|
|
||||||
.update_feedbacks(feedback_stats);
|
|
||||||
|
|
||||||
// Return the total fitness
|
|
||||||
is_corpus
|
|
||||||
};
|
|
||||||
|
|
||||||
if is_corpus {
|
if is_corpus {
|
||||||
res = ExecuteInputResult::Corpus;
|
res = ExecuteInputResult::Corpus;
|
||||||
@ -569,7 +557,7 @@ where
|
|||||||
Event::UpdatePerfStats {
|
Event::UpdatePerfStats {
|
||||||
executions: *state.executions(),
|
executions: *state.executions(),
|
||||||
time: cur,
|
time: cur,
|
||||||
introspection_stats: Box::new(*state.introspection_stats()),
|
introspection_stats: Box::new(state.introspection_stats().clone()),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
@ -113,7 +113,7 @@ where
|
|||||||
where
|
where
|
||||||
S: HasMetadata,
|
S: HasMetadata,
|
||||||
{
|
{
|
||||||
#[allow(clippy::clippy::option_if_let_else)] // we can't mutate state in a closure
|
#[allow(clippy::option_if_let_else)] // we can't mutate state in a closure
|
||||||
let meta = if let Some(meta) = state.metadata_mut().get_mut::<CmpValuesMetadata>() {
|
let meta = if let Some(meta) = state.metadata_mut().get_mut::<CmpValuesMetadata>() {
|
||||||
meta
|
meta
|
||||||
} else {
|
} else {
|
||||||
|
@ -19,12 +19,6 @@ use crate::bolts::current_time;
|
|||||||
|
|
||||||
const CLIENT_STATS_TIME_WINDOW_SECS: u64 = 5; // 5 seconds
|
const CLIENT_STATS_TIME_WINDOW_SECS: u64 = 5; // 5 seconds
|
||||||
|
|
||||||
/// Number of stages in the fuzzer
|
|
||||||
pub(crate) const NUM_STAGES: usize = 8;
|
|
||||||
|
|
||||||
/// Number of feedback mechanisms to measure for performance
|
|
||||||
pub(crate) const NUM_FEEDBACKS: usize = 16;
|
|
||||||
|
|
||||||
/// User-defined stats types
|
/// User-defined stats types
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub enum UserStats {
|
pub enum UserStats {
|
||||||
@ -294,7 +288,7 @@ where
|
|||||||
{
|
{
|
||||||
// Print the client performance stats.
|
// Print the client performance stats.
|
||||||
let fmt = format!(
|
let fmt = format!(
|
||||||
"Client {:03}: {}",
|
"Client {:03}:\n{}",
|
||||||
sender_id, self.client_stats[sender_id as usize].introspection_stats
|
sender_id, self.client_stats[sender_id as usize].introspection_stats
|
||||||
);
|
);
|
||||||
(self.print_fn)(fmt);
|
(self.print_fn)(fmt);
|
||||||
@ -358,7 +352,7 @@ macro_rules! mark_feedback_time {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Client performance statistics
|
/// Client performance statistics
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct ClientPerfStats {
|
pub struct ClientPerfStats {
|
||||||
/// Starting counter (in clock cycles from [`cpu::read_time_counter`])
|
/// Starting counter (in clock cycles from [`cpu::read_time_counter`])
|
||||||
start_time: u64,
|
start_time: u64,
|
||||||
@ -375,26 +369,22 @@ pub struct ClientPerfStats {
|
|||||||
/// Current stage index to write the next stage benchmark time
|
/// Current stage index to write the next stage benchmark time
|
||||||
curr_stage: u8,
|
curr_stage: u8,
|
||||||
|
|
||||||
/// Current feedback index to write the next feedback benchmark time
|
|
||||||
curr_feedback: u8,
|
|
||||||
|
|
||||||
/// Flag to dictate this stage is in use. Used during printing to not print the empty
|
/// Flag to dictate this stage is in use. Used during printing to not print the empty
|
||||||
/// stages if they are not in use.
|
/// stages if they are not in use.
|
||||||
stages_used: [bool; NUM_STAGES],
|
stages_used: Vec<bool>,
|
||||||
|
|
||||||
// TODO(andrea) use an hashmap and indetify feaures using a &'static str
|
|
||||||
/// Clock cycles spent in the the various features of each stage
|
/// Clock cycles spent in the the various features of each stage
|
||||||
stages: [[u64; PerfFeature::Count as usize]; NUM_STAGES],
|
stages: Vec<[u64; PerfFeature::Count as usize]>,
|
||||||
|
|
||||||
/// Clock cycles spent in each feedback mechanism of the fuzzer.
|
/// Clock cycles spent in each feedback mechanism of the fuzzer.
|
||||||
feedbacks: [u64; NUM_FEEDBACKS],
|
feedbacks: HashMap<String, u64>,
|
||||||
|
|
||||||
/// Current time set by `start_timer`
|
/// Current time set by `start_timer`
|
||||||
timer_start: Option<u64>,
|
timer_start: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Various features that are measured for performance
|
/// Various features that are measured for performance
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum PerfFeature {
|
pub enum PerfFeature {
|
||||||
/// Getting an input from the corpus
|
/// Getting an input from the corpus
|
||||||
@ -477,7 +467,7 @@ impl From<usize> for PerfFeature {
|
|||||||
|
|
||||||
/// Number of features we can measure for performance
|
/// Number of features we can measure for performance
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
const NUM_PERF_FEATURES: usize = PerfFeature::Count as usize;
|
pub const NUM_PERF_FEATURES: usize = PerfFeature::Count as usize;
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
impl ClientPerfStats {
|
impl ClientPerfStats {
|
||||||
@ -493,10 +483,9 @@ impl ClientPerfStats {
|
|||||||
scheduler: 0,
|
scheduler: 0,
|
||||||
manager: 0,
|
manager: 0,
|
||||||
curr_stage: 0,
|
curr_stage: 0,
|
||||||
curr_feedback: 0,
|
stages: vec![],
|
||||||
stages: [[0; NUM_PERF_FEATURES]; NUM_STAGES],
|
stages_used: vec![],
|
||||||
stages_used: [false; NUM_STAGES],
|
feedbacks: HashMap::new(),
|
||||||
feedbacks: [0; NUM_FEEDBACKS],
|
|
||||||
timer_start: None,
|
timer_start: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -514,12 +503,12 @@ impl ClientPerfStats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update the current [`ClientPerfStats`] with the given [`ClientPerfStats`]
|
/// Update the current [`ClientPerfStats`] with the given [`ClientPerfStats`]
|
||||||
pub fn update(&mut self, stats: ClientPerfStats) {
|
pub fn update(&mut self, stats: &ClientPerfStats) {
|
||||||
self.set_current_time(stats.current_time);
|
self.set_current_time(stats.current_time);
|
||||||
self.update_scheduler(stats.scheduler);
|
self.update_scheduler(stats.scheduler);
|
||||||
self.update_manager(stats.manager);
|
self.update_manager(stats.manager);
|
||||||
self.update_stages(stats.stages);
|
self.update_stages(&stats.stages);
|
||||||
self.update_feedbacks(stats.feedbacks);
|
self.update_feedbacks(&stats.feedbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the elapsed time since the internal timer started. Resets the timer when
|
/// Gets the elapsed time since the internal timer started. Resets the timer when
|
||||||
@ -578,33 +567,6 @@ impl ClientPerfStats {
|
|||||||
self.update_feature(feature, elapsed);
|
self.update_feature(feature, elapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the time spent in the current [`Feedback`] with the elapsed time that we
|
|
||||||
/// have seen
|
|
||||||
pub fn mark_feedback_time(&mut self) {
|
|
||||||
// Sanity check that these stats have enough room for these benchmarks
|
|
||||||
assert!(
|
|
||||||
(self.curr_feedback as usize) < NUM_FEEDBACKS,
|
|
||||||
"Current fuzzer has more
|
|
||||||
stages than the `ClientPerfStats` supports ({}). Please update the
|
|
||||||
NUM_FEEDBACKS const value in src/stats/mod.rs and rebuild",
|
|
||||||
NUM_FEEDBACKS
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get the current elapsed time
|
|
||||||
let elapsed = self.mark_time();
|
|
||||||
|
|
||||||
// Get a `usize` for the index
|
|
||||||
let index: usize = self.curr_feedback.try_into().unwrap();
|
|
||||||
|
|
||||||
// Update the current feedback's time with the given time
|
|
||||||
self.feedbacks[index] = self.feedbacks[index]
|
|
||||||
.checked_add(elapsed)
|
|
||||||
.expect("mark_feedback_time overflow");
|
|
||||||
|
|
||||||
// Increment the feedback index to the next feedback
|
|
||||||
self.curr_feedback += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add the given `time` to the `scheduler` stats
|
/// Add the given `time` to the `scheduler` stats
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn update_scheduler(&mut self, time: u64) {
|
pub fn update_scheduler(&mut self, time: u64) {
|
||||||
@ -637,23 +599,32 @@ impl ClientPerfStats {
|
|||||||
self.curr_stage = 0;
|
self.curr_stage = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the feedback index counter to zero
|
/// Update the time spent in the feedback
|
||||||
#[inline]
|
pub fn update_feedback(&mut self, name: &str, time: u64) {
|
||||||
pub fn reset_feedback_index(&mut self) {
|
self.feedbacks.insert(
|
||||||
self.curr_feedback = 0;
|
name.into(),
|
||||||
|
self.feedbacks
|
||||||
|
.get(name)
|
||||||
|
.unwrap_or(&0)
|
||||||
|
.checked_add(time)
|
||||||
|
.expect("update_feedback overflow"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the time spent in the feedbacks
|
/// Update the time spent in all the feedbacks
|
||||||
pub fn update_feedbacks(&mut self, feedbacks: [u64; NUM_FEEDBACKS]) {
|
pub fn update_feedbacks(&mut self, feedbacks: &HashMap<String, u64>) {
|
||||||
for (feedback_index, feedback) in feedbacks.iter().enumerate() {
|
for (key, value) in feedbacks {
|
||||||
self.feedbacks[feedback_index] = self.feedbacks[feedback_index]
|
self.update_feedback(key, *value);
|
||||||
.checked_add(*feedback)
|
|
||||||
.expect("update_feedback overflow");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the time spent in the stages
|
/// Update the time spent in the stages
|
||||||
pub fn update_stages(&mut self, stages: [[u64; NUM_PERF_FEATURES]; NUM_STAGES]) {
|
pub fn update_stages(&mut self, stages: &[[u64; PerfFeature::Count as usize]]) {
|
||||||
|
if self.stages.len() < stages.len() {
|
||||||
|
self.stages
|
||||||
|
.resize(stages.len(), [0; PerfFeature::Count as usize]);
|
||||||
|
self.stages_used.resize(stages.len(), false);
|
||||||
|
}
|
||||||
for (stage_index, features) in stages.iter().enumerate() {
|
for (stage_index, features) in stages.iter().enumerate() {
|
||||||
for (feature_index, feature) in features.iter().enumerate() {
|
for (feature_index, feature) in features.iter().enumerate() {
|
||||||
self.stages[stage_index][feature_index] = self.stages[stage_index][feature_index]
|
self.stages[stage_index][feature_index] = self.stages[stage_index][feature_index]
|
||||||
@ -665,21 +636,18 @@ impl ClientPerfStats {
|
|||||||
|
|
||||||
/// Update the given [`PerfFeature`] with the given `time`
|
/// Update the given [`PerfFeature`] with the given `time`
|
||||||
pub fn update_feature(&mut self, feature: PerfFeature, time: u64) {
|
pub fn update_feature(&mut self, feature: PerfFeature, time: u64) {
|
||||||
// Sanity check that these stats have enough room for these benchmarks
|
|
||||||
assert!(
|
|
||||||
(self.curr_stage as usize) < NUM_STAGES,
|
|
||||||
"Current fuzzer has more stages
|
|
||||||
than the `ClientPerfStats` supports ({}). Please update the NUM_STAGES
|
|
||||||
const value in src/stats/mod.rs and rebuild",
|
|
||||||
NUM_STAGES
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get the current stage index as `usize`
|
// Get the current stage index as `usize`
|
||||||
let stage_index: usize = self.curr_stage.try_into().unwrap();
|
let stage_index: usize = self.curr_stage.try_into().unwrap();
|
||||||
|
|
||||||
// Get the index of the given feature
|
// Get the index of the given feature
|
||||||
let feature_index: usize = feature.try_into().unwrap();
|
let feature_index: usize = feature.try_into().unwrap();
|
||||||
|
|
||||||
|
if stage_index >= self.stages.len() {
|
||||||
|
self.stages
|
||||||
|
.resize(stage_index + 1, [0; PerfFeature::Count as usize]);
|
||||||
|
self.stages_used.resize(stage_index + 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Update the given feature
|
// Update the given feature
|
||||||
self.stages[stage_index][feature_index] = self.stages[stage_index][feature_index]
|
self.stages[stage_index][feature_index] = self.stages[stage_index][feature_index]
|
||||||
.checked_add(time)
|
.checked_add(time)
|
||||||
@ -689,18 +657,25 @@ impl ClientPerfStats {
|
|||||||
self.stages_used[stage_index] = true;
|
self.stages_used[stage_index] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The elapsed cycles (or time)
|
||||||
|
#[must_use]
|
||||||
pub fn elapsed_cycles(&self) -> u64 {
|
pub fn elapsed_cycles(&self) -> u64 {
|
||||||
self.current_time - self.start_time
|
self.current_time - self.start_time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The amount of cycles the `manager` did
|
||||||
|
#[must_use]
|
||||||
pub fn manager_cycles(&self) -> u64 {
|
pub fn manager_cycles(&self) -> u64 {
|
||||||
self.manager
|
self.manager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The amount of cycles the `scheduler` did
|
||||||
|
#[must_use]
|
||||||
pub fn scheduler_cycles(&self) -> u64 {
|
pub fn scheduler_cycles(&self) -> u64 {
|
||||||
self.scheduler
|
self.scheduler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterator over all used stages
|
||||||
pub fn used_stages(
|
pub fn used_stages(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = (usize, &[u64; PerfFeature::Count as usize])> {
|
) -> impl Iterator<Item = (usize, &[u64; PerfFeature::Count as usize])> {
|
||||||
@ -711,8 +686,10 @@ impl ClientPerfStats {
|
|||||||
.filter(move |(stage_index, _)| used[*stage_index as usize])
|
.filter(move |(stage_index, _)| used[*stage_index as usize])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn feedbacks(&self) -> impl Iterator<Item = (usize, &u64)> {
|
/// A map of all `feedbacks`
|
||||||
self.feedbacks.iter().enumerate()
|
#[must_use]
|
||||||
|
pub fn feedbacks(&self) -> &HashMap<String, u64> {
|
||||||
|
&self.feedbacks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -735,7 +712,7 @@ impl core::fmt::Display for ClientPerfStats {
|
|||||||
// Create the formatted string
|
// Create the formatted string
|
||||||
writeln!(
|
writeln!(
|
||||||
f,
|
f,
|
||||||
"Scheduler: {:4.2} | Manager: {:4.2} | Stages:",
|
" {:6.4}: Scheduler\n {:6.4}: Manager",
|
||||||
scheduler_percent, manager_percent
|
scheduler_percent, manager_percent
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -763,29 +740,27 @@ impl core::fmt::Display for ClientPerfStats {
|
|||||||
// Write the percentage for this feature
|
// Write the percentage for this feature
|
||||||
writeln!(f, " {:6.4}: {:?}", feature_percent, feature)?;
|
writeln!(f, " {:6.4}: {:?}", feature_percent, feature)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (feedback_index, feedback) in self.feedbacks() {
|
|
||||||
// Calculate this current stage's percentage
|
|
||||||
let feedback_percent = *feedback as f64 / elapsed;
|
|
||||||
|
|
||||||
// Ignore this feedback if it isn't used
|
|
||||||
if feedback_percent == 0.0 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the other percent by removing this current percent
|
|
||||||
other_percent -= feedback_percent;
|
|
||||||
|
|
||||||
// Write the percentage for this feedback
|
|
||||||
writeln!(
|
|
||||||
f,
|
|
||||||
" {:6.4}: Feedback index {}",
|
|
||||||
feedback_percent, feedback_index
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, " Not Measured: {:4.2}", other_percent)?;
|
writeln!(f, " Feedbacks:")?;
|
||||||
|
|
||||||
|
for (feedback_name, feedback_time) in self.feedbacks() {
|
||||||
|
// Calculate this current stage's percentage
|
||||||
|
let feedback_percent = *feedback_time as f64 / elapsed;
|
||||||
|
|
||||||
|
// Ignore this feedback if it isn't used
|
||||||
|
if feedback_percent == 0.0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the other percent by removing this current percent
|
||||||
|
other_percent -= feedback_percent;
|
||||||
|
|
||||||
|
// Write the percentage for this feedback
|
||||||
|
writeln!(f, " {:6.4}: {}", feedback_percent, feedback_name)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, " {:6.4}: Not Measured", other_percent)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ where
|
|||||||
{
|
{
|
||||||
// Print the client performance stats. Skip the Client 0 which is the broker
|
// Print the client performance stats. Skip the Client 0 which is the broker
|
||||||
for (i, client) in self.client_stats.iter().skip(1).enumerate() {
|
for (i, client) in self.client_stats.iter().skip(1).enumerate() {
|
||||||
let fmt = format!("Client {:03}: {}", i + 1, client.introspection_stats);
|
let fmt = format!("Client {:03}:\n{}", i + 1, client.introspection_stats);
|
||||||
(self.print_fn)(fmt);
|
(self.print_fn)(fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ use libafl::{
|
|||||||
feedbacks::Feedback,
|
feedbacks::Feedback,
|
||||||
inputs::{HasTargetBytes, Input},
|
inputs::{HasTargetBytes, Input},
|
||||||
observers::{Observer, ObserversTuple},
|
observers::{Observer, ObserversTuple},
|
||||||
state::HasMetadata,
|
state::{HasClientPerfStats, HasMetadata},
|
||||||
Error, SerdeAny,
|
Error, SerdeAny,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -510,6 +510,7 @@ pub struct AsanErrorsFeedback {
|
|||||||
impl<I, S> Feedback<I, S> for AsanErrorsFeedback
|
impl<I, S> Feedback<I, S> for AsanErrorsFeedback
|
||||||
where
|
where
|
||||||
I: Input + HasTargetBytes,
|
I: Input + HasTargetBytes,
|
||||||
|
S: HasClientPerfStats,
|
||||||
{
|
{
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -73,8 +73,6 @@
|
|||||||
#define CHECK_WEAK_FN(Name) (Name != NULL)
|
#define CHECK_WEAK_FN(Name) (Name != NULL)
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#define EXT_FUNC_DEF(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
|
||||||
EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN)
|
|
||||||
#define EXT_FUNC_IMPL(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
#define EXT_FUNC_IMPL(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||||
EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN)
|
EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN)
|
||||||
|
|
||||||
@ -84,10 +82,7 @@
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
// TODO: Find a proper way to deal with weak fns on Apple!
|
|
||||||
// On Apple, weak_import and weak attrs behave differently to linux.
|
// On Apple, weak_import and weak attrs behave differently to linux.
|
||||||
#define EXT_FUNC_DEF(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
|
||||||
EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) { return (RETURN_TYPE) 0; }
|
|
||||||
|
|
||||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||||
__attribute__((weak, visibility("default"))) RETURN_TYPE NAME FUNC_SIG { \
|
__attribute__((weak, visibility("default"))) RETURN_TYPE NAME FUNC_SIG { \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user