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
41pub 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), GenericTy(String, HashSet<Ty<'tcx>>, HashSet<(usize, usize)>), 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 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 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 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 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 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 }
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 }
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.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 }
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 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 self.handle_ret_alias(dst_place, def_id, fn_map, args);
391
392 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 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 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 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 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 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 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 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 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 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 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 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 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}