rapx/analysis/safedrop/
check_bugs.rs

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