1use super::bug_records::*;
2use super::drop::*;
3use crate::analysis::alias::default::graph::AliasGraph;
4use crate::analysis::alias::default::types::ValueKind;
5use rustc_span::Span;
6
7pub fn sync_drop_record(graph: &AliasGraph, drop_record: &mut Vec<DropRecord>) {
14 let target_len = graph.values.len();
15 while drop_record.len() < target_len {
16 let new_idx = drop_record.len();
17 let father = if new_idx < graph.values.len() {
18 graph.values[new_idx].father.clone()
19 } else {
20 None
21 };
22 drop_record.push(
23 if let Some(ref fi) = father
24 && drop_record[fi.father_value_id].is_dropped
25 {
26 DropRecord::from(new_idx, &drop_record[fi.father_value_id])
27 } else {
28 DropRecord::false_record(new_idx)
29 },
30 );
31 }
32}
33
34pub fn clear_drop_info(graph: &AliasGraph, drop_record: &mut Vec<DropRecord>, value_idx: usize) {
35 rap_debug!("clear_drop: value_idx = {}", value_idx);
36 drop_record[value_idx].clear();
37 clear_field_drop(graph, drop_record, value_idx);
38 clear_father_drop(graph, drop_record, value_idx);
39}
40
41pub fn uaf_check(
42 graph: &AliasGraph,
43 drop_record: &mut Vec<DropRecord>,
44 bug_records: &mut BugRecords,
45 value_idx: usize,
46 bb_idx: usize,
47 span: Span,
48 is_fncall: bool,
49) {
50 let local = graph.values[value_idx].local;
51 rap_debug!(
52 "uaf_check, idx: {:?}, local: {:?}, drop_record: {:?}",
53 value_idx,
54 local,
55 drop_record[value_idx],
56 );
57 if !graph.value_may_drop(value_idx) {
58 return;
59 }
60 if graph.value_is_ptr(value_idx) && !is_fncall {
61 return;
62 }
63 let Some(confidence) = check_drop_status(graph, drop_record, value_idx) else {
64 return;
65 };
66 if bug_records.uaf_bugs.contains_key(&local) {
67 return;
68 }
69 let drop_spot = drop_record[value_idx].drop_spot;
70 if let Some(t) = bug_records.try_merge_pair(drop_spot, bb_idx, BugType::UseAfterFree) {
71 let bug = make_bug(
72 &drop_record[value_idx],
73 LocalSpot::new(bb_idx, local),
74 span.clone(),
75 confidence,
76 t,
77 );
78 rap_warn!("Find a use-after-free bug {:?}; add to records", bug);
79 bug_records.uaf_bugs.insert(local, bug);
80 }
81}
82
83pub fn check_drop_status(
86 graph: &AliasGraph,
87 drop_record: &mut Vec<DropRecord>,
88 idx: usize,
89) -> Option<usize> {
90 fetch_drop_info(graph, drop_record, idx);
91 let mut fully_dropped = true;
92 if !drop_record[idx].is_dropped {
93 fully_dropped = false;
94 if !drop_record[idx].has_dropped_field {
95 return None;
96 }
97 }
98 let kind = graph
99 .value_to_slot_idx(idx)
100 .map(|si| graph.pts_graph.slot_kind(si))
101 .unwrap_or(ValueKind::Adt);
102 Some(rate_confidence(kind, fully_dropped))
103}
104
105fn rate_confidence(kind: ValueKind, fully_dropped: bool) -> usize {
106 match (kind, fully_dropped) {
107 (ValueKind::SpecialPtr, _) => 0,
108 (_, true) => 99,
109 (_, false) => 50,
110 }
111}
112
113pub fn make_bug(
114 drop_record: &DropRecord,
115 trigger_info: LocalSpot,
116 span: Span,
117 confidence: usize,
118 bug_type: BugType,
119) -> TyBug {
120 TyBug {
121 drop_spot: drop_record.drop_spot,
122 trigger_info,
123 span,
124 confidence,
125 bug_type,
126 }
127}
128
129pub fn push_drop_info(
132 graph: &AliasGraph,
133 drop_record: &mut Vec<DropRecord>,
134 value_idx: usize,
135 drop_spot: LocalSpot,
136) {
137 push_drop_bottom_up(graph, drop_record, value_idx, drop_spot);
138 push_drop_top_down(graph, drop_record, value_idx, drop_spot);
139 push_drop_through_move(graph, drop_record, value_idx, drop_spot);
140}
141
142fn push_drop_through_move(
143 graph: &AliasGraph,
144 drop_record: &mut Vec<DropRecord>,
145 value_idx: usize,
146 drop_spot: LocalSpot,
147) {
148 if let Some(&src) = graph.owner_transfers.get(&value_idx) {
149 if !drop_record[src].is_dropped {
150 drop_record[src] = DropRecord::new(src, true, drop_spot);
151 }
152 }
153 for (&dest, &src) in graph.owner_transfers.iter() {
154 if src == value_idx && !drop_record[dest].is_dropped {
155 drop_record[dest] = DropRecord::new(dest, true, drop_spot);
156 }
157 }
158}
159
160fn push_drop_bottom_up(
161 graph: &AliasGraph,
162 drop_record: &mut Vec<DropRecord>,
163 value_idx: usize,
164 drop_spot: LocalSpot,
165) {
166 rap_debug!("push_drop_bottom_up: value_idx = {}", value_idx);
167 let mut father = graph.values[value_idx].father.clone();
168 let mut prop_chain = vec![value_idx];
169 while let Some(father_info) = father {
170 let father_idx = father_info.father_value_id;
171 drop_record[father_idx].has_dropped_field = true;
172 if !drop_record[father_idx].is_dropped {
173 prop_chain.push(father_idx);
174 drop_record[father_idx].prop_chain = prop_chain.clone();
175 drop_record[father_idx].drop_spot = drop_spot;
176 }
177 rap_debug!("{:?}", drop_record[father_idx]);
178 father = graph.values[father_idx].father.clone();
179 }
180}
181
182fn push_drop_top_down(
183 graph: &AliasGraph,
184 drop_record: &mut Vec<DropRecord>,
185 value_idx: usize,
186 drop_spot: LocalSpot,
187) {
188 rap_debug!("push_drop_top_down: value_idx = {}", value_idx);
189 let mut prop_chain = vec![value_idx];
190 for (_field_id, field_value_id) in graph.values[value_idx].fields.clone() {
191 if graph
192 .value_to_slot_idx(field_value_id)
193 .is_some_and(|si| graph.pts_graph.slot_kind(si) == ValueKind::Ref)
194 {
195 continue;
196 }
197 drop_record[field_value_id] = DropRecord::new(field_value_id, true, drop_spot);
198 prop_chain.push(field_value_id);
199 drop_record[field_value_id].prop_chain = prop_chain.clone();
200 rap_debug!("{:?}", drop_record[field_value_id]);
201 push_drop_top_down(graph, drop_record, field_value_id, drop_spot);
202 }
203}
204
205fn fetch_drop_info(graph: &AliasGraph, drop_record: &mut Vec<DropRecord>, value_idx: usize) {
208 fetch_drop_from_bottom(graph, drop_record, value_idx);
209 fetch_drop_from_top(graph, drop_record, value_idx);
210 fetch_drop_from_alias(graph, drop_record, value_idx);
211 fetch_drop_from_pointee(graph, drop_record, value_idx);
212}
213
214fn fetch_drop_from_pointee(
215 graph: &AliasGraph,
216 drop_record: &mut Vec<DropRecord>,
217 value_idx: usize,
218) {
219 if !graph.value_is_ptr(value_idx) {
220 return;
221 }
222 if drop_record[value_idx].is_dropped || drop_record[value_idx].has_dropped_field {
223 return;
224 }
225 let Some(slot_idx) = graph.value_to_slot_idx(value_idx) else {
226 return;
227 };
228 let pointees: Vec<usize> = graph
229 .pts_graph
230 .direct_pointees(slot_idx)
231 .filter_map(|loc| match loc {
232 crate::analysis::points_to::slot::AbstractLoc::Slot(s) => {
233 if s.fields.is_empty() && s.local < graph.values.len() {
234 Some(s.local)
235 } else {
236 for (v, _) in graph.values.iter().enumerate() {
237 if let Some(v_slot) = graph.value_to_slot_idx(v) {
238 if graph
239 .pts_graph
240 .get_slot(v_slot)
241 .is_some_and(|vs| vs.local == s.local && vs.fields == s.fields)
242 {
243 return Some(v);
244 }
245 }
246 }
247 None
248 }
249 }
250 _ => None,
251 })
252 .collect();
253 for &pointee_vidx in &pointees {
254 if pointee_vidx == value_idx {
255 continue;
256 }
257 check_drop_status(graph, drop_record, pointee_vidx);
258 if drop_record[pointee_vidx].is_dropped || drop_record[pointee_vidx].has_dropped_field {
259 drop_record[value_idx] = drop_record[pointee_vidx].clone();
260 drop_record[value_idx].value_index = value_idx;
261 drop_record[value_idx].prop_chain.push(value_idx);
262 break;
263 }
264 }
265}
266
267fn fetch_drop_from_bottom(graph: &AliasGraph, drop_record: &mut Vec<DropRecord>, value_idx: usize) {
268 rap_debug!("fetch_drop_from_bottom: value_idx = {}", value_idx);
269 for (_field_id, field_value_id) in graph.values[value_idx].fields.clone() {
270 rap_debug!("{:?}", drop_record[field_value_id]);
271 fetch_drop_from_alias(graph, drop_record, field_value_id);
272 if drop_record[field_value_id].is_dropped {
273 push_drop_bottom_up(
274 graph,
275 drop_record,
276 field_value_id,
277 drop_record[field_value_id].drop_spot,
278 );
279 rap_debug!("{:?}", drop_record[value_idx]);
280 break;
281 }
282 fetch_drop_from_bottom(graph, drop_record, field_value_id);
283 }
284 if drop_record[value_idx].is_dropped || drop_record[value_idx].has_dropped_field {
285 return;
286 }
287 fetch_drop_from_pts_fields(graph, drop_record, value_idx);
288}
289
290fn fetch_drop_from_pts_fields(
291 graph: &AliasGraph,
292 drop_record: &mut Vec<DropRecord>,
293 value_idx: usize,
294) {
295 let Some(slot_idx) = graph.value_to_slot_idx(value_idx) else {
296 return;
297 };
298 let base_slot = match graph.pts_graph.get_slot(slot_idx) {
299 Some(s) => s.clone(),
300 None => return,
301 };
302 for i in 0..graph.pts_graph.slot_count() {
303 let Some(child_slot) = graph.pts_graph.get_slot(i) else {
304 continue;
305 };
306 if child_slot.local != base_slot.local
307 || child_slot.fields.len() != base_slot.fields.len() + 1
308 {
309 continue;
310 }
311 if !child_slot.fields.starts_with(&base_slot.fields) {
312 continue;
313 }
314 let mut found = false;
315 for (v, dr) in drop_record.iter().enumerate() {
316 if !dr.is_dropped {
317 continue;
318 }
319 if let Some(drop_slot) = graph.value_to_slot_idx(v) {
320 if graph.pts_graph.may_alias(i, drop_slot) {
321 drop_record[value_idx].has_dropped_field = true;
322 drop_record[value_idx].drop_spot = drop_record[v].drop_spot.clone();
323 found = true;
324 break;
325 }
326 }
327 }
328 if found {
329 break;
330 }
331 }
332}
333
334fn fetch_drop_from_top(graph: &AliasGraph, drop_record: &mut Vec<DropRecord>, value_idx: usize) {
335 rap_debug!("fetch_drop_from_top: value_idx = {}", value_idx);
336 let mut father = graph.values[value_idx].father.clone();
337 while let Some(father_info) = father {
338 let father_idx = father_info.father_value_id;
339 fetch_drop_from_alias(graph, drop_record, father_idx);
340 if drop_record[father_idx].is_dropped {
341 push_drop_top_down(
342 graph,
343 drop_record,
344 father_idx,
345 drop_record[father_idx].drop_spot,
346 );
347 rap_debug!("{:?}", drop_record[value_idx]);
348 break;
349 }
350 father = graph.values[father_idx].father.clone();
351 }
352}
353
354fn fetch_drop_from_alias(graph: &AliasGraph, drop_record: &mut Vec<DropRecord>, value_idx: usize) {
355 rap_debug!("fetch_drop_from_alias: value_idx = {}", value_idx);
356 if let Some(aliases) = get_alias_set(graph, value_idx) {
357 for idx in aliases {
358 if drop_record[idx].is_dropped {
359 drop_record[value_idx] = drop_record[idx].clone();
360 drop_record[value_idx].value_index = value_idx;
361 drop_record[value_idx].prop_chain.push(value_idx);
362 }
363 }
364 }
365}
366
367fn clear_father_drop(graph: &AliasGraph, drop_record: &mut Vec<DropRecord>, value_idx: usize) {
370 rap_debug!("clear_drop_father: value_idx = {}", value_idx);
371 let mut father = graph.values[value_idx].father.clone();
372 while let Some(father_info) = father {
373 let father_idx = father_info.father_value_id;
374 if !drop_record[father_idx].is_dropped {
375 drop_record[father_idx].clear();
376 }
377 father = graph.values[father_idx].father.clone();
378 }
379}
380
381fn clear_field_drop(graph: &AliasGraph, drop_record: &mut Vec<DropRecord>, value_idx: usize) {
382 rap_debug!("clear_field_drop: value_idx = {}", value_idx);
383 for (_field_id, field_value_id) in graph.values[value_idx].fields.clone() {
384 drop_record[field_value_id].clear();
385 clear_field_drop(graph, drop_record, field_value_id);
386 }
387}
388
389fn get_alias_set(graph: &AliasGraph, e: usize) -> Option<Vec<usize>> {
392 graph.get_alias_set(e)
393}