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