rapx/analysis/safetyflow_analysis/
std_analysis.rs1use super::chain::*;
2use super::{
3 SafetyFlowAnalysis, safetyflow_graph::SafetyFlowGraph, safetyflow_unit::BasicUnitCounts,
4};
5use crate::helpers::{draw_dot::render_dot_graphs, fn_info::*, show_mir::display_mir};
6use rustc_hir::{Safety, def::DefKind, def_id::DefId};
7use rustc_middle::ty::Visibility;
8use rustc_span::Symbol;
9use std::collections::HashSet;
10
11impl<'tcx> SafetyFlowAnalysis<'tcx> {
12 pub fn audit_std_unsafe(&mut self) {
13 let all_std_fn_def = get_all_std_fns_by_rustc_public(self.tcx);
14 let symbol = Symbol::intern("Vec");
16 let vec_def_id = self.tcx.get_diagnostic_item(symbol).unwrap();
17 for &def_id in &all_std_fn_def {
18 let adt_def = get_adt_def_id_by_adt_method(self.tcx, def_id);
19 if adt_def.is_some() && adt_def.unwrap() == vec_def_id {
20 self.insert_upg(def_id);
21 }
22 }
23 if self.draw {
24 self.render_dot();
25 }
26 }
27
28 pub fn render_dot(&mut self) {
29 let mut dot_strs = Vec::new();
30 for upg in &self.units {
31 let dot_str = SafetyFlowGraph::generate_dot_from_unit(self.tcx, upg);
32 let caller_name = get_cleaned_def_path_name(self.tcx, upg.caller.def_id);
33 dot_strs.push((caller_name, dot_str));
34 }
35 render_dot_graphs(dot_strs);
36 }
37
38 pub fn get_chains(&mut self) {
39 let v_fn_def = self.tcx.mir_keys(());
40
41 for local_def_id in v_fn_def {
42 let def_id = local_def_id.to_def_id();
43 if !check_visibility(self.tcx, def_id) {
44 continue;
45 }
46 if get_cleaned_def_path_name(self.tcx, def_id) == "std::boxed::Box::<T>::from_raw" {
47 let body = self.tcx.mir_built(*local_def_id).steal();
48 display_mir(def_id, &body);
49 }
50 let chains = get_all_std_unsafe_chains(self.tcx, def_id);
51 let valid_chains: Vec<Vec<String>> = chains
52 .into_iter()
53 .filter(|chain| {
54 if chain.len() > 1 {
55 return true;
56 }
57 if chain.len() == 1 {
58 if check_safety(self.tcx, def_id) == Safety::Unsafe {
59 return true;
60 }
61 }
62 false
63 })
64 .collect();
65
66 print_unsafe_chains(&valid_chains);
67 }
68 }
69
70 pub fn get_units_data(&mut self) {
71 let mut counts = BasicUnitCounts::default();
72 let def_id_sets = self.tcx.mir_keys(());
73 for local_def_id in def_id_sets {
74 let def_id = local_def_id.to_def_id();
75 if self.tcx.def_kind(def_id) == DefKind::Fn
76 || self.tcx.def_kind(def_id) == DefKind::AssocFn
77 {
78 self.insert_upg(def_id);
79 }
80 }
81 for upg in &self.units {
82 upg.count_basic_units(&mut counts);
83 }
84 }
85
86 pub fn process_def_id(
87 &mut self,
88 def_id: DefId,
89 visited: &mut HashSet<DefId>,
90 unsafe_fn: &mut HashSet<DefId>,
91 ) {
92 if !visited.insert(def_id) {
93 return;
94 }
95 match self.tcx.def_kind(def_id) {
96 DefKind::Fn | DefKind::AssocFn => {
97 if check_safety(self.tcx, def_id) == Safety::Unsafe
98 && self.tcx.visibility(def_id) == Visibility::Public
99 {
100 unsafe_fn.insert(def_id);
101 self.insert_upg(def_id);
102 }
103 }
104 DefKind::Mod => {
105 for child in self.tcx.module_children(def_id) {
106 if let Some(child_def_id) = child.res.opt_def_id() {
107 self.process_def_id(child_def_id, visited, unsafe_fn);
108 }
109 }
110 }
111 DefKind::Impl { of_trait: _ } => {
112 for item in self.tcx.associated_item_def_ids(def_id) {
113 self.process_def_id(*item, visited, unsafe_fn);
114 }
115 }
116 DefKind::Struct => {
117 let impls = self.tcx.inherent_impls(def_id);
118 for impl_def_id in impls {
119 self.process_def_id(*impl_def_id, visited, unsafe_fn);
120 }
121 }
122 DefKind::Ctor(_of, _kind) => {
123 if self.tcx.is_mir_available(def_id) {
124 let _mir = self.tcx.optimized_mir(def_id);
125 }
126 }
127 _ => {
128 }
130 }
131 }
132}