1use super::{bug_records::TyBug, graph::*};
2use crate::{
3 analysis::{
4 core::alias_analysis::default::{types::TyKind, value::*},
5 utils::fn_info::{convert_alias_to_sets, generate_mir_cfg_dot},
6 },
7 utils::source::*,
8};
9use rustc_middle::mir::SourceInfo;
10use rustc_span::{Span, symbol::Symbol};
11
12impl<'tcx> SafeDropGraph<'tcx> {
13 pub fn report_bugs(&self) {
14 rap_debug!(
15 "report bugs, id: {:?}, uaf: {:?}",
16 self.mop_graph.def_id,
17 self.bug_records.uaf_bugs
18 );
19 let filename = get_filename(self.mop_graph.tcx, self.mop_graph.def_id);
20 match filename {
21 Some(filename) => {
22 if filename.contains(".cargo") {
23 return;
24 }
25 }
26 None => {}
27 }
28 if self.bug_records.is_bug_free() {
29 return;
30 }
31 let fn_name = match get_name(self.mop_graph.tcx, self.mop_graph.def_id) {
32 Some(name) => name,
33 None => Symbol::intern("no symbol available"),
34 };
35 let body = self.mop_graph.tcx.optimized_mir(self.mop_graph.def_id);
36 self.bug_records
37 .df_bugs_output(body, fn_name, self.mop_graph.span);
38 self.bug_records
39 .uaf_bugs_output(body, fn_name, self.mop_graph.span);
40 self.bug_records
41 .dp_bug_output(body, fn_name, self.mop_graph.span);
42 let _ = generate_mir_cfg_dot(
43 self.mop_graph.tcx,
44 self.mop_graph.def_id,
45 &self.mop_graph.alias_set,
46 );
47 rap_debug!(
48 "Alias: {:?}",
49 convert_alias_to_sets(self.mop_graph.alias_set.clone())
50 );
51 }
52
53 pub fn uaf_check(&mut self, bb_idx: usize, idx: usize, span: Span, is_fncall: bool) {
54 let local = self.mop_graph.values[idx].local;
55 if !self.mop_graph.values[idx].may_drop {
56 return;
57 }
58 rap_debug!(
59 "uaf_check, idx: {:?}, local: {:?}, drop_record: {:?}, local_drop_record: {:?}",
60 idx,
61 local,
62 self.drop_record[idx],
63 self.drop_record[local],
64 );
65
66 self.sync_drop_record(idx);
67 rap_debug!(
68 "after sync drop record: idx: {:?}, local: {:?}, drop_record: {:?}",
69 idx,
70 local,
71 self.drop_record[idx]
72 );
73 if !self.drop_record[idx].is_dropped {
74 return;
75 }
76 rap_debug!(
77 "is_ptr: {}, is_fn_call: {}",
78 self.mop_graph.values[idx].is_ptr(),
79 is_fncall
80 );
81 if self.mop_graph.values[idx].is_ptr() && !is_fncall {
82 return;
83 }
84
85 let confidence = match self.mop_graph.values[idx].kind {
86 TyKind::CornerCase => 0,
87 _ => 99,
88 };
89
90 let bug = TyBug {
91 drop_bb: self.drop_record[idx].drop_at_bb,
92 drop_id: self.drop_record[idx].drop_via_local,
93 trigger_bb: bb_idx,
94 trigger_id: local,
95 span: span.clone(),
96 confidence,
97 };
98 rap_debug!("Find use-after-free bug {:?}; add to records", bug);
99 if self.bug_records.uaf_bugs.contains_key(&local) {
100 return;
101 }
102 self.bug_records.uaf_bugs.insert(local, bug);
103 rap_debug!("Find use-after-free bug {:?}; add to records", local);
104 }
105
106 pub fn sync_drop_record(&mut self, idx: usize) {
107 if idx >= self.mop_graph.values.len() {
108 return;
109 }
110 let local = self.mop_graph.values[idx].local;
111 if self.drop_record[local].is_dropped {
112 self.drop_record[idx] = self.drop_record[local];
113 }
114 let aliases = self.mop_graph.get_alias_set(local);
115 for i in aliases {
116 if self.drop_record[i].is_dropped {
117 self.drop_record[idx] = self.drop_record[i];
118 return;
119 }
120 }
121 }
122
123 pub fn df_check(&mut self, bb_idx: usize, idx: usize, span: Span, flag_cleanup: bool) -> bool {
124 let local = self.mop_graph.values[idx].local;
125 rap_debug!(
127 "df_check: bb_idx = {:?}, idx = {:?}, local = {:?}",
128 bb_idx,
129 idx,
130 local
131 );
132 rap_debug!(
133 "df_check: is alive? {:?}",
134 self.mop_graph.values[idx].is_alive()
135 );
136 if self.mop_graph.values[idx].is_alive() {
137 return false;
138 }
139 let confidence = match self.mop_graph.values[idx].kind {
140 TyKind::CornerCase => 0,
141 _ => 99,
142 };
143 let bug = TyBug {
144 drop_bb: self.drop_record[idx].drop_at_bb,
145 drop_id: self.drop_record[idx].drop_via_local,
146 trigger_bb: bb_idx,
147 trigger_id: local,
148 span: span.clone(),
149 confidence,
150 };
151
152 if flag_cleanup {
153 if !self.bug_records.df_bugs_unwind.contains_key(&local) {
154 self.bug_records.df_bugs_unwind.insert(local, bug);
155 rap_debug!(
156 "Find double free bug {} during unwinding; add to records.",
157 local
158 );
159 }
160 } else {
161 if !self.bug_records.df_bugs.contains_key(&local) {
162 self.bug_records.df_bugs.insert(local, bug);
163 rap_debug!("Find double free bug {}; add to records.", local);
164 }
165 }
166 return true;
167 }
168
169 pub fn dp_check(&mut self, flag_cleanup: bool) {
170 if flag_cleanup {
171 for arg_idx in 1..self.mop_graph.arg_size + 1 {
172 if self.mop_graph.values[arg_idx].is_ptr() && self.drop_record[arg_idx].is_dropped {
173 let confidence = match self.mop_graph.values[arg_idx].kind {
174 TyKind::CornerCase => 0,
175 _ => 99,
176 };
177 let bug = TyBug {
178 drop_bb: self.drop_record[arg_idx].drop_at_bb,
179 drop_id: self.drop_record[arg_idx].drop_via_local,
180 trigger_bb: usize::MAX,
181 trigger_id: arg_idx,
182 span: self.mop_graph.span.clone(),
183 confidence,
184 };
185 self.bug_records.dp_bugs_unwind.insert(arg_idx, bug);
186 rap_debug!(
187 "Find dangling pointer {} during unwinding; add to record.",
188 arg_idx
189 );
190 }
191 }
192 } else {
193 if self.mop_graph.values[0].may_drop && self.drop_record[0].is_dropped {
194 let confidence = match self.mop_graph.values[0].kind {
195 TyKind::CornerCase => 0,
196 _ => 99,
197 };
198 let bug = TyBug {
199 drop_bb: self.drop_record[0].drop_at_bb,
200 drop_id: self.drop_record[0].drop_via_local,
201 trigger_bb: usize::MAX,
202 trigger_id: 0,
203 span: self.mop_graph.span.clone(),
204 confidence,
205 };
206 self.bug_records.dp_bugs.insert(0, bug);
207 rap_debug!("Find dangling pointer 0; add to record.");
208 } else {
209 for arg_idx in 0..self.mop_graph.arg_size + 1 {
210 if self.mop_graph.values[arg_idx].is_ptr()
211 && self.drop_record[arg_idx].is_dropped
212 {
213 let confidence = match self.mop_graph.values[arg_idx].kind {
214 TyKind::CornerCase => 0,
215 _ => 99,
216 };
217 let bug = TyBug {
218 drop_bb: self.drop_record[arg_idx].drop_at_bb,
219 drop_id: self.drop_record[arg_idx].drop_via_local,
220 trigger_bb: usize::MAX,
221 trigger_id: arg_idx,
222 span: self.mop_graph.span.clone(),
223 confidence,
224 };
225 self.bug_records.dp_bugs.insert(arg_idx, bug);
226 rap_debug!("Find dangling pointer {}; add to record.", arg_idx);
227 }
228 }
229 }
230 }
231 }
232
233 pub fn add_to_drop_record(
238 &mut self,
239 idx: usize, via_idx: usize, birth: usize,
242 info: &SourceInfo,
243 flag_inprocess: bool,
244 bb_idx: usize,
245 flag_cleanup: bool,
246 ) {
247 if self.mop_graph.values[idx].is_corner_case() {
249 return;
250 }
251 if !flag_inprocess && self.df_check(bb_idx, idx, self.mop_graph.span, flag_cleanup) {
253 return;
254 }
255 if !self.drop_record[idx].is_dropped {
256 self.drop_record[idx] =
257 DropRecord::new(true, bb_idx, self.mop_graph.values[via_idx].local);
258 rap_debug!(
259 "add_to_drop_record: idx = {}, {:?}",
260 idx,
261 self.drop_record[idx]
262 );
263 for i in 0..self.mop_graph.values.len() {
265 if !self.mop_graph.union_is_same(idx, i)
266 || i == idx
267 || self.mop_graph.values[i].is_ref()
268 {
269 continue;
270 }
271 self.add_to_drop_record(
272 i,
273 self.mop_graph.values[via_idx].local,
274 birth,
275 info,
276 true,
277 bb_idx,
278 flag_cleanup,
279 );
280 }
281 } else {
282 return;
283 }
284 if !flag_inprocess {
287 for (_, field_idx) in self.mop_graph.values[idx].fields.clone() {
288 if self.mop_graph.values[idx].is_tuple()
289 && !self.mop_graph.values[field_idx].need_drop
290 {
291 continue;
292 }
293 self.add_to_drop_record(
294 field_idx,
295 self.mop_graph.values[via_idx].local,
296 birth,
297 info,
298 false,
299 bb_idx,
300 flag_cleanup,
301 );
302 }
303 }
304 if self.mop_graph.values[idx].birth < birth as isize && self.mop_graph.values[idx].may_drop
306 {
307 self.mop_graph.values[idx].drop();
308 }
309 }
310
311 pub fn get_field_seq(&self, value: &Value) -> Vec<usize> {
312 let mut field_id_seq = vec![];
313 let mut node_ref = value;
314 while node_ref.field_id != usize::MAX {
315 field_id_seq.push(node_ref.field_id);
316 node_ref = &self.mop_graph.values[value.father];
317 }
318 return field_id_seq;
319 }
320}