rapx/analysis/safetyflow_analysis/
std_analysis.rs

1use 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        // Specific task for vec;
15        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                // println!("{:?}",tcx.def_kind(def_id));
129            }
130        }
131    }
132}