1use super::{UPGAnalysis, upg_graph::UPGraph};
2use crate::analysis::{
3 upg::draw_dot::render_dot_graphs,
4 utils::{fn_info::*, show_mir::display_mir},
5};
6use rustc_hir::{Safety, def::DefKind, def_id::DefId};
7use rustc_middle::{
8 mir::Local,
9 ty,
10 ty::{TyCtxt, Visibility},
11};
12use rustc_span::Symbol;
13use std::collections::{HashMap, HashSet};
14
15impl<'tcx> UPGAnalysis<'tcx> {
16 pub fn audit_std_unsafe(&mut self) {
17 let all_std_fn_def = get_all_std_fns_by_rustc_public(self.tcx);
18 let symbol = Symbol::intern("Vec");
20 let vec_def_id = self.tcx.get_diagnostic_item(symbol).unwrap();
21 for &def_id in &all_std_fn_def {
22 let adt_def = get_adt_def_id_by_adt_method(self.tcx, def_id);
23 if adt_def.is_some() && adt_def.unwrap() == vec_def_id {
24 self.insert_upg(def_id);
25 }
26 }
27 self.render_dot();
28 }
29
30 pub fn render_dot(&mut self) {
31 let mut dot_strs = Vec::new();
32 for upg in &self.upgs {
33 let dot_str = UPGraph::generate_dot_from_upg_unit(upg);
34 let caller_name = get_cleaned_def_path_name(self.tcx, upg.caller.def_id);
35 dot_strs.push((caller_name, dot_str));
36 }
37 render_dot_graphs(dot_strs);
38 }
39
40 pub fn get_chains(&mut self) {
41 let v_fn_def = self.tcx.mir_keys(());
42
43 for local_def_id in v_fn_def {
44 let def_id = local_def_id.to_def_id();
45 if !check_visibility(self.tcx, def_id) {
46 continue;
47 }
48 if get_cleaned_def_path_name(self.tcx, def_id) == "std::boxed::Box::<T>::from_raw" {
49 let body = self.tcx.mir_built(local_def_id).steal();
50 display_mir(def_id, &body);
51 }
52 let chains = get_all_std_unsafe_chains(self.tcx, def_id);
53 let valid_chains: Vec<Vec<String>> = chains
54 .into_iter()
55 .filter(|chain| {
56 if chain.len() > 1 {
57 return true;
58 }
59 if chain.len() == 1 {
60 if check_safety(self.tcx, def_id) == Safety::Unsafe {
61 return true;
62 }
63 }
64 false
65 })
66 .collect();
67
68 print_unsafe_chains(&valid_chains);
69 }
70 }
71
72 pub fn get_all_std_unsafe_def_id_by_treat_std_as_local_crate(
73 &mut self,
74 tcx: TyCtxt<'tcx>,
75 ) -> HashSet<DefId> {
76 let mut unsafe_fn = HashSet::default();
77 let mut total_cnt = 0;
78 let mut api_cnt = 0;
79 let mut sp_cnt = 0;
80 let mut sp_count_map: HashMap<String, usize> = HashMap::new();
81 let all_std_fn_def = get_all_std_fns_by_rustc_public(self.tcx);
82
83 for def_id in &all_std_fn_def {
84 if check_safety(tcx, *def_id) == Safety::Unsafe {
85 let sp_set = get_sp(tcx, *def_id);
86 if !sp_set.is_empty() {
87 unsafe_fn.insert(*def_id);
88 let mut flag = false;
89 for sp in &sp_set {
90 if sp.is_empty()
91 || sp == "Function_sp"
92 || sp == "System_sp"
93 || sp == "ValidSlice"
94 {
95 flag = true;
96 }
97 }
98 if !flag {
99 api_cnt += 1;
100 sp_cnt += sp_set.len();
101 }
102 total_cnt += 1;
103 }
104 for sp in sp_set {
105 *sp_count_map.entry(sp).or_insert(0) += 1;
106 }
107 }
108 self.insert_upg(*def_id);
109 }
110
111 rap_info!(
112 "fn_def : {}, count : {:?} and {:?}, sp cnt : {}",
113 all_std_fn_def.len(),
114 total_cnt,
115 api_cnt,
116 sp_cnt
117 );
118 unsafe_fn
119 }
120
121 pub fn check_params(&self, def_id: DefId) {
122 let body = self.tcx.optimized_mir(def_id);
123 let locals = body.local_decls.clone();
124 let fn_sig = self.tcx.fn_sig(def_id).skip_binder();
125 let param_len = fn_sig.inputs().skip_binder().len();
126 let return_ty = fn_sig.output().skip_binder();
127 for idx in 1..param_len + 1 {
128 let local_ty = locals[Local::from(idx)].ty;
129 if is_ptr(local_ty) && !return_ty.is_unit() {
130 println!("{:?}", get_cleaned_def_path_name(self.tcx, def_id));
131 }
132 }
133 }
134
135 pub fn analyze_upg(&self) {
136 let mut fn_no_callee = Vec::new();
137 let mut fn_unsafe_caller = Vec::new();
138 let mut fn_safe_caller = Vec::new();
139 let mut method_no_callee = Vec::new();
140 let mut method_unsafe_caller = Vec::new();
141 let mut method_safe_caller = Vec::new();
142 for upg in &self.upgs {
143 if upg.caller.fn_kind == FnKind::Method {
144 if upg.callees.is_empty() {
146 method_no_callee.push(upg.clone());
147 }
148 if upg.caller.fn_safety == Safety::Unsafe {
149 method_unsafe_caller.push(upg.clone());
150 } else {
151 method_safe_caller.push(upg.clone());
152 }
153 } else {
154 if upg.callees.is_empty() {
156 fn_no_callee.push(upg.clone());
157 }
158 if upg.caller.fn_safety == Safety::Unsafe {
159 fn_unsafe_caller.push(upg.clone());
160 } else {
161 fn_safe_caller.push(upg.clone());
162 }
163 }
164 }
165 rap_info!(
166 "func: {},{},{}, method: {},{},{}",
167 fn_no_callee.len(),
168 fn_unsafe_caller.len(),
169 fn_safe_caller.len(),
170 method_no_callee.len(),
171 method_unsafe_caller.len(),
172 method_safe_caller.len()
173 );
174 rap_info!("units: {}", self.upgs.len());
175 }
176
177 pub fn analyze_struct(&self) {
178 let mut cache = HashSet::default();
179 let mut s = 0;
180 let mut u = 0;
181 let mut e = 0;
182 let mut uc = 0;
183 let mut vi = 0;
184 for upg in &self.upgs {
185 self.get_struct(
186 upg.caller.def_id,
187 &mut cache,
188 &mut s,
189 &mut u,
190 &mut e,
191 &mut uc,
192 &mut vi,
193 );
194 }
195 println!("{},{},{},{}", s, u, e, vi);
196 }
197
198 pub fn get_struct(
199 &self,
200 def_id: DefId,
201 cache: &mut HashSet<DefId>,
202 s: &mut usize,
203 u: &mut usize,
204 e: &mut usize,
205 uc: &mut usize,
206 vi: &mut usize,
207 ) {
208 let tcx = self.tcx;
209 let mut safe_constructors = Vec::new();
210 let mut unsafe_constructors = Vec::new();
211 let mut unsafe_methods = Vec::new();
212 let mut safe_methods = Vec::new();
213 let mut mut_methods = Vec::new();
214 let mut struct_name = "".to_string();
215 let mut ty_flag = 0;
216 let mut vi_flag = false;
217 if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
218 if let Some(impl_id) = assoc_item.impl_container(tcx) {
219 let ty = tcx.type_of(impl_id).skip_binder();
221 if let Some(adt_def) = ty.ty_adt_def() {
222 if adt_def.is_union() {
223 ty_flag = 1;
224 } else if adt_def.is_enum() {
225 ty_flag = 2;
226 }
227 let adt_def_id = adt_def.did();
228 struct_name = get_cleaned_def_path_name(tcx, adt_def_id);
229 if !cache.insert(adt_def_id) {
230 return;
231 }
232
233 vi_flag = false;
234 let impl_vec = get_impls_for_struct(self.tcx, adt_def_id);
235 for impl_id in impl_vec {
236 let associated_items = tcx.associated_items(impl_id);
237 for item in associated_items.in_definition_order() {
238 if let ty::AssocKind::Fn {
239 name: _,
240 has_self: _,
241 } = item.kind
242 {
243 let item_def_id = item.def_id;
244 if !get_sp(self.tcx, item_def_id).is_empty() {
245 vi_flag = true;
246 }
247 if get_type(self.tcx, item_def_id) == FnKind::Constructor
248 && check_safety(self.tcx, item_def_id) == Safety::Unsafe
249 {
251 unsafe_constructors.push(item_def_id);
252 }
253 if get_type(self.tcx, item_def_id) == FnKind::Constructor
254 && check_safety(self.tcx, item_def_id) == Safety::Safe
255 {
256 safe_constructors.push(item_def_id);
257 }
258 if get_type(self.tcx, item_def_id) == FnKind::Method
259 && check_safety(self.tcx, item_def_id) == Safety::Unsafe
260 {
262 unsafe_methods.push(item_def_id);
263 }
264 if get_type(self.tcx, item_def_id) == FnKind::Method
265 && check_safety(self.tcx, item_def_id) == Safety::Safe
266 {
267 if !get_unsafe_callees(tcx, item_def_id).is_empty() {
268 safe_methods.push(item_def_id);
269 }
270 }
271 if get_type(self.tcx, item_def_id) == FnKind::Method
272 && has_mut_self_param(self.tcx, item_def_id)
273 {
274 mut_methods.push(item_def_id);
275 }
276 }
277 }
278 }
279 }
280 }
281 }
282 if struct_name == *""
283 || (unsafe_constructors.is_empty()
284 && unsafe_methods.is_empty()
285 && safe_methods.is_empty())
286 {
287 return;
288 }
289 if vi_flag {
290 *vi += 1;
291 }
292 if !unsafe_constructors.is_empty() {
293 *uc += 1;
294 }
295 if ty_flag == 0 {
296 *s += 1;
297 }
298 if ty_flag == 1 {
299 *u += 1;
300 }
301 if ty_flag == 2 {
302 *e += 1;
303 }
304
305 println!("Safe Cons: {}", safe_constructors.len());
306 for safe_cons in safe_constructors {
307 println!(" {:?}", get_cleaned_def_path_name(tcx, safe_cons));
308 }
309 println!("Unsafe Cons: {}", unsafe_constructors.len());
310 for unsafe_cons in unsafe_constructors {
311 println!(" {:?}", get_cleaned_def_path_name(tcx, unsafe_cons));
312 }
313 println!("Unsafe Methods: {}", unsafe_methods.len());
314 for method in unsafe_methods {
315 println!(" {:?}", get_cleaned_def_path_name(tcx, method));
316 }
317 println!("Safe Methods with unsafe callee: {}", safe_methods.len());
318 for method in safe_methods {
319 println!(" {:?}", get_cleaned_def_path_name(tcx, method));
320 }
321 println!("Mut self Methods: {}", mut_methods.len());
322 for method in mut_methods {
323 println!(" {:?}", get_cleaned_def_path_name(tcx, method));
324 }
325 }
326
327 pub fn get_units_data(&mut self, tcx: TyCtxt<'tcx>) {
328 let mut basic_units_data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
330 let def_id_sets = tcx.mir_keys(());
331 for local_def_id in def_id_sets {
332 let def_id = local_def_id.to_def_id();
333 if tcx.def_kind(def_id) == DefKind::Fn || tcx.def_kind(def_id) == DefKind::AssocFn {
334 self.insert_upg(def_id);
335 }
336 }
337 for upg in &self.upgs {
338 upg.count_basic_units(&mut basic_units_data);
339 }
340 }
341
342 pub fn process_def_id(
343 &mut self,
344 def_id: DefId,
345 visited: &mut HashSet<DefId>,
346 unsafe_fn: &mut HashSet<DefId>,
347 ) {
348 if !visited.insert(def_id) {
349 return;
350 }
351 match self.tcx.def_kind(def_id) {
352 DefKind::Fn | DefKind::AssocFn => {
353 if check_safety(self.tcx, def_id) == Safety::Unsafe
354 && self.tcx.visibility(def_id) == Visibility::Public
355 {
356 unsafe_fn.insert(def_id);
357 self.insert_upg(def_id);
358 }
359 }
360 DefKind::Mod => {
361 for child in self.tcx.module_children(def_id) {
362 if let Some(child_def_id) = child.res.opt_def_id() {
363 self.process_def_id(child_def_id, visited, unsafe_fn);
364 }
365 }
366 }
367 DefKind::Impl { of_trait: _ } => {
368 for item in self.tcx.associated_item_def_ids(def_id) {
369 self.process_def_id(*item, visited, unsafe_fn);
370 }
371 }
372 DefKind::Struct => {
373 let impls = self.tcx.inherent_impls(def_id);
374 for impl_def_id in impls {
375 self.process_def_id(*impl_def_id, visited, unsafe_fn);
376 }
377 }
378 DefKind::Ctor(_of, _kind) => {
379 if self.tcx.is_mir_available(def_id) {
380 let _mir = self.tcx.optimized_mir(def_id);
381 }
382 }
383 _ => {
384 }
386 }
387 }
388}