1use crate::compat::Spanned;
2use rustc_abi::VariantIdx;
3use rustc_data_structures::graph;
4use rustc_hir::def_id::DefId;
5use rustc_middle::{
6 mir::{
7 AggregateKind, BasicBlock, BasicBlockData, Body, Local, Operand, Place, ProjectionElem,
8 Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
9 },
10 ty::{self, InstanceKind::Item, Ty, TyKind, TypeVisitable},
11};
12use rustc_span::Symbol;
13
14use annotate_snippets::{Level, Renderer, Snippet};
15use std::ops::Add;
16use z3::ast::{self, Ast};
17
18use super::super::{IcxMut, IcxSliceMut, Rcx, RcxMut};
19use super::is_z3_goal_verbose;
20use super::ownership::IntraVar;
21use super::{FlowAnalysis, IcxSliceFroBlock, IntraFlowAnalysis};
22use crate::{
23 analysis::ownedheap_analysis::{default::*, *},
24 utils::{
25 log::{
26 are_spans_in_same_file, relative_pos_range, span_to_filename, span_to_line_number,
27 span_to_source_code,
28 },
29 source::get_name,
30 },
31};
32
33type Disc = Option<VariantIdx>;
34type Aggre = Option<usize>;
35
36#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
37pub enum AsgnKind {
38 Assign,
39 Reference,
40 Pointer,
41 Cast,
42 Aggregate,
43}
44
45impl<'tcx, 'a> FlowAnalysis<'tcx, 'a> {
46 pub fn intra_run(&mut self) {
47 let tcx = self.tcx();
48 let mir_keys = tcx.mir_keys(());
49
50 for each_mir in mir_keys {
51 let def_id = each_mir.to_def_id();
52 let body = tcx.instance_mir(Item(def_id));
53 if graph::is_cyclic(&body.basic_blocks) {
54 continue;
55 }
56 if format!("{:?}", def_id).contains("syscall_dispatch") {
57 continue;
58 }
59
60 let mut cfg = z3::Config::new();
61 cfg.set_model_generation(true);
62 cfg.set_timeout_msec(1000);
63 let ctx = z3::Context::new(&cfg);
64 let goal = z3::Goal::new(&ctx, true, false, false);
65 let solver = z3::Solver::new(&ctx);
66
67 let mut intra_visitor = IntraFlowAnalysis::new(self.rcx, def_id);
68 intra_visitor.visit_body(&ctx, &goal, &solver, body);
69 }
70 }
71}
72
73impl<'tcx, 'ctx, 'a> IntraFlowAnalysis<'tcx, 'ctx, 'a> {
74 pub(crate) fn visit_body(
75 &mut self,
76 ctx: &'ctx z3::Context,
77 goal: &'ctx z3::Goal<'ctx>,
78 solver: &'ctx z3::Solver<'ctx>,
79 body: &'tcx Body<'tcx>,
80 ) {
81 let topo: Vec<usize> = self.graph.get_topo().iter().map(|id| *id).collect();
82 for bidx in topo {
83 let data = &body.basic_blocks[BasicBlock::from(bidx)];
84 self.visit_block_data(ctx, goal, solver, data, bidx);
85 }
86 }
87
88 pub(crate) fn visit_block_data(
89 &mut self,
90 ctx: &'ctx z3::Context,
91 goal: &'ctx z3::Goal<'ctx>,
92 solver: &'ctx z3::Solver<'ctx>,
93 data: &'tcx BasicBlockData<'tcx>,
94 bidx: usize,
95 ) {
96 self.preprocess_for_basic_block(ctx, goal, solver, bidx);
97
98 for (sidx, stmt) in data.statements.iter().enumerate() {
99 self.visit_statement(ctx, goal, solver, stmt, bidx, sidx);
100 }
101
102 self.visit_terminator(ctx, goal, solver, data.terminator(), bidx);
103
104 self.reprocess_for_basic_block(bidx);
105 }
106
107 pub(crate) fn preprocess_for_basic_block(
108 &mut self,
109 ctx: &'ctx z3::Context,
110 goal: &'ctx z3::Goal<'ctx>,
111 solver: &'ctx z3::Solver<'ctx>,
112 bidx: usize,
113 ) {
114 if bidx == 0 {
116 let mut icx_slice = IcxSliceFroBlock::new_for_block_0(self.body.local_decls.len());
117
118 for arg_idx in 0..self.body.arg_count {
119 let idx = arg_idx + 1;
120 let ty = self.body.local_decls[Local::from_usize(idx)].ty;
121
122 let ty_with_index = TyWithIndex::new(ty, None);
123 if ty_with_index == TyWithIndex(None) {
124 self.handle_intra_var_unsupported(idx);
125 continue;
126 }
127
128 let default_layout = self.extract_default_ty_layout(ty, None);
129 if !default_layout.is_owned() {
130 icx_slice.len_mut()[idx] = 0;
131 icx_slice.var_mut()[idx] = IntraVar::Unsupported;
132 icx_slice.ty_mut()[idx] = TyWithIndex(None);
133 continue;
134 }
135 let int = rustbv_to_int(&heap_layout_to_rustbv(default_layout.layout()));
136
137 let name = new_local_name(idx, 0, 0).add("_arg_init");
138 let len = default_layout.layout().len();
139
140 let new_bv = ast::BV::new_const(ctx, name, len as u32);
141 let init_const = ast::BV::from_u64(ctx, int, len as u32);
142
143 let constraint_init_arg = new_bv._eq(&init_const);
144
145 goal.assert(&constraint_init_arg);
146 solver.assert(&constraint_init_arg);
147
148 icx_slice.len_mut()[idx] = len;
149 icx_slice.var_mut()[idx] = IntraVar::Init(new_bv);
150 icx_slice.ty_mut()[idx] = ty_with_index;
151 }
152
153 *self.icx_slice_mut() = icx_slice.clone();
154
155 return;
156 }
157
158 let pre = &self.graph.pre[bidx];
159
160 if pre.len() > 1 {
161 let mut v_pre_collect: Vec<IcxSliceFroBlock> = Vec::default();
163 for idx in pre {
164 v_pre_collect.push(IcxSliceFroBlock::new_out(self.icx_mut(), *idx));
165 }
166
167 let mut ans_icx_slice = v_pre_collect[0].clone();
169 let var_len = v_pre_collect[0].len().len();
170
171 for var_idx in 0..var_len {
173 let mut using_for_and_bv: Option<ast::BV> = None;
176 let mut ty = TyWithIndex::default();
177 let mut len = 0;
178
179 let mut unsupported = false;
180 for idx in 0..v_pre_collect.len() {
182 let var = &v_pre_collect[idx].var()[var_idx];
184 if var.is_declared() {
185 continue;
186 }
187 if var.is_unsupported() {
188 unsupported = true;
189 ans_icx_slice.len_mut()[var_idx] = 0;
190 ans_icx_slice.var_mut()[var_idx] = IntraVar::Unsupported;
191 break;
192 }
193
194 let var_bv = var.extract();
196 if ty == TyWithIndex(None) {
197 ty = v_pre_collect[idx].ty()[var_idx].clone();
198 len = v_pre_collect[idx].len()[var_idx];
199
200 ans_icx_slice.ty_mut()[var_idx] = ty.clone();
201 ans_icx_slice.len_mut()[var_idx] = len;
202
203 using_for_and_bv = Some(var_bv.clone());
204 }
205
206 if ty != v_pre_collect[idx].ty()[var_idx] {
207 unsupported = true;
208 ans_icx_slice.len_mut()[var_idx] = 0;
209 ans_icx_slice.var_mut()[var_idx] = IntraVar::Unsupported;
210 break;
211 }
212
213 let bv_and = using_for_and_bv.unwrap().bvand(&var_bv);
215 using_for_and_bv = Some(bv_and);
216 ans_icx_slice.taint_merge(&v_pre_collect[idx], var_idx);
217 }
218
219 if unsupported || using_for_and_bv.is_none() {
220 *self.icx_slice_mut() = ans_icx_slice.clone();
221 continue;
222 }
223
224 let name = new_local_name(var_idx, bidx, 0).add("_phi");
225 let phi_bv = ast::BV::new_const(ctx, name, len as u32);
226 let constraint_phi = phi_bv._eq(&using_for_and_bv.unwrap());
227
228 goal.assert(&constraint_phi);
229 solver.assert(&constraint_phi);
230
231 ans_icx_slice.var_mut()[var_idx] = IntraVar::Init(phi_bv);
232
233 *self.icx_slice_mut() = ans_icx_slice.clone();
234 }
235 } else {
236 if pre.len() == 0 {
237 rap_error!("The pre node is empty, check the logic is safe to launch.");
238 }
239 self.icx_mut().derive_from_pre_node(pre[0], bidx);
240 self.icx_slice = IcxSliceFroBlock::new_in(self.icx_mut(), bidx);
241 }
242
243 }
245
246 pub(crate) fn reprocess_for_basic_block(&mut self, bidx: usize) {
247 let icx_slice = self.icx_slice().clone();
248 self.icx_slice = IcxSliceFroBlock::default();
249 self.icx_mut().derive_from_icx_slice(icx_slice, bidx);
250 }
251
252 pub(crate) fn visit_statement(
253 &mut self,
254 ctx: &'ctx z3::Context,
255 goal: &'ctx z3::Goal<'ctx>,
256 solver: &'ctx z3::Solver<'ctx>,
257 stmt: &Statement<'tcx>,
258 bidx: usize,
259 sidx: usize,
260 ) {
261 match &stmt.kind {
262 StatementKind::Assign(assign) => {
263 let (place, rvalue) = &**assign;
264 help_debug_goal_stmt(ctx, goal, bidx, sidx);
265
266 let disc: Disc = None;
267
268 self.visit_assign(ctx, goal, solver, place, rvalue, disc, bidx, sidx);
294 rap_debug!(
295 "IcxSlice in Assign: {} {}: {:?}\n{:?}\n",
296 bidx,
297 sidx,
298 stmt.kind,
299 self.icx_slice()
300 );
301 }
302 StatementKind::StorageLive(_local) => {}
303 StatementKind::StorageDead(_local) => {}
304 _ => (),
305 }
306 }
307
308 pub(crate) fn visit_terminator(
309 &mut self,
310 ctx: &'ctx z3::Context,
311 goal: &'ctx z3::Goal<'ctx>,
312 solver: &'ctx z3::Solver<'ctx>,
313 term: &'tcx Terminator<'tcx>,
314 bidx: usize,
315 ) {
316 help_debug_goal_term(ctx, goal, bidx);
317
318 match &term.kind {
319 TerminatorKind::Drop { place, .. } => {
320 self.handle_drop(ctx, goal, solver, place, bidx, false);
321 }
322 TerminatorKind::Call {
323 func,
324 args,
325 destination,
326 ..
327 } => {
328 self.handle_call(
329 ctx,
330 goal,
331 solver,
332 term.clone(),
333 &func,
334 &args,
335 &destination,
336 bidx,
337 );
338 }
339 TerminatorKind::Return => {
340 self.handle_return(ctx, goal, solver, bidx);
341 }
342 _ => (),
343 }
344
345 rap_debug!(
346 "IcxSlice in Terminator: {}: {:?}\n{:?}\n",
347 bidx,
348 term.kind,
349 self.icx_slice()
350 );
351 }
352
353 pub(crate) fn visit_assign(
354 &mut self,
355 ctx: &'ctx z3::Context,
356 goal: &'ctx z3::Goal<'ctx>,
357 solver: &'ctx z3::Solver<'ctx>,
358 lplace: &Place<'tcx>,
359 rvalue: &Rvalue<'tcx>,
360 disc: Disc,
361 bidx: usize,
362 sidx: usize,
363 ) {
364 let lvalue_has_projection = has_projection(lplace);
365
366 match rvalue {
367 Rvalue::Use(op, ..) => {
368 let kind = AsgnKind::Assign;
369 let aggre = None;
370 match op {
371 Operand::Copy(rplace) => {
372 let rvalue_has_projection = has_projection(rplace);
373 match (lvalue_has_projection, rvalue_has_projection) {
374 (true, true) => {
375 self.handle_copy_field_to_field(
376 ctx, goal, solver, kind, lplace, rplace, disc, aggre, bidx,
377 sidx,
378 );
379 }
380 (true, false) => {
381 self.handle_copy_to_field(
382 ctx, goal, solver, kind, lplace, rplace, disc, aggre, bidx,
383 sidx,
384 );
385 }
386 (false, true) => {
387 self.handle_copy_from_field(
388 ctx, goal, solver, kind, lplace, rplace, bidx, sidx,
389 );
390 }
391 (false, false) => {
392 self.handle_copy(
393 ctx, goal, solver, kind, lplace, rplace, bidx, sidx,
394 );
395 }
396 }
397 }
398 Operand::Move(rplace) => {
399 let rvalue_has_projection = has_projection(rplace);
400 match (lvalue_has_projection, rvalue_has_projection) {
401 (true, true) => {
402 self.handle_move_field_to_field(
403 ctx, goal, solver, kind, lplace, rplace, disc, aggre, bidx,
404 sidx,
405 );
406 }
407 (true, false) => {
408 self.handle_move_to_field(
409 ctx, goal, solver, kind, lplace, rplace, disc, aggre, bidx,
410 sidx,
411 );
412 }
413 (false, true) => {
414 self.handle_move_from_field(
415 ctx, goal, solver, kind, lplace, rplace, bidx, sidx,
416 );
417 }
418 (false, false) => {
419 self.handle_move(
420 ctx, goal, solver, kind, lplace, rplace, bidx, sidx,
421 );
422 }
423 }
424 }
425 _ => (),
426 }
427 }
428 Rvalue::Ref(.., rplace) => {
429 let kind = AsgnKind::Reference;
430 let aggre = None;
431 let rvalue_has_projection = has_projection(rplace);
432 match (lvalue_has_projection, rvalue_has_projection) {
433 (true, true) => {
434 self.handle_copy_field_to_field(
435 ctx, goal, solver, kind, lplace, rplace, disc, aggre, bidx, sidx,
436 );
437 }
438 (true, false) => {
439 self.handle_copy_to_field(
440 ctx, goal, solver, kind, lplace, rplace, disc, aggre, bidx, sidx,
441 );
442 }
443 (false, true) => {
444 self.handle_copy_from_field(
445 ctx, goal, solver, kind, lplace, rplace, bidx, sidx,
446 );
447 }
448 (false, false) => {
449 self.handle_copy(ctx, goal, solver, kind, lplace, rplace, bidx, sidx);
450 }
451 }
452 }
453 Rvalue::RawPtr(_, rplace) => {
454 let kind = AsgnKind::Reference;
455 let aggre = None;
456 let rvalue_has_projection = has_projection(rplace);
457 match (lvalue_has_projection, rvalue_has_projection) {
458 (true, true) => {
459 self.handle_copy_field_to_field(
460 ctx, goal, solver, kind, lplace, rplace, disc, aggre, bidx, sidx,
461 );
462 }
463 (true, false) => {
464 self.handle_copy_to_field(
465 ctx, goal, solver, kind, lplace, rplace, disc, aggre, bidx, sidx,
466 );
467 }
468 (false, true) => {
469 self.handle_copy_from_field(
470 ctx, goal, solver, kind, lplace, rplace, bidx, sidx,
471 );
472 }
473 (false, false) => {
474 self.handle_copy(ctx, goal, solver, kind, lplace, rplace, bidx, sidx);
475 }
476 }
477 }
478 Rvalue::Cast(_cast_kind, op, ..) => {
479 let kind = AsgnKind::Cast;
480 let aggre = None;
481 match op {
482 Operand::Copy(rplace) => {
483 let rvalue_has_projection = has_projection(rplace);
484 match (lvalue_has_projection, rvalue_has_projection) {
485 (true, true) => {
486 self.handle_copy_field_to_field(
487 ctx, goal, solver, kind, lplace, rplace, disc, aggre, bidx,
488 sidx,
489 );
490 }
491 (true, false) => {
492 self.handle_copy_to_field(
493 ctx, goal, solver, kind, lplace, rplace, disc, aggre, bidx,
494 sidx,
495 );
496 }
497 (false, true) => {
498 self.handle_copy_from_field(
499 ctx, goal, solver, kind, lplace, rplace, bidx, sidx,
500 );
501 }
502 (false, false) => {
503 self.handle_copy(
504 ctx, goal, solver, kind, lplace, rplace, bidx, sidx,
505 );
506 }
507 }
508 }
509 Operand::Move(rplace) => {
510 let rvalue_has_projection = has_projection(rplace);
511 match (lvalue_has_projection, rvalue_has_projection) {
512 (true, true) => {
513 self.handle_move_field_to_field(
514 ctx, goal, solver, kind, lplace, rplace, disc, aggre, bidx,
515 sidx,
516 );
517 }
518 (true, false) => {
519 self.handle_move_to_field(
520 ctx, goal, solver, kind, lplace, rplace, disc, aggre, bidx,
521 sidx,
522 );
523 }
524 (false, true) => {
525 self.handle_move_from_field(
526 ctx, goal, solver, kind, lplace, rplace, bidx, sidx,
527 );
528 }
529 (false, false) => {
530 self.handle_move(
531 ctx, goal, solver, kind, lplace, rplace, bidx, sidx,
532 );
533 }
534 }
535 }
536 _ => (),
537 }
538 }
539 Rvalue::Aggregate(akind, operands) => {
540 if lvalue_has_projection {
541 return;
542 }
543 let kind = AsgnKind::Aggregate;
544 match **akind {
545 AggregateKind::Adt(did, vidx, ..) => {
546 self.handle_aggregate_init(
547 ctx, goal, solver, kind, lplace, did, vidx, disc, bidx, sidx,
548 );
549 for (fidx, op) in operands.iter().enumerate() {
550 let aggre = Some(fidx);
551 match op {
552 Operand::Copy(rplace) => {
553 let rvalue_has_projection = has_projection(rplace);
554 match rvalue_has_projection {
555 true => {
556 self.handle_copy_field_to_field(
557 ctx, goal, solver, kind, lplace, rplace, disc,
558 aggre, bidx, sidx,
559 );
560 }
561 false => {
562 self.handle_copy_to_field(
563 ctx, goal, solver, kind, lplace, rplace, disc,
564 aggre, bidx, sidx,
565 );
566 }
567 }
568 }
569 Operand::Move(rplace) => {
570 let rvalue_has_projection = has_projection(rplace);
571 match rvalue_has_projection {
572 true => {
573 self.handle_move_field_to_field(
574 ctx, goal, solver, kind, lplace, rplace, disc,
575 aggre, bidx, sidx,
576 );
577 }
578 false => {
579 self.handle_move_to_field(
580 ctx, goal, solver, kind, lplace, rplace, disc,
581 aggre, bidx, sidx,
582 );
583 }
584 }
585 }
586 _ => (),
587 }
588 }
589 }
590 _ => {
591 return;
592 }
593 }
594 }
595 _ => (),
596 }
597 }
598
599 pub(crate) fn handle_copy(
600 &mut self,
601 ctx: &'ctx z3::Context,
602 goal: &'ctx z3::Goal<'ctx>,
603 solver: &'ctx z3::Solver<'ctx>,
604 _kind: AsgnKind,
605 lplace: &Place<'tcx>,
606 rplace: &Place<'tcx>,
607 bidx: usize,
608 sidx: usize,
609 ) {
610 let llocal = lplace.local;
611 let rlocal = rplace.local;
612
613 let lu: usize = llocal.as_usize();
614 let ru: usize = rlocal.as_usize();
615
616 if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
618 {
619 self.handle_intra_var_unsupported(lu);
620 self.handle_intra_var_unsupported(ru);
621 return;
622 }
623 if !self.icx_slice().var[ru].is_init() {
624 return;
625 }
626
627 if self.icx_slice().len()[ru] == 0 {
630 return;
632 }
633
634 let mut llen = self.icx_slice().len()[lu];
636 let rlen = self.icx_slice().len()[ru];
637
638 let l_ori_bv: ast::BV;
640 let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
641
642 let mut is_ctor = true;
643 if self.icx_slice().var()[lu].is_init() {
644 if llen == 0 {
645 rap_debug!(
646 "handle_copy: lvalue length is 0 for local {:?}, skipping\n",
647 lu
648 );
649 return;
650 }
651 if self.icx_slice().ty()[lu] != self.icx_slice().ty[ru] {
656 self.handle_intra_var_unsupported(lu);
657 self.handle_intra_var_unsupported(ru);
658 return;
659 }
660 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
661 let l_zero_const = ast::BV::from_u64(ctx, 0, llen as u32);
662 let constraint_l_ori_zero = l_ori_bv._safe_eq(&l_zero_const).unwrap();
663 goal.assert(&constraint_l_ori_zero);
664 solver.assert(&constraint_l_ori_zero);
665 is_ctor = false;
666 } else {
667 let r_place_ty = rplace.ty(&self.body.local_decls, self.tcx());
669 let ty_with_vidx = TyWithIndex::new(r_place_ty.ty, r_place_ty.variant_index);
670 match ty_with_vidx.get_priority() {
671 0 => {
672 self.handle_intra_var_unsupported(lu);
674 self.handle_intra_var_unsupported(ru);
675 return;
676 }
677 1 => {
678 return;
679 }
680 2 => {
681 self.icx_slice_mut().ty_mut()[lu] = self.icx_slice().ty()[ru].clone();
683 self.icx_slice_mut().layout_mut()[lu] = self.icx_slice().layout()[ru].clone();
684 }
685 _ => unreachable!(),
686 }
687 }
688
689 llen = rlen;
691 self.icx_slice_mut().len_mut()[lu] = llen;
692
693 let l_name = if is_ctor {
695 new_local_name(lu, bidx, sidx).add("_ctor_asgn")
696 } else {
697 new_local_name(lu, bidx, sidx)
698 };
699 let r_name = new_local_name(ru, bidx, sidx);
700
701 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
703 let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
704
705 let l_zero_const = ast::BV::from_u64(ctx, 0, llen as u32);
706 let r_zero_const = ast::BV::from_u64(ctx, 0, rlen as u32);
707
708 let r_owning = r_new_bv._safe_eq(&r_ori_bv).unwrap();
712 let l_non_owning = l_new_bv._safe_eq(&l_zero_const).unwrap();
713 let args1 = &[&r_owning, &l_non_owning];
714 let summary_1 = ast::Bool::and(ctx, args1);
715
716 let l_owning = l_new_bv._safe_eq(&r_ori_bv).unwrap();
718 let r_non_owning = r_new_bv._safe_eq(&r_zero_const).unwrap();
719 let args2 = &[&l_owning, &r_non_owning];
720 let summary_2 = ast::Bool::and(ctx, args2);
721
722 let args3 = &[&summary_1, &summary_2];
724 let constraint_owning_now = ast::Bool::or(ctx, args3);
725
726 goal.assert(&constraint_owning_now);
727 solver.assert(&constraint_owning_now);
728
729 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
731 self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
732 self.handle_taint(lu, ru);
733 }
734
735 pub(crate) fn handle_move(
736 &mut self,
737 ctx: &'ctx z3::Context,
738 goal: &'ctx z3::Goal<'ctx>,
739 solver: &'ctx z3::Solver<'ctx>,
740 _kind: AsgnKind,
741 lplace: &Place<'tcx>,
742 rplace: &Place<'tcx>,
743 bidx: usize,
744 sidx: usize,
745 ) {
746 let llocal = lplace.local;
747 let rlocal = rplace.local;
748
749 let lu: usize = llocal.as_usize();
750 let ru: usize = rlocal.as_usize();
751
752 if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
754 {
755 self.handle_intra_var_unsupported(lu);
756 self.handle_intra_var_unsupported(ru);
757 return;
758 }
759 if !self.icx_slice.var()[ru].is_init() {
760 return;
761 }
762
763 if self.icx_slice().len()[ru] == 0 {
766 return;
768 }
769
770 let mut llen = self.icx_slice().len()[lu];
772 let rlen = self.icx_slice().len()[ru];
773
774 let l_ori_bv: ast::BV;
776 let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
777
778 let mut is_ctor = true;
779 if self.icx_slice().var()[lu].is_init() {
780 if llen == 0 {
781 rap_debug!(
782 "handle_move: lvalue length is 0 for local {:?}, skipping\n",
783 lu
784 );
785 return;
786 }
787 if self.icx_slice().ty()[lu] != self.icx_slice().ty[ru] {
792 self.handle_intra_var_unsupported(lu);
793 self.handle_intra_var_unsupported(ru);
794 return;
795 }
796 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
797 let l_zero_const = ast::BV::from_u64(ctx, 0, llen as u32);
798 let constraint_l_ori_zero = l_ori_bv._safe_eq(&l_zero_const).unwrap();
799 goal.assert(&constraint_l_ori_zero);
800 solver.assert(&constraint_l_ori_zero);
801 is_ctor = false;
802 } else {
803 let r_place_ty = rplace.ty(&self.body.local_decls, self.tcx());
805 let ty_with_vidx = TyWithIndex::new(r_place_ty.ty, r_place_ty.variant_index);
806 match ty_with_vidx.get_priority() {
807 0 => {
808 self.handle_intra_var_unsupported(lu);
810 self.handle_intra_var_unsupported(ru);
811 return;
812 }
813 1 => {
814 return;
815 }
816 2 => {
817 self.icx_slice_mut().ty_mut()[lu] = self.icx_slice().ty()[ru].clone();
819 self.icx_slice_mut().layout_mut()[lu] = self.icx_slice().layout()[ru].clone();
820 }
821 _ => unreachable!(),
822 }
823 }
824
825 llen = rlen;
827 self.icx_slice_mut().len_mut()[lu] = llen;
828
829 let l_name = if is_ctor {
831 new_local_name(lu, bidx, sidx).add("_ctor_asgn")
832 } else {
833 new_local_name(lu, bidx, sidx)
834 };
835 let r_name = new_local_name(ru, bidx, sidx);
836
837 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
839 let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
840
841 let r_zero_const = ast::BV::from_u64(ctx, 0, rlen as u32);
842
843 let r_non_owning = r_new_bv._safe_eq(&r_zero_const).unwrap();
847 let l_owning = l_new_bv._safe_eq(&r_ori_bv).unwrap();
849
850 goal.assert(&r_non_owning);
851 goal.assert(&l_owning);
852 solver.assert(&r_non_owning);
853 solver.assert(&l_owning);
854
855 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
857 self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
858 self.handle_taint(lu, ru);
859 }
860
861 pub(crate) fn handle_copy_from_field(
862 &mut self,
863 ctx: &'ctx z3::Context,
864 goal: &'ctx z3::Goal<'ctx>,
865 solver: &'ctx z3::Solver<'ctx>,
866 _kind: AsgnKind,
867 lplace: &Place<'tcx>,
868 rplace: &Place<'tcx>,
869 bidx: usize,
870 sidx: usize,
871 ) {
872 let llocal = lplace.local;
875 let rlocal = rplace.local;
876
877 let lu: usize = llocal.as_usize();
878 let ru: usize = rlocal.as_usize();
879
880 if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
882 {
883 self.handle_intra_var_unsupported(lu);
884 self.handle_intra_var_unsupported(ru);
885 return;
886 }
887 if !self.icx_slice().var()[ru].is_init() {
888 return;
889 }
890
891 if self.icx_slice().len[ru] == 0 {
894 return;
896 }
897
898 let rpj_ty = rplace.ty(&self.body.local_decls, self.tcx());
901 let rpj_fields = self.extract_projection(rplace, None);
902 if rpj_fields.is_unsupported() {
903 self.handle_intra_var_unsupported(lu);
905 self.handle_intra_var_unsupported(ru);
906 return;
907 }
908 if !rpj_fields.has_field() {
909 self.handle_copy(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
910 return;
911 }
912 let index_needed = rpj_fields.index_needed();
913
914 let default_heap = self.extract_default_ty_layout(rpj_ty.ty, rpj_ty.variant_index);
915 if !default_heap.get_requirement() || default_heap.is_empty() {
916 return;
917 }
918
919 let mut llen = self.icx_slice().len()[lu];
921 let rlen = self.icx_slice().len()[ru];
922 let rpj_len = default_heap.layout().len();
923
924 let l_ori_bv: ast::BV;
926 let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
927
928 let mut is_ctor = true;
929 if self.icx_slice().var()[lu].is_init() {
930 if llen == 0 {
931 rap_debug!(
932 "handle_copy_from_field: lvalue length is 0 for local {:?}, skipping\n",
933 lu
934 );
935 return;
936 }
937 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
941 let l_zero_const = ast::BV::from_u64(ctx, 0, llen as u32);
942 let constraint_l_ori_zero = l_ori_bv._safe_eq(&l_zero_const).unwrap();
943 goal.assert(&constraint_l_ori_zero);
944 solver.assert(&constraint_l_ori_zero);
945 is_ctor = false;
946 } else {
947 let r_place_ty = rplace.ty(&self.body.local_decls, self.tcx());
950 let ty_with_vidx = TyWithIndex::new(r_place_ty.ty, r_place_ty.variant_index);
951 match ty_with_vidx.get_priority() {
952 0 => {
953 self.handle_intra_var_unsupported(lu);
955 self.handle_intra_var_unsupported(ru);
956 return;
957 }
958 1 => {
959 return;
960 }
961 2 => {
962 self.icx_slice_mut().ty_mut()[lu] = ty_with_vidx;
964 self.icx_slice_mut().layout_mut()[lu] = default_heap.layout().clone();
965 }
966 _ => unreachable!(),
967 }
968 }
969
970 llen = rpj_len;
972 self.icx_slice_mut().len_mut()[lu] = llen;
973
974 let l_name = if is_ctor {
976 new_local_name(lu, bidx, sidx).add("_ctor_asgn")
977 } else {
978 new_local_name(lu, bidx, sidx)
979 };
980 let r_name = new_local_name(ru, bidx, sidx);
981
982 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
984 let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
985
986 let r_f_owning = r_new_bv._safe_eq(&r_ori_bv).unwrap();
990 let l_zero_const = ast::BV::from_u64(ctx, 0, llen as u32);
991 let l_non_owning = l_new_bv._safe_eq(&l_zero_const).unwrap();
992 let args1 = &[&r_f_owning, &l_non_owning];
993 let summary_1 = ast::Bool::and(ctx, args1);
994
995 let rust_bv_for_op_and = if self.icx_slice().taint()[ru].is_tainted() {
1000 rustbv_merge(
1001 &heap_layout_to_rustbv(default_heap.layout()),
1002 &self.generate_ptr_layout(rpj_ty.ty, rpj_ty.variant_index),
1003 )
1004 } else {
1005 heap_layout_to_rustbv(default_heap.layout())
1006 };
1007 let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1008 let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, llen as u32);
1009
1010 if index_needed >= rlen {
1011 rap_debug!(
1012 "handle_copy_from_field: field index {} out of bounds (rlen={}), skipping\n",
1013 index_needed,
1014 rlen
1015 );
1016 return;
1017 }
1018 let extract_from_field = r_ori_bv.extract(index_needed as u32, index_needed as u32);
1019 let repeat_field = if llen > 1 {
1020 extract_from_field.sign_ext((llen - 1) as u32)
1021 } else {
1022 extract_from_field
1023 };
1024 let after_op_and = z3_bv_for_op_and.bvand(&repeat_field);
1025 let l_extend_owning = l_new_bv._safe_eq(&after_op_and).unwrap();
1026 let mut rust_bv_for_op_and = vec![true; rlen];
1030 rust_bv_for_op_and[index_needed] = false;
1031 let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1032 let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, rlen as u32);
1033 let after_op_and = r_ori_bv.bvand(&z3_bv_for_op_and);
1034 let rpj_non_owning = r_new_bv._safe_eq(&after_op_and).unwrap();
1035
1036 let args2 = &[&l_extend_owning, &rpj_non_owning];
1037 let summary_2 = ast::Bool::and(ctx, args2);
1038
1039 let args3 = &[&summary_1, &summary_2];
1041 let constraint_owning_now = ast::Bool::or(ctx, args3);
1042
1043 goal.assert(&constraint_owning_now);
1044 solver.assert(&constraint_owning_now);
1045
1046 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1048 self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1049 self.handle_taint(lu, ru);
1050 }
1051
1052 pub(crate) fn handle_move_from_field(
1053 &mut self,
1054 ctx: &'ctx z3::Context,
1055 goal: &'ctx z3::Goal<'ctx>,
1056 solver: &'ctx z3::Solver<'ctx>,
1057 _kind: AsgnKind,
1058 lplace: &Place<'tcx>,
1059 rplace: &Place<'tcx>,
1060 bidx: usize,
1061 sidx: usize,
1062 ) {
1063 let llocal = lplace.local;
1066 let rlocal = rplace.local;
1067
1068 let lu: usize = llocal.as_usize();
1069 let ru: usize = rlocal.as_usize();
1070
1071 if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1073 {
1074 self.handle_intra_var_unsupported(lu);
1075 self.handle_intra_var_unsupported(ru);
1076 return;
1077 }
1078 if !self.icx_slice().var()[ru].is_init() {
1079 return;
1080 }
1081
1082 let rpj_ty = rplace.ty(&self.body.local_decls, self.tcx());
1085 let rpj_fields = self.extract_projection(rplace, None);
1086 if rpj_fields.is_unsupported() {
1087 self.handle_intra_var_unsupported(lu);
1089 self.handle_intra_var_unsupported(ru);
1090 return;
1091 }
1092 if !rpj_fields.has_field() {
1093 self.handle_move(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1094 return;
1095 }
1096 let index_needed = rpj_fields.index_needed();
1097
1098 let default_heap = self.extract_default_ty_layout(rpj_ty.ty, rpj_ty.variant_index);
1099 if !default_heap.get_requirement() || default_heap.is_empty() {
1100 return;
1101 }
1102
1103 let mut llen = self.icx_slice().len()[lu];
1105 let rlen = self.icx_slice().len()[ru];
1106 let rpj_len = default_heap.layout().len();
1107
1108 if self.icx_slice().len[ru] == 0 {
1111 return;
1113 }
1114
1115 let l_ori_bv: ast::BV;
1117 let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1118
1119 let mut is_ctor = true;
1120 if self.icx_slice().var()[lu].is_init() {
1121 if llen == 0 {
1122 rap_debug!(
1123 "handle_move_from_field: lvalue length is 0 for local {:?}, skipping\n",
1124 lu
1125 );
1126 return;
1127 }
1128 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1138 let l_zero_const = ast::BV::from_u64(ctx, 0, llen as u32);
1139 let constraint_l_ori_zero = l_ori_bv._safe_eq(&l_zero_const).unwrap();
1140 goal.assert(&constraint_l_ori_zero);
1141 solver.assert(&constraint_l_ori_zero);
1142 is_ctor = false;
1143 } else {
1144 let r_place_ty = rplace.ty(&self.body.local_decls, self.tcx());
1147 let ty_with_vidx = TyWithIndex::new(r_place_ty.ty, r_place_ty.variant_index);
1148 match ty_with_vidx.get_priority() {
1149 0 => {
1150 self.handle_intra_var_unsupported(lu);
1152 self.handle_intra_var_unsupported(ru);
1153 return;
1154 }
1155 1 => {
1156 return;
1157 }
1158 2 => {
1159 self.icx_slice_mut().ty_mut()[lu] = ty_with_vidx;
1161 self.icx_slice_mut().layout_mut()[lu] = default_heap.layout().clone();
1162 }
1163 _ => unreachable!(),
1164 }
1165 }
1166
1167 llen = rpj_len;
1169 self.icx_slice_mut().len_mut()[lu] = llen;
1170
1171 let l_name = if is_ctor {
1173 new_local_name(lu, bidx, sidx).add("_ctor_asgn")
1174 } else {
1175 new_local_name(lu, bidx, sidx)
1176 };
1177 let r_name = new_local_name(ru, bidx, sidx);
1178
1179 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1181 let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1182
1183 let rust_bv_for_op_and = if self.icx_slice().taint()[ru].is_tainted() {
1189 rustbv_merge(
1190 &heap_layout_to_rustbv(default_heap.layout()),
1191 &self.generate_ptr_layout(rpj_ty.ty, rpj_ty.variant_index),
1192 )
1193 } else {
1194 heap_layout_to_rustbv(default_heap.layout())
1195 };
1196 let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1197 let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, llen as u32);
1198
1199 if index_needed >= rlen {
1200 rap_debug!(
1201 "handle_move_from_field: field index {} out of bounds (rlen={}), skipping\n",
1202 index_needed,
1203 rlen
1204 );
1205 return;
1206 }
1207 let extract_from_field = r_ori_bv.extract(index_needed as u32, index_needed as u32);
1208 let repeat_field = if llen > 1 {
1209 extract_from_field.sign_ext((llen - 1) as u32)
1210 } else {
1211 extract_from_field
1212 };
1213 let after_op_and = z3_bv_for_op_and.bvand(&repeat_field);
1214 let l_extend_owning = l_new_bv._safe_eq(&after_op_and).unwrap();
1215
1216 let mut rust_bv_for_op_and = vec![true; rlen];
1220 rust_bv_for_op_and[index_needed] = false;
1221 let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1222 let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, rlen as u32);
1223 let after_op_and = r_ori_bv.bvand(&z3_bv_for_op_and);
1224 let rpj_non_owning = r_new_bv._safe_eq(&after_op_and).unwrap();
1225
1226 goal.assert(&l_extend_owning);
1227 goal.assert(&rpj_non_owning);
1228 solver.assert(&l_extend_owning);
1229 solver.assert(&rpj_non_owning);
1230
1231 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1233 self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1234 self.handle_taint(lu, ru);
1235 }
1236 pub(crate) fn handle_aggregate_init(
1237 &mut self,
1238 ctx: &'ctx z3::Context,
1239 goal: &'ctx z3::Goal<'ctx>,
1240 solver: &'ctx z3::Solver<'ctx>,
1241 _kind: AsgnKind,
1242 lplace: &Place<'tcx>,
1243 _aggre_did: DefId,
1244 vidx: VariantIdx,
1245 disc: Disc,
1246 bidx: usize,
1247 sidx: usize,
1248 ) {
1249 let llocal = lplace.local;
1250 let lu: usize = llocal.as_usize();
1251
1252 if self.icx_slice.var()[lu].is_unsupported() {
1253 return;
1254 }
1255
1256 let l_local_ty = self.body.local_decls[llocal].ty;
1257 let default_heap = self.extract_default_ty_layout(l_local_ty, Some(vidx));
1258 if !default_heap.get_requirement() || default_heap.is_empty() {
1259 return;
1260 }
1261
1262 let llen = default_heap.layout().len();
1263 self.icx_slice_mut().len_mut()[lu] = llen;
1264
1265 if !self.icx_slice().var[lu].is_init() {
1266 let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1267 let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1268 let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1269 let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1270 goal.assert(&constraint_l_ctor_zero);
1271 solver.assert(&constraint_l_ctor_zero);
1272 self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1273 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_ori_bv_ctor);
1274 }
1275 }
1276
1277 pub(crate) fn handle_copy_to_field(
1278 &mut self,
1279 ctx: &'ctx z3::Context,
1280 goal: &'ctx z3::Goal<'ctx>,
1281 solver: &'ctx z3::Solver<'ctx>,
1282 _kind: AsgnKind,
1283 lplace: &Place<'tcx>,
1284 rplace: &Place<'tcx>,
1285 mut disc: Disc,
1286 aggre: Aggre,
1287 bidx: usize,
1288 sidx: usize,
1289 ) {
1290 let llocal = lplace.local;
1293 let rlocal = rplace.local;
1294
1295 let lu: usize = llocal.as_usize();
1296 let ru: usize = rlocal.as_usize();
1297
1298 if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1300 {
1301 self.handle_intra_var_unsupported(lu);
1302 self.handle_intra_var_unsupported(ru);
1303 return;
1304 }
1305 if !self.icx_slice().var()[ru].is_init() {
1306 return;
1307 }
1308
1309 let l_local_ty = self.body.local_decls[llocal].ty;
1311 let lpj_fields = self.extract_projection(lplace, aggre);
1312 if lpj_fields.is_unsupported() {
1313 self.handle_intra_var_unsupported(lu);
1315 self.handle_intra_var_unsupported(ru);
1316 return;
1317 }
1318
1319 match (lpj_fields.has_field(), lpj_fields.has_downcast()) {
1320 (true, true) => {
1321 disc = lpj_fields.downcast();
1323 let ty_with_index = TyWithIndex::new(l_local_ty, disc);
1324
1325 if ty_with_index.0.is_none() {
1326 return;
1327 }
1328
1329 if lpj_fields.index_needed() == 0 && ty_with_index.0.unwrap().0 == 1 {
1331 self.handle_copy(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1332 return;
1333 }
1334 }
1335 (true, false) => {
1336 }
1338 (false, true) => {
1339 return;
1341 }
1342 (false, false) => {
1343 self.handle_copy(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1344 return;
1345 }
1346 }
1347
1348 let index_needed = lpj_fields.index_needed();
1349
1350 let default_heap = self.extract_default_ty_layout(l_local_ty, disc);
1351 if !default_heap.get_requirement() || default_heap.is_empty() {
1352 return;
1353 }
1354
1355 let llen = default_heap.layout().len();
1357 self.icx_slice_mut().len_mut()[lu] = llen;
1358 let rlen = self.icx_slice().len()[ru];
1359
1360 if self.icx_slice().len[ru] == 0 {
1363 return;
1365 }
1366
1367 let l_ori_bv: ast::BV;
1369 let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1370
1371 if self.icx_slice().var()[lu].is_init() {
1372 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1376 let extract_from_field = l_ori_bv.extract(index_needed as u32, index_needed as u32);
1377 if lu > self.body.arg_count {
1378 let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
1379 let constraint_l_f_ori_zero = extract_from_field._safe_eq(&l_f_zero_const).unwrap();
1380 goal.assert(&constraint_l_f_ori_zero);
1381 solver.assert(&constraint_l_f_ori_zero);
1382 }
1383 } else {
1384 let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1387 let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1388 let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1389 let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1390 goal.assert(&constraint_l_ctor_zero);
1391 solver.assert(&constraint_l_ctor_zero);
1392 l_ori_bv = l_ori_zero;
1393 self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1394 self.icx_slice_mut().layout_mut()[lu] = default_heap.layout().clone();
1395 }
1396
1397 let l_name = new_local_name(lu, bidx, sidx);
1403 let r_name = new_local_name(ru, bidx, sidx);
1404
1405 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1407 let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1408
1409 let r_zero_const = ast::BV::from_u64(ctx, 0, rlen as u32);
1410
1411 let r_owning = r_new_bv._safe_eq(&r_ori_bv).unwrap();
1416 let mut rust_bv_for_op_and = vec![true; llen];
1418 rust_bv_for_op_and[index_needed] = false;
1419 let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1420 let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, llen as u32);
1421 let after_op_and = l_ori_bv.bvand(&z3_bv_for_op_and);
1422 let lpj_non_owning = l_new_bv._safe_eq(&after_op_and).unwrap();
1423
1424 let args1 = &[&r_owning, &lpj_non_owning];
1425 let summary_1 = ast::Bool::and(ctx, args1);
1426
1427 let r_non_owning = r_new_bv._safe_eq(&r_zero_const).unwrap();
1430 let disjunction_r = r_ori_bv.bvredor();
1436 let mut final_bv: ast::BV;
1437
1438 if index_needed < llen - 1 {
1439 let end_part = l_ori_bv.extract((llen - 1) as u32, (index_needed + 1) as u32);
1440 final_bv = end_part.concat(&disjunction_r);
1441 } else {
1442 final_bv = disjunction_r;
1443 }
1444 if index_needed > 0 {
1445 let begin_part = l_ori_bv.extract((index_needed - 1) as u32, 0);
1446 final_bv = final_bv.concat(&begin_part);
1447 }
1448
1449 let lpj_shrink_owning = l_new_bv._safe_eq(&final_bv).unwrap();
1450
1451 let args2 = &[&r_non_owning, &lpj_shrink_owning];
1452 let summary_2 = ast::Bool::and(ctx, args2);
1453
1454 let args3 = &[&summary_1, &summary_2];
1456 let constraint_owning_now = ast::Bool::or(ctx, args3);
1457
1458 goal.assert(&constraint_owning_now);
1459 solver.assert(&constraint_owning_now);
1460
1461 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1463 self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1464 self.handle_taint(lu, ru);
1465 }
1466
1467 pub(crate) fn handle_move_to_field(
1468 &mut self,
1469 ctx: &'ctx z3::Context,
1470 goal: &'ctx z3::Goal<'ctx>,
1471 solver: &'ctx z3::Solver<'ctx>,
1472 _kind: AsgnKind,
1473 lplace: &Place<'tcx>,
1474 rplace: &Place<'tcx>,
1475 mut disc: Disc,
1476 aggre: Aggre,
1477 bidx: usize,
1478 sidx: usize,
1479 ) {
1480 let llocal = lplace.local;
1483 let rlocal = rplace.local;
1484
1485 let lu: usize = llocal.as_usize();
1486 let ru: usize = rlocal.as_usize();
1487
1488 if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1490 {
1491 self.handle_intra_var_unsupported(lu);
1492 self.handle_intra_var_unsupported(ru);
1493 return;
1494 }
1495 if !self.icx_slice().var()[ru].is_init() {
1496 return;
1497 }
1498
1499 let l_local_ty = self.body.local_decls[llocal].ty;
1501 let lpj_fields = self.extract_projection(lplace, aggre);
1502 if lpj_fields.is_unsupported() {
1503 self.handle_intra_var_unsupported(lu);
1505 self.handle_intra_var_unsupported(ru);
1506 return;
1507 }
1508
1509 match (lpj_fields.has_field(), lpj_fields.has_downcast()) {
1510 (true, true) => {
1511 disc = lpj_fields.downcast();
1513 let ty_with_index = TyWithIndex::new(l_local_ty, disc);
1514
1515 if ty_with_index.0.is_none() {
1516 return;
1517 }
1518
1519 if lpj_fields.index_needed() == 0 && ty_with_index.0.unwrap().0 == 1 {
1521 self.handle_move(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1522 return;
1523 }
1524 }
1525 (true, false) => {
1526 }
1528 (false, true) => {
1529 return;
1531 }
1532 (false, false) => {
1533 self.handle_move(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1534 return;
1535 }
1536 }
1537
1538 let index_needed = lpj_fields.index_needed();
1539
1540 let mut default_heap = self.extract_default_ty_layout(l_local_ty, disc);
1541 if !default_heap.get_requirement() || default_heap.is_empty() {
1542 return;
1543 }
1544
1545 let llen = default_heap.layout().len();
1547 self.icx_slice_mut().len_mut()[lu] = llen;
1548 let rlen = self.icx_slice().len()[ru];
1549
1550 if self.icx_slice().len[ru] == 0 {
1553 return;
1555 }
1556
1557 let l_ori_bv: ast::BV;
1559 let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1560
1561 if self.icx_slice().var()[lu].is_init() {
1562 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1567 let extract_from_field = l_ori_bv.extract(index_needed as u32, index_needed as u32);
1568 if lu > self.body.arg_count {
1569 let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
1570 let constraint_l_f_ori_zero = extract_from_field._safe_eq(&l_f_zero_const).unwrap();
1571 goal.assert(&constraint_l_f_ori_zero);
1572 solver.assert(&constraint_l_f_ori_zero);
1573 }
1574 } else {
1575 let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1578 let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1579 let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1580 let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1581 goal.assert(&constraint_l_ctor_zero);
1582 solver.assert(&constraint_l_ctor_zero);
1583 l_ori_bv = l_ori_zero;
1584 self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1585 self.icx_slice_mut().layout_mut()[lu] = default_heap.layout_mut().clone();
1586 }
1587
1588 let l_name = new_local_name(lu, bidx, sidx);
1594 let r_name = new_local_name(ru, bidx, sidx);
1595
1596 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1598 let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1599
1600 let r_zero_const = ast::BV::from_u64(ctx, 0, rlen as u32);
1601
1602 let r_non_owning = r_new_bv._safe_eq(&r_zero_const).unwrap();
1606
1607 let disjunction_r = r_ori_bv.bvredor();
1613 let mut final_bv: ast::BV;
1614 if index_needed < llen - 1 {
1615 let end_part = l_ori_bv.extract((llen - 1) as u32, (index_needed + 1) as u32);
1616 final_bv = end_part.concat(&disjunction_r);
1617 } else {
1618 final_bv = disjunction_r;
1619 }
1620 if index_needed > 0 {
1621 let begin_part = l_ori_bv.extract((index_needed - 1) as u32, 0);
1622 final_bv = final_bv.concat(&begin_part);
1623 }
1624 let lpj_shrink_owning = l_new_bv._safe_eq(&final_bv).unwrap();
1625
1626 goal.assert(&r_non_owning);
1627 goal.assert(&lpj_shrink_owning);
1628 solver.assert(&r_non_owning);
1629 solver.assert(&lpj_shrink_owning);
1630
1631 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1633 self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1634 self.handle_taint(lu, ru);
1635 }
1636
1637 pub(crate) fn handle_copy_field_to_field(
1638 &mut self,
1639 ctx: &'ctx z3::Context,
1640 goal: &'ctx z3::Goal<'ctx>,
1641 solver: &'ctx z3::Solver<'ctx>,
1642 _kind: AsgnKind,
1643 lplace: &Place<'tcx>,
1644 rplace: &Place<'tcx>,
1645 disc: Disc,
1646 aggre: Aggre,
1647 bidx: usize,
1648 sidx: usize,
1649 ) {
1650 let llocal = lplace.local;
1652 let rlocal = rplace.local;
1653
1654 let lu: usize = llocal.as_usize();
1655 let ru: usize = rlocal.as_usize();
1656
1657 if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1659 {
1660 self.handle_intra_var_unsupported(lu);
1661 self.handle_intra_var_unsupported(ru);
1662 return;
1663 }
1664 if !self.icx_slice().var()[ru].is_init() {
1665 return;
1666 }
1667
1668 let l_local_ty = self.body.local_decls[llocal].ty;
1669
1670 let rpj_fields = self.extract_projection(rplace, None);
1673 if rpj_fields.is_unsupported() {
1674 self.handle_intra_var_unsupported(lu);
1676 self.handle_intra_var_unsupported(ru);
1677 return;
1678 }
1679
1680 let lpj_fields = self.extract_projection(lplace, aggre);
1681 if lpj_fields.is_unsupported() {
1682 self.handle_intra_var_unsupported(lu);
1684 self.handle_intra_var_unsupported(ru);
1685 return;
1686 }
1687
1688 match (rpj_fields.has_field(), lpj_fields.has_field()) {
1689 (true, true) => (),
1690 (true, false) => {
1691 self.handle_copy_from_field(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1692 return;
1693 }
1694 (false, true) => {
1695 self.handle_copy_to_field(
1696 ctx, goal, solver, _kind, lplace, rplace, disc, aggre, bidx, sidx,
1697 );
1698 return;
1699 }
1700 (false, false) => {
1701 self.handle_copy(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1702 return;
1703 }
1704 }
1705
1706 let r_index_needed = rpj_fields.index_needed();
1707 let l_index_needed = lpj_fields.index_needed();
1708
1709 let default_heap = self.extract_default_ty_layout(l_local_ty, disc);
1710 if !default_heap.get_requirement() || default_heap.is_empty() {
1711 return;
1712 }
1713
1714 let llen = default_heap.layout().len();
1716 let rlen = self.icx_slice().len()[ru];
1717 self.icx_slice_mut().len_mut()[lu] = llen;
1718
1719 if self.icx_slice().len[ru] == 0 {
1722 return;
1724 }
1725
1726 let l_ori_bv: ast::BV;
1728 let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1729
1730 if self.icx_slice().var()[lu].is_init() {
1731 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1735 let extract_from_field = l_ori_bv.extract(l_index_needed as u32, l_index_needed as u32);
1736 if lu > self.body.arg_count {
1737 let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
1738 let constraint_l_f_ori_zero = extract_from_field._safe_eq(&l_f_zero_const).unwrap();
1739 goal.assert(&constraint_l_f_ori_zero);
1740 solver.assert(&constraint_l_f_ori_zero);
1741 }
1742 } else {
1743 let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1746 let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1747 let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1748 let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1749 goal.assert(&constraint_l_ctor_zero);
1750 solver.assert(&constraint_l_ctor_zero);
1751 l_ori_bv = l_ori_zero;
1752 self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1753 self.icx_slice_mut().layout_mut()[lu] = default_heap.layout().clone();
1754 }
1755
1756 let l_name = new_local_name(lu, bidx, sidx);
1758 let r_name = new_local_name(ru, bidx, sidx);
1759
1760 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1762 let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1763
1764 let mut rust_bv_for_op_and = vec![true; rlen];
1771 rust_bv_for_op_and[r_index_needed] = false;
1772 let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1773 let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, rlen as u32);
1774 let after_op_and = r_ori_bv.bvand(&z3_bv_for_op_and);
1775 let rpj_non_owning = r_new_bv._safe_eq(&after_op_and).unwrap();
1776 let extract_field_r = r_ori_bv.extract(r_index_needed as u32, r_index_needed as u32);
1781 let mut final_bv: ast::BV;
1782 if l_index_needed < llen - 1 {
1783 let end_part = l_ori_bv.extract((llen - 1) as u32, (l_index_needed + 1) as u32);
1784 final_bv = end_part.concat(&extract_field_r);
1785 } else {
1786 final_bv = extract_field_r;
1787 }
1788 if l_index_needed > 0 {
1789 let begin_part = l_ori_bv.extract((l_index_needed - 1) as u32, 0);
1790 final_bv = final_bv.concat(&begin_part);
1791 }
1792 let lpj_owning = l_new_bv._safe_eq(&final_bv).unwrap();
1793
1794 let args1 = &[&rpj_non_owning, &lpj_owning];
1795 let summary_1 = ast::Bool::and(ctx, args1);
1796
1797 let mut rust_bv_for_op_and = vec![true; llen];
1800 rust_bv_for_op_and[l_index_needed] = false;
1801 let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1802 let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, llen as u32);
1803 let after_op_and = l_ori_bv.bvand(&z3_bv_for_op_and);
1804 let lpj_non_owning = l_new_bv._safe_eq(&after_op_and).unwrap();
1805 let rpj_owning = r_new_bv._safe_eq(&r_ori_bv).unwrap();
1807
1808 let args2 = &[&lpj_non_owning, &rpj_owning];
1809 let summary_2 = ast::Bool::and(ctx, args2);
1810
1811 let args3 = &[&summary_1, &summary_2];
1813 let constraint_owning_now = ast::Bool::or(ctx, args3);
1814
1815 goal.assert(&constraint_owning_now);
1816 solver.assert(&constraint_owning_now);
1817
1818 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1820 self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1821 self.handle_taint(lu, ru);
1822 }
1823
1824 pub(crate) fn handle_move_field_to_field(
1825 &mut self,
1826 ctx: &'ctx z3::Context,
1827 goal: &'ctx z3::Goal<'ctx>,
1828 solver: &'ctx z3::Solver<'ctx>,
1829 _kind: AsgnKind,
1830 lplace: &Place<'tcx>,
1831 rplace: &Place<'tcx>,
1832 disc: Disc,
1833 aggre: Aggre,
1834 bidx: usize,
1835 sidx: usize,
1836 ) {
1837 let llocal = lplace.local;
1839 let rlocal = rplace.local;
1840
1841 let lu: usize = llocal.as_usize();
1842 let ru: usize = rlocal.as_usize();
1843
1844 if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1846 {
1847 self.handle_intra_var_unsupported(lu);
1848 self.handle_intra_var_unsupported(ru);
1849 return;
1850 }
1851 if !self.icx_slice().var()[ru].is_init() {
1852 return;
1853 }
1854
1855 let l_local_ty = self.body.local_decls[llocal].ty;
1856
1857 let rpj_fields = self.extract_projection(rplace, None);
1861 if rpj_fields.is_unsupported() {
1862 self.handle_intra_var_unsupported(lu);
1864 self.handle_intra_var_unsupported(ru);
1865 return;
1866 }
1867
1868 let lpj_fields = self.extract_projection(lplace, aggre);
1872 if lpj_fields.is_unsupported() {
1873 self.handle_intra_var_unsupported(lu);
1875 self.handle_intra_var_unsupported(ru);
1876 return;
1877 }
1878
1879 match (rpj_fields.has_field(), lpj_fields.has_field()) {
1880 (true, true) => (),
1881 (true, false) => {
1882 self.handle_move_from_field(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1883 return;
1884 }
1885 (false, true) => {
1886 self.handle_move_to_field(
1887 ctx, goal, solver, _kind, lplace, rplace, disc, aggre, bidx, sidx,
1888 );
1889 }
1890 (false, false) => {
1891 self.handle_move(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1892 return;
1893 }
1894 }
1895
1896 let r_index_needed = rpj_fields.index_needed();
1897 let l_index_needed = lpj_fields.index_needed();
1898
1899 let default_heap = self.extract_default_ty_layout(l_local_ty, disc);
1900 if !default_heap.get_requirement() || default_heap.is_empty() {
1901 return;
1902 }
1903
1904 let llen = default_heap.layout().len();
1906 let rlen = self.icx_slice().len()[ru];
1907 self.icx_slice_mut().len_mut()[lu] = llen;
1908
1909 if self.icx_slice().len[ru] == 0 {
1912 return;
1914 }
1915
1916 let l_ori_bv: ast::BV;
1918 let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1919
1920 if self.icx_slice().var()[lu].is_init() {
1921 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1925 let extract_from_field = l_ori_bv.extract(l_index_needed as u32, l_index_needed as u32);
1926 if lu > self.body.arg_count {
1927 let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
1928 let constraint_l_f_ori_zero = extract_from_field._safe_eq(&l_f_zero_const).unwrap();
1929 goal.assert(&constraint_l_f_ori_zero);
1930 solver.assert(&constraint_l_f_ori_zero);
1931 }
1932 } else {
1933 let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1936 let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1937 let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1938 let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1939 goal.assert(&constraint_l_ctor_zero);
1940 solver.assert(&constraint_l_ctor_zero);
1941 l_ori_bv = l_ori_zero;
1942 self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1943 self.icx_slice_mut().layout_mut()[lu] = default_heap.layout().clone();
1944 }
1945
1946 let l_name = new_local_name(lu, bidx, sidx);
1948 let r_name = new_local_name(ru, bidx, sidx);
1949
1950 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1952 let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1953
1954 let mut rust_bv_for_op_and = vec![true; rlen];
1960 rust_bv_for_op_and[r_index_needed] = false;
1961 let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1962 let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, rlen as u32);
1963 let after_op_and = r_ori_bv.bvand(&z3_bv_for_op_and);
1964 let rpj_non_owning = r_new_bv._safe_eq(&after_op_and).unwrap();
1965
1966 let extract_field_r = r_ori_bv.extract(r_index_needed as u32, r_index_needed as u32);
1971 let mut final_bv: ast::BV;
1972
1973 if l_index_needed < llen - 1 {
1974 let end_part = l_ori_bv.extract((llen - 1) as u32, (l_index_needed + 1) as u32);
1975 final_bv = end_part.concat(&extract_field_r);
1976 } else {
1977 final_bv = extract_field_r;
1978 }
1979 if l_index_needed > 0 {
1980 let begin_part = l_ori_bv.extract((l_index_needed - 1) as u32, 0);
1981 final_bv = final_bv.concat(&begin_part);
1982 }
1983 let lpj_owning = l_new_bv._safe_eq(&final_bv).unwrap();
1984
1985 goal.assert(&rpj_non_owning);
1986 goal.assert(&lpj_owning);
1987 solver.assert(&rpj_non_owning);
1988 solver.assert(&lpj_owning);
1989
1990 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1992 self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1993 self.handle_taint(lu, ru);
1994 }
1995
1996 pub(crate) fn check_fn_source(
1997 &mut self,
1998 args: &Box<[Spanned<Operand<'tcx>>]>,
2000 dest: &Place<'tcx>,
2001 ) -> bool {
2002 if args.len() != 1 {
2003 return false;
2004 }
2005
2006 let l_place_ty = dest.ty(&self.body.local_decls, self.tcx());
2007 if !is_place_containing_ptr(&l_place_ty.ty) {
2008 return false;
2009 }
2010
2011 match args[0].node {
2012 Operand::Move(aplace) => {
2013 let a_place_ty = aplace.ty(&self.body.local_decls, self.tcx());
2014 let default_layout =
2015 self.extract_default_ty_layout(a_place_ty.ty, a_place_ty.variant_index);
2016 if default_layout.is_owned() {
2017 self.taint_flag = true;
2018 true
2019 } else {
2020 false
2021 }
2022 }
2023 _ => false,
2024 }
2025 }
2026
2027 pub(crate) fn check_fn_recovery(
2028 &mut self,
2029 args: &Box<[Spanned<Operand<'tcx>>]>,
2031 dest: &Place<'tcx>,
2032 ) -> (bool, Vec<usize>) {
2033 let mut ans: (bool, Vec<usize>) = (false, Vec::new());
2034
2035 if args.len() == 0 {
2036 return ans;
2037 }
2038
2039 let l_place_ty = dest.ty(&self.body.local_decls, self.tcx());
2040 let default_layout =
2041 self.extract_default_ty_layout(l_place_ty.ty, l_place_ty.variant_index);
2042 if !default_layout.get_requirement() || default_layout.is_empty() {
2043 return ans;
2044 }
2045 let ty_with_idx = TyWithIndex::new(l_place_ty.ty, l_place_ty.variant_index);
2046
2047 for arg in args {
2048 match arg.node {
2049 Operand::Move(aplace) => {
2050 let au: usize = aplace.local.as_usize();
2051 let taint = &self.icx_slice().taint()[au];
2052 if taint.is_tainted() && taint.contains(&ty_with_idx) {
2053 ans.0 = true;
2054 ans.1.push(au);
2055 }
2056 }
2057 Operand::Copy(aplace) => {
2058 let au: usize = aplace.local.as_usize();
2059 let taint = &self.icx_slice().taint()[au];
2060 if taint.is_tainted() && taint.contains(&ty_with_idx) {
2061 ans.0 = true;
2062 ans.1.push(au);
2063 }
2064 }
2065 _ => (),
2066 }
2067 }
2068 ans
2069 }
2070
2071 pub(crate) fn handle_call(
2072 &mut self,
2073 ctx: &'ctx z3::Context,
2074 goal: &'ctx z3::Goal<'ctx>,
2075 solver: &'ctx z3::Solver<'ctx>,
2076 term: Terminator<'tcx>,
2077 func: &Operand<'tcx>,
2078 args: &Box<[Spanned<Operand<'tcx>>]>,
2080 dest: &Place<'tcx>,
2081 bidx: usize,
2082 ) {
2083 match func {
2084 Operand::Constant(constant) => {
2085 match constant.ty().kind() {
2086 ty::FnDef(id, ..) => {
2087 match id.index.as_usize() {
2090 2171 => {
2091 match args[0].node {
2093 Operand::Move(aplace) => {
2094 let a_place_ty =
2095 dest.ty(&self.body.local_decls, self.tcx());
2096 let a_ty = a_place_ty.ty;
2097 if a_ty.is_adt() {
2098 self.handle_drop(
2099 ctx, goal, solver, &aplace, bidx, false,
2100 );
2101 return;
2102 }
2103 }
2104 _ => (),
2105 }
2106 }
2107 _ => (),
2108 }
2109 }
2110 _ => (),
2111 }
2112 }
2113 _ => (),
2114 }
2115
2116 let llocal = dest.local;
2118 let lu: usize = llocal.as_usize();
2119
2120 let source_flag = self.check_fn_source(args, dest);
2123 let recovery_flag = self.check_fn_recovery(args, dest);
2127 if source_flag {
2128 self.add_taint(term);
2129 }
2130
2131 for arg in args {
2132 match arg.node {
2133 Operand::Move(aplace) => {
2134 let alocal = aplace.local;
2135 let au: usize = alocal.as_usize();
2136
2137 if self.icx_slice().len()[au] == 0 {
2140 continue;
2142 }
2143
2144 if !self.icx_slice().var()[au].is_init() {
2145 continue;
2146 }
2147
2148 let a_place_ty = aplace.ty(&self.body.local_decls, self.tcx());
2149 let a_ty = a_place_ty.ty;
2150 let is_a_ptr = a_ty.is_any_ptr();
2151
2152 let a_ori_bv = self.icx_slice_mut().var_mut()[au].extract();
2153 let alen = self.icx_slice().len()[au];
2154
2155 if source_flag {
2156 self.icx_slice_mut().taint_mut()[lu]
2157 .insert(TyWithIndex::new(a_place_ty.ty, a_place_ty.variant_index));
2158 }
2159
2160 match aplace.projection.len() {
2161 0 => {
2162 if is_a_ptr {
2164 if recovery_flag.0 && recovery_flag.1.contains(&au) {
2165 self.handle_drop(ctx, goal, solver, &aplace, bidx, true);
2166 continue;
2167 }
2168
2169 let a_zero_const = ast::BV::from_u64(ctx, 0, alen as u32);
2173 let a_ori_non_owing = a_ori_bv._safe_eq(&a_zero_const).unwrap();
2174
2175 let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2177 let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2178 let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2179
2180 goal.assert(&a_ori_non_owing);
2181 goal.assert(&update_a);
2182 solver.assert(&a_ori_non_owing);
2183 solver.assert(&update_a);
2184
2185 self.icx_slice_mut().var_mut()[au] = IntraVar::Init(a_new_bv);
2186 } else {
2187 self.handle_drop(ctx, goal, solver, &aplace, bidx, false);
2189 }
2190 }
2191 1 => {
2192 if is_a_ptr {
2194 if recovery_flag.0 && recovery_flag.1.contains(&au) {
2195 self.handle_drop(ctx, goal, solver, &aplace, bidx, true);
2196 continue;
2197 }
2198 let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2202 let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2203 let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2204
2205 goal.assert(&update_a);
2206 solver.assert(&update_a);
2207 } else {
2208 self.handle_drop(ctx, goal, solver, &aplace, bidx, false);
2210 }
2211 }
2212 _ => {
2213 self.handle_intra_var_unsupported(au);
2214 continue;
2215 }
2216 }
2217 }
2218 Operand::Copy(aplace) => {
2219 let alocal = aplace.local;
2220 let au: usize = alocal.as_usize();
2221
2222 if self.icx_slice().len()[au] == 0 {
2225 continue;
2227 }
2228
2229 if !self.icx_slice().var()[au].is_init() {
2230 continue;
2231 }
2232
2233 let a_ty = aplace.ty(&self.body.local_decls, self.tcx()).ty;
2234 let is_a_ptr = a_ty.is_any_ptr();
2235
2236 let a_ori_bv = self.icx_slice_mut().var_mut()[au].extract();
2237 let alen = self.icx_slice().len()[au];
2238
2239 match aplace.projection.len() {
2240 0 => {
2241 if is_a_ptr {
2243 if recovery_flag.0 && recovery_flag.1.contains(&au) {
2244 self.handle_drop(ctx, goal, solver, &aplace, bidx, true);
2245 continue;
2246 }
2247
2248 let a_zero_const = ast::BV::from_u64(ctx, 0, alen as u32);
2252 let a_ori_non_owing = a_ori_bv._safe_eq(&a_zero_const).unwrap();
2253
2254 let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2256 let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2257 let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2258
2259 goal.assert(&a_ori_non_owing);
2260 goal.assert(&update_a);
2261 solver.assert(&a_ori_non_owing);
2262 solver.assert(&update_a);
2263
2264 self.icx_slice_mut().var_mut()[au] = IntraVar::Init(a_new_bv);
2265 } else {
2266 if is_a_ptr {
2270 if recovery_flag.0 && recovery_flag.1.contains(&au) {
2271 self.handle_drop(ctx, goal, solver, &aplace, bidx, true);
2272 continue;
2273 }
2274 }
2275
2276 let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2277 let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2278 let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2279
2280 goal.assert(&update_a);
2281 solver.assert(&update_a);
2282 }
2283 }
2284 1 => {
2285 let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2287 let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2288 let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2289
2290 goal.assert(&update_a);
2291 solver.assert(&update_a);
2292 }
2293 _ => {
2294 self.handle_intra_var_unsupported(au);
2295 continue;
2296 }
2297 }
2298 }
2299 Operand::Constant(..) => continue,
2300 #[cfg(rapx_rustc_ge_196)]
2301 Operand::RuntimeChecks(_) => continue,
2302 }
2303 }
2304
2305 if self.icx_slice().var()[lu].is_unsupported() {
2307 self.handle_intra_var_unsupported(lu);
2308 return;
2309 }
2310
2311 let l_ori_bv: ast::BV;
2312
2313 let l_place_ty = dest.ty(&self.body.local_decls, self.tcx());
2314 let l_local_ty = self.body.local_decls[llocal].ty;
2315
2316 let mut is_ctor = true;
2317 match dest.projection.len() {
2318 0 => {
2319 let return_value_layout =
2322 self.extract_default_ty_layout(l_place_ty.ty, l_place_ty.variant_index);
2323 if return_value_layout.is_empty() || !return_value_layout.get_requirement() {
2324 return;
2325 }
2326
2327 let int_for_gen = if source_flag {
2328 let modified_layout_bv =
2329 self.generate_ptr_layout(l_place_ty.ty, l_place_ty.variant_index);
2330 let merge_layout_bv = rustbv_merge(
2331 &heap_layout_to_rustbv(return_value_layout.layout()),
2332 &modified_layout_bv,
2333 );
2334 rustbv_to_int(&merge_layout_bv)
2335 } else {
2336 rustbv_to_int(&heap_layout_to_rustbv(return_value_layout.layout()))
2337 };
2338
2339 let mut llen = self.icx_slice().len()[lu];
2340
2341 if self.icx_slice().var()[lu].is_init() {
2342 if llen == 0 {
2343 rap_debug!(
2344 "handle_call: lvalue length is 0 for local {:?}, skipping\n",
2345 lu
2346 );
2347 return;
2348 }
2349 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
2350 let l_zero_const = ast::BV::from_u64(ctx, 0, llen as u32);
2351 let constraint_l_ori_zero = l_ori_bv._safe_eq(&l_zero_const).unwrap();
2352 goal.assert(&constraint_l_ori_zero);
2353 solver.assert(&constraint_l_ori_zero);
2354 is_ctor = false;
2355 } else {
2356 let ty_with_vidx = TyWithIndex::new(l_place_ty.ty, l_place_ty.variant_index);
2358 match ty_with_vidx.get_priority() {
2359 0 => {
2360 self.handle_intra_var_unsupported(lu);
2362 return;
2363 }
2364 1 => {
2365 return;
2366 }
2367 2 => {
2368 self.icx_slice_mut().ty_mut()[lu] = ty_with_vidx;
2370 self.icx_slice_mut().layout_mut()[lu] =
2371 return_value_layout.layout().clone();
2372 }
2373 _ => unreachable!(),
2374 }
2375 }
2376
2377 llen = return_value_layout.layout().len();
2378
2379 let l_name = if is_ctor {
2380 new_local_name(lu, bidx, 0).add("_ctor_fn")
2381 } else {
2382 new_local_name(lu, bidx, 0).add("_cover_fn")
2383 };
2384
2385 let l_layout_bv = ast::BV::from_u64(ctx, int_for_gen, llen as u32);
2386 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
2387
2388 let constraint_new_owning = l_new_bv._safe_eq(&l_layout_bv).unwrap();
2389
2390 goal.assert(&constraint_new_owning);
2391 solver.assert(&constraint_new_owning);
2392
2393 self.icx_slice_mut().len_mut()[lu] = llen;
2394 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
2395 }
2396 1 => {
2397 let return_value_layout = self.extract_default_ty_layout(l_local_ty, None);
2400 if return_value_layout.is_empty() || !return_value_layout.get_requirement() {
2401 return;
2402 }
2403
2404 let llen = self.icx_slice().len()[lu];
2407
2408 let lpj_fields = self.extract_projection(dest, None);
2409 let index_needed = lpj_fields.index_needed();
2410
2411 if self.icx_slice().var()[lu].is_init() {
2412 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
2413 let extract_from_field =
2414 l_ori_bv.extract(index_needed as u32, index_needed as u32);
2415 let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
2416 let constraint_l_f_ori_zero =
2417 extract_from_field._safe_eq(&l_f_zero_const).unwrap();
2418
2419 goal.assert(&constraint_l_f_ori_zero);
2420 solver.assert(&constraint_l_f_ori_zero);
2421 } else {
2422 let l_ori_name_ctor = new_local_name(lu, bidx, 0).add("_ctor_fn");
2423 let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
2424 let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
2425 let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
2426
2427 goal.assert(&constraint_l_ctor_zero);
2428 solver.assert(&constraint_l_ctor_zero);
2429
2430 l_ori_bv = l_ori_zero;
2431 self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, None);
2432 self.icx_slice_mut().layout_mut()[lu] = return_value_layout.layout().clone();
2433 }
2434
2435 let l_name = new_local_name(lu, bidx, 0);
2436 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
2437
2438 let update_field = if source_flag {
2439 ast::BV::from_u64(ctx, 1, 1)
2440 } else {
2441 if return_value_layout.layout()[index_needed] == OwnedHeap::True {
2442 ast::BV::from_u64(ctx, 1, 1)
2443 } else {
2444 ast::BV::from_u64(ctx, 0, 1)
2445 }
2446 };
2447
2448 let mut final_bv: ast::BV;
2449 if index_needed < llen - 1 {
2450 let end_part = l_ori_bv.extract((llen - 1) as u32, (index_needed + 1) as u32);
2451 final_bv = end_part.concat(&update_field);
2452 } else {
2453 final_bv = update_field;
2454 }
2455 if index_needed > 0 {
2456 let begin_part = l_ori_bv.extract((index_needed - 1) as u32, 0);
2457 final_bv = final_bv.concat(&begin_part);
2458 }
2459 let update_filed_using_func = l_new_bv._safe_eq(&final_bv).unwrap();
2460
2461 goal.assert(&update_filed_using_func);
2462 solver.assert(&update_filed_using_func);
2463
2464 self.icx_slice_mut().len_mut()[lu] = return_value_layout.layout().len();
2465 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
2466 }
2467 _ => {
2468 self.handle_intra_var_unsupported(lu);
2469 return;
2470 }
2471 }
2472 }
2473
2474 pub(crate) fn handle_return(
2475 &mut self,
2476 ctx: &'ctx z3::Context,
2477 goal: &'ctx z3::Goal<'ctx>,
2478 solver: &'ctx z3::Solver<'ctx>,
2479 bidx: usize,
2480 ) {
2481 let place_0 = Place::from(Local::from_usize(0));
2482 self.handle_drop(ctx, goal, solver, &place_0, bidx, false);
2483
2484 for (iidx, var) in self.icx_slice().var.iter().enumerate() {
2486 let len = self.icx_slice().len()[iidx];
2487 if len == 0 {
2488 continue;
2489 }
2490 if iidx <= self.body.arg_count {
2491 continue;
2492 }
2493
2494 if var.is_init() {
2495 let var_ori_bv = var.extract();
2496
2497 let return_name = new_local_name(iidx, bidx, 0).add("_return");
2498 let var_return_bv = ast::BV::new_const(ctx, return_name, len as u32);
2499
2500 let zero_const = ast::BV::from_u64(ctx, 0, len as u32);
2501
2502 let var_update = var_return_bv._safe_eq(&var_ori_bv).unwrap();
2503 let var_freed = var_return_bv._safe_eq(&zero_const).unwrap();
2504
2505 let args = &[&var_update, &var_freed];
2506 let constraint_return = ast::Bool::and(ctx, args);
2507
2508 goal.assert(&constraint_return);
2509 solver.assert(&constraint_return);
2510 }
2511 }
2512
2513 let result = solver.check();
2514 let model = solver.get_model();
2515
2516 if is_z3_goal_verbose() {
2517 let g = format!("{}", goal);
2518 rap_trace!("{}\n", g);
2519 if model.is_some() {
2520 rap_trace!("{}", format!("{}", model.unwrap()));
2521 }
2522 }
2523
2524 if result == z3::SatResult::Unsat && self.taint_flag {
2530 let fn_name = get_name(self.tcx(), self.def_id)
2531 .unwrap_or_else(|| Symbol::intern("no symbol available"));
2532
2533 rap_warn!("Memory Leak detected in function {:}", fn_name);
2534 let source = span_to_source_code(self.body.span);
2535 let file = span_to_filename(self.body.span);
2536 let mut snippet = Snippet::source(&source)
2537 .line_start(span_to_line_number(self.body.span))
2538 .origin(&file)
2539 .fold(false);
2540
2541 for source in self.taint_source.iter() {
2542 if are_spans_in_same_file(self.body.span, source.source_info.span) {
2543 snippet = snippet.annotation(
2544 Level::Warning
2545 .span(relative_pos_range(self.body.span, source.source_info.span))
2546 .label("Memory Leak Candidates."),
2547 );
2548 }
2549 }
2557
2558 let message = Level::Warning
2559 .title("Memory Leak detected.")
2560 .snippet(snippet);
2561 let renderer = Renderer::styled();
2562 rap_warn!("{}", renderer.render(message));
2563 }
2564 }
2565
2566 pub(crate) fn handle_drop(
2567 &mut self,
2568 ctx: &'ctx z3::Context,
2569 goal: &'ctx z3::Goal<'ctx>,
2570 solver: &'ctx z3::Solver<'ctx>,
2571 dest: &Place<'tcx>,
2572 bidx: usize,
2573 recovery: bool,
2574 ) {
2575 let local = dest.local;
2576 let u: usize = local.as_usize();
2577
2578 if self.icx_slice().len()[u] == 0 {
2579 return;
2580 }
2581
2582 if self.icx_slice().var()[u].is_declared() || self.icx_slice().var()[u].is_unsupported() {
2583 return;
2584 }
2585
2586 let len = self.icx_slice().len()[u];
2587 let rust_bv = reverse_heap_layout_to_rustbv(&self.icx_slice().layout()[u]);
2588 let ori_bv = self.icx_slice().var()[u].extract();
2589
2590 let f = self.extract_projection(dest, None);
2591 if f.is_unsupported() {
2592 self.handle_intra_var_unsupported(u);
2593 return;
2594 }
2595
2596 match f.has_field() {
2597 false => {
2598 if recovery {
2601 let name = new_local_name(u, bidx, 0).add("_drop_recovery");
2603 let new_bv = ast::BV::new_const(ctx, name, len as u32);
2604 let zero_bv = ast::BV::from_u64(ctx, 0, len as u32);
2605
2606 let and_bv = ori_bv.bvand(&zero_bv);
2607
2608 let constraint_recovery = new_bv._eq(&and_bv);
2609
2610 goal.assert(&constraint_recovery);
2611 solver.assert(&constraint_recovery);
2612
2613 self.icx_slice_mut().var_mut()[u] = IntraVar::Init(new_bv);
2614 } else {
2615 let name = new_local_name(u, bidx, 0).add("_drop_all");
2617 let new_bv = ast::BV::new_const(ctx, name, len as u32);
2618 let int_for_rust_bv = rustbv_to_int(&rust_bv);
2619 let int_bv_const = ast::BV::from_u64(ctx, int_for_rust_bv, len as u32);
2620
2621 let and_bv = ori_bv.bvand(&int_bv_const);
2622
2623 let constraint_reverse = new_bv._eq(&and_bv);
2624
2625 goal.assert(&constraint_reverse);
2626 solver.assert(&constraint_reverse);
2627
2628 self.icx_slice_mut().var_mut()[u] = IntraVar::Init(new_bv);
2629 }
2630 }
2631 true => {
2632 let index_needed = f.index_needed();
2634
2635 if index_needed >= rust_bv.len() {
2636 return;
2637 }
2638
2639 let name = if recovery {
2640 new_local_name(u, bidx, 0).add("_drop_f_recovery")
2641 } else {
2642 new_local_name(u, bidx, 0).add("_drop_f")
2643 };
2644 let new_bv = ast::BV::new_const(ctx, name, len as u32);
2645
2646 if (rust_bv[index_needed] && !recovery) || (!rust_bv[index_needed] && recovery) {
2647 let constraint_update = new_bv._eq(&ori_bv);
2650
2651 goal.assert(&constraint_update);
2652 solver.assert(&constraint_update);
2653
2654 self.icx_slice_mut().var_mut()[u] = IntraVar::Init(new_bv);
2655 } else {
2656 let f_free = ast::BV::from_u64(ctx, 0, 1);
2657 let mut final_bv: ast::BV;
2658 if index_needed < len - 1 {
2659 let end_part = ori_bv.extract((len - 1) as u32, (index_needed + 1) as u32);
2660 final_bv = end_part.concat(&f_free);
2661 } else {
2662 final_bv = f_free;
2663 }
2664 if index_needed > 0 {
2665 let begin_part = ori_bv.extract((index_needed - 1) as u32, 0);
2666 final_bv = final_bv.concat(&begin_part);
2667 }
2668
2669 let constraint_free_f = new_bv._safe_eq(&final_bv).unwrap();
2670
2671 goal.assert(&constraint_free_f);
2672 solver.assert(&constraint_free_f);
2673
2674 self.icx_slice_mut().var_mut()[u] = IntraVar::Init(new_bv);
2675 }
2676 }
2677 }
2678 }
2679
2680 pub(crate) fn handle_intra_var_unsupported(&mut self, idx: usize) {
2681 match self.icx_slice_mut().var_mut()[idx] {
2682 IntraVar::Unsupported => return,
2683 IntraVar::Declared | IntraVar::Init(_) => {
2684 self.icx_slice_mut().var_mut()[idx] = IntraVar::Unsupported;
2686 self.icx_slice_mut().len_mut()[idx] = 0;
2687 return;
2688 }
2689 }
2690 }
2691
2692 pub(crate) fn handle_taint(&mut self, l: usize, r: usize) {
2693 if self.icx_slice().taint()[r].is_untainted() {
2694 return;
2695 }
2696
2697 if self.icx_slice().taint()[l].is_untainted() {
2698 self.icx_slice_mut().taint_mut()[l] = self.icx_slice().taint()[r].clone();
2699 } else {
2700 for elem in self.icx_slice().taint()[r].set().clone() {
2701 self.icx_slice_mut().taint_mut()[l].insert(elem);
2702 }
2703 }
2704 }
2705
2706 pub(crate) fn extract_default_ty_layout(
2707 &mut self,
2708 ty: Ty<'tcx>,
2709 variant: Option<VariantIdx>,
2710 ) -> OwnershipLayoutResult {
2711 match ty.kind() {
2712 TyKind::Array(..) => {
2713 let mut res = OwnershipLayoutResult::new();
2714 let mut default_heap = DefaultOwnership::new(self.tcx(), self.owner());
2715
2716 let _ = ty.visit_with(&mut default_heap);
2717 res.update_from_default_heap_visitor(&mut default_heap);
2718
2719 res
2720 }
2721 TyKind::Tuple(tuple_ty_list) => {
2722 let mut res = OwnershipLayoutResult::new();
2723
2724 for tuple_ty in tuple_ty_list.iter() {
2725 let mut default_heap = DefaultOwnership::new(self.tcx(), self.owner());
2726
2727 let _ = tuple_ty.visit_with(&mut default_heap);
2728 res.update_from_default_heap_visitor(&mut default_heap);
2729 }
2730
2731 res
2732 }
2733 TyKind::Adt(adtdef, substs) => {
2734 if adtdef.is_enum() && variant.is_none() {
2736 return OwnershipLayoutResult::new();
2737 }
2738
2739 let mut res = OwnershipLayoutResult::new();
2740
2741 if adtdef.is_struct() || adtdef.is_union() {
2743 for field in adtdef.all_fields() {
2744 let field_ty = field.ty(self.tcx(), substs);
2745
2746 let mut default_heap = DefaultOwnership::new(self.tcx(), self.owner());
2747
2748 let _ = field_ty.visit_with(&mut default_heap);
2749 res.update_from_default_heap_visitor(&mut default_heap);
2750 }
2751 }
2752 else if adtdef.is_enum() {
2754 let vidx = variant.unwrap();
2755
2756 for field in &adtdef.variants()[vidx].fields {
2757 let field_ty = field.ty(self.tcx(), substs);
2758
2759 let mut default_heap = DefaultOwnership::new(self.tcx(), self.owner());
2760
2761 let _ = field_ty.visit_with(&mut default_heap);
2762 res.update_from_default_heap_visitor(&mut default_heap);
2763 }
2764 }
2765 res
2766 }
2767 TyKind::Param(..) => {
2768 let mut res = OwnershipLayoutResult::new();
2769 res.set_requirement(true);
2770 res.set_param(true);
2771 res.set_owned(true);
2772 res.layout_mut().push(OwnedHeap::True);
2773 res
2774 }
2775 TyKind::RawPtr(..) => {
2776 let mut res = OwnershipLayoutResult::new();
2777 res.set_requirement(true);
2778 res.layout_mut().push(OwnedHeap::False);
2779 res
2780 }
2781 TyKind::Ref(..) => {
2782 let mut res = OwnershipLayoutResult::new();
2783 res.set_requirement(true);
2784 res.layout_mut().push(OwnedHeap::False);
2785 res
2786 }
2787 _ => OwnershipLayoutResult::new(),
2788 }
2789 }
2790
2791 pub(crate) fn generate_ptr_layout(
2792 &mut self,
2793 ty: Ty<'tcx>,
2794 variant: Option<VariantIdx>,
2795 ) -> Vec<bool> {
2796 let mut res = Vec::new();
2797 match ty.kind() {
2798 TyKind::Array(..) => {
2799 res.push(false);
2800 res
2801 }
2802 TyKind::Tuple(tuple_ty_list) => {
2803 for tuple_ty in tuple_ty_list.iter() {
2804 if tuple_ty.is_any_ptr() {
2805 res.push(true);
2806 } else {
2807 res.push(false);
2808 }
2809 }
2810
2811 res
2812 }
2813 TyKind::Adt(adtdef, _substs) => {
2814 if adtdef.is_enum() && variant.is_none() {
2816 return res;
2817 }
2818
2819 if adtdef.is_struct() || adtdef.is_union() {
2821 for _field in adtdef.all_fields() {
2822 res.push(false);
2823 }
2824 }
2825 else if adtdef.is_enum() {
2827 let vidx = variant.unwrap();
2828
2829 for _field in &adtdef.variants()[vidx].fields {
2830 res.push(false);
2831 }
2832 }
2833 res
2834 }
2835 TyKind::Param(..) => {
2836 res.push(false);
2837 res
2838 }
2839 TyKind::RawPtr(..) => {
2840 res.push(true);
2841 res
2842 }
2843 TyKind::Ref(..) => {
2844 res.push(true);
2845 res
2846 }
2847 _ => res,
2848 }
2849 }
2850
2851 fn extract_projection(&self, place: &Place<'tcx>, aggre: Aggre) -> ProjectionSupport<'tcx> {
2852 let mut prj: ProjectionSupport<'tcx> = ProjectionSupport::default();
2856 if aggre.is_some() {
2857 let ty = place.ty(&self.body.local_decls, self.tcx());
2862 prj.pf_vec.push((aggre.unwrap(), ty.ty));
2863 return prj;
2864 }
2865 for (idx, each_pj) in place.projection.iter().enumerate() {
2866 match each_pj {
2867 ProjectionElem::Field(field, ty) => {
2868 prj.pf_push(field.index(), ty);
2869 if prj.pf_vec.len() > 1 {
2870 prj.unsupport = true;
2871 break;
2872 }
2873 if prj.deref {
2874 prj.unsupport = true;
2875 break;
2876 }
2877 }
2878 ProjectionElem::Deref => {
2879 prj.deref = true;
2880 if idx > 0 {
2881 prj.unsupport = true;
2882 break;
2883 }
2884 }
2885 ProjectionElem::Downcast(.., ref vidx) => {
2886 prj.downcast = Some(*vidx);
2887 if idx > 0 {
2888 prj.unsupport = true;
2889 break;
2890 }
2891 }
2892 ProjectionElem::ConstantIndex { .. }
2893 | ProjectionElem::Subslice { .. }
2894 | ProjectionElem::Index(..)
2895 | ProjectionElem::OpaqueCast(..) => {
2896 prj.unsupport = true;
2897 break;
2898 }
2899 _ => todo!(),
2900 }
2901 }
2902 prj
2903 }
2904}
2905
2906fn new_local_name(local: usize, bidx: usize, sidx: usize) -> String {
2907 let s = bidx
2908 .to_string()
2909 .add("_")
2910 .add(&sidx.to_string())
2911 .add("_")
2912 .add(&local.to_string());
2913 s
2914}
2915
2916fn is_place_containing_ptr(ty: &Ty) -> bool {
2917 match ty.kind() {
2918 TyKind::Tuple(tuple_ty_list) => {
2919 for tuple_ty in tuple_ty_list.iter() {
2920 if tuple_ty.is_any_ptr() {
2921 return true;
2922 }
2923 }
2924 false
2925 }
2926 TyKind::RawPtr(..) => true,
2927 TyKind::Ref(..) => true,
2928 _ => false,
2929 }
2930}
2931
2932#[derive(Debug)]
2933struct ProjectionSupport<'tcx> {
2934 pf_vec: Vec<(usize, Ty<'tcx>)>,
2935 deref: bool,
2936 downcast: Disc,
2937 unsupport: bool,
2938}
2939
2940impl<'tcx> Default for ProjectionSupport<'tcx> {
2941 fn default() -> Self {
2942 Self {
2943 pf_vec: Vec::default(),
2944 deref: false,
2945 downcast: None,
2946 unsupport: false,
2947 }
2948 }
2949}
2950
2951impl<'tcx> ProjectionSupport<'tcx> {
2952 pub fn pf_push(&mut self, index: usize, ty: Ty<'tcx>) {
2953 self.pf_vec.push((index, ty));
2954 }
2955
2956 pub fn is_unsupported(&self) -> bool {
2957 self.unsupport == true
2958 }
2959
2960 pub fn has_field(&self) -> bool {
2961 self.pf_vec.len() > 0
2962 }
2963
2964 pub fn has_downcast(&self) -> bool {
2965 self.downcast.is_some()
2966 }
2967
2968 pub fn downcast(&self) -> Disc {
2969 self.downcast
2970 }
2971
2972 pub fn index_needed(&self) -> usize {
2973 self.pf_vec[0].0
2974 }
2975}
2976
2977fn has_projection(place: &Place) -> bool {
2978 return if place.projection.len() > 0 {
2979 true
2980 } else {
2981 false
2982 };
2983}
2984
2985fn heap_layout_to_rustbv(layout: &Vec<OwnedHeap>) -> Vec<bool> {
2986 let mut v = Vec::default();
2987 for item in layout.iter() {
2988 match item {
2989 OwnedHeap::Unknown => rap_error!("item of raw type owner is uninit"),
2990 OwnedHeap::False => v.push(false),
2991 OwnedHeap::True => v.push(true),
2992 }
2993 }
2994 v
2995}
2996
2997fn reverse_heap_layout_to_rustbv(layout: &Vec<OwnedHeap>) -> Vec<bool> {
2998 let mut v = Vec::default();
2999 for item in layout.iter() {
3000 match item {
3001 OwnedHeap::Unknown => rap_error!("item of raw type owner is uninit"),
3002 OwnedHeap::False => v.push(true),
3003 OwnedHeap::True => v.push(false),
3004 }
3005 }
3006 v
3007}
3008
3009fn rustbv_merge(a: &Vec<bool>, b: &Vec<bool>) -> Vec<bool> {
3010 assert_eq!(a.len(), b.len());
3011 let mut bv = Vec::new();
3012 for idx in 0..a.len() {
3013 bv.push(a[idx] || b[idx]);
3014 }
3015 bv
3016}
3017
3018fn rustbv_to_int(bv: &Vec<bool>) -> u64 {
3022 let mut ans = 0;
3023 let mut base = 1;
3024 for tf in bv.iter() {
3025 ans = ans + base * (*tf as u64);
3026 base = base * 2;
3027 }
3028 ans
3029}
3030
3031fn help_debug_goal_stmt<'tcx, 'ctx>(
3032 ctx: &'ctx z3::Context,
3033 goal: &'ctx z3::Goal<'ctx>,
3034 bidx: usize,
3035 sidx: usize,
3036) {
3037 let debug_name = format!("CONSTRAINTS: S {} {}", bidx, sidx);
3038 let dbg_bool = ast::Bool::new_const(ctx, debug_name);
3039 goal.assert(&dbg_bool);
3040}
3041
3042fn help_debug_goal_term<'tcx, 'ctx>(
3043 ctx: &'ctx z3::Context,
3044 goal: &'ctx z3::Goal<'ctx>,
3045 bidx: usize,
3046) {
3047 let debug_name = format!("CONSTRAINTS: T {}", bidx);
3048 let dbg_bool = ast::Bool::new_const(ctx, debug_name);
3049 goal.assert(&dbg_bool);
3050}