rapx/analysis/safedrop/
alias.rs

1use rustc_middle::{
2    mir::{Operand, Place, ProjectionElem, TerminatorKind},
3    ty::{self, TyCtxt, TypingEnv},
4};
5
6use super::graph::*;
7use crate::analysis::{
8    core::alias_analysis::default::{
9        MopAAFact, MopAAResultMap, assign::*, block::Term, types::*, value::*,
10    },
11    utils::fn_info::convert_alias_to_sets,
12};
13
14impl<'tcx> SafeDropGraph<'tcx> {
15    /* alias analysis for a single block */
16    pub fn alias_bb(&mut self, bb_index: usize) {
17        for stmt in self.mop_graph.blocks[bb_index].const_value.clone() {
18            self.mop_graph.constants.insert(stmt.def_id, stmt.value);
19        }
20        let cur_block = self.mop_graph.blocks[bb_index].clone();
21        for assign in cur_block.assignments {
22            let mut lv_idx = self.projection(false, assign.lv);
23            let rv_idx = self.projection(true, assign.rv);
24            match assign.atype {
25                AssignType::Variant => {
26                    self.mop_graph.alias_set[lv_idx] = rv_idx;
27                    continue;
28                }
29                AssignType::InitBox => {
30                    lv_idx = *self.mop_graph.values[lv_idx].fields.get(&0).unwrap();
31                }
32                _ => {} // Copy or Move
33            }
34            self.fill_birth(lv_idx, self.mop_graph.blocks[bb_index].scc.enter as isize);
35            if self.mop_graph.values[lv_idx].local != self.mop_graph.values[rv_idx].local {
36                rap_debug!(
37                    "merge alias: lv_idx/local:{}/{}, rv_idx/local:{}/{}",
38                    lv_idx,
39                    self.mop_graph.values[lv_idx].local,
40                    rv_idx,
41                    self.mop_graph.values[rv_idx].local
42                );
43                self.merge_alias(lv_idx, rv_idx, 0);
44                rap_debug!(
45                    "Alias sets: {:?}",
46                    convert_alias_to_sets(self.mop_graph.alias_set.clone())
47                );
48            }
49            self.uaf_check(bb_index, rv_idx, assign.span, false);
50        }
51    }
52
53    /* Check the aliases introduced by the terminators (function call) of a scc block */
54    pub fn alias_bbcall(&mut self, bb_index: usize, tcx: TyCtxt<'tcx>, fn_map: &MopAAResultMap) {
55        let cur_block = self.mop_graph.blocks[bb_index].clone();
56        if let Term::Call(call) | Term::Drop(call) = cur_block.terminator {
57            if let TerminatorKind::Call {
58                ref func,
59                ref args,
60                ref destination,
61                target: _,
62                unwind: _,
63                call_source: _,
64                fn_span: _,
65            } = call.kind
66            {
67                if let Operand::Constant(constant) = func {
68                    let lv = self.projection(false, destination.clone());
69                    self.mop_graph.values[lv].birth = self.mop_graph.blocks[bb_index].scc.enter as isize;
70                    let mut merge_vec = Vec::new();
71                    merge_vec.push(lv);
72                    let mut may_drop_flag = 0;
73                    if self.mop_graph.values[lv].may_drop {
74                        may_drop_flag += 1;
75                    }
76                    for arg in args {
77                        match arg.node {
78                            Operand::Copy(ref p) => {
79                                let rv = self.projection(true, p.clone());
80                                //self.uaf_check(rv, call.source_info.span, p.local.as_usize(), true);
81                                self.uaf_check(bb_index, rv, call.source_info.span, true);
82                                merge_vec.push(rv);
83                                if self.mop_graph.values[rv].may_drop {
84                                    may_drop_flag += 1;
85                                }
86                            }
87                            Operand::Move(ref p) => {
88                                let rv = self.projection(true, p.clone());
89                                self.uaf_check(bb_index, rv, call.source_info.span, true);
90                                merge_vec.push(rv);
91                                if self.mop_graph.values[rv].may_drop {
92                                    may_drop_flag += 1;
93                                }
94                            }
95                            Operand::Constant(_) => {
96                                merge_vec.push(0);
97                            }
98                        }
99                    }
100                    if let ty::FnDef(target_id, _) = constant.const_.ty().kind() {
101                        if may_drop_flag > 1 {
102                            if tcx.is_mir_available(*target_id) {
103                                if fn_map.contains_key(&target_id) {
104                                    let assignments = fn_map.get(&target_id).unwrap();
105                                    for assign in assignments.aliases().iter() {
106                                        if !assign.valuable() {
107                                            continue;
108                                        }
109                                        self.merge(assign, &merge_vec);
110                                    }
111                                }
112                            } else {
113                                if self.mop_graph.values[lv].may_drop {
114                                    if self.corner_handle(lv, &merge_vec, *target_id) {
115                                        return;
116                                    }
117                                    let mut right_set = Vec::new();
118                                    for rv in &merge_vec {
119                                        if self.mop_graph.values[*rv].may_drop
120                                            && lv != *rv
121                                            && self.mop_graph.values[lv].is_ptr()
122                                        {
123                                            right_set.push(*rv);
124                                        }
125                                    }
126                                    if right_set.len() == 1 {
127                                        self.merge_alias(lv, right_set[0], 0);
128                                    }
129                                }
130                            }
131                        }
132                    }
133                }
134            }
135        }
136    }
137
138    // assign to the variable _x, we will set the birth of _x and its child self.mop_graph.values a new birth.
139    pub fn fill_birth(&mut self, node: usize, birth: isize) {
140        self.mop_graph.values[node].birth = birth;
141        for i in 0..self.mop_graph.values.len() {
142            if self.mop_graph.union_is_same(i, node) && self.mop_graph.values[i].birth == -1 {
143                self.mop_graph.values[i].birth = birth;
144            }
145        }
146        for i in self.mop_graph.values[node].fields.clone().into_iter() {
147            self.fill_birth(i.1, birth); //i.1 corresponds to the local field.
148        }
149    }
150
151    /*
152     * This is the function for field sensitivity
153     * If the projection is a deref, we directly return its head alias or alias[0].
154     * If the id is not a ref, we further make the id and its first element an alias, i.e., level-insensitive
155     *
156     */
157    pub fn projection(&mut self, is_right: bool, place: Place<'tcx>) -> usize {
158        let mut local = place.local.as_usize();
159        let mut proj_id = local;
160        for proj in place.projection {
161            let new_id = self.mop_graph.values.len();
162            match proj {
163                ProjectionElem::Deref => {
164                    //proj_id = self.mop_graph.values[proj_id].alias[0];
165                    proj_id = self.mop_graph.alias_set[proj_id];
166                }
167                /*
168                 * Objective: 2 = 1.0; 0 = 2.0; => 0 = 1.0.0
169                 */
170                ProjectionElem::Field(field, ty) => {
171                    if is_right && self.mop_graph.alias_set[proj_id] != proj_id {
172                        proj_id = self.mop_graph.alias_set[proj_id];
173                        local = self.mop_graph.values[proj_id].local;
174                    }
175                    let field_idx = field.as_usize();
176                    if !self.mop_graph.values[proj_id]
177                        .fields
178                        .contains_key(&field_idx)
179                    {
180                        let ty_env =
181                            TypingEnv::post_analysis(self.mop_graph.tcx, self.mop_graph.def_id);
182                        let need_drop = ty.needs_drop(self.mop_graph.tcx, ty_env);
183                        let may_drop = !is_not_drop(self.mop_graph.tcx, ty);
184                        let mut node = Value::new(new_id, local, need_drop, need_drop || may_drop);
185                        node.kind = kind(ty);
186                        node.birth = self.mop_graph.values[proj_id].birth;
187                        node.field_id = field_idx;
188                        self.mop_graph.values[proj_id]
189                            .fields
190                            .insert(field_idx, node.index);
191                        self.mop_graph
192                            .alias_set
193                            .push(self.mop_graph.alias_set.len());
194                        self.drop_record.push(self.drop_record[proj_id]);
195                        self.mop_graph.values.push(node);
196                    }
197                    proj_id = *self.mop_graph.values[proj_id]
198                        .fields
199                        .get(&field_idx)
200                        .unwrap();
201                }
202                _ => {}
203            }
204        }
205        return proj_id;
206    }
207
208    //instruction to assign alias for a variable.
209    pub fn merge_alias(&mut self, lv: usize, rv: usize, depth: usize) {
210        // if self.mop_graph.values[lv].alias.len() > 1 {
211        //     let mut alias_clone = self.mop_graph.values[rv].alias.clone();
212        //     self.mop_graph.values[lv].alias.append(&mut alias_clone);
213        // } else {
214        //     self.mop_graph.values[lv].alias = self.mop_graph.values[rv].alias.clone();
215        // }
216        if lv >= self.mop_graph.values.len() || rv >= self.mop_graph.values.len() {
217            return;
218        }
219        self.mop_graph.union_merge(lv, rv);
220
221        let max_field_depth = match std::env::var_os("SAFEDROP") {
222            Some(val) if val == "0" => 10,
223            Some(val) if val == "1" => 20,
224            Some(val) if val == "2" => 30,
225            Some(val) if val == "3" => 50,
226            _ => 15,
227        };
228
229        if depth > max_field_depth {
230            return;
231        }
232
233        for field in self.mop_graph.values[rv].fields.clone().into_iter() {
234            if !self.mop_graph.values[lv].fields.contains_key(&field.0) {
235                let mut node = Value::new(
236                    self.mop_graph.values.len(),
237                    self.mop_graph.values[lv].local,
238                    self.mop_graph.values[field.1].need_drop,
239                    self.mop_graph.values[field.1].may_drop,
240                );
241                node.kind = self.mop_graph.values[field.1].kind;
242                node.birth = self.mop_graph.values[lv].birth;
243                node.field_id = field.0;
244                self.mop_graph.values[lv].fields.insert(field.0, node.index);
245                self.mop_graph
246                    .alias_set
247                    .push(self.mop_graph.alias_set.len());
248                self.drop_record.push(DropRecord::false_record());
249                self.mop_graph.values.push(node);
250            }
251            let lv_field = *(self.mop_graph.values[lv].fields.get(&field.0).unwrap());
252            self.merge_alias(lv_field, field.1, depth + 1);
253        }
254    }
255
256    //inter-procedure instruction to merge alias.
257    pub fn merge(&mut self, ret_alias: &MopAAFact, arg_vec: &Vec<usize>) {
258        if ret_alias.lhs_no() >= arg_vec.len() || ret_alias.rhs_no() >= arg_vec.len() {
259            rap_error!("Vector error!");
260            return;
261        }
262        let left_init = arg_vec[ret_alias.lhs_no()];
263        let mut right_init = arg_vec[ret_alias.rhs_no()];
264        let mut lv = left_init;
265        let mut rv = right_init;
266        for index in ret_alias.lhs_fields().iter() {
267            if self.mop_graph.values[lv].fields.contains_key(&index) == false {
268                let need_drop = ret_alias.lhs_need_drop;
269                let may_drop = ret_alias.lhs_may_drop;
270                let mut node =
271                    Value::new(self.mop_graph.values.len(), left_init, need_drop, may_drop);
272                node.kind = TyKind::RawPtr;
273                node.birth = self.mop_graph.values[lv].birth;
274                node.field_id = *index;
275                self.mop_graph.values[lv].fields.insert(*index, node.index);
276                self.mop_graph
277                    .alias_set
278                    .push(self.mop_graph.alias_set.len());
279                self.drop_record.push(self.drop_record[lv]);
280                self.mop_graph.values.push(node);
281            }
282            lv = *self.mop_graph.values[lv].fields.get(&index).unwrap();
283        }
284        for index in ret_alias.rhs_fields().iter() {
285            // if self.mop_graph.values[rv].alias[0] != rv {
286            if self
287                .mop_graph
288                .union_is_same(rv, self.mop_graph.alias_set[rv])
289            {
290                rv = self.mop_graph.values[rv].index;
291                right_init = self.mop_graph.values[rv].local;
292            }
293            if !self.mop_graph.values[rv].fields.contains_key(&index) {
294                let need_drop = ret_alias.rhs_need_drop;
295                let may_drop = ret_alias.rhs_may_drop;
296                let mut node = Value::new(
297                    self.mop_graph.alias_set.len(),
298                    right_init,
299                    need_drop,
300                    may_drop,
301                );
302                node.kind = TyKind::RawPtr;
303                node.birth = self.mop_graph.values[rv].birth;
304                node.field_id = *index;
305                self.mop_graph.values[rv].fields.insert(*index, node.index);
306                self.mop_graph.alias_set.push(self.mop_graph.values.len());
307                self.drop_record.push(self.drop_record[rv]);
308                self.mop_graph.values.push(node);
309            }
310            rv = *self.mop_graph.values[rv].fields.get(&index).unwrap();
311        }
312        self.merge_alias(lv, rv, 0);
313    }
314}