From 061f0f2d8c2472e52d559ce90fb4f7633dd5d300 Mon Sep 17 00:00:00 2001 From: Alwin Berger Date: Wed, 30 Jul 2025 12:14:22 +0000 Subject: [PATCH] avoid copy of function names --- fuzzers/FRET/src/systemstate/helpers.rs | 9 ++-- fuzzers/FRET/src/systemstate/mod.rs | 17 +++---- fuzzers/FRET/src/systemstate/stg.rs | 6 +-- .../src/systemstate/target_os/freertos/mod.rs | 23 ++++----- .../target_os/freertos/qemu_module.rs | 47 ++++++++++--------- fuzzers/FRET/src/systemstate/target_os/mod.rs | 3 +- 6 files changed, 54 insertions(+), 51 deletions(-) diff --git a/fuzzers/FRET/src/systemstate/helpers.rs b/fuzzers/FRET/src/systemstate/helpers.rs index d618e28ca0..58e4a40b58 100644 --- a/fuzzers/FRET/src/systemstate/helpers.rs +++ b/fuzzers/FRET/src/systemstate/helpers.rs @@ -1,8 +1,7 @@ use hashbrown::HashMap; use libafl_bolts::prelude::{SerdeAny, SerdeAnyMap}; use libafl_qemu::{elf::EasyElf, read_user_reg_unchecked, GuestAddr, GuestPhysAddr}; -use std::cmp::min; -use std::ops::Range; +use std::{borrow::Cow, cmp::min, hash::{DefaultHasher, Hash, Hasher}, ops::Range}; use crate::{ fuzzer::{DO_NUM_INTERRUPT, FIRST_INT}, @@ -77,7 +76,7 @@ pub fn get_function_range(elf: &EasyElf, symbol: &str) -> Option( - ranges: &'a Vec<(String, Range)>, + ranges: &'a Vec<(Cow<'static, str>, Range)>, addr: GuestAddr, ) -> Option<&'a std::ops::Range> { for (_, r) in ranges { @@ -194,8 +193,8 @@ where #[allow(unused)] pub fn abb_profile( mut intervals: Vec, -) -> HashMap> { - let mut ret: HashMap> = HashMap::new(); +) -> HashMap, HashMap> { + let mut ret: HashMap, HashMap> = HashMap::new(); intervals.sort_by_key(|x| x.get_task_name_unchecked()); intervals .chunk_by_mut(|x, y| x.get_task_name_unchecked() == y.get_task_name_unchecked()) diff --git a/fuzzers/FRET/src/systemstate/mod.rs b/fuzzers/FRET/src/systemstate/mod.rs index f61fd7d9af..3ddd8e0f48 100644 --- a/fuzzers/FRET/src/systemstate/mod.rs +++ b/fuzzers/FRET/src/systemstate/mod.rs @@ -9,6 +9,7 @@ use std::hash::Hash; use hashbrown::HashMap; use serde::{Deserialize, Serialize}; use itertools::Itertools; +use std::borrow::Cow; pub mod helpers; pub mod feedbacks; @@ -56,8 +57,8 @@ pub struct ExecInterval { pub end_tick: u64, pub start_state: u64, pub end_state: u64, - pub start_capture: (CaptureEvent, String), - pub end_capture: (CaptureEvent, String), + pub start_capture: (CaptureEvent, Cow<'static, str>), + pub end_capture: (CaptureEvent, Cow<'static, str>), pub level: u8, // tick_spend_preempted: u64, pub abb: Option @@ -93,11 +94,11 @@ impl ExecInterval { return (self.start_state, self.abb.as_ref().expect("ABB not set").get_hash()) } - pub fn get_task_name(&self) -> Option { + pub fn get_task_name(&self) -> Option> { self.abb.as_ref().map(|x| x.instance_name.clone()).flatten() } - pub fn get_task_name_unchecked(&self) -> String { - self.get_task_name().unwrap_or_else(|| "unknown".to_string()) + pub fn get_task_name_unchecked(&self) -> Cow<'static, str> { + self.get_task_name().unwrap_or_else(|| Cow::Owned("unknown".to_owned())) } pub fn is_abb_end(&self) -> bool { @@ -117,7 +118,7 @@ pub struct AtomicBasicBlock { ends: HashSet, level: u8, instance_id: usize, - instance_name: Option, + instance_name: Option>, } impl PartialEq for AtomicBasicBlock { @@ -146,7 +147,7 @@ impl fmt::Display for AtomicBasicBlock { for end in &self.ends { ends_str.push_str(&format!("0x{:#x}, ", end)); } - write!(f, "ABB {} {{ level: {}, start: 0x{:#x}, ends: [{}]}}", &self.instance_name.as_ref().unwrap_or(&"".to_string()), self.level, self.start, ends_str.trim().trim_matches(',')) + write!(f, "ABB {} {{ level: {}, start: 0x{:#x}, ends: [{}]}}", &self.instance_name.as_ref().unwrap_or(&Cow::Owned("".to_owned())), self.level, self.start, ends_str.trim().trim_matches(',')) } } impl fmt::Debug for AtomicBasicBlock { @@ -155,7 +156,7 @@ impl fmt::Debug for AtomicBasicBlock { for end in &self.ends { ends_str.push_str(&format!("{:#x}, ", end)); } - write!(f, "ABB {} {{ level: {}, start: 0x{:#x}, ends: [{}]}}", &self.instance_name.as_ref().unwrap_or(&"".to_string()), self.level, self.start, ends_str.trim().trim_matches(',')) + write!(f, "ABB {} {{ level: {}, start: 0x{:#x}, ends: [{}]}}", &self.instance_name.as_ref().unwrap_or(&Cow::Owned("".to_owned())), self.level, self.start, ends_str.trim().trim_matches(',')) } } diff --git a/fuzzers/FRET/src/systemstate/stg.rs b/fuzzers/FRET/src/systemstate/stg.rs index 74429db714..2810182c09 100644 --- a/fuzzers/FRET/src/systemstate/stg.rs +++ b/fuzzers/FRET/src/systemstate/stg.rs @@ -106,7 +106,7 @@ where pub struct STGEdge { pub event: CaptureEvent, - pub name: String, + pub name: Cow<'static, str>, pub worst: Option<(u64, Vec<(u32, u8)>)>, } @@ -124,7 +124,7 @@ impl STGEdge { short } pub fn color_print(&self) -> String { - let mut short = self.name.clone(); + let mut short = self.name.to_string(); short.push_str(match self.event { CaptureEvent::APIStart => "\", color=\"blue", CaptureEvent::APIEnd => "\", color=\"black", @@ -549,7 +549,7 @@ where } // every path terminates at the end 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 }; + let mut e__ = STGEdge { event: CaptureEvent::End, name: Cow::Borrowed("End"), worst: None }; 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())); } diff --git a/fuzzers/FRET/src/systemstate/target_os/freertos/mod.rs b/fuzzers/FRET/src/systemstate/target_os/freertos/mod.rs index b442788d07..cf378f00d3 100644 --- a/fuzzers/FRET/src/systemstate/target_os/freertos/mod.rs +++ b/fuzzers/FRET/src/systemstate/target_os/freertos/mod.rs @@ -1,6 +1,7 @@ use libafl_qemu::GuestAddr; use qemu_module::{FreeRTOSSystemStateHelper, MEM_READ}; use serde::{Deserialize, Serialize}; +use std::borrow::Cow; use crate::{ impl_emu_lookup, @@ -191,23 +192,23 @@ fn trigger_collection( match event { CaptureEvent::APIStart => { - let s = h.api_fn_addrs.get(&edge.1).unwrap(); - systemstate.capture_point = (CaptureEvent::APIStart, s.to_string()); + let s : &Cow<'static, str> = h.api_fn_addrs.get(&edge.1).unwrap(); + systemstate.capture_point = (CaptureEvent::APIStart, s.clone()); } CaptureEvent::APIEnd => { - let s = h.api_fn_addrs.get(&edge.0).unwrap(); - systemstate.capture_point = (CaptureEvent::APIEnd, s.to_string()); + let s : &Cow<'static, str> = h.api_fn_addrs.get(&edge.0).unwrap(); + systemstate.capture_point = (CaptureEvent::APIEnd, s.clone()); } CaptureEvent::ISRStart => { - let s = h.isr_fn_addrs.get(&edge.1).unwrap(); - systemstate.capture_point = (CaptureEvent::ISRStart, s.to_string()); + let s : &Cow<'static, str> = h.isr_fn_addrs.get(&edge.1).unwrap(); + systemstate.capture_point = (CaptureEvent::ISRStart, s.clone()); } CaptureEvent::ISREnd => { - let s = h.isr_fn_addrs.get(&edge.0).unwrap(); - systemstate.capture_point = (CaptureEvent::ISREnd, s.to_string()); + let s : &Cow<'static, str> = h.isr_fn_addrs.get(&edge.0).unwrap(); + systemstate.capture_point = (CaptureEvent::ISREnd, s.clone()); } CaptureEvent::End => { - systemstate.capture_point = (CaptureEvent::End, "".to_string()); + systemstate.capture_point = (CaptureEvent::End, Cow::Borrowed("")); } CaptureEvent::Undefined => (), } @@ -283,7 +284,7 @@ pub struct RawFreeRTOSSystemState { read_invalid: bool, input_counter: u32, edge: (GuestAddr, GuestAddr), - capture_point: (CaptureEvent, String), + capture_point: (CaptureEvent, Cow<'static, str>), mem_reads: Vec<(u32, u8)>, } /// List of system state dumps from EmulatorModules @@ -440,7 +441,7 @@ impl fmt::Display for FreeRTOSSystemState { #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub(crate)struct FreeRTOSSystemStateContext { pub qemu_tick: u64, - pub capture_point: (CaptureEvent, String), + pub capture_point: (CaptureEvent, Cow<'static, str>), pub edge: (GuestAddr, GuestAddr), pub mem_reads: Vec<(u32, u8)>, } diff --git a/fuzzers/FRET/src/systemstate/target_os/freertos/qemu_module.rs b/fuzzers/FRET/src/systemstate/target_os/freertos/qemu_module.rs index e194c3db3f..3450febd13 100644 --- a/fuzzers/FRET/src/systemstate/target_os/freertos/qemu_module.rs +++ b/fuzzers/FRET/src/systemstate/target_os/freertos/qemu_module.rs @@ -1,4 +1,7 @@ -use std::{cell::RefCell, collections::VecDeque, ops::Range, rc::Rc}; +use std::cell::RefCell; +use std::rc::Rc; +use std::{borrow::Cow, collections::VecDeque}; +use std::ops::Range; use freertos::{FreeRTOSTraceMetadata, USR_ISR_SYMBOLS}; use hashbrown::HashMap; @@ -33,11 +36,11 @@ pub struct FreeRTOSSystemStateHelper { // Address of the application code pub app_range: Range, // Address of API functions - pub api_fn_addrs: HashMap, - pub api_fn_ranges: Vec<(String, std::ops::Range)>, + pub api_fn_addrs: HashMap>, + pub api_fn_ranges: Vec<(Cow<'static, str>, std::ops::Range)>, // Address of interrupt routines - pub isr_fn_addrs: HashMap, - pub isr_fn_ranges: Vec<(String, std::ops::Range)>, + pub isr_fn_addrs: HashMap>, + pub isr_fn_ranges: Vec<(Cow<'static, str>, std::ops::Range)>, // Address of input memory pub input_mem: Range, // FreeRTOS specific addresses @@ -60,9 +63,9 @@ impl FreeRTOSSystemStateHelper { ) -> Self { let app_range = target_ranges.get("APP_CODE").unwrap().clone(); - let api_fn_ranges : Vec<_> = target_groups.get("API_FN").unwrap().iter().sorted_by_key(|x|x.1.start).map(|(n,r)| (n.clone(),r.clone())).collect(); + let api_fn_ranges : Vec<_> = target_groups.get("API_FN").unwrap().iter().sorted_by_key(|x|x.1.start).map(|(n,r)| (Cow::Borrowed(Box::leak(n.clone().into_boxed_str())),r.clone())).collect(); let api_fn_addrs = api_fn_ranges.iter().map(|(n,r)| (r.start,n.clone())).collect(); - let isr_fn_ranges : Vec<_> = target_groups.get("ISR_FN").unwrap().iter().sorted_by_key(|x|x.1.start).map(|(n,r)| (n.clone(),r.clone())).collect(); + let isr_fn_ranges : Vec<_> = target_groups.get("ISR_FN").unwrap().iter().sorted_by_key(|x|x.1.start).map(|(n,r)| (Cow::Borrowed(Box::leak(n.clone().into_boxed_str())),r.clone())).collect(); let isr_fn_addrs = isr_fn_ranges.iter().map(|(n,r)| (r.start,n.clone())).collect(); let input_mem = target_symbols.get("FUZZ_INPUT").map(|x| *x..(*x+unsafe{MAX_INPUT_SIZE as GuestAddr})).unwrap(); @@ -164,13 +167,11 @@ where } // Collect the final system state trigger_collection(&emulator_modules.qemu(), (0, 0), CaptureEvent::End, self); - unsafe { - let c = emulator_modules.qemu().cpu_from_index(0); - let pc = c.read_reg::(15).unwrap(); - CURRENT_SYSTEMSTATE_VEC[CURRENT_SYSTEMSTATE_VEC.len() - 1].edge = (pc, 0); - CURRENT_SYSTEMSTATE_VEC[CURRENT_SYSTEMSTATE_VEC.len() - 1].capture_point = - (CaptureEvent::End, "Breakpoint".to_string()); - } + let c = emulator_modules.qemu().cpu_from_index(0); + let pc = c.read_reg::(15).unwrap(); + let last = unsafe { CURRENT_SYSTEMSTATE_VEC.last_mut().unwrap() }; + last.edge = (pc, 0); + last.capture_point =(CaptureEvent::End, Cow::Borrowed("Breakpoint")); // Find the first ISREnd of vPortSVCHandler (start of the first task) and drop anything before unsafe { let mut index = 0; @@ -574,7 +575,7 @@ fn refine_system_states( }); ret.1.push(FreeRTOSSystemStateContext { qemu_tick: i.qemu_tick, - capture_point: (i.capture_point.0, i.capture_point.1.to_string()), + capture_point: (i.capture_point.0, i.capture_point.1), edge: i.edge, mem_reads: i.mem_reads, }); @@ -701,13 +702,13 @@ fn add_abb_info( ) -> bool { let mut id_count = 0; let mut ret = true; - let mut task_has_started: HashSet = HashSet::new(); + let mut task_has_started: HashSet<&String> = HashSet::new(); let mut wip_abb_trace: Vec>> = vec![]; // let mut open_abb_at_this_task_or_level : HashMap<(u8,&str),usize> = HashMap::new(); let mut open_abb_at_this_ret_addr_and_task: HashMap<(u32, &str), usize> = HashMap::new(); for i in 0..trace.len() { - let curr_name = &table[&trace[i].start_state].current_task().task_name(); + let curr_name = table[&trace[i].start_state].current_task().task_name(); // let last : Option<&usize> = last_abb_start_of_task.get(&curr_name); // let open_abb = open_abb_at_this_task_or_level.get(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""})).to_owned(); // apps/apis are differentiated by task name, isrs by nested level @@ -778,7 +779,7 @@ fn add_abb_info( }, instance_id: id_count, instance_name: if trace[i].level < 2 { - Some(curr_name.clone().clone()) + Some(Cow::Owned(curr_name.to_owned())) } else { None }, @@ -789,7 +790,7 @@ fn add_abb_info( CaptureEvent::ISREnd => { // special case app abb start if trace[i].start_capture.1 == "xPortPendSVHandler" - && !task_has_started.contains(curr_name.clone()) + && !task_has_started.contains(&curr_name) { // assert_eq!(open_abb, None); ret &= open_abb.is_none(); @@ -802,14 +803,14 @@ fn add_abb_info( 2 }, instance_id: id_count, - instance_name: Some(curr_name.clone().clone()), + instance_name: Some(Cow::Owned(curr_name.to_owned())), }))); id_count += 1; open_abb_at_this_ret_addr_and_task.insert( (edges[i].1, if trace[i].level < 2 { &curr_name } else { "" }), i, ); - task_has_started.insert(curr_name.clone().clone()); + task_has_started.insert(&curr_name); } else { if let Some(last) = open_abb_at_this_ret_addr_and_task .get(&(edges[i].0, if trace[i].level < 2 { &curr_name } else { "" })) @@ -840,7 +841,7 @@ fn add_abb_info( }, instance_id: id_count, instance_name: if trace[i].level < 1 { - Some(curr_name.clone().clone()) + Some(Cow::Owned(curr_name.to_owned())) } else { None }, @@ -924,7 +925,7 @@ fn get_releases( // A timed release is SysTickHandler isr block that moves a task from the delay list to the ready list. if i.start_capture.0 == CaptureEvent::ISRStart && (i.start_capture.1 == "xPortSysTickHandler" - || USR_ISR_SYMBOLS.contains(&i.start_capture.1.as_str())) + || USR_ISR_SYMBOLS.contains(&&*i.start_capture.1)) { // detect race-conditions, get start and end state from the nearest valid intervals if states diff --git a/fuzzers/FRET/src/systemstate/target_os/mod.rs b/fuzzers/FRET/src/systemstate/target_os/mod.rs index 67b8df6cff..6f1136b1c3 100644 --- a/fuzzers/FRET/src/systemstate/target_os/mod.rs +++ b/fuzzers/FRET/src/systemstate/target_os/mod.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::collections::hash_map::DefaultHasher; use std::fmt; use hashbrown::HashSet; @@ -81,7 +82,7 @@ pub trait SystemTraceData: Serialize + Sized + for<'a> Deserialize<'a> + Default fn select_abb_profile( &self, select_task: Option, - ) -> HashMap> { + ) -> HashMap, HashMap> { if let Some(select_task) = select_task.as_ref() { // Task selected, only profile this task let wjptybrt = self.worst_jobs_per_task_by_response_time();