rapx/analysis/unsafety_isolation/
std_unsafety_isolation.rs

1use super::{
2    generate_dot::{NodeType, UigUnit},
3    UnsafetyIsolationCheck,
4};
5use crate::analysis::unsafety_isolation::draw_dot::render_dot_graphs;
6use crate::analysis::utils::fn_info::*;
7use rustc_hir::def::DefKind;
8use rustc_hir::def_id::DefId;
9use rustc_middle::mir::Local;
10use rustc_middle::ty::Visibility;
11use rustc_middle::{ty, ty::TyCtxt};
12use std::collections::HashMap;
13use std::collections::HashSet;
14
15impl<'tcx> UnsafetyIsolationCheck<'tcx> {
16    pub fn handle_std_unsafe(&mut self) {
17        self.get_all_std_unsafe_def_id_by_treat_std_as_local_crate(self.tcx);
18        // self.get_units_data(self.tcx);
19        let mut dot_strs = Vec::new();
20        for uig in &self.uigs {
21            // let dot_str = uig.generate_dot_str();
22            if get_cleaned_def_path_name(self.tcx, uig.caller.0).contains("core::slice::")
23                && check_visibility(self.tcx, uig.caller.0)
24            {
25                let dot_str = uig.generate_dot_str();
26                dot_strs.push(dot_str);
27                // uig.print_self(self.tcx);
28            }
29        }
30        for uig in &self.single {
31            // let dot_str = uig.generate_dot_str();
32            if get_cleaned_def_path_name(self.tcx, uig.caller.0).contains("core::slice::")
33                && check_visibility(self.tcx, uig.caller.0)
34            {
35                let dot_str = uig.generate_dot_str();
36                dot_strs.push(dot_str);
37                // uig.print_self(self.tcx);
38            }
39        }
40        // println!("single {:?}",self.uigs.len());
41        // println!("single {:?}",self.single.len());
42        render_dot_graphs(dot_strs);
43        // println!("{:?}", dot_strs);
44    }
45
46    pub fn get_all_std_unsafe_def_id_by_treat_std_as_local_crate(
47        &mut self,
48        tcx: TyCtxt<'tcx>,
49    ) -> HashSet<DefId> {
50        let mut unsafe_fn = HashSet::new();
51        let mut total_cnt = 0;
52        let mut api_cnt = 0;
53        let mut sp_cnt = 0;
54        let def_id_sets = tcx.mir_keys(());
55        let mut sp_count_map: HashMap<String, usize> = HashMap::new();
56
57        for local_def_id in def_id_sets {
58            let def_id = local_def_id.to_def_id();
59            if Self::filter_mir(def_id) {
60                continue;
61            }
62            if tcx.def_kind(def_id) == DefKind::Fn || tcx.def_kind(def_id) == DefKind::AssocFn {
63                if check_safety(tcx, def_id)
64                    && !get_cleaned_def_path_name(self.tcx, def_id).contains("intrinsic")
65                {
66                    let sp_set = get_sp(tcx, def_id);
67                    if !sp_set.is_empty() {
68                        unsafe_fn.insert(def_id);
69                        let mut flag = false;
70                        for sp in &sp_set {
71                            if sp.is_empty()
72                                || sp == "Function_sp"
73                                || sp == "System_sp"
74                                || sp == "ValidSlice"
75                            {
76                                flag = true;
77                            }
78                        }
79                        if !flag {
80                            api_cnt += 1;
81                            sp_cnt += sp_set.len();
82                        }
83                        total_cnt += 1;
84                        // println!("unsafe fn : {:?}", get_cleaned_def_path_name(self.tcx, def_id));
85                    }
86                    for sp in sp_set {
87                        *sp_count_map.entry(sp).or_insert(0) += 1;
88                    }
89                    // self.check_params(def_id);
90                }
91                self.insert_uig(def_id, get_callees(tcx, def_id), get_cons(tcx, def_id));
92            }
93        }
94        // self.analyze_struct();
95        // self.analyze_uig();
96        // self.get_units_data(self.tcx);
97        // for (sp, count) in &sp_count_map {
98        //     println!("SP: {}, Count: {}", sp, count);
99        // }
100        println!(
101            "count : {:?} and {:?}, sp cnt : {}",
102            total_cnt, api_cnt, sp_cnt
103        );
104        // println!("unsafe fn len {}", unsafe_fn.len());
105        unsafe_fn
106    }
107
108    pub fn check_params(&self, def_id: DefId) {
109        let body = self.tcx.optimized_mir(def_id);
110        let locals = body.local_decls.clone();
111        let fn_sig = self.tcx.fn_sig(def_id).skip_binder();
112        let param_len = fn_sig.inputs().skip_binder().len();
113        let return_ty = fn_sig.output().skip_binder();
114        for idx in 1..param_len + 1 {
115            let local_ty = locals[Local::from(idx)].ty;
116            if is_ptr(local_ty) && !return_ty.is_unit() {
117                println!("{:?}", get_cleaned_def_path_name(self.tcx, def_id));
118            }
119        }
120    }
121
122    pub fn analyze_uig(&self) {
123        let mut func_nc = Vec::new();
124        let mut func_pro1 = Vec::new();
125        let mut func_enc1 = Vec::new();
126        let mut m_nc = Vec::new();
127        let mut m_pro1 = Vec::new();
128        let mut m_enc1 = Vec::new();
129        for uig in &self.uigs {
130            if uig.caller.2 == 1 {
131                // method
132                if uig.caller.1 {
133                    m_pro1.push(uig.clone());
134                } else if !uig.caller.1 {
135                    m_enc1.push(uig.clone());
136                }
137            } else {
138                //function
139                if uig.caller.1 {
140                    func_pro1.push(uig.clone());
141                } else if !uig.caller.1 {
142                    func_enc1.push(uig.clone());
143                }
144            }
145        }
146        for uig in &self.single {
147            if uig.caller.2 == 1 {
148                // method
149                m_nc.push(uig.clone());
150            } else {
151                func_nc.push(uig.clone());
152            }
153        }
154        println!(
155            "func: {},{},{}, method: {},{},{}",
156            func_nc.len(),
157            func_pro1.len(),
158            func_enc1.len(),
159            m_nc.len(),
160            m_pro1.len(),
161            m_enc1.len()
162        );
163        println!("units: {}", self.uigs.len() + self.single.len());
164        // let mut no_unsafe_con = Vec::new();
165        // for uig in pro1 {
166        //     let mut flag = 0;
167        //     for con in &uig.caller_cons {
168        //         if con.1 == true {
169        //             flag = 1;
170        //         }
171        //     }
172        //     if flag == 0 {
173        //         no_unsafe_con.push(uig.clone());
174        //     }
175        // }
176    }
177
178    pub fn analyze_struct(&self) {
179        let mut cache = HashSet::new();
180        let mut s = 0;
181        let mut u = 0;
182        let mut e = 0;
183        let mut uc = 0;
184        let mut vi = 0;
185        for uig in &self.uigs {
186            self.get_struct(
187                uig.caller.0,
188                &mut cache,
189                &mut s,
190                &mut u,
191                &mut e,
192                &mut uc,
193                &mut vi,
194            );
195        }
196        for uig in &self.single {
197            self.get_struct(
198                uig.caller.0,
199                &mut cache,
200                &mut s,
201                &mut u,
202                &mut e,
203                &mut uc,
204                &mut vi,
205            );
206        }
207        println!("{},{},{},{}", s, u, e, vi);
208    }
209
210    pub fn get_struct(
211        &self,
212        def_id: DefId,
213        cache: &mut HashSet<DefId>,
214        s: &mut usize,
215        u: &mut usize,
216        e: &mut usize,
217        uc: &mut usize,
218        vi: &mut usize,
219    ) {
220        let tcx = self.tcx;
221        let mut safe_constructors = Vec::new();
222        let mut unsafe_constructors = Vec::new();
223        let mut unsafe_methods = Vec::new();
224        let mut safe_methods = Vec::new();
225        let mut mut_methods = Vec::new();
226        let mut struct_name = "".to_string();
227        let mut ty_flag = 0;
228        let mut vi_flag = false;
229        if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
230            if let Some(impl_id) = assoc_item.impl_container(tcx) {
231                // get struct ty
232                let ty = tcx.type_of(impl_id).skip_binder();
233                if let Some(adt_def) = ty.ty_adt_def() {
234                    if adt_def.is_union() {
235                        ty_flag = 1;
236                    } else if adt_def.is_enum() {
237                        ty_flag = 2;
238                    }
239                    let adt_def_id = adt_def.did();
240                    struct_name = get_cleaned_def_path_name(tcx, adt_def_id);
241                    if !cache.insert(adt_def_id) {
242                        return;
243                    }
244
245                    vi_flag = false;
246                    let impl_vec = get_impls_for_struct(self.tcx, adt_def_id);
247                    for impl_id in impl_vec {
248                        let associated_items = tcx.associated_items(impl_id);
249                        for item in associated_items.in_definition_order() {
250                            if let ty::AssocKind::Fn {
251                                name: _,
252                                has_self: _,
253                            } = item.kind
254                            {
255                                let item_def_id = item.def_id;
256                                if !get_sp(self.tcx, item_def_id).is_empty() {
257                                    vi_flag = true;
258                                }
259                                if get_type(self.tcx, item_def_id) == 0
260                                    && check_safety(self.tcx, item_def_id)
261                                // && get_sp(self.tcx, item_def_id).len() > 0
262                                {
263                                    unsafe_constructors.push(item_def_id);
264                                }
265                                if get_type(self.tcx, item_def_id) == 0
266                                    && !check_safety(self.tcx, item_def_id)
267                                {
268                                    safe_constructors.push(item_def_id);
269                                }
270                                if get_type(self.tcx, item_def_id) == 1
271                                    && check_safety(self.tcx, item_def_id)
272                                // && get_sp(self.tcx, item_def_id).len() > 0
273                                {
274                                    unsafe_methods.push(item_def_id);
275                                }
276                                if get_type(self.tcx, item_def_id) == 1
277                                    && !check_safety(self.tcx, item_def_id)
278                                {
279                                    if !get_callees(tcx, item_def_id).is_empty() {
280                                        safe_methods.push(item_def_id);
281                                    }
282                                }
283                                if get_type(self.tcx, item_def_id) == 1
284                                    && has_mut_self_param(self.tcx, item_def_id)
285                                {
286                                    mut_methods.push(item_def_id);
287                                }
288                            }
289                        }
290                    }
291                }
292            }
293        }
294        if struct_name == *""
295            || (unsafe_constructors.is_empty()
296                && unsafe_methods.is_empty()
297                && safe_methods.is_empty())
298        {
299            return;
300        }
301        if vi_flag {
302            *vi += 1;
303        }
304        if !unsafe_constructors.is_empty() {
305            *uc += 1;
306        }
307        if ty_flag == 0 {
308            *s += 1;
309            // println!("Struct:{:?}", struct_name);
310        }
311        if ty_flag == 1 {
312            *u += 1;
313            // println!("Union:{:?}", struct_name);
314        }
315        if ty_flag == 2 {
316            *e += 1;
317            // println!("Enum:{:?}", struct_name);
318        }
319
320        // println!("Safe Cons: {}", safe_constructors.len());
321        // for safe_cons in safe_constructors {
322        //     println!(" {:?}", get_cleaned_def_path_name(tcx, safe_cons));
323        // }
324        // println!("Unsafe Cons: {}", unsafe_constructors.len());
325        // for unsafe_cons in unsafe_constructors {
326        //     println!(" {:?}", get_cleaned_def_path_name(tcx, unsafe_cons));
327        // }
328        // println!("Unsafe Methods: {}", unsafe_methods.len());
329        // for method in unsafe_methods {
330        //     println!(" {:?}", get_cleaned_def_path_name(tcx, method));
331        // }
332        // println!("Safe Methods with unsafe callee: {}", safe_methods.len());
333        // for method in safe_methods {
334        //     println!(" {:?}", get_cleaned_def_path_name(tcx, method));
335        // }
336        // println!("Mut self Methods: {}", mut_methods.len());
337        // for method in mut_methods {
338        //     println!(" {:?}", get_cleaned_def_path_name(tcx, method));
339        // }
340    }
341
342    pub fn get_units_data(&mut self, tcx: TyCtxt<'tcx>) {
343        // [uf/um, sf-uf, sf-um, uf-uf, uf-um, um(sf)-uf, um(uf)-uf, um(sf)-um, um(uf)-um, sm(sf)-uf, sm(uf)-uf, sm(sf)-um, sm(uf)-um]
344        let mut basic_units_data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
345        let def_id_sets = tcx.mir_keys(());
346        for local_def_id in def_id_sets {
347            let def_id = local_def_id.to_def_id();
348            if Self::filter_mir(def_id) {
349                continue;
350            }
351            if tcx.def_kind(def_id) == DefKind::Fn || tcx.def_kind(def_id) == DefKind::AssocFn {
352                self.insert_uig(def_id, get_callees(tcx, def_id), get_cons(tcx, def_id));
353            }
354        }
355        for uig in &self.uigs {
356            uig.count_basic_units(&mut basic_units_data);
357        }
358        for single in &self.single {
359            single.count_basic_units(&mut basic_units_data);
360        }
361    }
362
363    pub fn process_def_id(
364        &mut self,
365        tcx: TyCtxt<'tcx>,
366        def_id: DefId,
367        visited: &mut HashSet<DefId>,
368        unsafe_fn: &mut HashSet<DefId>,
369    ) {
370        if !visited.insert(def_id) || Self::filter_mir(def_id) {
371            return;
372        }
373        match tcx.def_kind(def_id) {
374            DefKind::Fn | DefKind::AssocFn => {
375                if check_safety(tcx, def_id) && self.tcx.visibility(def_id) == Visibility::Public {
376                    unsafe_fn.insert(def_id);
377                    self.insert_uig(def_id, get_callees(tcx, def_id), get_cons(tcx, def_id));
378                }
379            }
380            DefKind::Mod => {
381                for child in tcx.module_children(def_id) {
382                    if let Some(child_def_id) = child.res.opt_def_id() {
383                        self.process_def_id(tcx, child_def_id, visited, unsafe_fn);
384                    }
385                }
386            }
387            DefKind::Impl { of_trait: _ } => {
388                for item in tcx.associated_item_def_ids(def_id) {
389                    self.process_def_id(tcx, *item, visited, unsafe_fn);
390                }
391            }
392            DefKind::Struct => {
393                let impls = tcx.inherent_impls(def_id);
394                for impl_def_id in impls {
395                    self.process_def_id(tcx, *impl_def_id, visited, unsafe_fn);
396                }
397            }
398            DefKind::Ctor(_of, _kind) => {
399                if tcx.is_mir_available(def_id) {
400                    let _mir = tcx.optimized_mir(def_id);
401                }
402            }
403            _ => {
404                // println!("{:?}",tcx.def_kind(def_id));
405            }
406        }
407    }
408
409    pub fn filter_mir(_def_id: DefId) -> bool {
410        // let def_id_fmt = format!("{:?}", def_id);
411        false
412        // def_id_fmt.contains("core_arch")
413        //     || def_id_fmt.contains("::__")
414        //     || def_id_fmt.contains("backtrace_rs")
415        //     || def_id_fmt.contains("stack_overflow")
416        //     || def_id_fmt.contains("thread_local")
417        //     || def_id_fmt.contains("raw_vec")
418        //     || def_id_fmt.contains("sys_common")
419        //     || def_id_fmt.contains("adapters")
420        //     || def_id_fmt.contains("sys::sync")
421        //     || def_id_fmt.contains("personality")
422        //     || def_id_fmt.contains("collections::btree::borrow")
423        //     || def_id_fmt.contains("num::int_sqrt")
424        //     || def_id_fmt.contains("collections::btree::node")
425        //     || def_id_fmt.contains("collections::btree::navigate")
426        //     || def_id_fmt.contains("core_simd")
427        //     || def_id_fmt.contains("unique")
428    }
429
430    pub fn insert_uig(
431        &mut self,
432        caller: DefId,
433        callee_set: HashSet<DefId>,
434        caller_cons: Vec<NodeType>,
435    ) {
436        let mut pairs = HashSet::new();
437        for callee in &callee_set {
438            let callee_cons = get_cons(self.tcx, *callee);
439            pairs.insert((generate_node_ty(self.tcx, *callee), callee_cons));
440        }
441        if !check_safety(self.tcx, caller) && callee_set.is_empty() {
442            return;
443        }
444        // if check_safety(self.tcx, caller)
445        // && get_sp(self.tcx, caller).len() == 0
446        // {
447        //     println!("{:?}",get_cleaned_def_path_name(self.tcx, caller));
448        //     return;
449        // }
450        let uig = UigUnit::new_by_pair(generate_node_ty(self.tcx, caller), caller_cons, pairs);
451        if !callee_set.is_empty() {
452            self.uigs.push(uig);
453        } else {
454            self.single.push(uig);
455        }
456    }
457}