rapx/analysis/safedrop/
check_bugs.rs

1use super::graph::*;
2use crate::analysis::utils::fn_info::{convert_alias_to_sets, generate_mir_cfg_dot};
3use crate::utils::source::*;
4use rustc_data_structures::fx::FxHashSet;
5use rustc_middle::mir::SourceInfo;
6use rustc_span::Span;
7use rustc_span::symbol::Symbol;
8
9impl<'tcx> SafeDropGraph<'tcx> {
10    pub fn report_bugs(&self) {
11        let filename = get_filename(self.tcx, self.def_id);
12        match filename {
13            Some(filename) => {
14                if filename.contains(".cargo") {
15                    return;
16                }
17            }
18            None => {}
19        }
20        if self.bug_records.is_bug_free() {
21            return;
22        }
23        let fn_name = match get_name(self.tcx, self.def_id) {
24            Some(name) => name,
25            None => Symbol::intern("no symbol available"),
26        };
27        self.bug_records.df_bugs_output(fn_name, self.span);
28        self.bug_records.uaf_bugs_output(fn_name, self.span);
29        self.bug_records.dp_bug_output(fn_name, self.span);
30        let _ = generate_mir_cfg_dot(self.tcx, self.def_id);
31        rap_debug!("Alias: {:?}", convert_alias_to_sets(self.alias_set.clone()));
32    }
33
34    pub fn uaf_check(&mut self, aliaset_idx: usize, span: Span, local: usize, is_func_call: bool) {
35        let mut record = FxHashSet::default();
36        if self.values[aliaset_idx].may_drop
37            && (!self.values[aliaset_idx].is_ptr()
38                || self.values[aliaset_idx].local != local
39                || is_func_call)
40            && self.exist_dead(aliaset_idx, &mut record, false)
41            && !self.bug_records.uaf_bugs.contains(&span)
42        {
43            self.bug_records.uaf_bugs.insert(span.clone());
44            rap_debug!("UAF bug for {:?}", self.values[aliaset_idx]);
45        }
46    }
47
48    pub fn exist_dead(
49        &mut self,
50        node: usize,
51        record: &mut FxHashSet<usize>,
52        dangling: bool,
53    ) -> bool {
54        if node >= self.values.len() {
55            return false;
56        }
57        //if is a dangling pointer check, only check the pointer type varible.
58        if self.values[node].is_alive() == false
59            && (dangling && self.values[node].is_ptr() || !dangling)
60        {
61            return true;
62        }
63        record.insert(node);
64        if self.union_has_alias(node) {
65            // for i in self.values[node].alias.clone().into_iter() {
66            //     if i != node && record.contains(&i) == false && self.exist_dead(i, record, dangling)
67            //     {
68            //         return true;
69            //     }
70            // }
71            for i in 0..self.alias_set.len() {
72                if i != node && !self.union_is_same(i, node) {
73                    continue;
74                }
75                if record.contains(&i) == false && self.exist_dead(i, record, dangling) {
76                    return true;
77                }
78            }
79        }
80        for i in self.values[node].fields.clone().into_iter() {
81            if record.contains(&i.1) == false && self.exist_dead(i.1, record, dangling) {
82                return true;
83            }
84        }
85        return false;
86    }
87
88    pub fn is_dangling(&mut self, local: usize) -> bool {
89        let mut record = FxHashSet::default();
90        return self.exist_dead(local, &mut record, local != 0);
91    }
92
93    pub fn df_check(&mut self, drop: usize, span: Span) -> bool {
94        let root = self.values[drop].local;
95        if self.values[drop].is_alive() == false
96            && self.bug_records.df_bugs.contains_key(&root) == false
97        {
98            self.bug_records.df_bugs.insert(root, span.clone());
99            rap_debug!("DF bug for {:?}", drop);
100        }
101        return self.values[drop].is_alive() == false;
102    }
103
104    pub fn dp_check(&mut self, current_block: &BlockNode<'tcx>) {
105        match current_block.is_cleanup {
106            true => {
107                for i in 0..self.arg_size {
108                    if self.values[i + 1].is_ptr() && self.is_dangling(i + 1) {
109                        self.bug_records.dp_bugs_unwind.insert(self.span);
110                        rap_debug!("DP bug for {:?}", self.values[i + 1]);
111                    }
112                }
113            }
114            false => {
115                if self.values[0].may_drop && self.is_dangling(0) {
116                    self.bug_records.dp_bugs.insert(self.span);
117                    rap_debug!("DP bug for {:?}", self.values[0]);
118                } else {
119                    for i in 0..self.arg_size {
120                        if self.values[i + 1].is_ptr() && self.is_dangling(i + 1) {
121                            self.bug_records.dp_bugs.insert(self.span);
122                            rap_debug!("DP bug for {:?}", self.values[i + 1]);
123                        }
124                    }
125                }
126            }
127        }
128    }
129
130    pub fn dead_node(&mut self, drop: usize, birth: usize, info: &SourceInfo, alias: bool) {
131        //Rc drop
132        if self.values[drop].is_corner_case() {
133            return;
134        }
135        //check if there is a double free bug.
136        if !alias && self.df_check(drop, info.span) {
137            return;
138        }
139        if self.dead_record[drop] {
140            return;
141        } else {
142            self.dead_record[drop] = true;
143        }
144        //drop their alias
145        if self.alias_set[drop] != drop {
146            // for i in self.values[drop].alias.clone().into_iter() {
147            //     if self.values[i].is_ref() {
148            //         continue;
149            //     }
150            //     self.dead_node(i, birth, info, true);
151            // }
152            for i in 0..self.values.len() {
153                if !self.union_is_same(drop, i) || i == drop || self.values[i].is_ref() {
154                    continue;
155                }
156                self.dead_node(i, birth, info, true);
157            }
158        }
159        //drop the fields of the root node.
160        //alias flag is used to avoid the fields of the alias are dropped repeatly.
161        if alias == false {
162            for i in self.values[drop].fields.clone().into_iter() {
163                if self.values[drop].is_tuple() == true && self.values[i.1].need_drop == false {
164                    continue;
165                }
166                self.dead_node(i.1, birth, info, false);
167            }
168        }
169        //SCC.
170        if self.values[drop].birth < birth as isize && self.values[drop].may_drop {
171            self.values[drop].dead();
172        }
173    }
174
175    pub fn get_field_seq(&self, value: &ValueNode) -> Vec<usize> {
176        let mut field_id_seq = vec![];
177        let mut node_ref = value;
178        while node_ref.field_id != usize::MAX {
179            field_id_seq.push(node_ref.field_id);
180            node_ref = &self.values[value.father];
181        }
182        return field_id_seq;
183    }
184}