diff --git a/casr/src/bin/casr-cluster.rs b/casr/src/bin/casr-cluster.rs index 9cb57303..60307802 100644 --- a/casr/src/bin/casr-cluster.rs +++ b/casr/src/bin/casr-cluster.rs @@ -366,12 +366,7 @@ fn update_clusters( let casreps = util::get_reports(cluster)?; let (_, stacktraces, crashlines, _) = util::reports_from_dirs(casreps, jobs); // Fill cluster info structures - let diam = diam(&stacktraces); - clusters.push(Cluster { - number: i, - stacktraces, - diam, - }); + clusters.push(Cluster::new(i, stacktraces)); if dedup { for crashline in crashlines { // NOTE: Clusters enumerate from 1, not 0 @@ -396,8 +391,7 @@ fn update_clusters( let mut outers: Vec<(usize, f64)> = Vec::new(); // Checker if casrep is duplicate of someone else let mut dup = false; - for cluster in &clusters { - // TODO: Add strategy options + for cluster in &mut clusters { let relation = relation( stacktrace, cluster, @@ -454,8 +448,7 @@ fn update_clusters( // Update cluster let i = clusters.iter().position(|a| a.number == number).unwrap(); - clusters[i].stacktraces.push(stacktrace.to_vec()); - clusters[i].diam = diam(&clusters[i].stacktraces); + clusters[i].push(stacktrace.to_vec()); } // Handle deviant casreps diff --git a/casr/src/util.rs b/casr/src/util.rs index 4217dafb..72cc56c9 100644 --- a/casr/src/util.rs +++ b/casr/src/util.rs @@ -302,7 +302,7 @@ pub fn get_atheris_lib() -> Result { Ok(format!("{out}/asan_with_fuzzer.so")) } -/// Create output, timeout and oOLDdirectories +/// Create output, timeout and oom directories /// /// # Arguments /// diff --git a/libcasr/src/stacktrace.rs b/libcasr/src/stacktrace.rs index 45f329fe..90031367 100644 --- a/libcasr/src/stacktrace.rs +++ b/libcasr/src/stacktrace.rs @@ -61,17 +61,43 @@ pub enum AccumStrategy { Dist, } -// TODO: lazy diam -// TODO: encapsulation /// Structure provides an interface for leverages with CASR report clusters #[derive(Clone, Debug)] pub struct Cluster { /// Cluster number pub number: usize, /// Cluster report stacktraces - pub stacktraces: Vec, + stacktraces: Vec, /// Cluster diameter - pub diam: f64, + diam: Option, +} + +impl Cluster { + /// Create new `Cluster` + pub fn new(number: usize, stacktraces: Vec) -> Self { + Cluster { + number, + stacktraces, + diam: None, + } + } + /// Get CASR report stactraces + pub fn stacktraces(&self) -> Vec { + self.stacktraces.clone() + } + /// Add CASR report stacktrace to cluster + pub fn push(&mut self, stacktrace: Stacktrace) { + self.stacktraces.push(stacktrace); + self.diam = None; + } + /// Get cluster diameter + pub fn diam(&mut self) -> f64 { + if self.diam.is_none() { + diam(&self.stacktraces) + } else { + self.diam.unwrap() + } + } } /// This macro updates variables used to remove trusted functions from stack trace @@ -339,7 +365,7 @@ pub fn dedup_crashlines(crashlines: &[String], clusters: &mut [usize]) -> usize /// # Return value /// /// Value of diameter -pub fn diam(stacktraces: &[Stacktrace]) -> f64 { +fn diam(stacktraces: &[Stacktrace]) -> f64 { let mut diam = 0f64; let len = stacktraces.len(); for i in 0..len { @@ -370,15 +396,15 @@ pub fn diam(stacktraces: &[Stacktrace]) -> f64 { /// `Relation` enum with measure according specified strategy pub fn relation( new: &Stacktrace, - cluster: &Cluster, + cluster: &mut Cluster, inner_strategy: AccumStrategy, outer_strategy: AccumStrategy, ) -> Relation { - let diam = cluster.diam; + let diam = cluster.diam(); let mut min = MAX; let mut max = 0f64; - for stacktrace in &cluster.stacktraces { - let dist = 1.0 - similarity(new, stacktrace); + for stacktrace in cluster.stacktraces() { + let dist = 1.0 - similarity(new, &stacktrace); if dist == 0.0 { return Relation::Dup; } else if dist > THRESHOLD {