From ead2e7a08c28f569ce9cba8d3a72930159741804 Mon Sep 17 00:00:00 2001 From: VaynNecol Date: Thu, 2 Jan 2025 16:56:11 +0800 Subject: [PATCH] refactor the alias for whole project --- rap/src/analysis/safedrop/alias.rs | 89 ++++++++++++++++++++----- rap/src/analysis/safedrop/check_bugs.rs | 40 ++++++++--- rap/src/analysis/safedrop/graph.rs | 12 +++- rap/src/analysis/safedrop/safedrop.rs | 14 +++- 4 files changed, 124 insertions(+), 31 deletions(-) diff --git a/rap/src/analysis/safedrop/alias.rs b/rap/src/analysis/safedrop/alias.rs index 80b1db9..18e1143 100644 --- a/rap/src/analysis/safedrop/alias.rs +++ b/rap/src/analysis/safedrop/alias.rs @@ -19,7 +19,7 @@ impl<'tcx> SafeDropGraph<'tcx> { let rv_aliaset_idx = self.projection(tcx, true, assign.rv.clone()); match assign.atype { AssignType::Variant => { - self.values[lv_aliaset_idx].alias[0] = rv_aliaset_idx; + self.alias_set[lv_aliaset_idx] = rv_aliaset_idx; continue; } AssignType::InitBox => { @@ -127,9 +127,8 @@ impl<'tcx> SafeDropGraph<'tcx> { // assign to the variable _x, we will set the birth of _x and its child self.values a new birth. pub fn fill_birth(&mut self, node: usize, birth: isize) { self.values[node].birth = birth; - //TODO: check the correctness. - for i in self.values[node].alias.clone() { - if self.values[i].birth == -1 { + for i in 0..self.alias_set.len() { + if self.union_is_same(i, node) && self.values[i].birth == -1 { self.values[i].birth = birth; } } @@ -151,14 +150,15 @@ impl<'tcx> SafeDropGraph<'tcx> { let new_id = self.values.len(); match proj { ProjectionElem::Deref => { - proj_id = self.values[proj_id].alias[0]; + //proj_id = self.values[proj_id].alias[0]; + proj_id = self.alias_set[proj_id]; } /* * Objective: 2 = 1.0; 0 = 2.0; => 0 = 1.0.0 */ ProjectionElem::Field(field, ty) => { - if is_right && self.values[proj_id].alias[0] != proj_id { - proj_id = self.values[proj_id].alias[0]; + if is_right && self.alias_set[proj_id] != proj_id { + proj_id = self.alias_set[proj_id]; local = self.values[proj_id].local; } let field_idx = field.as_usize(); @@ -172,6 +172,8 @@ impl<'tcx> SafeDropGraph<'tcx> { node.birth = self.values[proj_id].birth; node.field_id = field_idx; self.values[proj_id].fields.insert(field_idx, node.index); + self.alias_set.push(self.values.len()); + self.dead_record.push(false); self.values.push(node); } proj_id = *self.values[proj_id].fields.get(&field_idx).unwrap(); @@ -184,12 +186,14 @@ impl<'tcx> SafeDropGraph<'tcx> { //instruction to assign alias for a variable. pub fn merge_alias(&mut self, lv: usize, rv: usize) { - if self.values[lv].alias.len() > 1 { - let mut alias_clone = self.values[rv].alias.clone(); - self.values[lv].alias.append(&mut alias_clone); - } else { - self.values[lv].alias = self.values[rv].alias.clone(); - } + // if self.values[lv].alias.len() > 1 { + // let mut alias_clone = self.values[rv].alias.clone(); + // self.values[lv].alias.append(&mut alias_clone); + // } else { + // self.values[lv].alias = self.values[rv].alias.clone(); + // } + self.union_merge(lv, rv); + for field in self.values[rv].fields.clone().into_iter() { if !self.values[lv].fields.contains_key(&field.0) { let mut node = ValueNode::new( @@ -202,12 +206,15 @@ impl<'tcx> SafeDropGraph<'tcx> { node.birth = self.values[lv].birth; node.field_id = field.0; self.values[lv].fields.insert(field.0, node.index); + self.alias_set.push(self.values.len()); + self.dead_record.push(false); self.values.push(node); } let lv_field = *(self.values[lv].fields.get(&field.0).unwrap()); self.merge_alias(lv_field, field.1); } } + //inter-procedure instruction to merge alias. pub fn merge(&mut self, ret_alias: &RetAlias, arg_vec: &Vec) { if ret_alias.left_index >= arg_vec.len() || ret_alias.right_index >= arg_vec.len() { @@ -227,16 +234,19 @@ impl<'tcx> SafeDropGraph<'tcx> { node.birth = self.values[lv].birth; node.field_id = *index; self.values[lv].fields.insert(*index, node.index); + self.alias_set.push(self.values.len()); + self.dead_record.push(false); self.values.push(node); } lv = *self.values[lv].fields.get(&index).unwrap(); } for index in ret_alias.right_field_seq.iter() { - if self.values[rv].alias[0] != rv { - rv = self.values[rv].alias[0]; + // if self.values[rv].alias[0] != rv { + if self.union_is_same(rv, self.alias_set[rv]) { + rv = self.values[rv].index; right_init = self.values[rv].local; } - if self.values[rv].fields.contains_key(&index) == false { + if !self.values[rv].fields.contains_key(&index) { let need_drop = ret_alias.right_need_drop; let may_drop = ret_alias.right_may_drop; let mut node = ValueNode::new(self.values.len(), right_init, need_drop, may_drop); @@ -244,10 +254,57 @@ impl<'tcx> SafeDropGraph<'tcx> { node.birth = self.values[rv].birth; node.field_id = *index; self.values[rv].fields.insert(*index, node.index); + self.alias_set.push(self.values.len()); + self.dead_record.push(false); self.values.push(node); } rv = *self.values[rv].fields.get(&index).unwrap(); } self.merge_alias(lv, rv); } + + #[inline] + pub fn union_find(&mut self, e: usize) -> usize { + let mut r = e; + while self.alias_set[r] != r { + r = self.alias_set[r]; + } + r + } + + #[inline] + pub fn union_merge(&mut self, e1: usize, e2: usize) { + let f1 = self.union_find(e1); + let f2 = self.union_find(e2); + + if f1 < f2 { + self.alias_set[f2] = f1; + } + if f1 > f2 { + self.alias_set[f1] = f2; + } + + for member in 0..self.alias_set.len() { + self.alias_set[member] = self.union_find(self.alias_set[member]); + } + } + + #[inline] + pub fn union_is_same(&mut self, e1: usize, e2: usize) -> bool { + let f1 = self.union_find(e1); + let f2 = self.union_find(e2); + f1 == f2 + } + + pub fn union_has_alias(&mut self, e: usize) -> bool { + for i in 0..self.alias_set.len() { + if i == e { + continue; + } + if self.union_is_same(e, i) { + return true; + } + } + false + } } diff --git a/rap/src/analysis/safedrop/check_bugs.rs b/rap/src/analysis/safedrop/check_bugs.rs index a92c9ed..28f0f08 100644 --- a/rap/src/analysis/safedrop/check_bugs.rs +++ b/rap/src/analysis/safedrop/check_bugs.rs @@ -41,7 +41,12 @@ impl<'tcx> SafeDropGraph<'tcx> { } } - pub fn exist_dead(&self, node: usize, record: &mut FxHashSet, dangling: bool) -> bool { + pub fn exist_dead( + &mut self, + node: usize, + record: &mut FxHashSet, + dangling: bool, + ) -> bool { //if is a dangling pointer check, only check the pointer type varible. if self.values[node].is_alive() == false && (dangling && self.values[node].is_ptr() || !dangling) @@ -49,10 +54,18 @@ impl<'tcx> SafeDropGraph<'tcx> { return true; } record.insert(node); - if self.values[node].alias[0] != node { - for i in self.values[node].alias.clone().into_iter() { - if i != node && record.contains(&i) == false && self.exist_dead(i, record, dangling) - { + if self.union_has_alias(node) { + // for i in self.values[node].alias.clone().into_iter() { + // if i != node && record.contains(&i) == false && self.exist_dead(i, record, dangling) + // { + // return true; + // } + // } + for i in 0..self.alias_set.len() { + if i != node && !self.union_is_same(i, node) { + continue; + } + if record.contains(&i) == false && self.exist_dead(i, record, dangling) { return true; } } @@ -65,7 +78,7 @@ impl<'tcx> SafeDropGraph<'tcx> { return false; } - pub fn is_dangling(&self, local: usize) -> bool { + pub fn is_dangling(&mut self, local: usize) -> bool { let mut record = FxHashSet::default(); return self.exist_dead(local, &mut record, local != 0); } @@ -109,13 +122,20 @@ impl<'tcx> SafeDropGraph<'tcx> { return; } //check if there is a double free bug. - if self.df_check(drop, info.span) { + if !alias && self.df_check(drop, info.span) { return; } + if self.dead_record[drop] { return; } else { self.dead_record[drop] = true; } //drop their alias - if self.values[drop].alias[0] != drop { - for i in self.values[drop].alias.clone().into_iter() { - if self.values[i].is_ref() { + if self.alias_set[drop] != drop { + // for i in self.values[drop].alias.clone().into_iter() { + // if self.values[i].is_ref() { + // continue; + // } + // self.dead_node(i, birth, info, true); + // } + for i in 0..self.alias_set.len() { + if !self.union_is_same(drop, i) || i == drop || self.values[i].is_ref() { continue; } self.dead_node(i, birth, info, true); diff --git a/rap/src/analysis/safedrop/graph.rs b/rap/src/analysis/safedrop/graph.rs index 60809cb..c2be060 100644 --- a/rap/src/analysis/safedrop/graph.rs +++ b/rap/src/analysis/safedrop/graph.rs @@ -98,7 +98,6 @@ pub struct ValueNode { pub kind: TyKind, pub father: usize, pub field_id: usize, // the field id of its father node. - pub alias: Vec, pub birth: isize, pub fields: FxHashMap, } @@ -111,7 +110,6 @@ impl ValueNode { need_drop: need_drop, father: local, field_id: usize::MAX, - alias: vec![index], birth: 0, may_drop: may_drop, kind: TyKind::Adt, @@ -163,6 +161,8 @@ pub struct SafeDropGraph<'tcx> { pub bug_records: BugRecords, // a threhold to avoid path explosion. pub visit_times: usize, + pub alias_set: Vec, + pub dead_record: Vec, // analysis of heap item pub adt_owner: AdtOwner, } @@ -178,6 +178,8 @@ impl<'tcx> SafeDropGraph<'tcx> { let locals = &body.local_decls; let arg_size = body.arg_count; let mut values = Vec::::new(); + let mut alias = Vec::::new(); + let mut dead = Vec::::new(); let param_env = tcx.param_env(def_id); for (local, local_decl) in locals.iter_enumerated() { let need_drop = local_decl.ty.needs_drop(tcx, param_env); // the type is drop @@ -189,6 +191,8 @@ impl<'tcx> SafeDropGraph<'tcx> { need_drop || may_drop, ); node.kind = kind(local_decl.ty); + alias.push(values.len()); + dead.push(false); values.push(node); } @@ -273,6 +277,8 @@ impl<'tcx> SafeDropGraph<'tcx> { lvl0.birth = values[lv_local].birth; lvl0.field_id = 0; values[lv_local].fields.insert(0, lvl0.index); + alias.push(values.len()); + dead.push(false); values.push(lvl0); } match x { @@ -470,6 +476,8 @@ impl<'tcx> SafeDropGraph<'tcx> { return_set: FxHashSet::default(), bug_records: BugRecords::new(), visit_times: 0, + alias_set: alias, + dead_record: dead, adt_owner, } } diff --git a/rap/src/analysis/safedrop/safedrop.rs b/rap/src/analysis/safedrop/safedrop.rs index 2cc4988..16b96ed 100644 --- a/rap/src/analysis/safedrop/safedrop.rs +++ b/rap/src/analysis/safedrop/safedrop.rs @@ -76,10 +76,14 @@ impl<'tcx> SafeDropGraph<'tcx> { /* duplicate the status before visiting a path; */ let backup_values = self.values.clone(); // duplicate the status when visiting different paths; let backup_constant = self.constant.clone(); + let backup_alias_set = self.alias_set.clone(); + let backup_dead = self.dead_record.clone(); self.check(bb_index, tcx, fn_map); /* restore after visit */ self.values = backup_values; self.constant = backup_constant; + self.alias_set = backup_alias_set; + self.dead_record = backup_dead; } pub fn split_check_with_cond( &mut self, @@ -92,12 +96,16 @@ impl<'tcx> SafeDropGraph<'tcx> { /* duplicate the status before visiting a path; */ let backup_values = self.values.clone(); // duplicate the status when visiting different paths; let backup_constant = self.constant.clone(); + let backup_alias_set = self.alias_set.clone(); + let backup_dead = self.dead_record.clone(); /* add control-sensitive indicator to the path status */ self.constant.insert(path_discr_id, path_discr_val); self.check(bb_index, tcx, fn_map); /* restore after visit */ self.values = backup_values; self.constant = backup_constant; + self.alias_set = backup_alias_set; + self.dead_record = backup_dead; } // the core function of the safedrop. @@ -158,12 +166,12 @@ impl<'tcx> SafeDropGraph<'tcx> { match discr { Copy(p) | Move(p) => { let place = self.projection(tcx, false, p.clone()); - if let Some(constant) = self.constant.get(&self.values[place].alias[0]) { + if let Some(constant) = self.constant.get(&self.values[place].index) { single_target = true; sw_val = *constant; } - if self.values[place].alias[0] != place { - path_discr_id = self.values[place].alias[0]; + if self.values[place].index != place { + path_discr_id = self.values[place].index; sw_targets = Some(targets.clone()); } }