Tuneable Stage, Scheduler, ScheduledMutator (#874)
* Tuneable Stage, Scheduler, and Mutators * rename * fix build * get rid of prelude * fmt * Reworked tunable, fixed stuff, add testcase * clippy * further fixes * fix typo, fmt
This commit is contained in:
parent
fe459f6fa5
commit
e5aaf85d3c
@ -18,9 +18,9 @@ use libafl::{
|
||||
Error,
|
||||
};
|
||||
|
||||
const _TAG_SIMPLE_U32_V1: Tag = 0x51300321;
|
||||
const _TAG_MATH_RESULT_V1: Tag = 0x77474331;
|
||||
const _TAG_1MEG_V1: Tag = 0xB1111161;
|
||||
const _TAG_SIMPLE_U32_V1: Tag = 0x5130_0321;
|
||||
const _TAG_MATH_RESULT_V1: Tag = 0x7747_4331;
|
||||
const _TAG_1MEG_V1: Tag = 0xB111_1161;
|
||||
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
fn adder_loop(port: u16) -> ! {
|
||||
@ -71,15 +71,17 @@ fn large_msg_loop(port: u16) -> ! {
|
||||
let mut client =
|
||||
llmp::LlmpClient::create_attach_to_tcp(StdShMemProvider::new().unwrap(), port).unwrap();
|
||||
|
||||
#[allow(clippy::large_stack_arrays)]
|
||||
let meg_buf = [1u8; 1 << 20];
|
||||
|
||||
loop {
|
||||
client.send_buf(_TAG_1MEG_V1, &meg_buf).unwrap();
|
||||
println!("Sending the next megabyte");
|
||||
thread::sleep(time::Duration::from_millis(100))
|
||||
thread::sleep(time::Duration::from_millis(100));
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
fn broker_message_hook(
|
||||
client_id: u32,
|
||||
@ -133,20 +135,20 @@ fn main() {
|
||||
.unwrap_or_else(|| "4242".into())
|
||||
.parse::<u16>()
|
||||
.unwrap();
|
||||
println!("Launching in mode {} on port {}", mode, port);
|
||||
println!("Launching in mode {mode} on port {port}");
|
||||
|
||||
match mode.as_str() {
|
||||
"broker" => {
|
||||
let mut broker = llmp::LlmpBroker::new(StdShMemProvider::new().unwrap()).unwrap();
|
||||
broker.launch_tcp_listener_on(port).unwrap();
|
||||
broker.loop_forever(&mut broker_message_hook, Some(Duration::from_millis(5)))
|
||||
broker.loop_forever(&mut broker_message_hook, Some(Duration::from_millis(5)));
|
||||
}
|
||||
"b2b" => {
|
||||
let mut broker = llmp::LlmpBroker::new(StdShMemProvider::new().unwrap()).unwrap();
|
||||
broker.launch_tcp_listener_on(b2b_port).unwrap();
|
||||
// connect back to the main broker.
|
||||
broker.connect_b2b(("127.0.0.1", port)).unwrap();
|
||||
broker.loop_forever(&mut broker_message_hook, Some(Duration::from_millis(5)))
|
||||
broker.loop_forever(&mut broker_message_hook, Some(Duration::from_millis(5)));
|
||||
}
|
||||
"ctr" => {
|
||||
let mut client =
|
||||
@ -158,8 +160,8 @@ fn main() {
|
||||
client
|
||||
.send_buf(_TAG_SIMPLE_U32_V1, &counter.to_le_bytes())
|
||||
.unwrap();
|
||||
println!("CTR Client writing {}", counter);
|
||||
thread::sleep(Duration::from_secs(1))
|
||||
println!("CTR Client writing {counter}");
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
}
|
||||
}
|
||||
"adder" => {
|
||||
|
@ -35,10 +35,10 @@ use crate::{
|
||||
use crate::{inputs::Input, Error};
|
||||
|
||||
/// How to deliver input to an external program
|
||||
/// `StdIn`: The traget reads from stdin
|
||||
/// `StdIn`: The target reads from stdin
|
||||
/// `File`: The target reads from the specified [`InputFile`]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
enum InputLocation {
|
||||
pub enum InputLocation {
|
||||
/// Mutate a commandline argument to deliver an input
|
||||
Arg {
|
||||
/// The offset of the argument to mutate
|
||||
|
@ -14,6 +14,8 @@ pub mod gramatron;
|
||||
pub use gramatron::*;
|
||||
pub mod grimoire;
|
||||
pub use grimoire::*;
|
||||
pub mod tuneable;
|
||||
pub use tuneable::*;
|
||||
|
||||
#[cfg(feature = "nautilus")]
|
||||
pub mod nautilus;
|
||||
|
@ -644,6 +644,7 @@ where
|
||||
}
|
||||
|
||||
/// Get the next mutation to apply
|
||||
#[inline]
|
||||
fn schedule(&self, state: &mut S, _: &S::Input) -> usize {
|
||||
state
|
||||
.metadata_mut()
|
||||
|
240
libafl/src/mutators/tuneable.rs
Normal file
240
libafl/src/mutators/tuneable.rs
Normal file
@ -0,0 +1,240 @@
|
||||
//! An extension to the `ScheduledMutator` which schedules multiple mutations internally.
|
||||
//! Instead of a random mutator for a random amount of iterations, we can run
|
||||
//! a specific mutator for a specified amount of iterations
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::{
|
||||
fmt::{self, Debug},
|
||||
marker::PhantomData,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub use crate::mutators::{mutations::*, token_mutations::*};
|
||||
use crate::{
|
||||
bolts::rands::Rand,
|
||||
impl_serdeany,
|
||||
mutators::{ComposedByMutations, MutationResult, Mutator, MutatorsTuple, ScheduledMutator},
|
||||
state::{HasMetadata, HasRand, State},
|
||||
Error,
|
||||
};
|
||||
|
||||
/// Metadata in the state, that controls the behavior of the [`TuneableScheduledMutator`] at runtime
|
||||
#[derive(Default, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub struct TuneableScheduledMutatorMetadata {
|
||||
/// The offsets of mutators to run, in order. Clear to fall back to random.
|
||||
pub next: Vec<usize>,
|
||||
/// The next index to read from in the `next` vec
|
||||
pub next_idx: usize,
|
||||
/// The count of total mutations to perform.
|
||||
/// If `next` is of length `10`, and this number is `20`,
|
||||
/// the mutations will be iterated through twice.
|
||||
pub iters: Option<u64>,
|
||||
}
|
||||
|
||||
impl TuneableScheduledMutatorMetadata {
|
||||
/// Gets the stored metadata, used to alter the [`TuneableScheduledMutator`] behavior
|
||||
pub fn get<S: HasMetadata>(state: &S) -> Result<&Self, Error> {
|
||||
state
|
||||
.metadata()
|
||||
.get::<Self>()
|
||||
.ok_or_else(|| Error::illegal_state("TuneableScheduledMutator not in use"))
|
||||
}
|
||||
|
||||
/// Gets the stored metadata, used to alter the [`TuneableScheduledMutator`] behavior, mut
|
||||
pub fn get_mut<S: HasMetadata>(state: &mut S) -> Result<&mut Self, Error> {
|
||||
state
|
||||
.metadata_mut()
|
||||
.get_mut::<Self>()
|
||||
.ok_or_else(|| Error::illegal_state("TuneableScheduledMutator not in use"))
|
||||
}
|
||||
}
|
||||
|
||||
impl_serdeany!(TuneableScheduledMutatorMetadata);
|
||||
|
||||
/// A [`Mutator`] that schedules one of the embedded mutations on each call.
|
||||
/// The index of the next mutation can be set.
|
||||
pub struct TuneableScheduledMutator<MT, S>
|
||||
where
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand,
|
||||
{
|
||||
mutations: MT,
|
||||
max_stack_pow: u64,
|
||||
phantom: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<MT, S> Debug for TuneableScheduledMutator<MT, S>
|
||||
where
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"TuneableScheduledMutator with {} mutations for Input type {}",
|
||||
self.mutations.len(),
|
||||
core::any::type_name::<S::Input>()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<MT, S> Mutator<S> for TuneableScheduledMutator<MT, S>
|
||||
where
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand + HasMetadata,
|
||||
{
|
||||
#[inline]
|
||||
fn mutate(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &mut S::Input,
|
||||
stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
self.scheduled_mutate(state, input, stage_idx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<MT, S> ComposedByMutations<MT, S> for TuneableScheduledMutator<MT, S>
|
||||
where
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand,
|
||||
{
|
||||
/// Get the mutations
|
||||
#[inline]
|
||||
fn mutations(&self) -> &MT {
|
||||
&self.mutations
|
||||
}
|
||||
|
||||
// Get the mutations (mutable)
|
||||
#[inline]
|
||||
fn mutations_mut(&mut self) -> &mut MT {
|
||||
&mut self.mutations
|
||||
}
|
||||
}
|
||||
|
||||
impl<MT, S> ScheduledMutator<MT, S> for TuneableScheduledMutator<MT, S>
|
||||
where
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand + HasMetadata,
|
||||
{
|
||||
/// Compute the number of iterations used to apply stacked mutations
|
||||
fn iterations(&self, state: &mut S, _: &S::Input) -> u64 {
|
||||
if let Some(iters) = Self::get_iters(state) {
|
||||
iters
|
||||
} else {
|
||||
// fall back to random
|
||||
1 << (1 + state.rand_mut().below(self.max_stack_pow))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the next mutation to apply
|
||||
fn schedule(&self, state: &mut S, _: &S::Input) -> usize {
|
||||
debug_assert!(!self.mutations().is_empty());
|
||||
// Assumption: we can not reach this code path without previously adding this metadatum.
|
||||
let metadata = TuneableScheduledMutatorMetadata::get_mut(state).unwrap();
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
if metadata.next.is_empty() {
|
||||
// fall back to random if no entries in the vec
|
||||
state.rand_mut().below(self.mutations().len() as u64) as usize
|
||||
} else {
|
||||
let ret = metadata.next[metadata.next_idx];
|
||||
metadata.next_idx += 1_usize;
|
||||
if metadata.next_idx >= metadata.next.len() {
|
||||
metadata.next_idx = 0;
|
||||
}
|
||||
debug_assert!(
|
||||
self.mutations().len() > ret,
|
||||
"TuneableScheduler: next vec may not contain idx larger than number of mutations!"
|
||||
);
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<MT, S> TuneableScheduledMutator<MT, S>
|
||||
where
|
||||
MT: MutatorsTuple<S>,
|
||||
S: State + HasRand + HasMetadata,
|
||||
{
|
||||
/// Create a new [`TuneableScheduledMutator`] instance specifying mutations
|
||||
pub fn new(state: &mut S, mutations: MT) -> Self {
|
||||
if !state.has_metadata::<TuneableScheduledMutatorMetadata>() {
|
||||
state.add_metadata(TuneableScheduledMutatorMetadata::default());
|
||||
}
|
||||
TuneableScheduledMutator {
|
||||
mutations,
|
||||
max_stack_pow: 7,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn metadata_mut(state: &mut S) -> &mut TuneableScheduledMutatorMetadata {
|
||||
state
|
||||
.metadata_mut()
|
||||
.get_mut::<TuneableScheduledMutatorMetadata>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn metadata(state: &S) -> &TuneableScheduledMutatorMetadata {
|
||||
state
|
||||
.metadata()
|
||||
.get::<TuneableScheduledMutatorMetadata>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Sets the next iterations count, i.e., how many times to mutate the input
|
||||
///
|
||||
/// Using `set_next_and_iter` to set multiple values at the same time
|
||||
/// will be faster than setting them individually
|
||||
/// as it internally only needs a single metadata lookup
|
||||
pub fn set_iters(state: &mut S, iters: u64) {
|
||||
let metadata = Self::metadata_mut(state);
|
||||
metadata.iters = Some(iters);
|
||||
}
|
||||
|
||||
/// Gets the set iterations
|
||||
pub fn get_iters(state: &S) -> Option<u64> {
|
||||
let metadata = Self::metadata(state);
|
||||
metadata.iters
|
||||
}
|
||||
|
||||
/// Resets this to a randomic mutational stage
|
||||
pub fn reset(state: &mut S) {
|
||||
let metadata = Self::metadata_mut(state);
|
||||
metadata.next.clear();
|
||||
metadata.next_idx = 0;
|
||||
metadata.iters = None;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{
|
||||
BitFlipMutator, ByteDecMutator, TuneableScheduledMutator, TuneableScheduledMutatorMetadata,
|
||||
};
|
||||
use crate::{
|
||||
bolts::tuples::tuple_list,
|
||||
inputs::BytesInput,
|
||||
mutators::{ByteRandMutator, ScheduledMutator},
|
||||
state::NopState,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_tuning() {
|
||||
let mut state = NopState::new();
|
||||
let mutators = tuple_list!(
|
||||
BitFlipMutator::new(),
|
||||
ByteDecMutator::new(),
|
||||
ByteRandMutator::new()
|
||||
);
|
||||
let tuneable = TuneableScheduledMutator::new(&mut state, mutators);
|
||||
let input = BytesInput::new(vec![42]);
|
||||
let metadata = TuneableScheduledMutatorMetadata::get_mut(&mut state).unwrap();
|
||||
metadata.next.push(1);
|
||||
metadata.next.push(2);
|
||||
assert_eq!(tuneable.schedule(&mut state, &input), 1);
|
||||
assert_eq!(tuneable.schedule(&mut state, &input), 2);
|
||||
assert_eq!(tuneable.schedule(&mut state, &input), 1);
|
||||
}
|
||||
}
|
@ -27,6 +27,9 @@ use alloc::borrow::ToOwned;
|
||||
|
||||
pub use powersched::PowerQueueScheduler;
|
||||
|
||||
pub mod tuneable;
|
||||
pub use tuneable::*;
|
||||
|
||||
use crate::{
|
||||
bolts::rands::Rand,
|
||||
corpus::{Corpus, Testcase},
|
||||
|
108
libafl/src/schedulers/tuneable.rs
Normal file
108
libafl/src/schedulers/tuneable.rs
Normal file
@ -0,0 +1,108 @@
|
||||
//! The queue corpus scheduler implements an AFL-like queue mechanism
|
||||
//! The [`TuneableScheduler`] extends the queue scheduler with a method to
|
||||
//! chose the next corpus entry manually
|
||||
|
||||
use alloc::borrow::ToOwned;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
impl_serdeany,
|
||||
inputs::UsesInput,
|
||||
schedulers::Scheduler,
|
||||
state::{HasCorpus, HasMetadata, UsesState},
|
||||
Error,
|
||||
};
|
||||
|
||||
#[derive(Default, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
||||
struct TuneableSchedulerMetadata {
|
||||
next: Option<usize>,
|
||||
}
|
||||
|
||||
impl_serdeany!(TuneableSchedulerMetadata);
|
||||
|
||||
/// Walk the corpus in a queue-like fashion
|
||||
/// With the specific `set_next` method, we can chose the next corpus entry manually
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TuneableScheduler<S> {
|
||||
phantom: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<S> TuneableScheduler<S>
|
||||
where
|
||||
S: HasMetadata + HasCorpus,
|
||||
{
|
||||
/// Creates a new `TuneableScheduler`
|
||||
#[must_use]
|
||||
pub fn new(state: &mut S) -> Self {
|
||||
if !state.has_metadata::<TuneableSchedulerMetadata>() {
|
||||
state.add_metadata(TuneableSchedulerMetadata::default());
|
||||
}
|
||||
Self {
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn metadata_mut(state: &mut S) -> &mut TuneableSchedulerMetadata {
|
||||
state
|
||||
.metadata_mut()
|
||||
.get_mut::<TuneableSchedulerMetadata>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn metadata(state: &S) -> &TuneableSchedulerMetadata {
|
||||
state.metadata().get::<TuneableSchedulerMetadata>().unwrap()
|
||||
}
|
||||
|
||||
/// Sets the next corpus id to be used
|
||||
pub fn set_next(state: &mut S, next: usize) {
|
||||
Self::metadata_mut(state).next = Some(next);
|
||||
}
|
||||
|
||||
/// Gets the next set corpus id
|
||||
pub fn get_next(state: &S) -> Option<usize> {
|
||||
Self::metadata(state).next
|
||||
}
|
||||
|
||||
/// Resets this to a queue scheduler
|
||||
pub fn reset(state: &mut S) {
|
||||
let metadata = Self::metadata_mut(state);
|
||||
metadata.next = None;
|
||||
}
|
||||
|
||||
/// Gets the current corpus entry id
|
||||
pub fn get_current(state: &S) -> usize {
|
||||
state.corpus().current().unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> UsesState for TuneableScheduler<S>
|
||||
where
|
||||
S: UsesInput,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<S> Scheduler for TuneableScheduler<S>
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
{
|
||||
/// Gets the next entry in the queue
|
||||
fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
|
||||
if state.corpus().count() == 0 {
|
||||
return Err(Error::empty("No entries in corpus".to_owned()));
|
||||
}
|
||||
let id = if let Some(next) = Self::get_next(state) {
|
||||
// next was set
|
||||
next
|
||||
} else if Self::get_current(state) + 1 >= state.corpus().count() {
|
||||
0
|
||||
} else {
|
||||
Self::get_current(state) + 1
|
||||
};
|
||||
*state.corpus_mut().current_mut() = Some(id);
|
||||
Ok(id)
|
||||
}
|
||||
}
|
@ -30,6 +30,9 @@ pub use generalization::GeneralizationStage;
|
||||
pub mod owned;
|
||||
pub use owned::StagesOwnedList;
|
||||
|
||||
pub mod tuneable;
|
||||
pub use tuneable::*;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub mod concolic;
|
||||
#[cfg(feature = "std")]
|
||||
|
@ -37,7 +37,7 @@ where
|
||||
fn mutator_mut(&mut self) -> &mut M;
|
||||
|
||||
/// Gets the number of iterations this mutator should run for.
|
||||
fn iterations(&self, state: &mut Z::State, corpus_idx: usize) -> Result<usize, Error>;
|
||||
fn iterations(&self, state: &mut Z::State, corpus_idx: usize) -> Result<u64, Error>;
|
||||
|
||||
/// Runs this (mutational) stage for the given testcase
|
||||
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
|
||||
@ -109,8 +109,8 @@ where
|
||||
}
|
||||
|
||||
/// Gets the number of iterations as a random number
|
||||
fn iterations(&self, state: &mut Z::State, _corpus_idx: usize) -> Result<usize, Error> {
|
||||
Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize)
|
||||
fn iterations(&self, state: &mut Z::State, _corpus_idx: usize) -> Result<u64, Error> {
|
||||
Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,10 +58,10 @@ where
|
||||
|
||||
/// Gets the number of iterations as a random number
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
fn iterations(&self, state: &mut E::State, corpus_idx: usize) -> Result<usize, Error> {
|
||||
fn iterations(&self, state: &mut E::State, corpus_idx: usize) -> Result<u64, Error> {
|
||||
// Update handicap
|
||||
let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut();
|
||||
let score = F::compute(&mut *testcase, state)? as usize;
|
||||
let score = F::compute(&mut *testcase, state)? as u64;
|
||||
|
||||
Ok(score)
|
||||
}
|
||||
|
148
libafl/src/stages/tuneable.rs
Normal file
148
libafl/src/stages/tuneable.rs
Normal file
@ -0,0 +1,148 @@
|
||||
//! A [`crate::stages::MutationalStage`] where the mutator iteration can be tuned at runtime
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
bolts::rands::Rand,
|
||||
impl_serdeany,
|
||||
mutators::Mutator,
|
||||
stages::{mutational::DEFAULT_MUTATIONAL_MAX_ITERATIONS, MutationalStage, Stage},
|
||||
state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState},
|
||||
Error, Evaluator,
|
||||
};
|
||||
|
||||
#[derive(Default, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
||||
struct TuneableMutationalStageMetadata {
|
||||
iters: Option<u64>,
|
||||
}
|
||||
|
||||
impl_serdeany!(TuneableMutationalStageMetadata);
|
||||
|
||||
/// Set the number of iterations to be used by this mutational stage
|
||||
pub fn set_iters<S: HasMetadata>(state: &mut S, iters: u64) -> Result<(), Error> {
|
||||
let metadata = state
|
||||
.metadata_mut()
|
||||
.get_mut::<TuneableMutationalStageMetadata>()
|
||||
.ok_or_else(|| Error::illegal_state("TuneableMutationslStage not in use"));
|
||||
metadata.map(|metadata| {
|
||||
metadata.iters = Some(iters);
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the set iterations
|
||||
pub fn get_iters<S: HasMetadata>(state: &S) -> Result<Option<u64>, Error> {
|
||||
state
|
||||
.metadata()
|
||||
.get::<TuneableMutationalStageMetadata>()
|
||||
.ok_or_else(|| Error::illegal_state("TuneableMutationslStage not in use"))
|
||||
.map(|metadata| metadata.iters)
|
||||
}
|
||||
|
||||
/// Reset this to a normal, randomized, stage
|
||||
pub fn reset<S: HasMetadata>(state: &mut S) -> Result<(), Error> {
|
||||
state
|
||||
.metadata_mut()
|
||||
.get_mut::<TuneableMutationalStageMetadata>()
|
||||
.ok_or_else(|| Error::illegal_state("TuneableMutationslStage not in use"))
|
||||
.map(|metadata| metadata.iters = None)
|
||||
}
|
||||
|
||||
/// A [`crate::stages::MutationalStage`] where the mutator iteration can be tuned at runtime
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TuneableMutationalStage<E, EM, M, Z> {
|
||||
mutator: M,
|
||||
phantom: PhantomData<(E, EM, Z)>,
|
||||
}
|
||||
|
||||
impl<E, EM, M, Z> MutationalStage<E, EM, M, Z> for TuneableMutationalStage<E, EM, M, Z>
|
||||
where
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
M: Mutator<Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
|
||||
{
|
||||
/// The mutator, added to this stage
|
||||
#[inline]
|
||||
fn mutator(&self) -> &M {
|
||||
&self.mutator
|
||||
}
|
||||
|
||||
/// The list of mutators, added to this stage (as mutable ref)
|
||||
#[inline]
|
||||
fn mutator_mut(&mut self) -> &mut M {
|
||||
&mut self.mutator
|
||||
}
|
||||
|
||||
/// Gets the number of iterations as a random number
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn iterations(&self, state: &mut Z::State, _corpus_idx: usize) -> Result<u64, Error> {
|
||||
Ok(if let Some(iters) = get_iters(state)? {
|
||||
iters
|
||||
} else {
|
||||
// fall back to random
|
||||
1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, EM, M, Z> UsesState for TuneableMutationalStage<E, EM, M, Z>
|
||||
where
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
M: Mutator<Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
|
||||
{
|
||||
type State = Z::State;
|
||||
}
|
||||
|
||||
impl<E, EM, M, Z> Stage<E, EM, Z> for TuneableMutationalStage<E, EM, M, Z>
|
||||
where
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
M: Mutator<Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
|
||||
{
|
||||
#[inline]
|
||||
#[allow(clippy::let_and_return)]
|
||||
fn perform(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
executor: &mut E,
|
||||
state: &mut Z::State,
|
||||
manager: &mut EM,
|
||||
corpus_idx: usize,
|
||||
) -> Result<(), Error> {
|
||||
let ret = self.perform_mutational(fuzzer, executor, state, manager, corpus_idx);
|
||||
|
||||
#[cfg(feature = "introspection")]
|
||||
state.introspection_monitor_mut().finish_stage();
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, EM, M, Z> TuneableMutationalStage<E, EM, M, Z>
|
||||
where
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
M: Mutator<Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
|
||||
{
|
||||
/// Creates a new default mutational stage
|
||||
#[must_use]
|
||||
pub fn new(state: &mut Z::State, mutator: M) -> Self {
|
||||
if !state.has_metadata::<TuneableMutationalStageMetadata>() {
|
||||
state.add_metadata(TuneableMutationalStageMetadata::default());
|
||||
}
|
||||
Self {
|
||||
mutator,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,8 @@ use std::{
|
||||
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::bolts::rands::StdRand;
|
||||
use crate::{
|
||||
bolts::{
|
||||
rands::Rand,
|
||||
@ -599,8 +601,11 @@ impl<I, C, R, SC> HasClientPerfMonitor for StdState<I, C, R, SC> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// A very simple state without any bells or whistles, for testing.
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct NopState<I> {
|
||||
metadata: SerdeAnyMap,
|
||||
rand: StdRand,
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
@ -610,6 +615,8 @@ impl<I> NopState<I> {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
NopState {
|
||||
metadata: SerdeAnyMap::new(),
|
||||
rand: StdRand::default(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -637,11 +644,24 @@ impl<I> HasExecutions for NopState<I> {
|
||||
#[cfg(test)]
|
||||
impl<I> HasMetadata for NopState<I> {
|
||||
fn metadata(&self) -> &SerdeAnyMap {
|
||||
unimplemented!()
|
||||
&self.metadata
|
||||
}
|
||||
|
||||
fn metadata_mut(&mut self) -> &mut SerdeAnyMap {
|
||||
unimplemented!()
|
||||
&mut self.metadata
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<I> HasRand for NopState<I> {
|
||||
type Rand = StdRand;
|
||||
|
||||
fn rand(&self) -> &Self::Rand {
|
||||
&self.rand
|
||||
}
|
||||
|
||||
fn rand_mut(&mut self) -> &mut Self::Rand {
|
||||
&mut self.rand
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ echo "[+] Done fixing build"
|
||||
echo
|
||||
|
||||
echo 'Fixing clippy (might need a "git commit" and a rerun, if "cargo fix" changed the source)'
|
||||
RUST_BACKTRACE=full cargo +nightly clippy --fix --release --all --all-features --tests -- -Z macro-backtrace \
|
||||
RUST_BACKTRACE=full cargo +nightly clippy --fix --release --all --all-features --tests --examples --benches -- -Z macro-backtrace \
|
||||
-D clippy::all \
|
||||
-D clippy::pedantic \
|
||||
-W clippy::similar_names \
|
||||
@ -32,7 +32,7 @@ RUST_BACKTRACE=full cargo +nightly clippy --fix --release --all --all-features -
|
||||
-A clippy::module-name-repetitions \
|
||||
-A clippy::unreadable-literal \
|
||||
|
||||
cargo +nightly clippy --fix --tests --all-features --allow-dirty --allow-staged
|
||||
cargo +nightly clippy --fix --tests --examples --benches --all-features --allow-dirty --allow-staged
|
||||
|
||||
echo "[+] Done fixing clippy"
|
||||
echo
|
||||
|
@ -1,4 +1,4 @@
|
||||
cargo clippy --all --all-features --tests -- `
|
||||
cargo clippy --all --all-features --tests --benches --examples -- `
|
||||
-D clippy::all `
|
||||
-D clippy::pedantic `
|
||||
-W clippy::similar_names `
|
||||
|
@ -2,7 +2,7 @@
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
cd "$SCRIPT_DIR/.." || exit 1
|
||||
|
||||
RUST_BACKTRACE=full cargo +nightly clippy --all --all-features --release --tests -- -Z macro-backtrace \
|
||||
RUST_BACKTRACE=full cargo +nightly clippy --all --all-features --release --tests --examples --benches -- -Z macro-backtrace \
|
||||
-D clippy::all \
|
||||
-D clippy::pedantic \
|
||||
-W clippy::similar_names \
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
# Script to find .rs files that don't get built.
|
||||
|
||||
cargo +nightly build --examples --all-features --tests
|
||||
cargo +nightly build --examples --all-features --tests --examples --benches
|
||||
|
||||
# Find all files in deps, then compare to all actual .d files. Ignore a range of files.
|
||||
grep --no-filename '^[^/].*\.rs:$' target/debug/deps/*.d | sed 's/:$//' | sort -u | diff - <(find . -name '*.rs' | sed 's/\.\///' | sort -u) | grep -Ev '(target/|scripts/|symcc_runtime/|build.rs|fuzzers/)'
|
@ -15,7 +15,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|
||||
}
|
||||
|
||||
c.bench_function("xxh3", |b| {
|
||||
b.iter(|| xxh3::xxh3_64_with_seed(black_box(&bench_vec), 0))
|
||||
b.iter(|| xxh3::xxh3_64_with_seed(black_box(&bench_vec), 0));
|
||||
});
|
||||
/*c.bench_function("const_xxh3", |b| {
|
||||
b.iter(|| const_xxh3::xxh3_64_with_seed(black_box(&bench_vec), 0))
|
||||
@ -24,15 +24,15 @@ fn criterion_benchmark(c: &mut Criterion) {
|
||||
b.iter(|| {
|
||||
let mut hasher = ahash::AHasher::new_with_keys(123, 456);
|
||||
hasher.write(black_box(&bench_vec));
|
||||
hasher.finish()
|
||||
})
|
||||
hasher.finish();
|
||||
});
|
||||
});
|
||||
c.bench_function("fxhash", |b| {
|
||||
b.iter(|| {
|
||||
let mut hasher = rustc_hash::FxHasher::default();
|
||||
hasher.write(black_box(&bench_vec));
|
||||
hasher.finish()
|
||||
})
|
||||
hasher.finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user