rapx/analysis/safedrop/
check_bugs.rs1use 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 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 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 if self.values[drop].is_corner_case() {
133 return;
134 }
135 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 if self.alias_set[drop] != drop {
146 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 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 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}