rapx/analysis/senryx/
visitor.rs

1use crate::analysis::core::alias::mop::FnMap;
2use crate::analysis::safedrop::graph::SafeDropGraph;
3use crate::analysis::utils::fn_info::display_hashmap;
4use crate::analysis::utils::fn_info::get_all_std_unsafe_callees_block_id;
5use crate::analysis::utils::fn_info::get_callees;
6use crate::analysis::utils::fn_info::get_cleaned_def_path_name;
7use crate::analysis::utils::fn_info::is_ptr;
8use crate::analysis::utils::fn_info::is_ref;
9use crate::analysis::utils::show_mir::display_mir;
10use crate::rap_warn;
11use rustc_middle::mir::Local;
12use rustc_middle::mir::ProjectionElem;
13use rustc_middle::ty::PseudoCanonicalInput;
14use rustc_span::source_map::Spanned;
15use rustc_span::Span;
16use std::collections::{HashMap, HashSet};
17use std::fmt::Debug;
18use std::hash::Hash;
19
20use super::contracts::abstract_state::{
21    AbstractStateItem, AlignState, PathInfo, StateType, VType, Value,
22};
23use super::contracts::contract::Contract;
24use super::dominated_chain::DominatedGraph;
25use super::dominated_chain::InterResultNode;
26use super::generic_check::GenericChecker;
27use super::inter_record::InterAnalysisRecord;
28use super::matcher::UnsafeApi;
29use super::matcher::{get_arg_place, parse_unsafe_api};
30use crate::analysis::core::heap_item::AdtOwner;
31use rustc_hir::def_id::DefId;
32use rustc_middle::ty::TyCtxt;
33use rustc_middle::{
34    mir::{
35        self, AggregateKind, BasicBlock, BasicBlockData, BinOp, CastKind, Operand, Place, Rvalue,
36        Statement, StatementKind, Terminator, TerminatorKind,
37    },
38    ty::{self, GenericArgKind, Ty, TyKind},
39};
40
41//TODO: modify contracts vec to contract-bool pairs (we can also use path index to record path info)
42pub struct CheckResult {
43    pub func_name: String,
44    pub func_span: Span,
45    pub failed_contracts: HashMap<usize, HashSet<String>>,
46    pub passed_contracts: HashMap<usize, HashSet<String>>,
47}
48
49impl CheckResult {
50    pub fn new(func_name: &str, func_span: Span) -> Self {
51        Self {
52            func_name: func_name.to_string(),
53            func_span,
54            failed_contracts: HashMap::new(),
55            passed_contracts: HashMap::new(),
56        }
57    }
58}
59
60#[derive(Debug, PartialEq, Eq, Clone)]
61pub enum PlaceTy<'tcx> {
62    Ty(usize, usize), // layout(align,size) of one specific type
63    GenericTy(String, HashSet<Ty<'tcx>>, HashSet<(usize, usize)>), // get specific type in generic map
64    Unknown,
65}
66
67impl<'tcx> PlaceTy<'tcx> {
68    pub fn possible_aligns(&self) -> HashSet<usize> {
69        match self {
70            PlaceTy::Ty(align, _size) => {
71                let mut set = HashSet::new();
72                set.insert(*align);
73                set
74            }
75            PlaceTy::GenericTy(_, _, tys) => tys.iter().map(|ty| ty.0).collect(),
76            _ => HashSet::new(),
77        }
78    }
79}
80
81impl<'tcx> Hash for PlaceTy<'tcx> {
82    fn hash<H: std::hash::Hasher>(&self, _state: &mut H) {}
83}
84
85pub struct BodyVisitor<'tcx> {
86    pub tcx: TyCtxt<'tcx>,
87    pub def_id: DefId,
88    pub safedrop_graph: SafeDropGraph<'tcx>,
89    // abstract_states records the path index and variables' ab states in this path
90    pub abstract_states: HashMap<usize, PathInfo<'tcx>>,
91    pub unsafe_callee_report: HashMap<String, usize>,
92    pub local_ty: HashMap<usize, PlaceTy<'tcx>>,
93    pub visit_time: usize,
94    pub check_results: Vec<CheckResult>,
95    pub generic_map: HashMap<String, HashSet<Ty<'tcx>>>,
96    pub global_recorder: HashMap<DefId, InterAnalysisRecord<'tcx>>,
97    pub proj_ty: HashMap<usize, Ty<'tcx>>,
98    pub chains: DominatedGraph<'tcx>,
99    pub paths: Vec<Vec<usize>>,
100}
101
102impl<'tcx> BodyVisitor<'tcx> {
103    pub fn new(
104        tcx: TyCtxt<'tcx>,
105        def_id: DefId,
106        global_recorder: HashMap<DefId, InterAnalysisRecord<'tcx>>,
107        visit_time: usize,
108    ) -> Self {
109        let body = tcx.optimized_mir(def_id);
110        let param_env = tcx.param_env(def_id);
111        let satisfied_ty_map_for_generic =
112            GenericChecker::new(tcx, param_env).get_satisfied_ty_map();
113        let mut chains = DominatedGraph::new(tcx, def_id);
114        chains.init_arg();
115        Self {
116            tcx,
117            def_id,
118            safedrop_graph: SafeDropGraph::new(body, tcx, def_id, AdtOwner::default()),
119            abstract_states: HashMap::new(),
120            unsafe_callee_report: HashMap::new(),
121            local_ty: HashMap::new(),
122            visit_time,
123            check_results: Vec::new(),
124            generic_map: satisfied_ty_map_for_generic,
125            global_recorder,
126            proj_ty: HashMap::new(),
127            chains,
128            paths: Vec::new(),
129        }
130    }
131
132    pub fn get_ty_by_place(&self, p: usize) -> Ty<'tcx> {
133        let body = self.tcx.optimized_mir(self.def_id);
134        let locals = body.local_decls.clone();
135        return locals[Local::from(p)].ty;
136    }
137
138    pub fn update_fields_states(&mut self, inter_result: InterResultNode<'tcx>) {
139        self.chains.init_self_with_inter(inter_result);
140    }
141
142    pub fn path_forward_check(&mut self, fn_map: &FnMap) -> InterResultNode<'tcx> {
143        let tmp_chain = self.chains.clone();
144        let mut inter_return_value =
145            InterResultNode::construct_from_var_node(self.chains.clone(), 0);
146        if self.visit_time >= 1000 {
147            return inter_return_value;
148        }
149
150        // get path and body
151        let paths: Vec<Vec<usize>> = self.get_all_paths();
152        self.paths = paths.clone();
153        let body = self.tcx.optimized_mir(self.def_id);
154
155        // initialize local vars' types
156        let locals = body.local_decls.clone();
157        for (idx, local) in locals.iter().enumerate() {
158            let local_ty = local.ty;
159            let layout = self.visit_ty_and_get_layout(local_ty);
160            self.local_ty.insert(idx, layout);
161        }
162
163        // Iterate all the paths. Paths have been handled by tarjan.
164        for (index, path_info) in paths.iter().enumerate() {
165            self.chains = tmp_chain.clone();
166            self.abstract_states.insert(index, PathInfo::new());
167            for block_index in path_info.iter() {
168                if block_index >= &body.basic_blocks.len() {
169                    continue;
170                }
171                self.path_analyze_block(
172                    &body.basic_blocks[BasicBlock::from_usize(*block_index)].clone(),
173                    index,
174                    *block_index,
175                    fn_map,
176                );
177                let tem_scc_sub_blocks = self.safedrop_graph.blocks[*block_index]
178                    .scc_sub_blocks
179                    .clone();
180                if tem_scc_sub_blocks.len() > 0 {
181                    for sub_block in &tem_scc_sub_blocks {
182                        self.path_analyze_block(
183                            &body.basic_blocks[BasicBlock::from_usize(*sub_block)].clone(),
184                            index,
185                            *block_index,
186                            fn_map,
187                        );
188                    }
189                }
190            }
191            // merge path analysis results
192            let curr_path_inter_return_value =
193                InterResultNode::construct_from_var_node(self.chains.clone(), 0);
194            inter_return_value.merge(curr_path_inter_return_value);
195        }
196
197        if get_cleaned_def_path_name(self.tcx, self.def_id).contains("::get") {
198            display_hashmap(&self.chains.variables, 1);
199        }
200
201        inter_return_value
202    }
203
204    pub fn path_analyze_block(
205        &mut self,
206        block: &BasicBlockData<'tcx>,
207        path_index: usize,
208        bb_index: usize,
209        fn_map: &FnMap,
210    ) {
211        for statement in block.statements.iter() {
212            self.path_analyze_statement(statement, path_index);
213        }
214        self.path_analyze_terminator(&block.terminator(), path_index, bb_index, fn_map);
215    }
216
217    pub fn path_analyze_statement(&mut self, statement: &Statement<'tcx>, _path_index: usize) {
218        match statement.kind {
219            StatementKind::Assign(box (ref lplace, ref rvalue)) => {
220                self.path_analyze_assign(lplace, rvalue, _path_index);
221            }
222            StatementKind::Intrinsic(box ref intrinsic) => match intrinsic {
223                mir::NonDivergingIntrinsic::CopyNonOverlapping(cno) => {
224                    if cno.src.place().is_some() && cno.dst.place().is_some() {
225                        let _src_pjc_local =
226                            self.handle_proj(true, cno.src.place().unwrap().clone());
227                        let _dst_pjc_local =
228                            self.handle_proj(true, cno.dst.place().unwrap().clone());
229                    }
230                }
231                _ => {}
232            },
233            StatementKind::StorageDead(local) => {
234                // self.chains.delete_node(local.as_usize());
235            }
236            _ => {}
237        }
238    }
239
240    pub fn path_analyze_terminator(
241        &mut self,
242        terminator: &Terminator<'tcx>,
243        path_index: usize,
244        bb_index: usize,
245        fn_map: &FnMap,
246    ) {
247        match &terminator.kind {
248            TerminatorKind::Call {
249                func,
250                args,
251                destination: dst_place,
252                target: _,
253                unwind: _,
254                call_source: _,
255                fn_span,
256            } => {
257                if let Operand::Constant(func_constant) = func {
258                    if let ty::FnDef(ref callee_def_id, raw_list) = func_constant.const_.ty().kind()
259                    {
260                        self.handle_call(
261                            dst_place,
262                            callee_def_id,
263                            args,
264                            path_index,
265                            fn_map,
266                            *fn_span,
267                        );
268                    }
269                }
270            }
271            TerminatorKind::Drop {
272                place,
273                target: _,
274                unwind: _,
275                replace: _,
276                drop: _,
277                async_fut: _,
278            } => {
279                let drop_local = self.handle_proj(false, *place);
280                if !self.chains.set_drop(drop_local) {
281                    // rap_warn!(
282                    //     "In path {:?}, double drop {drop_local} in block {bb_index}",
283                    //     self.paths[path_index]
284                    // );
285                }
286            }
287            _ => {}
288        }
289    }
290
291    pub fn path_analyze_assign(
292        &mut self,
293        lplace: &Place<'tcx>,
294        rvalue: &Rvalue<'tcx>,
295        path_index: usize,
296    ) {
297        let lpjc_local = self.handle_proj(false, lplace.clone());
298        match rvalue {
299            Rvalue::Use(op) => match op {
300                Operand::Move(rplace) => {
301                    let rpjc_local = self.handle_proj(true, rplace.clone());
302                    self.chains.merge(lpjc_local, rpjc_local);
303                }
304                Operand::Copy(rplace) => {
305                    let rpjc_local = self.handle_proj(true, rplace.clone());
306                    self.chains.copy_node(lpjc_local, rpjc_local);
307                }
308                _ => {}
309            },
310            Rvalue::Repeat(op, _const) => match op {
311                Operand::Move(rplace) | Operand::Copy(rplace) => {
312                    let _rpjc_local = self.handle_proj(true, rplace.clone());
313                }
314                _ => {}
315            },
316            Rvalue::Ref(_, _, rplace) | Rvalue::RawPtr(_, rplace) => {
317                let rpjc_local = self.handle_proj(true, rplace.clone());
318                // self.chains.insert_node(lpjc_local, self.chains.get_local_ty_by_place(lpjc_local));
319                self.chains.point(lpjc_local, rpjc_local);
320            }
321            Rvalue::Cast(cast_kind, op, ty) => match op {
322                Operand::Move(rplace) | Operand::Copy(rplace) => {
323                    let rpjc_local = self.handle_proj(true, rplace.clone());
324                    self.chains.merge(lpjc_local, rpjc_local);
325                    self.handle_cast(rpjc_local, lpjc_local, ty, path_index, cast_kind);
326                }
327                _ => {}
328            },
329            Rvalue::BinaryOp(_bin_op, box (ref _op1, ref _op2)) => {}
330            Rvalue::ShallowInitBox(op, _ty) => match op {
331                Operand::Move(rplace) | Operand::Copy(rplace) => {
332                    let _rpjc_local = self.handle_proj(true, rplace.clone());
333                }
334                _ => {}
335            },
336            Rvalue::Aggregate(box ref agg_kind, op_vec) => match agg_kind {
337                AggregateKind::Array(_ty) => {}
338                AggregateKind::Adt(_adt_def_id, _, _, _, _) => {
339                    for (idx, op) in op_vec.into_iter().enumerate() {
340                        let (is_const, val) = get_arg_place(op);
341                        if is_const {
342                            self.chains.insert_field_node(
343                                lpjc_local,
344                                idx,
345                                Some(Ty::new_uint(self.tcx, rustc_middle::ty::UintTy::Usize)),
346                            );
347                        } else {
348                            let node = self.chains.get_var_node_mut(lpjc_local).unwrap();
349                            node.field.insert(idx, val);
350                        }
351                    }
352                }
353                _ => {}
354            },
355            Rvalue::Discriminant(_place) => {
356                // println!("Discriminant {}:{:?}",lpjc_local,rvalue);
357            }
358            _ => {}
359        }
360    }
361
362    pub fn handle_call(
363        &mut self,
364        dst_place: &Place<'tcx>,
365        def_id: &DefId,
366        args: &Box<[Spanned<Operand>]>,
367        path_index: usize,
368        fn_map: &FnMap,
369        fn_span: Span,
370    ) {
371        if !self.tcx.is_mir_available(def_id) {
372            self.insert_path_abstate(
373                path_index,
374                dst_place.local.as_usize(),
375                AbstractStateItem::new_default(),
376            );
377            return;
378        }
379
380        // Find std unsafe API call, then check the contracts.
381        if let Some(fn_result) =
382            parse_unsafe_api(get_cleaned_def_path_name(self.tcx, *def_id).as_str())
383        {
384            self.handle_std_unsafe_call(
385                dst_place, def_id, args, path_index, fn_map, fn_span, fn_result,
386            );
387        }
388
389        // merge alias results
390        self.handle_ret_alias(dst_place, def_id, fn_map, args);
391
392        // to be deleted!
393        // get pre analysis state
394        let mut pre_analysis_state = HashMap::new();
395        for (idx, arg) in args.iter().enumerate() {
396            let arg_place = get_arg_place(&arg.node);
397            let ab_state_item = self.get_abstate_by_place_in_path(arg_place.1, path_index);
398            pre_analysis_state.insert(idx, ab_state_item);
399        }
400
401        // check cache and update new states for args and return value
402        let mut gr = self.global_recorder.clone();
403        if let Some(record) = gr.get_mut(def_id) {
404            if record.is_pre_state_same(&pre_analysis_state) {
405                self.update_post_state(&record.post_analysis_state, args, path_index);
406                self.insert_path_abstate(
407                    path_index,
408                    dst_place.local.as_usize(),
409                    record.ret_state.clone(),
410                );
411                return;
412            }
413        }
414
415        // update post states and cache
416        let tcx = self.tcx;
417        let mut inter_body_visitor: BodyVisitor<'_> = BodyVisitor::new(
418            tcx,
419            *def_id,
420            self.global_recorder.clone(),
421            self.visit_time + 1,
422        );
423        inter_body_visitor.path_forward_check(fn_map);
424        let post_analysis_state: HashMap<usize, AbstractStateItem<'_>> =
425            inter_body_visitor.get_args_post_states().clone();
426        self.update_post_state(&post_analysis_state, args, path_index);
427        let ret_state = post_analysis_state.get(&0).unwrap().clone();
428        self.global_recorder.insert(
429            *def_id,
430            InterAnalysisRecord::new(pre_analysis_state, post_analysis_state, ret_state),
431        );
432    }
433
434    // Use the alias analysis to support quick merge inter analysis results.
435    pub fn handle_ret_alias(
436        &mut self,
437        dst_place: &Place<'tcx>,
438        def_id: &DefId,
439        fn_map: &FnMap,
440        args: &Box<[Spanned<Operand>]>,
441    ) {
442        let d_local = self.handle_proj(false, dst_place.clone());
443        // Find alias relationship in cache.
444        // If one of the op is ptr, then alias the pointed node with another.
445        if let Some(retalias) = fn_map.get(def_id) {
446            for alias_set in retalias.aliases() {
447                let (l, r) = (alias_set.fact.lhs_no, alias_set.fact.rhs_no);
448                let (l_fields, r_fields) = (
449                    alias_set.fact.lhs_fields.clone(),
450                    alias_set.fact.rhs_fields.clone(),
451                );
452                let (l_place, r_place) = (
453                    if l != 0 {
454                        get_arg_place(&args[l - 1].node)
455                    } else {
456                        (false, d_local)
457                    },
458                    if r != 0 {
459                        get_arg_place(&args[r - 1].node)
460                    } else {
461                        (false, d_local)
462                    },
463                );
464                // if left value is a constant, then update right variable's value
465                if l_place.0 {
466                    let snd_var = self.chains.find_var_id_with_fields_seq(r_place.1, r_fields);
467                    self.chains
468                        .update_value(self.chains.get_point_to_id(snd_var), l_place.1);
469                    continue;
470                }
471                // if right value is a constant, then update left variable's value
472                if r_place.0 {
473                    let fst_var = self.chains.find_var_id_with_fields_seq(l_place.1, l_fields);
474                    self.chains
475                        .update_value(self.chains.get_point_to_id(fst_var), r_place.1);
476                    continue;
477                }
478                let (fst_var, snd_var) = (
479                    self.chains.find_var_id_with_fields_seq(l_place.1, l_fields),
480                    self.chains.find_var_id_with_fields_seq(r_place.1, r_fields),
481                );
482                // If this var is ptr or ref, then get the next level node.
483                let fst_to = self.chains.get_point_to_id(fst_var);
484                let snd_to = self.chains.get_point_to_id(snd_var);
485                let is_fst_ptr = fst_to != fst_var;
486                let is_snd_ptr = snd_to != snd_var;
487                match (is_fst_ptr, is_snd_ptr) {
488                    (false, true) => {
489                        self.chains.merge(snd_to, fst_to);
490                    }
491                    _ => {
492                        self.chains.merge(fst_to, snd_to);
493                    }
494                }
495            }
496        }
497        // If no alias cache is found and dst is a ptr, then initialize dst's states.
498        else {
499            let d_ty = self.chains.get_local_ty_by_place(d_local);
500            if d_ty.is_some() && (is_ptr(d_ty.unwrap()) || is_ref(d_ty.unwrap())) {
501                self.chains
502                    .generate_ptr_with_obj_node(d_ty.unwrap(), d_local);
503            }
504        }
505    }
506
507    // if inter analysis's params are in mut_ref, then we should update their post states
508    pub fn update_post_state(
509        &mut self,
510        post_state: &HashMap<usize, AbstractStateItem<'tcx>>,
511        args: &Box<[Spanned<Operand>]>,
512        path_index: usize,
513    ) {
514        for (idx, arg) in args.iter().enumerate() {
515            let arg_place = get_arg_place(&arg.node);
516            if let Some(state_item) = post_state.get(&idx) {
517                self.insert_path_abstate(path_index, arg_place.1, state_item.clone());
518            }
519        }
520    }
521
522    pub fn get_args_post_states(&mut self) -> HashMap<usize, AbstractStateItem<'tcx>> {
523        let tcx = self.tcx;
524        let def_id = self.def_id;
525        let final_states = self.abstract_states_mop();
526        let mut result_states = HashMap::new();
527        let fn_sig = tcx.fn_sig(def_id).skip_binder();
528        let num_params = fn_sig.inputs().skip_binder().len();
529        for i in 0..num_params + 1 {
530            if let Some(state) = final_states.state_map.get(&(i)) {
531                result_states.insert(i, state.clone());
532            } else {
533                result_states.insert(i, AbstractStateItem::new_default());
534            }
535        }
536        result_states
537    }
538
539    pub fn get_all_paths(&mut self) -> Vec<Vec<usize>> {
540        self.safedrop_graph.solve_scc();
541        let mut results: Vec<Vec<usize>> = self.safedrop_graph.get_paths();
542        let contains_unsafe_blocks = get_all_std_unsafe_callees_block_id(self.tcx, self.def_id);
543        results.retain(|path| {
544            path.iter()
545                .any(|block_id| contains_unsafe_blocks.contains(block_id))
546        });
547        results
548    }
549
550    pub fn abstract_states_mop(&mut self) -> PathInfo<'tcx> {
551        let mut result_state = PathInfo {
552            state_map: HashMap::new(),
553        };
554
555        for (_path_idx, abstract_state) in &self.abstract_states {
556            for (var_index, state_item) in &abstract_state.state_map {
557                if let Some(existing_state_item) = result_state.state_map.get_mut(&var_index) {
558                    existing_state_item
559                        .clone()
560                        .meet_state_item(&state_item.clone());
561                } else {
562                    result_state
563                        .state_map
564                        .insert(*var_index, state_item.clone());
565                }
566            }
567        }
568        result_state
569    }
570
571    pub fn update_callee_report_level(&mut self, unsafe_callee: String, report_level: usize) {
572        self.unsafe_callee_report
573            .entry(unsafe_callee)
574            .and_modify(|e| {
575                if report_level < *e {
576                    *e = report_level;
577                }
578            })
579            .or_insert(report_level);
580    }
581
582    // level: 0 bug_level, 1-3 unsound_level
583    // TODO: add more information about the result
584    pub fn output_results(&self, threshold: usize) {
585        for (unsafe_callee, report_level) in &self.unsafe_callee_report {
586            if *report_level == 0 {
587                rap_warn!("Find one bug in {:?}!", unsafe_callee);
588            } else if *report_level <= threshold {
589                rap_warn!("Find an unsoundness issue in {:?}!", unsafe_callee);
590            }
591        }
592    }
593
594    pub fn insert_path_abstate(
595        &mut self,
596        path_index: usize,
597        place: usize,
598        abitem: AbstractStateItem<'tcx>,
599    ) {
600        self.abstract_states
601            .entry(path_index)
602            .or_insert_with(|| PathInfo {
603                state_map: HashMap::new(),
604            })
605            .state_map
606            .insert(place, abitem);
607    }
608
609    pub fn get_layout_by_place_usize(&self, place: usize) -> PlaceTy<'tcx> {
610        if let Some(ty) = self.chains.get_obj_ty_through_chain(place) {
611            return self.visit_ty_and_get_layout(ty);
612        } else {
613            return PlaceTy::Unknown;
614        }
615    }
616
617    pub fn visit_ty_and_get_layout(&self, ty: Ty<'tcx>) -> PlaceTy<'tcx> {
618        match ty.kind() {
619            TyKind::RawPtr(ty, _)
620            | TyKind::Ref(_, ty, _)
621            | TyKind::Slice(ty)
622            | TyKind::Array(ty, _) => self.visit_ty_and_get_layout(*ty),
623            TyKind::Param(param_ty) => {
624                let generic_name = param_ty.name.as_str().to_string();
625                let mut layout_set: HashSet<(usize, usize)> = HashSet::new();
626                let ty_set = self.generic_map.get(&generic_name.clone());
627                if ty_set.is_none() {
628                    if self.visit_time == 0 {
629                        rap_warn!(
630                            "Can not get generic type set: {:?}, def_id:{:?}",
631                            generic_name,
632                            self.def_id
633                        );
634                    }
635                    return PlaceTy::GenericTy(generic_name, HashSet::new(), layout_set);
636                }
637                for ty in ty_set.unwrap().clone() {
638                    if let PlaceTy::Ty(align, size) = self.visit_ty_and_get_layout(ty) {
639                        layout_set.insert((align, size));
640                    }
641                }
642                return PlaceTy::GenericTy(generic_name, ty_set.unwrap().clone(), layout_set);
643            }
644            TyKind::Adt(def, _list) => {
645                if def.is_enum() {
646                    return PlaceTy::Unknown;
647                } else {
648                    PlaceTy::Unknown
649                }
650            }
651            TyKind::Closure(_, _) => PlaceTy::Unknown,
652            TyKind::Alias(_, ty) => {
653                // rap_warn!("self ty {:?}",ty.self_ty());
654                return self.visit_ty_and_get_layout(ty.self_ty());
655            }
656            _ => {
657                let param_env = self.tcx.param_env(self.def_id);
658                let ty_env = ty::TypingEnv::post_analysis(self.tcx, self.def_id);
659                let input = PseudoCanonicalInput {
660                    typing_env: ty_env,
661                    value: ty,
662                };
663                if let Ok(layout) = self.tcx.layout_of(input) {
664                    // let layout = self.tcx.layout_of(param_env.and(ty)).unwrap();
665                    let align = layout.align.abi.bytes_usize();
666                    let size = layout.size.bytes() as usize;
667                    return PlaceTy::Ty(align, size);
668                } else {
669                    rap_warn!("Find type {:?} that can't get layout!", ty);
670                    PlaceTy::Unknown
671                }
672            }
673        }
674    }
675
676    pub fn get_abstate_by_place_in_path(
677        &self,
678        place: usize,
679        path_index: usize,
680    ) -> AbstractStateItem<'tcx> {
681        if let Some(abstate) = self.abstract_states.get(&path_index) {
682            if let Some(abs) = abstate.state_map.get(&place).cloned() {
683                return abs;
684            }
685        }
686        AbstractStateItem::new_default()
687    }
688
689    pub fn handle_cast(
690        &mut self,
691        rpjc_local: usize,
692        lpjc_local: usize,
693        ty: &Ty<'tcx>,
694        path_index: usize,
695        cast_kind: &CastKind,
696    ) {
697        let mut src_ty = self.get_layout_by_place_usize(rpjc_local);
698        match cast_kind {
699            CastKind::PtrToPtr | CastKind::PointerCoercion(_, _) => {
700                let r_abitem = self.get_abstate_by_place_in_path(rpjc_local, path_index);
701                for state in &r_abitem.state {
702                    if let StateType::AlignState(r_align_state) = state.clone() {
703                        match r_align_state {
704                            AlignState::Cast(from, _to) => {
705                                src_ty = from.clone();
706                            }
707                            _ => {}
708                        }
709                    }
710                }
711
712                let dst_ty = self.visit_ty_and_get_layout(*ty);
713                let align_state =
714                    StateType::AlignState(AlignState::Cast(src_ty.clone(), dst_ty.clone()));
715                let abitem = AbstractStateItem::new(
716                    (Value::None, Value::None),
717                    VType::Pointer(dst_ty),
718                    HashSet::from([align_state]),
719                );
720                self.insert_path_abstate(path_index, lpjc_local, abitem);
721            }
722            _ => {}
723        }
724    }
725
726    pub fn handle_binary_op(
727        &mut self,
728        first_op: &Operand,
729        bin_op: &BinOp,
730        second_op: &Operand,
731        path_index: usize,
732    ) {
733        match bin_op {
734            BinOp::Offset => {
735                let _first_place = get_arg_place(first_op);
736                let _second_place = get_arg_place(second_op);
737            }
738            _ => {}
739        }
740    }
741
742    pub fn handle_proj(&mut self, is_right: bool, place: Place<'tcx>) -> usize {
743        let mut proj_id = place.local.as_usize();
744        for proj in place.projection {
745            match proj {
746                ProjectionElem::Deref => {
747                    proj_id = self.chains.get_point_to_id(place.local.as_usize());
748                    if proj_id == place.local.as_usize() {
749                        proj_id = self.chains.check_ptr(proj_id);
750                    }
751                }
752                ProjectionElem::Field(field, ty) => {
753                    proj_id = self
754                        .chains
755                        .get_field_node_id(proj_id, field.as_usize(), Some(ty));
756                }
757                _ => {}
758            }
759        }
760        proj_id
761    }
762}