draft: add graph feedback

This commit is contained in:
Alwin Berger 2022-12-19 18:14:52 +01:00
parent 4587f442d0
commit b812e994a6
2 changed files with 294 additions and 286 deletions

View File

@ -1,16 +1,21 @@
use libafl::SerdeAny;
/// Feedbacks organizing SystemStates as a graph /// Feedbacks organizing SystemStates as a graph
use libafl::inputs::HasBytesVec; use libafl::inputs::HasBytesVec;
use libafl::bolts::rands::RandomSeed; use libafl::bolts::rands::RandomSeed;
use libafl::bolts::rands::StdRand; use libafl::bolts::rands::StdRand;
use libafl::mutators::Mutator; use libafl::mutators::Mutator;
use libafl::mutators::MutationResult; use libafl::mutators::MutationResult;
use libafl::prelude::HasTargetBytes;
use libafl::prelude::UsesInput;
use libafl::state::HasNamedMetadata;
use libafl::state::UsesState;
use core::marker::PhantomData; use core::marker::PhantomData;
use libafl::state::HasCorpus; use libafl::state::HasCorpus;
use libafl::state::HasSolutions; use libafl::state::HasSolutions;
use libafl::state::HasRand; use libafl::state::HasRand;
use crate::worst::MaxExecsLenFavFactor; use crate::worst::MaxExecsLenFavFactor;
use libafl::corpus::MinimizerCorpusScheduler; use libafl::schedulers::MinimizerScheduler;
use libafl::bolts::HasRefCnt; use libafl::bolts::HasRefCnt;
use libafl::bolts::AsSlice; use libafl::bolts::AsSlice;
use libafl::bolts::ownedref::OwnedSlice; use libafl::bolts::ownedref::OwnedSlice;
@ -33,7 +38,7 @@ use serde::{Deserialize, Serialize};
use super::RefinedFreeRTOSSystemState; use super::RefinedFreeRTOSSystemState;
use super::FreeRTOSSystemStateMetadata; use super::FreeRTOSSystemStateMetadata;
use super::observers::QemusystemstateObserver; use super::observers::QemuSystemStateObserver;
use petgraph::prelude::DiGraph; use petgraph::prelude::DiGraph;
use petgraph::graph::NodeIndex; use petgraph::graph::NodeIndex;
use petgraph::Direction; use petgraph::Direction;
@ -124,11 +129,13 @@ impl SysGraphMetadata {
Self {indices: inner.iter().map(|x| x.index()).collect(), inner: inner, tcref: 0} Self {indices: inner.iter().map(|x| x.index()).collect(), inner: inner, tcref: 0}
} }
} }
impl AsSlice<usize> for SysGraphMetadata { impl AsSlice for SysGraphMetadata {
/// Convert the slice of system-states to a slice of hashes over enumerated states /// Convert the slice of system-states to a slice of hashes over enumerated states
fn as_slice(&self) -> &[usize] { fn as_slice(&self) -> &[usize] {
self.indices.as_slice() self.indices.as_slice()
} }
type Entry = usize;
} }
impl HasRefCnt for SysGraphMetadata { impl HasRefCnt for SysGraphMetadata {
@ -143,13 +150,13 @@ impl HasRefCnt for SysGraphMetadata {
libafl::impl_serdeany!(SysGraphMetadata); libafl::impl_serdeany!(SysGraphMetadata);
pub type GraphMaximizerCorpusScheduler<CS, I, S> = pub type GraphMaximizerCorpusScheduler<CS> =
MinimizerCorpusScheduler<CS, MaxExecsLenFavFactor<I>, I, SysGraphMetadata, S>; MinimizerScheduler<CS, MaxExecsLenFavFactor<<CS as UsesState>::State>,SysGraphMetadata>;
//============================= Graph Feedback //============================= Graph Feedback
/// Improved System State Graph /// Improved System State Graph
#[derive(Serialize, Deserialize, Clone, Debug, Default)] #[derive(Serialize, Deserialize, Clone, Debug, Default, SerdeAny)]
pub struct SysGraphFeedbackState pub struct SysGraphFeedbackState
{ {
pub graph: DiGraph<SysGraphNode, ()>, pub graph: DiGraph<SysGraphNode, ()>,
@ -226,7 +233,7 @@ impl Named for SysGraphFeedbackState
&self.name &self.name
} }
} }
impl FeedbackState for SysGraphFeedbackState impl SysGraphFeedbackState
{ {
fn reset(&mut self) -> Result<(), Error> { fn reset(&mut self) -> Result<(), Error> {
self.graph.clear(); self.graph.clear();
@ -253,28 +260,29 @@ impl SysMapFeedback {
} }
} }
impl<I, S> Feedback<I, S> for SysMapFeedback impl<S> Feedback<S> for SysMapFeedback
where where
I: Input, S: UsesInput + HasClientPerfMonitor + HasNamedMetadata,
S: HasClientPerfMonitor + HasFeedbackStates, S::Input: HasTargetBytes,
{ {
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
&mut self, &mut self,
state: &mut S, state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &I, _input: &S::Input,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
let observer = observers.match_name::<QemusystemstateObserver>("systemstate") let observer = observers.match_name::<QemuSystemStateObserver>("systemstate")
.expect("QemusystemstateObserver not found"); .expect("QemusystemstateObserver not found");
let feedbackstate = state let feedbackstate = state
.feedback_states_mut() .named_metadata_mut()
.match_name_mut::<SysGraphFeedbackState>("SysMap") .get_mut::<SysGraphFeedbackState>("SysMap")
.unwrap(); .unwrap();
let ret = feedbackstate.update(&observer.last_run, &observer.last_input); let ret = feedbackstate.update(&observer.last_run, &observer.last_input);
self.last_trace = Some(ret.1); self.last_trace = Some(ret.1);
@ -283,7 +291,7 @@ where
/// Append to the testcase the generated metadata in case of a new corpus item /// Append to the testcase the generated metadata in case of a new corpus item
#[inline] #[inline]
fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<I>) -> Result<(), Error> { fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
let a = self.last_trace.take(); let a = self.last_trace.take();
match a { match a {
Some(s) => testcase.metadata_mut().insert(SysGraphMetadata::new(s)), Some(s) => testcase.metadata_mut().insert(SysGraphMetadata::new(s)),
@ -294,7 +302,7 @@ where
/// Discard the stored metadata in case that the testcase is not added to the corpus /// Discard the stored metadata in case that the testcase is not added to the corpus
#[inline] #[inline]
fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.last_trace = None; self.last_trace = None;
Ok(()) Ok(())
} }
@ -309,282 +317,282 @@ impl Named for SysMapFeedback
//============================= Mutators //============================= Mutators
//=============================== Snippets //=============================== Snippets
pub struct RandGraphSnippetMutator<I, S> // pub struct RandGraphSnippetMutator<I, S>
where // where
I: Input + HasBytesVec, // I: Input + HasBytesVec,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>, // S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ // {
phantom: PhantomData<(I, S)>, // phantom: PhantomData<(I, S)>,
} // }
impl<I, S> RandGraphSnippetMutator<I, S> // impl<I, S> RandGraphSnippetMutator<I, S>
where // where
I: Input + HasBytesVec, // I: Input + HasBytesVec,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>, // S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ // {
pub fn new() -> Self { // pub fn new() -> Self {
RandGraphSnippetMutator{phantom: PhantomData} // RandGraphSnippetMutator{phantom: PhantomData}
} // }
} // }
impl<I, S> Mutator<I, S> for RandGraphSnippetMutator<I, S> // impl<I, S> Mutator<I, S> for RandGraphSnippetMutator<I, S>
where // where
I: Input + HasBytesVec, // I: Input + HasBytesVec,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I> + HasFeedbackStates, // S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ // {
fn mutate( // fn mutate(
&mut self, // &mut self,
state: &mut S, // state: &mut S,
input: &mut I, // input: &mut I,
_stage_idx: i32 // _stage_idx: i32
) -> Result<MutationResult, Error> // ) -> Result<MutationResult, Error>
{ // {
// need our own random generator, because borrowing rules // // need our own random generator, because borrowing rules
let mut myrand = StdRand::new(); // let mut myrand = StdRand::new();
let tmp = &mut state.rand_mut(); // let tmp = &mut state.rand_mut();
myrand.set_seed(tmp.next()); // myrand.set_seed(tmp.next());
drop(tmp); // drop(tmp);
let feedbackstate = state // let feedbackstate = state
.feedback_states() // .feedback_states()
.match_name::<SysGraphFeedbackState>("SysMap") // .match_name::<SysGraphFeedbackState>("SysMap")
.unwrap(); // .unwrap();
let g = &feedbackstate.graph; // let g = &feedbackstate.graph;
let tmp = state.metadata().get::<SysGraphMetadata>(); // let tmp = state.metadata().get::<SysGraphMetadata>();
if tmp.is_none() { // if there are no metadata it was probably not interesting anyways // if tmp.is_none() { // if there are no metadata it was probably not interesting anyways
return Ok(MutationResult::Skipped); // return Ok(MutationResult::Skipped);
} // }
let trace =tmp.expect("SysGraphMetadata not found"); // let trace =tmp.expect("SysGraphMetadata not found");
// follow the path, extract snippets from last reads, find common snippets. // // follow the path, extract snippets from last reads, find common snippets.
// those are likley keys parts. choose random parts from other sibling traces // // those are likley keys parts. choose random parts from other sibling traces
let sibling_inputs : Vec<&Vec<u8>>= g[*trace.inner.last().unwrap()].variants.iter().map(|x| &x.input).collect(); // let sibling_inputs : Vec<&Vec<u8>>= g[*trace.inner.last().unwrap()].variants.iter().map(|x| &x.input).collect();
let mut snippet_collector = vec![]; // let mut snippet_collector = vec![];
let mut per_input_counters = HashMap::<&Vec<u8>,usize>::new(); // ugly workaround to track multiple inputs // let mut per_input_counters = HashMap::<&Vec<u8>,usize>::new(); // ugly workaround to track multiple inputs
for t in &trace.inner { // for t in &trace.inner {
let node = &g[*t]; // let node = &g[*t];
let mut per_node_snippets = HashMap::<&Vec<u8>,&[u8]>::new(); // let mut per_node_snippets = HashMap::<&Vec<u8>,&[u8]>::new();
for v in &node.variants { // for v in &node.variants {
match per_input_counters.get_mut(&v.input) { // match per_input_counters.get_mut(&v.input) {
None => { // None => {
if sibling_inputs.iter().any(|x| *x==&v.input) { // only collect info about siblin inputs from target // if sibling_inputs.iter().any(|x| *x==&v.input) { // only collect info about siblin inputs from target
per_input_counters.insert(&v.input, v.input_counter.try_into().unwrap()); // per_input_counters.insert(&v.input, v.input_counter.try_into().unwrap());
} // }
}, // },
Some(x) => { // Some(x) => {
let x_u = *x; // let x_u = *x;
if x_u<v.input_counter as usize { // if x_u<v.input_counter as usize {
*x=v.input_counter as usize; // *x=v.input_counter as usize;
per_node_snippets.insert(&v.input,&v.input[x_u..v.input_counter as usize]); // per_node_snippets.insert(&v.input,&v.input[x_u..v.input_counter as usize]);
} // }
} // }
} // }
} // }
snippet_collector.push(per_node_snippets); // snippet_collector.push(per_node_snippets);
} // }
let mut new_input : Vec<u8> = vec![]; // let mut new_input : Vec<u8> = vec![];
for c in snippet_collector { // for c in snippet_collector {
new_input.extend_from_slice(myrand.choose(c).1); // new_input.extend_from_slice(myrand.choose(c).1);
} // }
for i in new_input.iter().enumerate() { // for i in new_input.iter().enumerate() {
input.bytes_mut()[i.0]=*i.1; // input.bytes_mut()[i.0]=*i.1;
} // }
Ok(MutationResult::Mutated) // Ok(MutationResult::Mutated)
} // }
fn post_exec( // fn post_exec(
&mut self, // &mut self,
_state: &mut S, // _state: &mut S,
_stage_idx: i32, // _stage_idx: i32,
_corpus_idx: Option<usize> // _corpus_idx: Option<usize>
) -> Result<(), Error> { // ) -> Result<(), Error> {
Ok(()) // Ok(())
} // }
} // }
impl<I, S> Named for RandGraphSnippetMutator<I, S> // impl<I, S> Named for RandGraphSnippetMutator<I, S>
where // where
I: Input + HasBytesVec, // I: Input + HasBytesVec,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I> + HasFeedbackStates, // S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ // {
fn name(&self) -> &str { // fn name(&self) -> &str {
"RandGraphSnippetMutator" // "RandGraphSnippetMutator"
} // }
} // }
//=============================== Snippets // //=============================== Snippets
pub struct RandInputSnippetMutator<I, S> // pub struct RandInputSnippetMutator<I, S>
where // where
I: Input + HasBytesVec, // I: Input + HasBytesVec,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>, // S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ // {
phantom: PhantomData<(I, S)>, // phantom: PhantomData<(I, S)>,
} // }
impl<I, S> RandInputSnippetMutator<I, S> // impl<I, S> RandInputSnippetMutator<I, S>
where // where
I: Input + HasBytesVec, // I: Input + HasBytesVec,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>, // S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ // {
pub fn new() -> Self { // pub fn new() -> Self {
RandInputSnippetMutator{phantom: PhantomData} // RandInputSnippetMutator{phantom: PhantomData}
} // }
} // }
impl<I, S> Mutator<I, S> for RandInputSnippetMutator<I, S> // impl<I, S> Mutator<I, S> for RandInputSnippetMutator<I, S>
where // where
I: Input + HasBytesVec, // I: Input + HasBytesVec,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I> + HasFeedbackStates, // S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ // {
fn mutate( // fn mutate(
&mut self, // &mut self,
state: &mut S, // state: &mut S,
input: &mut I, // input: &mut I,
_stage_idx: i32 // _stage_idx: i32
) -> Result<MutationResult, Error> // ) -> Result<MutationResult, Error>
{ // {
// need our own random generator, because borrowing rules // // need our own random generator, because borrowing rules
let mut myrand = StdRand::new(); // let mut myrand = StdRand::new();
let tmp = &mut state.rand_mut(); // let tmp = &mut state.rand_mut();
myrand.set_seed(tmp.next()); // myrand.set_seed(tmp.next());
drop(tmp); // drop(tmp);
let feedbackstate = state // let feedbackstate = state
.feedback_states() // .feedback_states()
.match_name::<SysGraphFeedbackState>("SysMap") // .match_name::<SysGraphFeedbackState>("SysMap")
.unwrap(); // .unwrap();
let g = &feedbackstate.graph; // let g = &feedbackstate.graph;
let tmp = state.metadata().get::<SysGraphMetadata>(); // let tmp = state.metadata().get::<SysGraphMetadata>();
if tmp.is_none() { // if there are no metadata it was probably not interesting anyways // if tmp.is_none() { // if there are no metadata it was probably not interesting anyways
return Ok(MutationResult::Skipped); // return Ok(MutationResult::Skipped);
} // }
let trace = tmp.expect("SysGraphMetadata not found"); // let trace = tmp.expect("SysGraphMetadata not found");
let mut collection : Vec<Vec<u8>> = Vec::new(); // let mut collection : Vec<Vec<u8>> = Vec::new();
let mut current_pointer : usize = 0; // let mut current_pointer : usize = 0;
for t in &trace.inner { // for t in &trace.inner {
let node = &g[*t]; // let node = &g[*t];
for v in &node.variants { // for v in &node.variants {
if v.input == input.bytes() { // if v.input == input.bytes() {
if v.input_counter > current_pointer.try_into().unwrap() { // if v.input_counter > current_pointer.try_into().unwrap() {
collection.push(v.input[current_pointer..v.input_counter as usize].to_owned()); // collection.push(v.input[current_pointer..v.input_counter as usize].to_owned());
current_pointer = v.input_counter as usize; // current_pointer = v.input_counter as usize;
} // }
break; // break;
} // }
} // }
} // }
let index_to_mutate = myrand.below(collection.len() as u64) as usize; // let index_to_mutate = myrand.below(collection.len() as u64) as usize;
for i in 0..collection[index_to_mutate].len() { // for i in 0..collection[index_to_mutate].len() {
collection[index_to_mutate][i] = myrand.below(0xFF) as u8; // collection[index_to_mutate][i] = myrand.below(0xFF) as u8;
} // }
for i in collection.concat().iter().enumerate() { // for i in collection.concat().iter().enumerate() {
input.bytes_mut()[i.0]=*i.1; // input.bytes_mut()[i.0]=*i.1;
} // }
Ok(MutationResult::Mutated) // Ok(MutationResult::Mutated)
} // }
fn post_exec( // fn post_exec(
&mut self, // &mut self,
_state: &mut S, // _state: &mut S,
_stage_idx: i32, // _stage_idx: i32,
_corpus_idx: Option<usize> // _corpus_idx: Option<usize>
) -> Result<(), Error> { // ) -> Result<(), Error> {
Ok(()) // Ok(())
} // }
} // }
impl<I, S> Named for RandInputSnippetMutator<I, S> // impl<I, S> Named for RandInputSnippetMutator<I, S>
where // where
I: Input + HasBytesVec, // I: Input + HasBytesVec,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I> + HasFeedbackStates, // S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ // {
fn name(&self) -> &str { // fn name(&self) -> &str {
"RandInputSnippetMutator" // "RandInputSnippetMutator"
} // }
} // }
//=============================== Suffix // //=============================== Suffix
pub struct RandGraphSuffixMutator<I, S> // pub struct RandGraphSuffixMutator<I, S>
where // where
I: Input + HasBytesVec, // I: Input + HasBytesVec,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>, // S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ // {
phantom: PhantomData<(I, S)>, // phantom: PhantomData<(I, S)>,
} // }
impl<I, S> RandGraphSuffixMutator<I, S> // impl<I, S> RandGraphSuffixMutator<I, S>
where // where
I: Input + HasBytesVec, // I: Input + HasBytesVec,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>, // S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ // {
pub fn new() -> Self { // pub fn new() -> Self {
RandGraphSuffixMutator{phantom: PhantomData} // RandGraphSuffixMutator{phantom: PhantomData}
} // }
} // }
impl<I, S> Mutator<I, S> for RandGraphSuffixMutator<I, S> // impl<I, S> Mutator<I, S> for RandGraphSuffixMutator<I, S>
where // where
I: Input + HasBytesVec, // I: Input + HasBytesVec,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I> + HasFeedbackStates, // S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ // {
fn mutate( // fn mutate(
&mut self, // &mut self,
state: &mut S, // state: &mut S,
input: &mut I, // input: &mut I,
_stage_idx: i32 // _stage_idx: i32
) -> Result<MutationResult, Error> // ) -> Result<MutationResult, Error>
{ // {
// need our own random generator, because borrowing rules // // need our own random generator, because borrowing rules
let mut myrand = StdRand::new(); // let mut myrand = StdRand::new();
let tmp = &mut state.rand_mut(); // let tmp = &mut state.rand_mut();
myrand.set_seed(tmp.next()); // myrand.set_seed(tmp.next());
drop(tmp); // drop(tmp);
let feedbackstate = state // let feedbackstate = state
.feedback_states() // .feedback_states()
.match_name::<SysGraphFeedbackState>("SysMap") // .match_name::<SysGraphFeedbackState>("SysMap")
.unwrap(); // .unwrap();
let g = &feedbackstate.graph; // let g = &feedbackstate.graph;
let tmp = state.metadata().get::<SysGraphMetadata>(); // let tmp = state.metadata().get::<SysGraphMetadata>();
if tmp.is_none() { // if there are no metadata it was probably not interesting anyways // if tmp.is_none() { // if there are no metadata it was probably not interesting anyways
return Ok(MutationResult::Skipped); // return Ok(MutationResult::Skipped);
} // }
let trace =tmp.expect("SysGraphMetadata not found"); // let trace =tmp.expect("SysGraphMetadata not found");
// follow the path, extract snippets from last reads, find common snippets. // // follow the path, extract snippets from last reads, find common snippets.
// those are likley keys parts. choose random parts from other sibling traces // // those are likley keys parts. choose random parts from other sibling traces
let inp_c_end = g[*trace.inner.last().unwrap()].base.input_counter; // let inp_c_end = g[*trace.inner.last().unwrap()].base.input_counter;
let mut num_to_reverse = myrand.below(trace.inner.len().try_into().unwrap()); // let mut num_to_reverse = myrand.below(trace.inner.len().try_into().unwrap());
for t in trace.inner.iter().rev() { // for t in trace.inner.iter().rev() {
let int_c_prefix = g[*t].base.input_counter; // let int_c_prefix = g[*t].base.input_counter;
if int_c_prefix < inp_c_end { // if int_c_prefix < inp_c_end {
num_to_reverse-=1; // num_to_reverse-=1;
if num_to_reverse<=0 { // if num_to_reverse<=0 {
let mut new_input=input.bytes()[..(int_c_prefix as usize)].to_vec(); // let mut new_input=input.bytes()[..(int_c_prefix as usize)].to_vec();
let mut ext : Vec<u8> = (int_c_prefix..inp_c_end).map(|_| myrand.next().to_le_bytes()).flatten().collect(); // let mut ext : Vec<u8> = (int_c_prefix..inp_c_end).map(|_| myrand.next().to_le_bytes()).flatten().collect();
new_input.append(&mut ext); // new_input.append(&mut ext);
for i in new_input.iter().enumerate() { // for i in new_input.iter().enumerate() {
if input.bytes_mut().len()>i.0 { // if input.bytes_mut().len()>i.0 {
input.bytes_mut()[i.0]=*i.1; // input.bytes_mut()[i.0]=*i.1;
} // }
else { break }; // else { break };
} // }
break; // break;
} // }
} // }
} // }
Ok(MutationResult::Mutated) // Ok(MutationResult::Mutated)
} // }
fn post_exec( // fn post_exec(
&mut self, // &mut self,
_state: &mut S, // _state: &mut S,
_stage_idx: i32, // _stage_idx: i32,
_corpus_idx: Option<usize> // _corpus_idx: Option<usize>
) -> Result<(), Error> { // ) -> Result<(), Error> {
Ok(()) // Ok(())
} // }
} // }
impl<I, S> Named for RandGraphSuffixMutator<I, S> // impl<I, S> Named for RandGraphSuffixMutator<I, S>
where // where
I: Input + HasBytesVec, // I: Input + HasBytesVec,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I> + HasFeedbackStates, // S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ // {
fn name(&self) -> &str { // fn name(&self) -> &str {
"RandGraphSuffixMutator" // "RandGraphSuffixMutator"
} // }
} // }

View File

@ -13,7 +13,7 @@ pub mod freertos;
pub mod helpers; pub mod helpers;
pub mod observers; pub mod observers;
pub mod feedbacks; pub mod feedbacks;
// pub mod graph; pub mod graph;
// pub mod mutators; // pub mod mutators;
#[cfg(feature = "fuzz_interrupt")] #[cfg(feature = "fuzz_interrupt")]