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 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 }
84 for sp in sp_set {
85 *sp_count_map.entry(sp).or_insert(0) += 1;
86 }
87 }
89 self.insert_uig(def_id, get_callees(tcx, def_id), get_cons(tcx, def_id));
90 }
91 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 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 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 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 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 }
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 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 {
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 {
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 }
312 if ty_flag == 1 {
313 *u += 1;
314 }
316 if ty_flag == 2 {
317 *e += 1;
318 }
320
321 }
342
343 pub fn get_units_data(&mut self, tcx: TyCtxt<'tcx>) {
344 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 }
407 }
408 }
409
410 pub fn filter_mir(_def_id: DefId) -> bool {
411 false
413 }
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 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}