rapx/analysis/unsafety_isolation/
std_unsafety_isolation.rs1use 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 let mut dot_strs = Vec::new();
20 for uig in &self.uigs {
21 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 }
29 }
30 for uig in &self.single {
31 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 }
39 }
40 render_dot_graphs(dot_strs);
43 }
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 }
86 for sp in sp_set {
87 *sp_count_map.entry(sp).or_insert(0) += 1;
88 }
89 }
91 self.insert_uig(def_id, get_callees(tcx, def_id), get_cons(tcx, def_id));
92 }
93 }
94 println!(
101 "count : {:?} and {:?}, sp cnt : {}",
102 total_cnt, api_cnt, sp_cnt
103 );
104 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 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 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 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 }
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 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 {
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 {
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 }
311 if ty_flag == 1 {
312 *u += 1;
313 }
315 if ty_flag == 2 {
316 *e += 1;
317 }
319
320 }
341
342 pub fn get_units_data(&mut self, tcx: TyCtxt<'tcx>) {
343 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 }
406 }
407 }
408
409 pub fn filter_mir(_def_id: DefId) -> bool {
410 false
412 }
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 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}