From bde16f82974d3c7e34d43c47f294ef048d039d57 Mon Sep 17 00:00:00 2001 From: Alwin Berger Date: Wed, 22 May 2024 21:54:07 +0200 Subject: [PATCH] scheduler, mutator changes --- fuzzers/FRET/Cargo.toml | 5 +- fuzzers/FRET/src/mutational.rs | 283 +++++++++++++--------- fuzzers/FRET/src/systemstate/mod.rs | 2 +- fuzzers/FRET/src/systemstate/observers.rs | 2 +- fuzzers/FRET/src/systemstate/stg.rs | 81 +++++-- libafl/src/schedulers/minimizer.rs | 10 + 6 files changed, 253 insertions(+), 130 deletions(-) diff --git a/fuzzers/FRET/Cargo.toml b/fuzzers/FRET/Cargo.toml index 22dcd7231d..869303d657 100644 --- a/fuzzers/FRET/Cargo.toml +++ b/fuzzers/FRET/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Alwin Berger "] edition = "2021" [features] -default = ["std", "snapshot_restore", "singlecore", "restarting", "do_hash_notify_state", "config_stg" ] +default = ["std", "snapshot_restore", "singlecore", "restarting", "do_hash_notify_state", "config_stg", "fuzz_int" ] std = [] # Exec environemnt basics snapshot_restore = [] @@ -26,6 +26,7 @@ feed_stg = [ "trace_stg", "observe_systemstate" ] feed_stg_pathhash = [ "feed_stg"] feed_stg_abbhash = [ "feed_stg"] feed_stg_aggregatehash = [ "feed_stg"] +mutate_stg = [ "observe_systemstate" ] feed_longest = [ ] feed_afl = [ "observe_edges" ] feed_genetic = [] @@ -44,7 +45,7 @@ sched_stg_aggregatehash = ['sched_stg'] # every aggregated path (order independe config_genetic = ["gensize_100","feed_genetic","sched_genetic"] config_afl = ["feed_afl","sched_afl","observe_hitcounts"] config_frafl = ["feed_afl","sched_afl","feed_longest"] -config_stg = ["feed_stg","sched_stg"] +config_stg = ["feed_stg_aggregatehash","sched_stg_aggregatehash","mutate_stg"] [profile.release] lto = true diff --git a/fuzzers/FRET/src/mutational.rs b/fuzzers/FRET/src/mutational.rs index f9e4ac751b..ff794e3da6 100644 --- a/fuzzers/FRET/src/mutational.rs +++ b/fuzzers/FRET/src/mutational.rs @@ -4,6 +4,7 @@ use core::marker::PhantomData; use std::cmp::{max, min}; +use hashbrown::HashMap; use libafl_bolts::rands::{ StdRand, RandomSeed, Rand @@ -12,7 +13,7 @@ use libafl::{ corpus::{self, Corpus}, fuzzer::Evaluator, mark_feature_time, prelude::{new_hash_feedback, CorpusId, HasBytesVec, MutationResult, Mutator, UsesInput}, stages::Stage, start_timer, state::{HasCorpus, HasMetadata, HasNamedMetadata, HasRand, MaybeHasClientPerfMonitor, UsesState}, Error }; use libafl::prelude::State; -use crate::{clock::IcHist, fuzzer::{DO_NUM_INTERRUPT, FIRST_INT}, systemstate::{stg::{STGFeedbackState, STGNodeMetadata}, ExecInterval, FreeRTOSSystemStateMetadata, ReducedFreeRTOSSystemState}}; +use crate::{clock::IcHist, fuzzer::{DO_NUM_INTERRUPT, FIRST_INT}, systemstate::{stg::{STGFeedbackState, STGNodeMetadata}, CaptureEvent, ExecInterval, FreeRTOSSystemStateMetadata, ReducedFreeRTOSSystemState}}; pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*ms*/ * 62500; // one isn per 2**4 ns @@ -89,9 +90,8 @@ where .get(corpus_idx)? .borrow_mut().clone(); let mut newinput = _input.input_mut().as_mut().unwrap().clone(); - // let mut tmpinput = _input.input_mut().as_mut().unwrap().clone(); let mut do_rerun = false; - if state.rand_mut().between(1, 100) <= 50 // only attempt the mutation half of the time + // if state.rand_mut().between(1, 100) <= 50 // only attempt the mutation half of the time { // need our own random generator, because borrowing rules let mut myrand = StdRand::new(); @@ -120,127 +120,188 @@ where let mut suffix = target_bytes.split_off(4 * num_interrupts); let mut prefix : Vec<[u8; 4]> = vec![]; // let mut suffix : Vec = vec![]; - #[cfg(feature = "trace_stg")] + #[cfg(feature = "mutate_stg")] { - if myrand.between(1,100) <= 25 { // 0.5*0.25 = 12.5% of the time fully randomize all interrupts + let metadata = state.metadata_map(); + let hist = metadata.get::().unwrap(); + let maxtick : u64 = hist.1.0; + drop(hist); + if interrupt_offsets[0] as u64 > maxtick { do_rerun = true; - let metadata = state.metadata_map(); - let hist = metadata.get::().unwrap(); - let maxtick : u64 = hist.1.0; - // let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap(); - let mut numbers : Vec = vec![]; - for i in 0..num_interrupts { + for _ in 0..num_interrupts { prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick, u32::MAX as u64)).try_into().expect("ticks > u32"))); } } else { - let feedbackstate = match state - .named_metadata_map_mut() - .get_mut::("stgfeedbackstate") { - Some(s) => s, - None => { - panic!("STGfeedbackstate not visible") - } - }; - - let tmp = _input.metadata_map().get::(); - if tmp.is_some() { - let trace = tmp.expect("STGNodeMetadata not found"); - - // calculate hits and identify snippets - let mut last_m = false; - let mut marks : Vec<(&ExecInterval, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler - for i in 0..trace.intervals.len() { - let curr = &trace.intervals[i]; - let m = interrupt_offsets[0..num_interrupts].iter().any(|x| (curr.start_tick..curr.end_tick).contains(&(*x as u64))); - if m { - marks.push((curr, i, 1)); - // println!("1: {}",curr.current_task.0.task_name); - } else if last_m { - marks.push((curr, i, 2)); - // println!("2: {}",curr.current_task.0.task_name); - } else { - marks.push((curr, i, 0)); + let choice = myrand.between(1,100); + if choice <= 25 { // 0.5*0.25 = 12.5% of the time fully randomize all interrupts + do_rerun = true; + // let metadata = state.metadata_map(); + let hist = metadata.get::().unwrap(); + let maxtick : u64 = hist.1.0; + // let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap(); + let mut numbers : Vec = vec![]; + for i in 0..num_interrupts { + prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick, u32::MAX as u64)).try_into().expect("ticks > u32"))); } - last_m = m; } - for i in 0..num_interrupts { - // bounds based on minimum inter-arrival time - let mut lb = 0; - let mut ub : u32 = marks[marks.len()-1].0.end_tick.try_into().expect("ticks > u32"); - if i > 0 { - lb = u32::saturating_add(interrupt_offsets[i-1],unsafe{MINIMUM_INTER_ARRIVAL_TIME}); - } - if i < num_interrupts-1 { - ub = u32::saturating_sub(interrupt_offsets[i+1],unsafe{MINIMUM_INTER_ARRIVAL_TIME}); - } - // get old hit and handler - let old_hit = marks.iter().filter( - |x| x.0.start_tick < (interrupt_offsets[i] as u64) && (interrupt_offsets[i] as u64) < x.0.end_tick - ).next(); - let old_handler = match old_hit { - Some(s) => if s.1 < num_interrupts-1 && s.1 < marks.len()-1 { - Some(marks[s.1+1]) - } else {None}, - None => None - }; - // find reachable alternatives - let alternatives : Vec<_> = marks.iter().filter(|x| - x.2 != 2 && - ( - x.0.start_tick < (lb as u64) && (lb as u64) < x.0.end_tick - || x.0.start_tick < (ub as u64) && (ub as u64) < x.0.end_tick ) - ).collect(); - // in cases there are no alternatives - if alternatives.len() == 0 { - if old_hit.is_none() { - // choose something random - let untouched : Vec<_> = marks.iter().filter( - |x| x.2 == 0 - ).collect(); - if untouched.len() > 0 { - let tmp = interrupt_offsets[i]; - let choice = myrand.choose(untouched); - interrupt_offsets[i] = myrand.between(choice.0.start_tick, choice.0.end_tick) - .try_into().expect("tick > u32"); - do_rerun = true; + else if choice <= 75 { // 0.5 * 0.25 = 12.5% of cases + let feedbackstate = match state + .named_metadata_map_mut() + .get_mut::("stgfeedbackstate") { + Some(s) => s, + None => { + panic!("STGfeedbackstate not visible") } - // println!("no alternatives, choose random i: {} {} -> {}",i,tmp,interrupt_offsets[i]); + }; + let tmp = _input.metadata_map().get::(); + if tmp.is_some() { + let trace = tmp.expect("STGNodeMetadata not found"); + let mut node_indices = vec![]; + for i in (0..trace.intervals.len()).into_iter() { + if let Some(abb) = &trace.intervals[i].abb { + if let Some(idx) = feedbackstate.state_abb_hash_index.get(&(abb.get_hash(), trace.intervals[i].start_state)) { + node_indices.push(Some(idx)); + continue; + } + } + node_indices.push(None); + } + // let mut marks : HashMap= HashMap::new(); // interrupt -> block hit + // for i in 0..trace.intervals.len() { + // let curr = &trace.intervals[i]; + // let m = interrupt_offsets[0..num_interrupts].iter().filter(|x| (curr.start_tick..curr.end_tick).contains(&((**x) as u64))); + // for k in m { + // marks.insert(*k,i); + // } + // } + // walk backwards trough the trace and try moving the interrupt to a block that does not have an outgoing interrupt edge or ist already hit by a predecessor + for i in (0..num_interrupts).rev() { + let mut lb = FIRST_INT; + let mut ub : u32 = trace.intervals[trace.intervals.len()-1].end_tick.try_into().expect("ticks > u32"); + if i > 0 { + lb = u32::saturating_add(interrupt_offsets[i-1],unsafe{MINIMUM_INTER_ARRIVAL_TIME}); + } + if i < num_interrupts-1 { + ub = u32::saturating_sub(interrupt_offsets[i+1],unsafe{MINIMUM_INTER_ARRIVAL_TIME}); + } + let alternatives : Vec<_> = (0..trace.intervals.len()).filter(|x| + trace.intervals[*x].start_tick < (lb as u64) && (lb as u64) < trace.intervals[*x].end_tick + || trace.intervals[*x].start_tick > (lb as u64) && trace.intervals[*x].start_tick < (ub as u64) + ).collect(); + let not_yet_hit : Vec<_> = alternatives.iter().filter( + |x| feedbackstate.graph.edges_directed(*node_indices[**x].unwrap(), petgraph::Direction::Outgoing).any(|y| y.weight().event != CaptureEvent::ISRStart)).collect(); + if not_yet_hit.len() > 0 { + let replacement = &trace.intervals[*myrand.choose(not_yet_hit)]; + interrupt_offsets[i] = (myrand.between(replacement.start_tick, + replacement.end_tick)).try_into().expect("ticks > u32"); + // println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]); + do_rerun = true; + break; + } + } + } + } + else { // old version of the alternative search + let tmp = _input.metadata_map().get::(); + if tmp.is_some() { + let trace = tmp.expect("STGNodeMetadata not found"); + + // calculate hits and identify snippets + let mut last_m = false; + let mut marks : Vec<(&ExecInterval, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler + for i in 0..trace.intervals.len() { + let curr = &trace.intervals[i]; + let m = interrupt_offsets[0..num_interrupts].iter().any(|x| (curr.start_tick..curr.end_tick).contains(&(*x as u64))); + if m { + marks.push((curr, i, 1)); + // println!("1: {}",curr.current_task.0.task_name); + } else if last_m { + marks.push((curr, i, 2)); + // println!("2: {}",curr.current_task.0.task_name); + } else { + marks.push((curr, i, 0)); + } + last_m = m; + } + for i in 0..num_interrupts { + // bounds based on minimum inter-arrival time + let mut lb = FIRST_INT; + let mut ub : u32 = marks[marks.len()-1].0.end_tick.try_into().expect("ticks > u32"); + if i > 0 { + lb = u32::saturating_add(interrupt_offsets[i-1],unsafe{MINIMUM_INTER_ARRIVAL_TIME}); + } + if i < num_interrupts-1 { + ub = u32::saturating_sub(interrupt_offsets[i+1],unsafe{MINIMUM_INTER_ARRIVAL_TIME}); + } + // get old hit and handler + let old_hit = marks.iter().filter( + |x| x.0.start_tick < (interrupt_offsets[i] as u64) && (interrupt_offsets[i] as u64) < x.0.end_tick + ).next(); + let old_handler = match old_hit { + Some(s) => if s.1 < num_interrupts-1 && s.1 < marks.len()-1 { + Some(marks[s.1+1]) + } else {None}, + None => None + }; + // find reachable alternatives + let alternatives : Vec<_> = marks.iter().filter(|x| + x.2 != 2 && + ( + x.0.start_tick < (lb as u64) && (lb as u64) < x.0.end_tick + || x.0.start_tick > (lb as u64) && x.0.start_tick < (ub as u64)) + ).collect(); + // in cases there are no alternatives + if alternatives.len() == 0 { + if old_hit.is_none() { + // choose something random + let untouched : Vec<_> = marks.iter().filter( + |x| x.2 == 0 + ).collect(); + if untouched.len() > 0 { + let tmp = interrupt_offsets[i]; + let choice = myrand.choose(untouched); + interrupt_offsets[i] = myrand.between(choice.0.start_tick, choice.0.end_tick) + .try_into().expect("tick > u32"); + do_rerun = true; + } + // println!("no alternatives, choose random i: {} {} -> {}",i,tmp,interrupt_offsets[i]); + continue; + } else { + // do nothing + // println!("no alternatives, do nothing i: {} {}",i,interrupt_offsets[i]); + continue; + } + } + let replacement = myrand.choose(alternatives); + if (old_hit.map_or(false, |x| x == replacement)) { + // use the old value + // println!("chose old value, do nothing i: {} {}",i,interrupt_offsets[i]); continue; } else { - // do nothing - // println!("no alternatives, do nothing i: {} {}",i,interrupt_offsets[i]); - continue; + let extra = if (old_hit.map_or(false, |x| x.1 < replacement.1)) { + // move futher back, respect old_handler + old_handler.map_or(0, |x| x.0.end_tick - x.0.start_tick) + } else { 0 }; + let tmp = interrupt_offsets[i]; + interrupt_offsets[i] = (myrand.between(replacement.0.start_tick, + replacement.0.end_tick) + extra).try_into().expect("ticks > u32"); + // println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]); + do_rerun = true; } } - let replacement = myrand.choose(alternatives); - if (old_hit.map_or(false, |x| x == replacement)) { - // use the old value - // println!("chose old value, do nothing i: {} {}",i,interrupt_offsets[i]); - continue; - } else { - let extra = if (old_hit.map_or(false, |x| x.1 < replacement.1)) { - // move futher back, respect old_handler - old_handler.map_or(0, |x| x.0.end_tick - x.0.start_tick) - } else { 0 }; - let tmp = interrupt_offsets[i]; - interrupt_offsets[i] = (myrand.between(replacement.0.start_tick, - replacement.0.end_tick) + extra).try_into().expect("ticks > u32"); - // println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]); - do_rerun = true; + let mut numbers : Vec = interrupt_offsets[0..num_interrupts].to_vec(); + numbers.sort(); + // println!("Mutator: {:?}", numbers); + // let mut start : u32 = 0; + // for i in 0..numbers.len() { + // let tmp = numbers[i]; + // numbers[i] = numbers[i]-start; + // start = tmp; + // } + for i in 0..numbers.len() { + prefix.push(u32::to_le_bytes(numbers[i])); + } } - } - let mut numbers : Vec = interrupt_offsets[0..num_interrupts].to_vec(); - numbers.sort(); - // println!("Mutator: {:?}", numbers); - // let mut start : u32 = 0; - // for i in 0..numbers.len() { - // let tmp = numbers[i]; - // numbers[i] = numbers[i]-start; - // start = tmp; - // } - for i in 0..numbers.len() { - prefix.push(u32::to_le_bytes(numbers[i])); - } } } } diff --git a/fuzzers/FRET/src/systemstate/mod.rs b/fuzzers/FRET/src/systemstate/mod.rs index 642f5e22a6..8ba7cc3b50 100644 --- a/fuzzers/FRET/src/systemstate/mod.rs +++ b/fuzzers/FRET/src/systemstate/mod.rs @@ -336,7 +336,7 @@ impl Ord for AtomicBasicBlock { } impl AtomicBasicBlock { - fn get_hash(&self) -> u64 { + pub fn get_hash(&self) -> u64 { let mut s = DefaultHasher::new(); self.hash(&mut s); s.finish() diff --git a/fuzzers/FRET/src/systemstate/observers.rs b/fuzzers/FRET/src/systemstate/observers.rs index a97690369a..4f04b63f97 100644 --- a/fuzzers/FRET/src/systemstate/observers.rs +++ b/fuzzers/FRET/src/systemstate/observers.rs @@ -344,7 +344,7 @@ fn add_abb_info(trace: &mut Vec, table: &HashMap, Option))>) { for i in meta.iter_mut() { - if i.1 == CaptureEvent::APIStart && i.2 == "vTaskGenericNotifyGiveFromISR" { + if i.1 == CaptureEvent::APIStart && i.2.ends_with("FromISR") { i.1 = CaptureEvent::ISREnd; i.2 = "isr_starter".to_string(); } diff --git a/fuzzers/FRET/src/systemstate/stg.rs b/fuzzers/FRET/src/systemstate/stg.rs index 616257b785..9eb74a499d 100644 --- a/fuzzers/FRET/src/systemstate/stg.rs +++ b/fuzzers/FRET/src/systemstate/stg.rs @@ -1,4 +1,5 @@ +use hashbrown::HashSet; use libafl::SerdeAny; /// Feedbacks organizing SystemStates as a graph use libafl::inputs::HasBytesVec; @@ -108,8 +109,8 @@ impl PartialEq for STGNode { pub struct STGEdge { // is_interrupt: bool, - event: CaptureEvent, - name: String + pub event: CaptureEvent, + pub name: String } impl STGEdge { @@ -146,14 +147,15 @@ pub struct STGFeedbackState // aggregated traces as a graph pub graph: DiGraph, systemstate_index: HashMap, - state_abb_hash_index: HashMap<(u64, u64), NodeIndex>, + pub state_abb_hash_index: HashMap<(u64, u64), NodeIndex>, stgnode_index: HashMap, entrypoint: NodeIndex, exitpoint: NodeIndex, // Metadata about aggregated traces. aggegated meaning, order has been removed worst_observed_per_aggegated_path: HashMap,u64>, worst_observed_per_abb_path: HashMap, - worst_observed_per_stg_path: HashMap + worst_observed_per_stg_path: HashMap, + worst_abb_exec_count: HashMap } impl Default for STGFeedbackState { @@ -184,6 +186,7 @@ impl Default for STGFeedbackState { worst_observed_per_aggegated_path: HashMap::new(), worst_observed_per_abb_path: HashMap::new(), worst_observed_per_stg_path: HashMap::new(), + worst_abb_exec_count: HashMap::new(), systemstate_index, state_abb_hash_index } @@ -203,13 +206,15 @@ impl Named for STGFeedbackState pub struct STGNodeMetadata { pub nodes: Vec, pub edges: Vec, - pub abbs: Vec, + pub abbs: u64, + pub aggregate: u64, + pub top_abb_counts: Vec, pub intervals: Vec, indices: Vec, tcref: isize, } impl STGNodeMetadata { - pub fn new(nodes: Vec, edges: Vec, abbs: Vec, intervals: Vec) -> Self{ + pub fn new(nodes: Vec, edges: Vec, abbs: u64, aggregate: u64, top_abb_counts: Vec, intervals: Vec) -> Self{ let mut indices : Vec<_> = vec![]; #[cfg(all(feature = "sched_stg",not(any(feature = "sched_stg_pathhash",feature = "sched_stg_abbhash",feature = "sched_stg_aggregatehash"))))] { @@ -223,15 +228,14 @@ impl STGNodeMetadata { } #[cfg(feature = "sched_stg_abbhash")] { - indices.push(get_generic_hash(&abbs) as usize); + indices.push(abbs as usize); } #[cfg(feature = "sched_stg_aggregatehash")] { - let mut _abbs = abbs.clone(); - _abbs.sort_unstable(); - indices.push(get_generic_hash(&_abbs) as usize); + // indices.push(aggregate as usize); + indices = top_abb_counts.iter().map(|x| (*x) as usize).collect(); } - Self {indices, intervals, nodes, abbs, edges, tcref: 0} + Self {indices, intervals, nodes, abbs, aggregate, top_abb_counts, edges, tcref: 0} } } impl AsSlice for STGNodeMetadata { @@ -258,6 +262,36 @@ libafl_bolts::impl_serdeany!(STGNodeMetadata); pub type GraphMaximizerCorpusScheduler = MinimizerScheduler::State>,STGNodeMetadata>; +// AI generated, human verified +fn count_occurrences(vec: &Vec) -> HashMap<&T, usize> +where + T: PartialEq + Eq + Hash + Clone, +{ + let mut counts = HashMap::new(); + + if vec.is_empty() { + return counts; + } + + let mut current_obj = &vec[0]; + let mut current_count = 1; + + for obj in vec.iter().skip(1) { + if obj == current_obj { + current_count += 1; + } else { + counts.insert(current_obj, current_count); + current_obj = obj; + current_count = 1; + } + } + + // Insert the count of the last object + counts.insert(current_obj, current_count); + + counts +} + //============================= Graph Feedback pub static mut STG_MAP: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE]; @@ -274,7 +308,9 @@ pub struct StgFeedback last_node_trace: Option>, last_edge_trace: Option>, last_intervals: Option>, - last_abbs: Option>, + last_abbs_hash: Option, // only set, if it was interesting + last_aggregate_hash: Option, // only set, if it was interesting + last_top_abb_hashes: Option>, // only set, if it was interesting dump_path: Option } #[cfg(feature = "feed_stg")] @@ -458,6 +494,7 @@ where if INTEREST_AGGREGATE || INTEREST_ABBPATH { if INTEREST_ABBPATH { let h = get_generic_hash(&tmp); + self.last_abbs_hash = Some(h); // order of execution is relevant if let Some(x) = feedbackstate.worst_observed_per_abb_path.get_mut(&h) { let t = clock_observer.last_runtime(); @@ -474,6 +511,22 @@ where // aggegation by sorting, order of states is not relevant let mut _tmp = tmp.clone(); _tmp.sort(); + let counts = count_occurrences(&_tmp); + let mut top_indices = Vec::new(); + for (k,c) in counts { + if let Some(reference) = feedbackstate.worst_abb_exec_count.get_mut(k) { + if *reference < c { + *reference = c; + top_indices.push(get_generic_hash(k)); + } + } else { + top_indices.push(get_generic_hash(k)); + feedbackstate.worst_abb_exec_count.insert(k.clone(), c); + } + } + self.last_top_abb_hashes = Some(top_indices); + + self.last_aggregate_hash = Some(get_generic_hash(&_tmp)); if let Some(x) = feedbackstate.worst_observed_per_aggegated_path.get_mut(&_tmp) { let t = clock_observer.last_runtime(); if t > *x { @@ -494,7 +547,6 @@ where self.last_node_trace = Some(nodetrace); self.last_edge_trace = Some(edgetrace); self.last_intervals = Some(observer.last_trace.clone()); - self.last_abbs = Some(tmp); if let Some(dp) = &self.dump_path { if updated { @@ -516,9 +568,8 @@ where fn append_metadata(&mut self, _state: &mut S, _observers: &OT, testcase: &mut Testcase) -> Result<(), Error> { let nodes = self.last_node_trace.take(); let edges = self.last_edge_trace.take(); - let abbs = self.last_abbs.take(); match nodes { - Some(s) => testcase.metadata_map_mut().insert(STGNodeMetadata::new(s, edges.unwrap(), abbs.unwrap(), self.last_intervals.take().unwrap())), + Some(s) => testcase.metadata_map_mut().insert(STGNodeMetadata::new(s, edges.unwrap(), self.last_abbs_hash.take().unwrap_or_default(), self.last_aggregate_hash.take().unwrap_or_default(), self.last_top_abb_hashes.take().unwrap_or_default(), self.last_intervals.take().unwrap())), None => (), } Ok(()) diff --git a/libafl/src/schedulers/minimizer.rs b/libafl/src/schedulers/minimizer.rs index 170feba6f2..ee72775e8d 100644 --- a/libafl/src/schedulers/minimizer.rs +++ b/libafl/src/schedulers/minimizer.rs @@ -58,6 +58,15 @@ impl TopRatedsMetadata { pub fn map(&self) -> &HashMap { &self.map } + + /// Retruns the number of inices that are considered interesting + pub fn get_number(&self) -> usize { + let mut tmp = HashSet::new(); + for i in self.map.values() { + tmp.insert(*i); + } + tmp.len() + } } impl Default for TopRatedsMetadata { @@ -325,6 +334,7 @@ where .map .insert(elem, idx); } + println!("Number of interesting corpus elements: {}", state.metadata_map_mut().get::().unwrap().get_number()); Ok(()) }