1use crate::{
2 analysis::{
3 Analysis,
4 core::{
5 alias_analysis::AAResult,
6 ownedheap_analysis::OHAResultMap,
7 range_analysis::{RangeAnalysis, default::RangeAnalyzer},
8 },
9 safedrop::graph::SafeDropGraph,
10 senryx::{
11 contracts::property::{CisRangeItem, PropertyContract},
12 symbolic_analysis::ValueDomain,
13 },
14 utils::{
15 fn_info::{
16 display_hashmap, get_all_std_unsafe_callees, get_all_std_unsafe_callees_block_id,
17 get_callees, get_cleaned_def_path_name, is_ptr, is_ref,
18 },
19 show_mir::display_mir,
20 },
21 },
22 rap_debug, rap_warn,
23};
24use rustc_middle::ty::GenericParamDefKind;
25use serde::de;
26use std::{
27 collections::{HashMap, HashSet},
28 fmt::Debug,
29 hash::Hash,
30};
31use syn::Constraint;
32
33use super::contracts::abstract_state::{
34 AbstractStateItem, AlignState, PathInfo, StateType, VType, Value,
35};
36use super::contracts::contract::Contract;
37use super::dominated_graph::DominatedGraph;
38use super::dominated_graph::InterResultNode;
39use super::generic_check::GenericChecker;
40use super::inter_record::InterAnalysisRecord;
41use super::matcher::UnsafeApi;
42use super::matcher::{get_arg_place, parse_unsafe_api};
43use rustc_data_structures::fx::FxHashMap;
44use rustc_hir::def_id::DefId;
45use rustc_middle::{
46 mir::{
47 self, AggregateKind, BasicBlock, BasicBlockData, BinOp, CastKind, Local, Operand, Place,
48 ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
49 },
50 ty::{self, GenericArgKind, PseudoCanonicalInput, Ty, TyCtxt, TyKind},
51};
52use rustc_span::{Span, source_map::Spanned};
53
54pub struct CheckResult {
56 pub func_name: String,
57 pub func_span: Span,
58 pub failed_contracts: HashMap<usize, HashSet<String>>,
59 pub passed_contracts: HashMap<usize, HashSet<String>>,
60}
61
62impl CheckResult {
63 pub fn new(func_name: &str, func_span: Span) -> Self {
64 Self {
65 func_name: func_name.to_string(),
66 func_span,
67 failed_contracts: HashMap::new(),
68 passed_contracts: HashMap::new(),
69 }
70 }
71}
72
73#[derive(Debug, PartialEq, Eq, Clone)]
74pub enum PlaceTy<'tcx> {
75 Ty(usize, usize), GenericTy(String, HashSet<Ty<'tcx>>, HashSet<(usize, usize)>), Unknown,
78}
79
80impl<'tcx> PlaceTy<'tcx> {
81 pub fn possible_aligns(&self) -> HashSet<usize> {
82 match self {
83 PlaceTy::Ty(align, _size) => {
84 let mut set = HashSet::new();
85 set.insert(*align);
86 set
87 }
88 PlaceTy::GenericTy(_, _, tys) => tys.iter().map(|ty| ty.0).collect(),
89 _ => HashSet::new(),
90 }
91 }
92}
93
94impl<'tcx> Hash for PlaceTy<'tcx> {
95 fn hash<H: std::hash::Hasher>(&self, _state: &mut H) {}
96}
97
98pub struct BodyVisitor<'tcx> {
99 pub tcx: TyCtxt<'tcx>,
100 pub def_id: DefId,
101 pub safedrop_graph: SafeDropGraph<'tcx>,
102 pub abstract_states: HashMap<usize, PathInfo<'tcx>>,
104 pub unsafe_callee_report: HashMap<String, usize>,
105 pub local_ty: HashMap<usize, PlaceTy<'tcx>>,
106 pub visit_time: usize,
107 pub check_results: Vec<CheckResult>,
108 pub generic_map: HashMap<String, HashSet<Ty<'tcx>>>,
109 pub global_recorder: HashMap<DefId, InterAnalysisRecord<'tcx>>,
110 pub proj_ty: HashMap<usize, Ty<'tcx>>,
111 pub chains: DominatedGraph<'tcx>,
112 pub value_domains: HashMap<usize, ValueDomain>,
113}
114
115impl<'tcx> BodyVisitor<'tcx> {
116 pub fn new(
117 tcx: TyCtxt<'tcx>,
118 def_id: DefId,
119 global_recorder: HashMap<DefId, InterAnalysisRecord<'tcx>>,
120 visit_time: usize,
121 ) -> Self {
122 let body = tcx.optimized_mir(def_id);
123 let param_env = tcx.param_env(def_id);
124 let satisfied_ty_map_for_generic =
125 GenericChecker::new(tcx, param_env).get_satisfied_ty_map();
126 let mut chains = DominatedGraph::new(tcx, def_id);
127 chains.init_arg();
128 Self {
129 tcx,
130 def_id,
131 safedrop_graph: SafeDropGraph::new(body, tcx, def_id, OHAResultMap::default()),
132 abstract_states: HashMap::new(),
133 unsafe_callee_report: HashMap::new(),
134 local_ty: HashMap::new(),
135 visit_time,
136 check_results: Vec::new(),
137 generic_map: satisfied_ty_map_for_generic,
138 global_recorder,
139 proj_ty: HashMap::new(),
140 chains,
141 value_domains: HashMap::new(),
142 }
144 }
145
146 pub fn get_ty_by_place(&self, p: usize) -> Ty<'tcx> {
147 let body = self.tcx.optimized_mir(self.def_id);
148 let locals = body.local_decls.clone();
149 return locals[Local::from(p)].ty;
150 }
151
152 pub fn update_fields_states(&mut self, inter_result: InterResultNode<'tcx>) {
153 self.chains.init_self_with_inter(inter_result);
154 }
155
156 pub fn path_forward_check(
157 &mut self,
158 fn_map: &FxHashMap<DefId, AAResult>,
159 ) -> InterResultNode<'tcx> {
160 let mut inter_return_value =
161 InterResultNode::construct_from_var_node(self.chains.clone(), 0);
162 if self.visit_time >= 1000 {
163 return inter_return_value;
164 }
165 let paths = self.get_all_paths();
167 let body = self.tcx.optimized_mir(self.def_id);
169 let target_name = get_cleaned_def_path_name(self.tcx, self.def_id);
170 let locals = body.local_decls.clone();
172 for (idx, local) in locals.iter().enumerate() {
173 let local_ty = local.ty;
174 let layout = self.visit_ty_and_get_layout(local_ty);
175 self.local_ty.insert(idx, layout);
176 }
177
178 let tmp_chain = self.chains.clone();
180 for (index, (path, constraint)) in paths.iter().enumerate() {
181 self.chains = tmp_chain.clone();
182 self.set_constraint(constraint);
183 self.abstract_states.insert(index, PathInfo::new());
184 for block_index in path.iter() {
185 if block_index >= &body.basic_blocks.len() {
186 continue;
187 }
188 self.path_analyze_block(
189 &body.basic_blocks[BasicBlock::from_usize(*block_index)].clone(),
190 index,
191 *block_index,
192 fn_map,
193 );
194 let tem_scc_sub_blocks = self.safedrop_graph.blocks[*block_index]
195 .scc_sub_blocks
196 .clone();
197 if tem_scc_sub_blocks.len() > 0 {
198 for sub_block in &tem_scc_sub_blocks {
199 self.path_analyze_block(
200 &body.basic_blocks[BasicBlock::from_usize(*sub_block)].clone(),
201 index,
202 *block_index,
203 fn_map,
204 );
205 }
206 }
207 }
208 let curr_path_inter_return_value =
210 InterResultNode::construct_from_var_node(self.chains.clone(), 0);
211 inter_return_value.merge(curr_path_inter_return_value);
212 }
213 if self.visit_time == 0 && target_name.contains("into_raw_parts_with_alloc") {
214 display_mir(self.def_id, body);
215 display_hashmap(&self.chains.variables, 1);
216 }
217
218 inter_return_value
219 }
220
221 pub fn path_analyze_block(
222 &mut self,
223 block: &BasicBlockData<'tcx>,
224 path_index: usize,
225 bb_index: usize,
226 fn_map: &FxHashMap<DefId, AAResult>,
227 ) {
228 for statement in block.statements.iter() {
229 self.path_analyze_statement(statement, path_index);
230 }
231 self.path_analyze_terminator(&block.terminator(), path_index, bb_index, fn_map);
232 }
233
234 pub fn path_analyze_statement(&mut self, statement: &Statement<'tcx>, _path_index: usize) {
235 match statement.kind {
236 StatementKind::Assign(box (ref lplace, ref rvalue)) => {
237 self.path_analyze_assign(lplace, rvalue, _path_index);
238 }
239 StatementKind::Intrinsic(box ref intrinsic) => match intrinsic {
240 mir::NonDivergingIntrinsic::CopyNonOverlapping(cno) => {
241 if cno.src.place().is_some() && cno.dst.place().is_some() {
242 let _src_pjc_local =
243 self.handle_proj(true, cno.src.place().unwrap().clone());
244 let _dst_pjc_local =
245 self.handle_proj(true, cno.dst.place().unwrap().clone());
246 }
247 }
248 _ => {}
249 },
250 StatementKind::StorageDead(local) => {
251 }
253 _ => {}
254 }
255 }
256
257 pub fn path_analyze_terminator(
258 &mut self,
259 terminator: &Terminator<'tcx>,
260 path_index: usize,
261 bb_index: usize,
262 fn_map: &FxHashMap<DefId, AAResult>,
263 ) {
264 match &terminator.kind {
265 TerminatorKind::Call {
266 func,
267 args,
268 destination: dst_place,
269 target: _,
270 unwind: _,
271 call_source: _,
272 fn_span,
273 } => {
274 if let Operand::Constant(func_constant) = func {
275 if let ty::FnDef(callee_def_id, raw_list) = func_constant.const_.ty().kind() {
276 let mut mapping = FxHashMap::default();
277 self.get_generic_mapping(raw_list.as_slice(), callee_def_id, &mut mapping);
278 rap_debug!(
279 "func {:?}, generic type mapping {:?}",
280 callee_def_id,
281 mapping
282 );
283 self.handle_call(
284 dst_place,
285 callee_def_id,
286 args,
287 path_index,
288 fn_map,
289 *fn_span,
290 mapping,
291 );
292 }
293 }
294 }
295 TerminatorKind::Drop {
296 place,
297 target: _,
298 unwind: _,
299 replace: _,
300 drop: _,
301 async_fut: _,
302 } => {
303 let drop_local = self.handle_proj(false, *place);
304 if !self.chains.set_drop(drop_local) {
305 }
310 }
311 _ => {}
312 }
313 }
314
315 fn get_generic_mapping(
320 &self,
321 raw_list: &[rustc_middle::ty::GenericArg<'tcx>],
322 def_id: &DefId,
323 generic_mapping: &mut FxHashMap<String, Ty<'tcx>>,
324 ) {
325 let generics = self.tcx.generics_of(def_id);
326 for param in &generics.own_params {
327 if let GenericParamDefKind::Type {
328 has_default: _,
329 synthetic: _,
330 } = param.kind
331 {
332 if let Some(ty) = raw_list.get(param.index as usize) {
333 if let GenericArgKind::Type(actual_ty) = (*ty).kind() {
334 let param_name = param.name.to_string();
335 generic_mapping.insert(param_name, actual_ty);
336 }
337 }
338 }
339 }
340 if generics.own_params.len() == 0 && generics.parent.is_some() {
341 let parent_def_id = generics.parent.unwrap();
342 self.get_generic_mapping(raw_list, &parent_def_id, generic_mapping);
343 }
344 }
345
346 pub fn path_analyze_assign(
347 &mut self,
348 lplace: &Place<'tcx>,
349 rvalue: &Rvalue<'tcx>,
350 path_index: usize,
351 ) {
352 let lpjc_local = self.handle_proj(false, lplace.clone());
353 match rvalue {
354 Rvalue::Use(op) => match op {
355 Operand::Move(rplace) => {
356 let rpjc_local = self.handle_proj(true, rplace.clone());
357 self.chains.merge(lpjc_local, rpjc_local);
358 }
359 Operand::Copy(rplace) => {
360 let rpjc_local = self.handle_proj(true, rplace.clone());
361 self.chains.copy_node(lpjc_local, rpjc_local);
362 }
363 _ => {}
364 },
365 Rvalue::Repeat(op, _const) => match op {
366 Operand::Move(rplace) | Operand::Copy(rplace) => {
367 let _rpjc_local = self.handle_proj(true, rplace.clone());
368 }
369 _ => {}
370 },
371 Rvalue::Ref(_, _, rplace) | Rvalue::RawPtr(_, rplace) => {
372 let rpjc_local = self.handle_proj(true, rplace.clone());
373 self.chains.point(lpjc_local, rpjc_local);
375 }
376 Rvalue::Cast(cast_kind, op, ty) => match op {
377 Operand::Move(rplace) | Operand::Copy(rplace) => {
378 let rpjc_local = self.handle_proj(true, rplace.clone());
379 let r_point_to = self.chains.get_point_to_id(rpjc_local);
380 if r_point_to == rpjc_local {
381 self.chains.merge(lpjc_local, rpjc_local);
382 } else {
383 self.chains.point(lpjc_local, r_point_to);
384 }
385 }
386 _ => {}
387 },
388 Rvalue::BinaryOp(_bin_op, box (_op1, _op2)) => {}
389 Rvalue::ShallowInitBox(op, _ty) => match op {
390 Operand::Move(rplace) | Operand::Copy(rplace) => {
391 let _rpjc_local = self.handle_proj(true, rplace.clone());
392 }
393 _ => {}
394 },
395 Rvalue::Aggregate(box agg_kind, op_vec) => match agg_kind {
396 AggregateKind::Array(_ty) => {}
397 AggregateKind::Adt(_adt_def_id, _, _, _, _) => {
398 for (idx, op) in op_vec.into_iter().enumerate() {
399 let (is_const, val) = get_arg_place(op);
400 if is_const {
401 self.chains.insert_field_node(
402 lpjc_local,
403 idx,
404 Some(Ty::new_uint(self.tcx, rustc_middle::ty::UintTy::Usize)),
405 );
406 } else {
407 let node = self.chains.get_var_node_mut(lpjc_local).unwrap();
408 node.field.insert(idx, val);
409 }
410 }
411 }
412 _ => {}
413 },
414 Rvalue::Discriminant(_place) => {
415 }
417 _ => {}
418 }
419 }
420
421 pub fn handle_call(
422 &mut self,
423 dst_place: &Place<'tcx>,
424 def_id: &DefId,
425 args: &Box<[Spanned<Operand>]>,
426 path_index: usize,
427 fn_map: &FxHashMap<DefId, AAResult>,
428 fn_span: Span,
429 generic_mapping: FxHashMap<String, Ty<'tcx>>,
430 ) {
431 if !self.tcx.is_mir_available(def_id) {
432 self.insert_path_abstate(
433 path_index,
434 dst_place.local.as_usize(),
435 AbstractStateItem::new_default(),
436 );
437 return;
438 }
439
440 if let Some(fn_result) =
442 parse_unsafe_api(get_cleaned_def_path_name(self.tcx, *def_id).as_str())
443 {
444 self.handle_std_unsafe_call(
445 dst_place,
446 def_id,
447 args,
448 path_index,
449 fn_map,
450 fn_span,
451 fn_result,
452 generic_mapping,
453 );
454 }
455
456 self.set_bound(def_id, dst_place, args);
457
458 self.handle_ret_alias(dst_place, def_id, fn_map, args);
460
461 }
502
503 fn set_bound(
504 &mut self,
505 def_id: &DefId,
506 dst_place: &Place<'tcx>,
507 args: &Box<[Spanned<Operand>]>,
508 ) {
509 if args.len() == 0 || !get_cleaned_def_path_name(self.tcx, *def_id).contains("slice::len") {
510 return;
511 }
512 let d_local = self.handle_proj(false, dst_place.clone());
513 let ptr_local = get_arg_place(&args[0].node).1;
514 let mem_local = self.chains.get_point_to_id(ptr_local);
515 let mem_var = self.chains.get_var_node_mut(mem_local).unwrap();
516 for cis in &mut mem_var.cis.contracts {
517 if let PropertyContract::InBound(cis_ty, len) = cis {
518 *len = CisRangeItem::new_var(d_local);
519 }
520 }
521 }
522
523 pub fn handle_ret_alias(
525 &mut self,
526 dst_place: &Place<'tcx>,
527 def_id: &DefId,
528 fn_map: &FxHashMap<DefId, AAResult>,
529 args: &Box<[Spanned<Operand>]>,
530 ) {
531 let d_local = self.handle_proj(false, dst_place.clone());
532 if let Some(retalias) = fn_map.get(def_id) {
535 for alias_set in retalias.aliases() {
536 let (l, r) = (alias_set.lhs_no, alias_set.rhs_no);
537 let (l_fields, r_fields) =
538 (alias_set.lhs_fields.clone(), alias_set.rhs_fields.clone());
539 let (l_place, r_place) = (
540 if l != 0 {
541 get_arg_place(&args[l - 1].node)
542 } else {
543 (false, d_local)
544 },
545 if r != 0 {
546 get_arg_place(&args[r - 1].node)
547 } else {
548 (false, d_local)
549 },
550 );
551 if l_place.0 {
553 let snd_var = self.chains.find_var_id_with_fields_seq(r_place.1, r_fields);
554 self.chains
555 .update_value(self.chains.get_point_to_id(snd_var), l_place.1);
556 continue;
557 }
558 if r_place.0 {
560 let fst_var = self.chains.find_var_id_with_fields_seq(l_place.1, l_fields);
561 self.chains
562 .update_value(self.chains.get_point_to_id(fst_var), r_place.1);
563 continue;
564 }
565 let (fst_var, snd_var) = (
566 self.chains.find_var_id_with_fields_seq(l_place.1, l_fields),
567 self.chains.find_var_id_with_fields_seq(r_place.1, r_fields),
568 );
569 let fst_to = self.chains.get_point_to_id(fst_var);
571 let snd_to = self.chains.get_point_to_id(snd_var);
572 let is_fst_point = fst_to != fst_var;
573 let is_snd_point = snd_to != snd_var;
574 let fst_node = self.chains.get_var_node(fst_var).unwrap();
575 let snd_node = self.chains.get_var_node(snd_var).unwrap();
576 let is_fst_ptr = is_ptr(fst_node.ty.unwrap()) || is_ref(fst_node.ty.unwrap());
577 let is_snd_ptr = is_ptr(snd_node.ty.unwrap()) || is_ref(snd_node.ty.unwrap());
578 rap_debug!(
579 "{:?}: {fst_var},{fst_to},{is_fst_ptr} -- {snd_var},{snd_to},{is_snd_ptr}",
580 def_id
581 );
582 match (is_fst_ptr, is_snd_ptr) {
583 (false, true) => {
584 if is_snd_point {
586 self.chains.point(snd_var, fst_var);
587 } else {
588 self.chains.merge(fst_var, snd_to);
589 }
590 }
591 (false, false) => {
592 self.chains.merge(fst_var, snd_var);
593 }
594 (true, true) => {
595 if is_fst_point && is_snd_point {
596 self.chains.merge(fst_to, snd_to);
597 } else if !is_fst_point && is_snd_point {
598 self.chains.point(fst_var, snd_to);
599 } else if is_fst_point && !is_snd_point {
600 self.chains.point(snd_var, fst_to);
601 } else {
602 self.chains.merge(fst_var, snd_var);
603 }
604 }
605 (true, false) => {
606 if is_fst_point {
607 self.chains.point(fst_var, snd_var);
608 } else {
609 self.chains.merge(snd_var, fst_to);
610 }
611 }
612 }
613 }
614 }
615 else {
617 let d_ty = self.chains.get_local_ty_by_place(d_local);
618 if d_ty.is_some() && (is_ptr(d_ty.unwrap()) || is_ref(d_ty.unwrap())) {
619 self.chains
620 .generate_ptr_with_obj_node(d_ty.unwrap(), d_local);
621 }
622 }
623 }
624
625 pub fn update_post_state(
627 &mut self,
628 post_state: &HashMap<usize, AbstractStateItem<'tcx>>,
629 args: &Box<[Spanned<Operand>]>,
630 path_index: usize,
631 ) {
632 for (idx, arg) in args.iter().enumerate() {
633 let arg_place = get_arg_place(&arg.node);
634 if let Some(state_item) = post_state.get(&idx) {
635 self.insert_path_abstate(path_index, arg_place.1, state_item.clone());
636 }
637 }
638 }
639
640 pub fn get_args_post_states(&mut self) -> HashMap<usize, AbstractStateItem<'tcx>> {
641 let tcx = self.tcx;
642 let def_id = self.def_id;
643 let final_states = self.abstract_states_mop();
644 let mut result_states = HashMap::new();
645 let fn_sig = tcx.fn_sig(def_id).skip_binder();
646 let num_params = fn_sig.inputs().skip_binder().len();
647 for i in 0..num_params + 1 {
648 if let Some(state) = final_states.state_map.get(&(i)) {
649 result_states.insert(i, state.clone());
650 } else {
651 result_states.insert(i, AbstractStateItem::new_default());
652 }
653 }
654 result_states
655 }
656
657 pub fn get_all_paths(&mut self) -> HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> {
658 let mut range_analyzer = RangeAnalyzer::<i128>::new(self.tcx, false);
659 let path_constraints_option =
660 range_analyzer.start_path_constraints_analysis_for_defid(self.def_id); let mut path_constraints: HashMap<Vec<usize>, Vec<(_, _, _)>> =
662 if path_constraints_option.is_none() {
663 let mut results = HashMap::new();
664 let paths: Vec<Vec<usize>> = self.safedrop_graph.get_paths();
665 for path in paths {
666 results.insert(path, Vec::new());
667 }
668 results
669 } else {
670 path_constraints_option.unwrap()
671 };
672 self.safedrop_graph.solve_scc();
673 if self.visit_time == 0 {
675 let contains_unsafe_blocks = get_all_std_unsafe_callees_block_id(self.tcx, self.def_id);
676 path_constraints.retain(|path, cons| {
677 path.iter()
678 .any(|block_id| contains_unsafe_blocks.contains(block_id))
679 });
680 }
681 path_constraints
683 }
684
685 pub fn abstract_states_mop(&mut self) -> PathInfo<'tcx> {
700 let mut result_state = PathInfo {
701 state_map: HashMap::new(),
702 };
703
704 for (_path_idx, abstract_state) in &self.abstract_states {
705 for (var_index, state_item) in &abstract_state.state_map {
706 if let Some(existing_state_item) = result_state.state_map.get_mut(&var_index) {
707 existing_state_item
708 .clone()
709 .meet_state_item(&state_item.clone());
710 } else {
711 result_state
712 .state_map
713 .insert(*var_index, state_item.clone());
714 }
715 }
716 }
717 result_state
718 }
719
720 pub fn update_callee_report_level(&mut self, unsafe_callee: String, report_level: usize) {
721 self.unsafe_callee_report
722 .entry(unsafe_callee)
723 .and_modify(|e| {
724 if report_level < *e {
725 *e = report_level;
726 }
727 })
728 .or_insert(report_level);
729 }
730
731 pub fn output_results(&self, threshold: usize) {
734 for (unsafe_callee, report_level) in &self.unsafe_callee_report {
735 if *report_level == 0 {
736 rap_warn!("Find one bug in {:?}!", unsafe_callee);
737 } else if *report_level <= threshold {
738 rap_warn!("Find an unsoundness issue in {:?}!", unsafe_callee);
739 }
740 }
741 }
742
743 pub fn insert_path_abstate(
744 &mut self,
745 path_index: usize,
746 place: usize,
747 abitem: AbstractStateItem<'tcx>,
748 ) {
749 self.abstract_states
750 .entry(path_index)
751 .or_insert_with(|| PathInfo {
752 state_map: HashMap::new(),
753 })
754 .state_map
755 .insert(place, abitem);
756 }
757
758 pub fn set_constraint(&mut self, constraint: &Vec<(Place<'tcx>, Place<'tcx>, BinOp)>) {
759 for (p1, p2, op) in constraint {
760 let p1_num = self.handle_proj(false, p1.clone());
761 let p2_num = self.handle_proj(false, p2.clone());
762 self.chains.insert_patial_op(p1_num, p2_num, op);
763 }
764 }
765
766 pub fn get_layout_by_place_usize(&self, place: usize) -> PlaceTy<'tcx> {
767 if let Some(ty) = self.chains.get_obj_ty_through_chain(place) {
768 return self.visit_ty_and_get_layout(ty);
769 } else {
770 return PlaceTy::Unknown;
771 }
772 }
773
774 pub fn visit_ty_and_get_layout(&self, ty: Ty<'tcx>) -> PlaceTy<'tcx> {
775 match ty.kind() {
776 TyKind::RawPtr(ty, _)
777 | TyKind::Ref(_, ty, _)
778 | TyKind::Slice(ty)
779 | TyKind::Array(ty, _) => self.visit_ty_and_get_layout(*ty),
780 TyKind::Param(param_ty) => {
781 let generic_name = param_ty.name.to_string();
782 let mut layout_set: HashSet<(usize, usize)> = HashSet::new();
783 let ty_set = self.generic_map.get(&generic_name.clone());
784 if ty_set.is_none() {
785 if self.visit_time == 0 {
786 rap_warn!(
787 "Can not get generic type set: {:?}, def_id:{:?}",
788 generic_name,
789 self.def_id
790 );
791 }
792 return PlaceTy::GenericTy(generic_name, HashSet::new(), layout_set);
793 }
794 for ty in ty_set.unwrap().clone() {
795 if let PlaceTy::Ty(align, size) = self.visit_ty_and_get_layout(ty) {
796 layout_set.insert((align, size));
797 }
798 }
799 return PlaceTy::GenericTy(generic_name, ty_set.unwrap().clone(), layout_set);
800 }
801 TyKind::Adt(def, _list) => {
802 if def.is_enum() {
803 return PlaceTy::Unknown;
804 } else {
805 PlaceTy::Unknown
806 }
807 }
808 TyKind::Closure(_, _) => PlaceTy::Unknown,
809 TyKind::Alias(_, ty) => {
810 return self.visit_ty_and_get_layout(ty.self_ty());
812 }
813 _ => {
814 let param_env = self.tcx.param_env(self.def_id);
815 let ty_env = ty::TypingEnv::post_analysis(self.tcx, self.def_id);
816 let input = PseudoCanonicalInput {
817 typing_env: ty_env,
818 value: ty,
819 };
820 if let Ok(layout) = self.tcx.layout_of(input) {
821 let align = layout.align.abi.bytes_usize();
823 let size = layout.size.bytes() as usize;
824 return PlaceTy::Ty(align, size);
825 } else {
826 PlaceTy::Unknown
828 }
829 }
830 }
831 }
832
833 pub fn get_abstate_by_place_in_path(
834 &self,
835 place: usize,
836 path_index: usize,
837 ) -> AbstractStateItem<'tcx> {
838 if let Some(abstate) = self.abstract_states.get(&path_index) {
839 if let Some(abs) = abstate.state_map.get(&place).cloned() {
840 return abs;
841 }
842 }
843 AbstractStateItem::new_default()
844 }
845
846 pub fn handle_cast(
847 &mut self,
848 rpjc_local: usize,
849 lpjc_local: usize,
850 ty: &Ty<'tcx>,
851 path_index: usize,
852 cast_kind: &CastKind,
853 ) {
854 let mut src_ty = self.get_layout_by_place_usize(rpjc_local);
855 match cast_kind {
856 CastKind::PtrToPtr | CastKind::PointerCoercion(_, _) => {
857 let r_abitem = self.get_abstate_by_place_in_path(rpjc_local, path_index);
858 for state in &r_abitem.state {
859 if let StateType::AlignState(r_align_state) = state.clone() {
860 match r_align_state {
861 AlignState::Cast(from, _to) => {
862 src_ty = from.clone();
863 }
864 _ => {}
865 }
866 }
867 }
868
869 let dst_ty = self.visit_ty_and_get_layout(*ty);
870 let align_state =
871 StateType::AlignState(AlignState::Cast(src_ty.clone(), dst_ty.clone()));
872 let abitem = AbstractStateItem::new(
873 (Value::None, Value::None),
874 VType::Pointer(dst_ty),
875 HashSet::from([align_state]),
876 );
877 self.insert_path_abstate(path_index, lpjc_local, abitem);
878 }
879 _ => {}
880 }
881 }
882
883 pub fn handle_binary_op(
884 &mut self,
885 first_op: &Operand,
886 bin_op: &BinOp,
887 second_op: &Operand,
888 path_index: usize,
889 ) {
890 match bin_op {
891 BinOp::Offset => {
892 let _first_place = get_arg_place(first_op);
893 let _second_place = get_arg_place(second_op);
894 }
895 _ => {}
896 }
897 }
898
899 pub fn handle_proj(&mut self, is_right: bool, place: Place<'tcx>) -> usize {
900 let mut proj_id = place.local.as_usize();
901 for proj in place.projection {
902 match proj {
903 ProjectionElem::Deref => {
904 proj_id = self.chains.get_point_to_id(place.local.as_usize());
905 if proj_id == place.local.as_usize() {
906 proj_id = self.chains.check_ptr(proj_id);
907 }
908 }
909 ProjectionElem::Field(field, ty) => {
910 proj_id = self
911 .chains
912 .get_field_node_id(proj_id, field.as_usize(), Some(ty));
913 }
914 _ => {}
915 }
916 }
917 proj_id
918 }
919}