diff --git a/fuzzers/FRET/Cargo.toml b/fuzzers/FRET/Cargo.toml index 1241936e0f..cfcd4281f4 100644 --- a/fuzzers/FRET/Cargo.toml +++ b/fuzzers/FRET/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Alwin Berger "] edition = "2021" [features] -default = ["std", "snapshot_fast", "restarting", "do_hash_notify_state", "config_stg", "fuzz_int", "shortcut", "trace_job_response_times" ] +default = ["std", "snapshot_fast", "restarting", "do_hash_notify_state", "config_stg_edge", "fuzz_int", "shortcut", "trace_job_response_times" ] std = [] # Exec environemnt basics snapshot_restore = [] @@ -25,7 +25,7 @@ trace_stg = [ "observe_systemstate" ] trace_reads = [ "trace_stg", "trace_job_response_times" ] # feedbacks feed_stg = [ "trace_stg", "observe_systemstate" ] -# feed_stg_edge = [ "feed_stg"] +feed_stg_edge = [ "feed_stg"] feed_stg_pathhash = [ "feed_stg"] feed_stg_abbhash = [ "feed_stg"] feed_stg_aggregatehash = [ "feed_stg"] @@ -41,7 +41,7 @@ gensize_1000 = [ ] sched_genetic = [] sched_afl = [] sched_stg = [] -# sched_stg_edge = ['sched_stg'] # every edge in the stg +sched_stg_edge = ['sched_stg'] # every edge in the stg sched_stg_pathhash = ['sched_stg'] # every path in the stg sched_stg_abbhash = ['sched_stg'] # every path of abbs sched_stg_aggregatehash = ['sched_stg'] # every aggregated path (order independent) @@ -50,6 +50,7 @@ config_genetic = ["gensize_100","feed_genetic","sched_genetic","trace_stg"] config_afl = ["feed_afl","sched_afl","observe_hitcounts","trace_stg"] config_frafl = ["feed_afl","sched_afl","feed_longest","trace_stg"] config_stg = ["feed_stg_aggregatehash","sched_stg_aggregatehash","mutate_stg"] +config_stg_edge = ["feed_stg_edge","sched_stg_edge","mutate_stg"] [profile.release] lto = true diff --git a/fuzzers/FRET/benchmark/Snakefile b/fuzzers/FRET/benchmark/Snakefile index ec0c4ccb00..aaac608e42 100644 --- a/fuzzers/FRET/benchmark/Snakefile +++ b/fuzzers/FRET/benchmark/Snakefile @@ -54,13 +54,21 @@ rule build_stg: shell: "cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_stg" -rule build_stgpath: +rule build_stg_path: input: "bins/target_default" output: - directory("bins/target_stgpath") + directory("bins/target_stg_path") shell: - "cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},feed_stg_abbhash,sched_stg_abbhash,mutate_stg" + "cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_stg_aggregate" + +rule build_stg_edge: + input: + "bins/target_default" + output: + directory("bins/target_stg_edge") + shell: + "cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_stg_edge" rule build_feedgeneration1: input: @@ -221,6 +229,11 @@ rule quicktest: expand("timedump/{fuzzer}/{target}{variant}#{num}.time", fuzzer=['random'], target=['release', 'waters', 'copter'], variant=['_full', '_bytes', '_int'], num=range(0,int( NUM_ITERS/2 ))), + +rule stgcomp: + input: + expand("timedump/{fuzzer}/{target}{variant}#{num}.time", fuzzer=['stg', 'stg_path', 'stg_edge'], target=['release', 'waters', 'copter'], variant=['_full'], num=range(0,7)), + rule all_bins: input: expand("bins/target_{target}",target=['random','frafl','stg','stgpath','feedgeneration100', 'feedgeneration1000', 'genetic100', 'genetic1000']) diff --git a/fuzzers/FRET/src/fuzzer.rs b/fuzzers/FRET/src/fuzzer.rs index 2dc028a3db..f0e3661d93 100644 --- a/fuzzers/FRET/src/fuzzer.rs +++ b/fuzzers/FRET/src/fuzzer.rs @@ -397,7 +397,7 @@ let run_client = |state: Option<_>, mut mgr, _core_id| { OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE), addr_of_mut!(MAX_EDGES_FOUND), )}.track_indices(); - #[cfg(feature = "observer_hitcounts")] + #[cfg(feature = "observe_hitcounts")] let edges_observer = HitcountsMapObserver::new(edges_observer).track_indices(); #[cfg(feature = "observe_systemstate")] diff --git a/fuzzers/FRET/src/systemstate/stg.rs b/fuzzers/FRET/src/systemstate/stg.rs index d876aa13f1..bb84074d49 100644 --- a/fuzzers/FRET/src/systemstate/stg.rs +++ b/fuzzers/FRET/src/systemstate/stg.rs @@ -217,10 +217,10 @@ pub struct STGNodeMetadata { tcref: isize, } impl STGNodeMetadata { - pub fn new(nodes: Vec, edges: Vec, abbs: u64, aggregate: u64, top_abb_counts: Vec, intervals: Vec, jobs: Vec) -> Self { + pub fn new(nodes: Vec, edges: Vec, abb_trace: Vec, abbs_pathhash: u64, aggregate: u64, top_abb_counts: Vec, intervals: Vec, jobs: Vec) -> Self { #[allow(unused)] let mut indices : Vec<_> = vec![]; - #[cfg(all(feature = "sched_stg",not(any(feature = "sched_stg_pathhash",feature = "sched_stg_abbhash",feature = "sched_stg_aggregatehash"))))] + #[cfg(feature = "sched_stg_edge")] { indices = edges.iter().map(|x| x.index()).collect(); indices.sort_unstable(); @@ -232,14 +232,14 @@ impl STGNodeMetadata { } #[cfg(feature = "sched_stg_abbhash")] { - indices.push(abbs as usize); + indices.push(abbs_pathhash as usize); } #[cfg(feature = "sched_stg_aggregatehash")] { // indices.push(aggregate as usize); indices = top_abb_counts.iter().map(|x| (*x) as usize).collect(); } - Self {indices, intervals, jobs, nodes, abbs, aggregate, top_abb_counts, edges, tcref: 0} + Self {indices, intervals, jobs, nodes, abbs: abbs_pathhash, aggregate, top_abb_counts, edges, tcref: 0} } pub fn nodes(&self) -> &Vec { @@ -348,6 +348,7 @@ pub struct StgFeedback last_node_trace: Option>, last_edge_trace: Option>, last_intervals: Option>, + last_abb_trace: 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 @@ -379,6 +380,7 @@ const INTEREST_AGGREGATE : bool = false; const INTEREST_JOB_INSTANCE : bool = true; fn set_observer_map(trace : &Vec) { + // dbg!(trace); unsafe { for i in 0..MAX_STG_NUM { STG_MAP[i] = 0; @@ -387,7 +389,7 @@ fn set_observer_map(trace : &Vec) { if MAX_STG_NUM < i.index() { MAX_STG_NUM = i.index(); } - STG_MAP[i.index()]+=1; + STG_MAP[i.index()] = STG_MAP[i.index()].saturating_add(1); } } } @@ -438,8 +440,8 @@ impl StgFeedback { /// newly discovered node? /// side effect: /// the graph gets new nodes and edge - fn update_stg_interval(trace: &Vec, read_trace: &Vec>, table: &HashMap, fbs: &mut STGFeedbackState) -> (Vec, Vec, bool, bool) { - let mut return_node_trace = vec![fbs.entrypoint]; + fn update_stg_interval(trace: &Vec, read_trace: &Vec>, table: &HashMap, fbs: &mut STGFeedbackState) -> (Vec<(NodeIndex, u64)>, Vec<(EdgeIndex, u64)>, bool, bool) { + let mut return_node_trace = vec![(fbs.entrypoint, 0)]; // Assuming entrypoint timestamp is 0 let mut return_edge_trace = vec![]; let mut interesting = false; let mut updated = false; @@ -452,7 +454,7 @@ impl StgFeedback { let node = STGNode {base: table[&interval.start_state].clone(), abb: interval.abb.as_ref().unwrap().clone()}; let h_node = node.get_hash(); let next_idx = if let Some(idx) = fbs.stgnode_index.get(&h_node) { - // alredy present + // already present *idx } else { // not present @@ -465,10 +467,10 @@ impl StgFeedback { idx }; // connect in graph if edge not present - let e = fbs.graph.edges_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).find(|x| petgraph::visit::EdgeRef::target(x) == next_idx); + let e = fbs.graph.edges_directed(return_node_trace[return_node_trace.len()-1].0, Direction::Outgoing).find(|x| petgraph::visit::EdgeRef::target(x) == next_idx); if let Some(e_) = e { - return_edge_trace.push(petgraph::visit::EdgeRef::id(&e_)); - if let Some((time,accesses)) = instance_time.get_mut(&interval.abb.as_ref().unwrap().instance_id) { + return_edge_trace.push((petgraph::visit::EdgeRef::id(&e_), interval.start_tick)); + if let Some((time, accesses)) = instance_time.get_mut(&interval.abb.as_ref().unwrap().instance_id) { let ref_ = &mut fbs.graph.edge_weight_mut(e_.id()).unwrap().worst; if ref_.is_some() { let w = ref_.as_mut().unwrap(); @@ -484,36 +486,27 @@ impl StgFeedback { e__.worst = Some((*time, accesses.clone())); } } - let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], next_idx, e__); - return_edge_trace.push(e_); + let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1].0, next_idx, e__); + return_edge_trace.push((e_, interval.start_tick)); interesting |= INTEREST_EDGE; updated = true; } - return_node_trace.push(next_idx); - /* - Ideas: - Mark edges triggered by interrupts - Specify path with edges instead of nodes? - Form a coverage map over edges? - Sum up execution time per ABB - */ + return_node_trace.push((next_idx, interval.start_tick)); } // every path terminates at the end - if !fbs.graph.neighbors_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).any(|x| x == fbs.exitpoint) { - let mut e__ = STGEdge { event: CaptureEvent::End, name: String::from("End"), worst: None}; + if !fbs.graph.neighbors_directed(return_node_trace[return_node_trace.len()-1].0, Direction::Outgoing).any(|x| x == fbs.exitpoint) { + let mut e__ = STGEdge { event: CaptureEvent::End, name: String::from("End"), worst: None }; if e__.is_abb_end() { - if let Some((time,accesses)) = instance_time.get_mut(&trace[trace.len()-1].abb.as_ref().unwrap().instance_id) { + if let Some((time, accesses)) = instance_time.get_mut(&trace[trace.len()-1].abb.as_ref().unwrap().instance_id) { e__.worst = Some((*time, accesses.clone())); } } - let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], fbs.exitpoint, e__); - return_edge_trace.push(e_); + let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1].0, fbs.exitpoint, e__); + return_edge_trace.push((e_, trace[trace.len()-1].start_tick)); interesting |= INTEREST_EDGE; updated = true; } - return_node_trace.push(fbs.exitpoint); - #[cfg(feature = "feed_stg")] - set_observer_map(&return_edge_trace); + return_node_trace.push((fbs.exitpoint, trace[trace.len()-1].start_tick)); (return_node_trace, return_edge_trace, interesting, updated) } @@ -568,7 +561,25 @@ where }; // --------------------------------- Update STG - let (nodetrace, edgetrace, mut interesting, mut updated) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_reads, &observer.last_states, feedbackstate); + let (mut nodetrace, mut edgetrace, mut interesting, mut updated) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_reads, &observer.last_states, feedbackstate); + + + #[cfg(feature = "trace_job_response_times")] + let worst_target_instance = observer.job_instances.iter().filter(|x| Some(x.name.clone()) == observer.select_task).max_by(|a,b| (a.response-a.release).cmp(&(b.response-b.release))); + + #[cfg(feature = "trace_job_response_times")] + if let Some(worst_instance) = worst_target_instance { + edgetrace = edgetrace.into_iter().filter(|x| x.1 <= worst_instance.response && x.1 >= worst_instance.release ).collect(); + nodetrace = nodetrace.into_iter().filter(|x| x.1 <= worst_instance.response && x.1 >= worst_instance.release ).collect(); + } else { + if observer.select_task.is_none() { // if nothing was selected, just take the whole trace, otherwise there is nothing interesting here + edgetrace = Vec::new(); + nodetrace = Vec::new(); + } + } + + #[cfg(feature = "feed_stg")] + set_observer_map(&edgetrace.iter().map(|x| x.0).collect::>()); // --------------------------------- Update job instances for i in observer.worst_job_instances.iter() { @@ -603,7 +614,7 @@ where let tmp = StgFeedback::abbs_in_exec_order(&observer.last_trace); #[cfg(feature = "trace_job_response_times")] let tmp = { - if let Some(worst_instance) = observer.job_instances.iter().filter(|x| Some(x.name.clone()) == observer.select_task).max_by(|a,b| (a.response-a.release).cmp(&(b.response-b.release))) { + if let Some(worst_instance) = worst_target_instance { let t = observer.last_trace.iter().filter(|x| x.start_tick < worst_instance.response && x.end_tick > worst_instance.release ).cloned().collect(); StgFeedback::abbs_in_exec_order(&t) } else { @@ -667,9 +678,10 @@ where // let outs = Dot::with_config(&out, &[Config::EdgeNoLabel]).to_string(); // let outs = outs.replace(';',"\\n"); // fs::write("./mystg.dot",outs).expect("Failed to write graph"); - self.last_node_trace = Some(nodetrace); - self.last_edge_trace = Some(edgetrace); + self.last_node_trace = Some(nodetrace.into_iter().map(|x| x.0).collect::>()); + self.last_edge_trace = Some(edgetrace.into_iter().map(|x| x.0).collect::>()); self.last_intervals = Some(observer.last_trace.clone()); + self.last_abb_trace = Some(tmp); if let Some(dp) = &self.dump_path { if updated { @@ -689,7 +701,7 @@ where /// Append to the testcase the generated metadata in case of a new corpus item #[inline] fn append_metadata(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, testcase: &mut Testcase) -> Result<(), Error> { - let meta = STGNodeMetadata::new(self.last_node_trace.take().unwrap_or_default(), self.last_edge_trace.take().unwrap_or_default(), 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_or_default(), self.last_job_trace.take().unwrap_or_default()); + let meta = STGNodeMetadata::new(self.last_node_trace.take().unwrap_or_default(), self.last_edge_trace.take().unwrap_or_default(), self.last_abb_trace.take().unwrap_or_default(), 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_or_default(), self.last_job_trace.take().unwrap_or_default()); testcase.metadata_map_mut().insert(meta); Ok(()) }