rapx/analysis/safedrop/
check_bugs.rs1use 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 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 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 if self.values[drop].is_corner_case() {
125 return;
126 }
127 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 if self.alias_set[drop] != drop {
138 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 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 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}