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::owned_heap::{default::*, *},
24 utils::{
25 span::{
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().layout_mut()[lu] = default_heap.layout().clone();
1274 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_ori_bv_ctor);
1275 }
1276 }
1277
1278 pub(crate) fn handle_copy_to_field(
1279 &mut self,
1280 ctx: &'ctx z3::Context,
1281 goal: &'ctx z3::Goal<'ctx>,
1282 solver: &'ctx z3::Solver<'ctx>,
1283 _kind: AsgnKind,
1284 lplace: &Place<'tcx>,
1285 rplace: &Place<'tcx>,
1286 mut disc: Disc,
1287 aggre: Aggre,
1288 bidx: usize,
1289 sidx: usize,
1290 ) {
1291 let llocal = lplace.local;
1294 let rlocal = rplace.local;
1295
1296 let lu: usize = llocal.as_usize();
1297 let ru: usize = rlocal.as_usize();
1298
1299 if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1301 {
1302 self.handle_intra_var_unsupported(lu);
1303 self.handle_intra_var_unsupported(ru);
1304 return;
1305 }
1306 if !self.icx_slice().var()[ru].is_init() {
1307 return;
1308 }
1309
1310 let l_local_ty = self.body.local_decls[llocal].ty;
1312 let lpj_fields = self.extract_projection(lplace, aggre);
1313 if lpj_fields.is_unsupported() {
1314 self.handle_intra_var_unsupported(lu);
1316 self.handle_intra_var_unsupported(ru);
1317 return;
1318 }
1319
1320 match (lpj_fields.has_field(), lpj_fields.has_downcast()) {
1321 (true, true) => {
1322 disc = lpj_fields.downcast();
1324 let ty_with_index = TyWithIndex::new(l_local_ty, disc);
1325
1326 if ty_with_index.0.is_none() {
1327 return;
1328 }
1329
1330 if lpj_fields.index_needed() == 0 && ty_with_index.0.unwrap().0 == 1 {
1332 self.handle_copy(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1333 return;
1334 }
1335 }
1336 (true, false) => {
1337 }
1339 (false, true) => {
1340 return;
1342 }
1343 (false, false) => {
1344 self.handle_copy(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1345 return;
1346 }
1347 }
1348
1349 let index_needed = lpj_fields.index_needed();
1350
1351 let default_heap = self.extract_default_ty_layout(l_local_ty, disc);
1352 if !default_heap.get_requirement() || default_heap.is_empty() {
1353 return;
1354 }
1355
1356 let llen = default_heap.layout().len();
1358 self.icx_slice_mut().len_mut()[lu] = llen;
1359 let rlen = self.icx_slice().len()[ru];
1360
1361 if self.icx_slice().len[ru] == 0 {
1364 return;
1366 }
1367
1368 let l_ori_bv: ast::BV;
1370 let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1371
1372 if self.icx_slice().var()[lu].is_init() {
1373 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1377 let extract_from_field = l_ori_bv.extract(index_needed as u32, index_needed as u32);
1378 if lu > self.body.arg_count {
1379 let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
1380 let constraint_l_f_ori_zero = extract_from_field._safe_eq(&l_f_zero_const).unwrap();
1381 goal.assert(&constraint_l_f_ori_zero);
1382 solver.assert(&constraint_l_f_ori_zero);
1383 }
1384 } else {
1385 let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1388 let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1389 let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1390 let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1391 goal.assert(&constraint_l_ctor_zero);
1392 solver.assert(&constraint_l_ctor_zero);
1393 l_ori_bv = l_ori_zero;
1394 self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1395 self.icx_slice_mut().layout_mut()[lu] = default_heap.layout().clone();
1396 }
1397
1398 let l_name = new_local_name(lu, bidx, sidx);
1404 let r_name = new_local_name(ru, bidx, sidx);
1405
1406 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1408 let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1409
1410 let r_zero_const = ast::BV::from_u64(ctx, 0, rlen as u32);
1411
1412 let r_owning = r_new_bv._safe_eq(&r_ori_bv).unwrap();
1417 let mut rust_bv_for_op_and = vec![true; llen];
1419 rust_bv_for_op_and[index_needed] = false;
1420 let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1421 let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, llen as u32);
1422 let after_op_and = l_ori_bv.bvand(&z3_bv_for_op_and);
1423 let lpj_non_owning = l_new_bv._safe_eq(&after_op_and).unwrap();
1424
1425 let args1 = &[&r_owning, &lpj_non_owning];
1426 let summary_1 = ast::Bool::and(ctx, args1);
1427
1428 let r_non_owning = r_new_bv._safe_eq(&r_zero_const).unwrap();
1431 let disjunction_r = r_ori_bv.bvredor();
1437 let mut final_bv: ast::BV;
1438
1439 if index_needed < llen - 1 {
1440 let end_part = l_ori_bv.extract((llen - 1) as u32, (index_needed + 1) as u32);
1441 final_bv = end_part.concat(&disjunction_r);
1442 } else {
1443 final_bv = disjunction_r;
1444 }
1445 if index_needed > 0 {
1446 let begin_part = l_ori_bv.extract((index_needed - 1) as u32, 0);
1447 final_bv = final_bv.concat(&begin_part);
1448 }
1449
1450 let lpj_shrink_owning = l_new_bv._safe_eq(&final_bv).unwrap();
1451
1452 let args2 = &[&r_non_owning, &lpj_shrink_owning];
1453 let summary_2 = ast::Bool::and(ctx, args2);
1454
1455 let args3 = &[&summary_1, &summary_2];
1457 let constraint_owning_now = ast::Bool::or(ctx, args3);
1458
1459 goal.assert(&constraint_owning_now);
1460 solver.assert(&constraint_owning_now);
1461
1462 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1464 self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1465 self.handle_taint(lu, ru);
1466 }
1467
1468 pub(crate) fn handle_move_to_field(
1469 &mut self,
1470 ctx: &'ctx z3::Context,
1471 goal: &'ctx z3::Goal<'ctx>,
1472 solver: &'ctx z3::Solver<'ctx>,
1473 _kind: AsgnKind,
1474 lplace: &Place<'tcx>,
1475 rplace: &Place<'tcx>,
1476 mut disc: Disc,
1477 aggre: Aggre,
1478 bidx: usize,
1479 sidx: usize,
1480 ) {
1481 let llocal = lplace.local;
1484 let rlocal = rplace.local;
1485
1486 let lu: usize = llocal.as_usize();
1487 let ru: usize = rlocal.as_usize();
1488
1489 if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1491 {
1492 self.handle_intra_var_unsupported(lu);
1493 self.handle_intra_var_unsupported(ru);
1494 return;
1495 }
1496 if !self.icx_slice().var()[ru].is_init() {
1497 return;
1498 }
1499
1500 let l_local_ty = self.body.local_decls[llocal].ty;
1502 let lpj_fields = self.extract_projection(lplace, aggre);
1503 if lpj_fields.is_unsupported() {
1504 self.handle_intra_var_unsupported(lu);
1506 self.handle_intra_var_unsupported(ru);
1507 return;
1508 }
1509
1510 match (lpj_fields.has_field(), lpj_fields.has_downcast()) {
1511 (true, true) => {
1512 disc = lpj_fields.downcast();
1514 let ty_with_index = TyWithIndex::new(l_local_ty, disc);
1515
1516 if ty_with_index.0.is_none() {
1517 return;
1518 }
1519
1520 if lpj_fields.index_needed() == 0 && ty_with_index.0.unwrap().0 == 1 {
1522 self.handle_move(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1523 return;
1524 }
1525 }
1526 (true, false) => {
1527 }
1529 (false, true) => {
1530 return;
1532 }
1533 (false, false) => {
1534 self.handle_move(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1535 return;
1536 }
1537 }
1538
1539 let index_needed = lpj_fields.index_needed();
1540
1541 let mut default_heap = self.extract_default_ty_layout(l_local_ty, disc);
1542 if !default_heap.get_requirement() || default_heap.is_empty() {
1543 return;
1544 }
1545
1546 let llen = default_heap.layout().len();
1548 self.icx_slice_mut().len_mut()[lu] = llen;
1549 let rlen = self.icx_slice().len()[ru];
1550
1551 if self.icx_slice().len[ru] == 0 {
1554 return;
1556 }
1557
1558 let l_ori_bv: ast::BV;
1560 let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1561
1562 if self.icx_slice().var()[lu].is_init() {
1563 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1568 let extract_from_field = l_ori_bv.extract(index_needed as u32, index_needed as u32);
1569 if lu > self.body.arg_count {
1570 let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
1571 let constraint_l_f_ori_zero = extract_from_field._safe_eq(&l_f_zero_const).unwrap();
1572 goal.assert(&constraint_l_f_ori_zero);
1573 solver.assert(&constraint_l_f_ori_zero);
1574 }
1575 } else {
1576 let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1579 let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1580 let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1581 let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1582 goal.assert(&constraint_l_ctor_zero);
1583 solver.assert(&constraint_l_ctor_zero);
1584 l_ori_bv = l_ori_zero;
1585 self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1586 self.icx_slice_mut().layout_mut()[lu] = default_heap.layout_mut().clone();
1587 }
1588
1589 let l_name = new_local_name(lu, bidx, sidx);
1595 let r_name = new_local_name(ru, bidx, sidx);
1596
1597 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1599 let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1600
1601 let r_zero_const = ast::BV::from_u64(ctx, 0, rlen as u32);
1602
1603 let r_non_owning = r_new_bv._safe_eq(&r_zero_const).unwrap();
1607
1608 let disjunction_r = r_ori_bv.bvredor();
1614 let mut final_bv: ast::BV;
1615 if index_needed < llen - 1 {
1616 let end_part = l_ori_bv.extract((llen - 1) as u32, (index_needed + 1) as u32);
1617 final_bv = end_part.concat(&disjunction_r);
1618 } else {
1619 final_bv = disjunction_r;
1620 }
1621 if index_needed > 0 {
1622 let begin_part = l_ori_bv.extract((index_needed - 1) as u32, 0);
1623 final_bv = final_bv.concat(&begin_part);
1624 }
1625 let lpj_shrink_owning = l_new_bv._safe_eq(&final_bv).unwrap();
1626
1627 goal.assert(&r_non_owning);
1628 goal.assert(&lpj_shrink_owning);
1629 solver.assert(&r_non_owning);
1630 solver.assert(&lpj_shrink_owning);
1631
1632 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1634 self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1635 self.handle_taint(lu, ru);
1636 }
1637
1638 pub(crate) fn handle_copy_field_to_field(
1639 &mut self,
1640 ctx: &'ctx z3::Context,
1641 goal: &'ctx z3::Goal<'ctx>,
1642 solver: &'ctx z3::Solver<'ctx>,
1643 _kind: AsgnKind,
1644 lplace: &Place<'tcx>,
1645 rplace: &Place<'tcx>,
1646 disc: Disc,
1647 aggre: Aggre,
1648 bidx: usize,
1649 sidx: usize,
1650 ) {
1651 let llocal = lplace.local;
1653 let rlocal = rplace.local;
1654
1655 let lu: usize = llocal.as_usize();
1656 let ru: usize = rlocal.as_usize();
1657
1658 if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1660 {
1661 self.handle_intra_var_unsupported(lu);
1662 self.handle_intra_var_unsupported(ru);
1663 return;
1664 }
1665 if !self.icx_slice().var()[ru].is_init() {
1666 return;
1667 }
1668
1669 let l_local_ty = self.body.local_decls[llocal].ty;
1670
1671 let rpj_fields = self.extract_projection(rplace, None);
1674 if rpj_fields.is_unsupported() {
1675 self.handle_intra_var_unsupported(lu);
1677 self.handle_intra_var_unsupported(ru);
1678 return;
1679 }
1680
1681 let lpj_fields = self.extract_projection(lplace, aggre);
1682 if lpj_fields.is_unsupported() {
1683 self.handle_intra_var_unsupported(lu);
1685 self.handle_intra_var_unsupported(ru);
1686 return;
1687 }
1688
1689 match (rpj_fields.has_field(), lpj_fields.has_field()) {
1690 (true, true) => (),
1691 (true, false) => {
1692 self.handle_copy_from_field(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1693 return;
1694 }
1695 (false, true) => {
1696 self.handle_copy_to_field(
1697 ctx, goal, solver, _kind, lplace, rplace, disc, aggre, bidx, sidx,
1698 );
1699 return;
1700 }
1701 (false, false) => {
1702 self.handle_copy(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1703 return;
1704 }
1705 }
1706
1707 let r_index_needed = rpj_fields.index_needed();
1708 let l_index_needed = lpj_fields.index_needed();
1709
1710 let default_heap = self.extract_default_ty_layout(l_local_ty, disc);
1711 if !default_heap.get_requirement() || default_heap.is_empty() {
1712 return;
1713 }
1714
1715 let llen = default_heap.layout().len();
1717 let rlen = self.icx_slice().len()[ru];
1718 self.icx_slice_mut().len_mut()[lu] = llen;
1719
1720 if self.icx_slice().len[ru] == 0 {
1723 return;
1725 }
1726
1727 let l_ori_bv: ast::BV;
1729 let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1730
1731 if self.icx_slice().var()[lu].is_init() {
1732 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1736 let extract_from_field = l_ori_bv.extract(l_index_needed as u32, l_index_needed as u32);
1737 if lu > self.body.arg_count {
1738 let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
1739 let constraint_l_f_ori_zero = extract_from_field._safe_eq(&l_f_zero_const).unwrap();
1740 goal.assert(&constraint_l_f_ori_zero);
1741 solver.assert(&constraint_l_f_ori_zero);
1742 }
1743 } else {
1744 let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1747 let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1748 let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1749 let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1750 goal.assert(&constraint_l_ctor_zero);
1751 solver.assert(&constraint_l_ctor_zero);
1752 l_ori_bv = l_ori_zero;
1753 self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1754 self.icx_slice_mut().layout_mut()[lu] = default_heap.layout().clone();
1755 }
1756
1757 let l_name = new_local_name(lu, bidx, sidx);
1759 let r_name = new_local_name(ru, bidx, sidx);
1760
1761 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1763 let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1764
1765 let mut rust_bv_for_op_and = vec![true; rlen];
1772 rust_bv_for_op_and[r_index_needed] = false;
1773 let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1774 let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, rlen as u32);
1775 let after_op_and = r_ori_bv.bvand(&z3_bv_for_op_and);
1776 let rpj_non_owning = r_new_bv._safe_eq(&after_op_and).unwrap();
1777 let extract_field_r = r_ori_bv.extract(r_index_needed as u32, r_index_needed as u32);
1782 let mut final_bv: ast::BV;
1783 if l_index_needed < llen - 1 {
1784 let end_part = l_ori_bv.extract((llen - 1) as u32, (l_index_needed + 1) as u32);
1785 final_bv = end_part.concat(&extract_field_r);
1786 } else {
1787 final_bv = extract_field_r;
1788 }
1789 if l_index_needed > 0 {
1790 let begin_part = l_ori_bv.extract((l_index_needed - 1) as u32, 0);
1791 final_bv = final_bv.concat(&begin_part);
1792 }
1793 let lpj_owning = l_new_bv._safe_eq(&final_bv).unwrap();
1794
1795 let args1 = &[&rpj_non_owning, &lpj_owning];
1796 let summary_1 = ast::Bool::and(ctx, args1);
1797
1798 let mut rust_bv_for_op_and = vec![true; llen];
1801 rust_bv_for_op_and[l_index_needed] = false;
1802 let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1803 let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, llen as u32);
1804 let after_op_and = l_ori_bv.bvand(&z3_bv_for_op_and);
1805 let lpj_non_owning = l_new_bv._safe_eq(&after_op_and).unwrap();
1806 let rpj_owning = r_new_bv._safe_eq(&r_ori_bv).unwrap();
1808
1809 let args2 = &[&lpj_non_owning, &rpj_owning];
1810 let summary_2 = ast::Bool::and(ctx, args2);
1811
1812 let args3 = &[&summary_1, &summary_2];
1814 let constraint_owning_now = ast::Bool::or(ctx, args3);
1815
1816 goal.assert(&constraint_owning_now);
1817 solver.assert(&constraint_owning_now);
1818
1819 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1821 self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1822 self.handle_taint(lu, ru);
1823 }
1824
1825 pub(crate) fn handle_move_field_to_field(
1826 &mut self,
1827 ctx: &'ctx z3::Context,
1828 goal: &'ctx z3::Goal<'ctx>,
1829 solver: &'ctx z3::Solver<'ctx>,
1830 _kind: AsgnKind,
1831 lplace: &Place<'tcx>,
1832 rplace: &Place<'tcx>,
1833 disc: Disc,
1834 aggre: Aggre,
1835 bidx: usize,
1836 sidx: usize,
1837 ) {
1838 let llocal = lplace.local;
1840 let rlocal = rplace.local;
1841
1842 let lu: usize = llocal.as_usize();
1843 let ru: usize = rlocal.as_usize();
1844
1845 if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1847 {
1848 self.handle_intra_var_unsupported(lu);
1849 self.handle_intra_var_unsupported(ru);
1850 return;
1851 }
1852 if !self.icx_slice().var()[ru].is_init() {
1853 return;
1854 }
1855
1856 let l_local_ty = self.body.local_decls[llocal].ty;
1857
1858 let rpj_fields = self.extract_projection(rplace, None);
1862 if rpj_fields.is_unsupported() {
1863 self.handle_intra_var_unsupported(lu);
1865 self.handle_intra_var_unsupported(ru);
1866 return;
1867 }
1868
1869 let lpj_fields = self.extract_projection(lplace, aggre);
1873 if lpj_fields.is_unsupported() {
1874 self.handle_intra_var_unsupported(lu);
1876 self.handle_intra_var_unsupported(ru);
1877 return;
1878 }
1879
1880 match (rpj_fields.has_field(), lpj_fields.has_field()) {
1881 (true, true) => (),
1882 (true, false) => {
1883 self.handle_move_from_field(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1884 return;
1885 }
1886 (false, true) => {
1887 self.handle_move_to_field(
1888 ctx, goal, solver, _kind, lplace, rplace, disc, aggre, bidx, sidx,
1889 );
1890 }
1891 (false, false) => {
1892 self.handle_move(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1893 return;
1894 }
1895 }
1896
1897 let r_index_needed = rpj_fields.index_needed();
1898 let l_index_needed = lpj_fields.index_needed();
1899
1900 let default_heap = self.extract_default_ty_layout(l_local_ty, disc);
1901 if !default_heap.get_requirement() || default_heap.is_empty() {
1902 return;
1903 }
1904
1905 let llen = default_heap.layout().len();
1907 let rlen = self.icx_slice().len()[ru];
1908 self.icx_slice_mut().len_mut()[lu] = llen;
1909
1910 if self.icx_slice().len[ru] == 0 {
1913 return;
1915 }
1916
1917 let l_ori_bv: ast::BV;
1919 let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1920
1921 if self.icx_slice().var()[lu].is_init() {
1922 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1926 let extract_from_field = l_ori_bv.extract(l_index_needed as u32, l_index_needed as u32);
1927 if lu > self.body.arg_count {
1928 let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
1929 let constraint_l_f_ori_zero = extract_from_field._safe_eq(&l_f_zero_const).unwrap();
1930 goal.assert(&constraint_l_f_ori_zero);
1931 solver.assert(&constraint_l_f_ori_zero);
1932 }
1933 } else {
1934 let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1937 let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1938 let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1939 let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1940 goal.assert(&constraint_l_ctor_zero);
1941 solver.assert(&constraint_l_ctor_zero);
1942 l_ori_bv = l_ori_zero;
1943 self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1944 self.icx_slice_mut().layout_mut()[lu] = default_heap.layout().clone();
1945 }
1946
1947 let l_name = new_local_name(lu, bidx, sidx);
1949 let r_name = new_local_name(ru, bidx, sidx);
1950
1951 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1953 let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1954
1955 let mut rust_bv_for_op_and = vec![true; rlen];
1961 rust_bv_for_op_and[r_index_needed] = false;
1962 let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1963 let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, rlen as u32);
1964 let after_op_and = r_ori_bv.bvand(&z3_bv_for_op_and);
1965 let rpj_non_owning = r_new_bv._safe_eq(&after_op_and).unwrap();
1966
1967 let extract_field_r = r_ori_bv.extract(r_index_needed as u32, r_index_needed as u32);
1972 let mut final_bv: ast::BV;
1973
1974 if l_index_needed < llen - 1 {
1975 let end_part = l_ori_bv.extract((llen - 1) as u32, (l_index_needed + 1) as u32);
1976 final_bv = end_part.concat(&extract_field_r);
1977 } else {
1978 final_bv = extract_field_r;
1979 }
1980 if l_index_needed > 0 {
1981 let begin_part = l_ori_bv.extract((l_index_needed - 1) as u32, 0);
1982 final_bv = final_bv.concat(&begin_part);
1983 }
1984 let lpj_owning = l_new_bv._safe_eq(&final_bv).unwrap();
1985
1986 goal.assert(&rpj_non_owning);
1987 goal.assert(&lpj_owning);
1988 solver.assert(&rpj_non_owning);
1989 solver.assert(&lpj_owning);
1990
1991 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1993 self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1994 self.handle_taint(lu, ru);
1995 }
1996
1997 pub(crate) fn check_fn_source(
1998 &mut self,
1999 args: &Box<[Spanned<Operand<'tcx>>]>,
2001 dest: &Place<'tcx>,
2002 ) -> bool {
2003 if args.len() != 1 {
2004 return false;
2005 }
2006
2007 let l_place_ty = dest.ty(&self.body.local_decls, self.tcx());
2008 if !is_place_containing_ptr(&l_place_ty.ty) {
2009 return false;
2010 }
2011
2012 match args[0].node {
2013 Operand::Move(aplace) => {
2014 let a_place_ty = aplace.ty(&self.body.local_decls, self.tcx());
2015 let default_layout =
2016 self.extract_default_ty_layout(a_place_ty.ty, a_place_ty.variant_index);
2017 if default_layout.is_owned() {
2018 self.taint_flag = true;
2019 true
2020 } else {
2021 false
2022 }
2023 }
2024 _ => false,
2025 }
2026 }
2027
2028 pub(crate) fn check_fn_recovery(
2029 &mut self,
2030 args: &Box<[Spanned<Operand<'tcx>>]>,
2032 dest: &Place<'tcx>,
2033 ) -> (bool, Vec<usize>) {
2034 let mut ans: (bool, Vec<usize>) = (false, Vec::new());
2035
2036 if args.len() == 0 {
2037 return ans;
2038 }
2039
2040 let l_place_ty = dest.ty(&self.body.local_decls, self.tcx());
2041 let default_layout =
2042 self.extract_default_ty_layout(l_place_ty.ty, l_place_ty.variant_index);
2043 if !default_layout.get_requirement() || default_layout.is_empty() {
2044 return ans;
2045 }
2046 let ty_with_idx = TyWithIndex::new(l_place_ty.ty, l_place_ty.variant_index);
2047
2048 for arg in args {
2049 match arg.node {
2050 Operand::Move(aplace) => {
2051 let au: usize = aplace.local.as_usize();
2052 let taint = &self.icx_slice().taint()[au];
2053 if taint.is_tainted() && taint.contains(&ty_with_idx) {
2054 ans.0 = true;
2055 ans.1.push(au);
2056 }
2057 }
2058 Operand::Copy(aplace) => {
2059 let au: usize = aplace.local.as_usize();
2060 let taint = &self.icx_slice().taint()[au];
2061 if taint.is_tainted() && taint.contains(&ty_with_idx) {
2062 ans.0 = true;
2063 ans.1.push(au);
2064 }
2065 }
2066 _ => (),
2067 }
2068 }
2069 ans
2070 }
2071
2072 pub(crate) fn handle_call(
2073 &mut self,
2074 ctx: &'ctx z3::Context,
2075 goal: &'ctx z3::Goal<'ctx>,
2076 solver: &'ctx z3::Solver<'ctx>,
2077 term: Terminator<'tcx>,
2078 func: &Operand<'tcx>,
2079 args: &Box<[Spanned<Operand<'tcx>>]>,
2081 dest: &Place<'tcx>,
2082 bidx: usize,
2083 ) {
2084 match func {
2085 Operand::Constant(constant) => {
2086 match constant.ty().kind() {
2087 ty::FnDef(id, ..) => {
2088 match id.index.as_usize() {
2091 2171 => {
2092 match args[0].node {
2094 Operand::Move(aplace) => {
2095 let a_place_ty =
2096 dest.ty(&self.body.local_decls, self.tcx());
2097 let a_ty = a_place_ty.ty;
2098 if a_ty.is_adt() {
2099 self.handle_drop(
2100 ctx, goal, solver, &aplace, bidx, false,
2101 );
2102 return;
2103 }
2104 }
2105 _ => (),
2106 }
2107 }
2108 _ => (),
2109 }
2110 }
2111 _ => (),
2112 }
2113 }
2114 _ => (),
2115 }
2116
2117 let llocal = dest.local;
2119 let lu: usize = llocal.as_usize();
2120
2121 let source_flag = self.check_fn_source(args, dest);
2124 let recovery_flag = self.check_fn_recovery(args, dest);
2128 if source_flag {
2129 self.add_taint(term);
2130 }
2131
2132 for arg in args {
2133 match arg.node {
2134 Operand::Move(aplace) => {
2135 let alocal = aplace.local;
2136 let au: usize = alocal.as_usize();
2137
2138 if self.icx_slice().len()[au] == 0 {
2141 continue;
2143 }
2144
2145 if !self.icx_slice().var()[au].is_init() {
2146 continue;
2147 }
2148
2149 let a_place_ty = aplace.ty(&self.body.local_decls, self.tcx());
2150 let a_ty = a_place_ty.ty;
2151 let is_a_ptr = a_ty.is_any_ptr();
2152
2153 let a_ori_bv = self.icx_slice_mut().var_mut()[au].extract();
2154 let alen = self.icx_slice().len()[au];
2155
2156 if source_flag {
2157 self.icx_slice_mut().taint_mut()[lu]
2158 .insert(TyWithIndex::new(a_place_ty.ty, a_place_ty.variant_index));
2159 }
2160
2161 match aplace.projection.len() {
2162 0 => {
2163 if is_a_ptr {
2165 if recovery_flag.0 && recovery_flag.1.contains(&au) {
2166 self.handle_drop(ctx, goal, solver, &aplace, bidx, true);
2167 continue;
2168 }
2169
2170 let a_zero_const = ast::BV::from_u64(ctx, 0, alen as u32);
2174 let a_ori_non_owing = a_ori_bv._safe_eq(&a_zero_const).unwrap();
2175
2176 let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2178 let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2179 let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2180
2181 goal.assert(&a_ori_non_owing);
2182 goal.assert(&update_a);
2183 solver.assert(&a_ori_non_owing);
2184 solver.assert(&update_a);
2185
2186 self.icx_slice_mut().var_mut()[au] = IntraVar::Init(a_new_bv);
2187 } else {
2188 self.handle_drop(ctx, goal, solver, &aplace, bidx, false);
2190 }
2191 }
2192 1 => {
2193 if is_a_ptr {
2195 if recovery_flag.0 && recovery_flag.1.contains(&au) {
2196 self.handle_drop(ctx, goal, solver, &aplace, bidx, true);
2197 continue;
2198 }
2199 let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2203 let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2204 let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2205
2206 goal.assert(&update_a);
2207 solver.assert(&update_a);
2208 } else {
2209 self.handle_drop(ctx, goal, solver, &aplace, bidx, false);
2211 }
2212 }
2213 _ => {
2214 self.handle_intra_var_unsupported(au);
2215 continue;
2216 }
2217 }
2218 }
2219 Operand::Copy(aplace) => {
2220 let alocal = aplace.local;
2221 let au: usize = alocal.as_usize();
2222
2223 if self.icx_slice().len()[au] == 0 {
2226 continue;
2228 }
2229
2230 if !self.icx_slice().var()[au].is_init() {
2231 continue;
2232 }
2233
2234 let a_ty = aplace.ty(&self.body.local_decls, self.tcx()).ty;
2235 let is_a_ptr = a_ty.is_any_ptr();
2236
2237 let a_ori_bv = self.icx_slice_mut().var_mut()[au].extract();
2238 let alen = self.icx_slice().len()[au];
2239
2240 match aplace.projection.len() {
2241 0 => {
2242 if is_a_ptr {
2244 if recovery_flag.0 && recovery_flag.1.contains(&au) {
2245 self.handle_drop(ctx, goal, solver, &aplace, bidx, true);
2246 continue;
2247 }
2248
2249 let a_zero_const = ast::BV::from_u64(ctx, 0, alen as u32);
2253 let a_ori_non_owing = a_ori_bv._safe_eq(&a_zero_const).unwrap();
2254
2255 let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2257 let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2258 let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2259
2260 goal.assert(&a_ori_non_owing);
2261 goal.assert(&update_a);
2262 solver.assert(&a_ori_non_owing);
2263 solver.assert(&update_a);
2264
2265 self.icx_slice_mut().var_mut()[au] = IntraVar::Init(a_new_bv);
2266 } else {
2267 if is_a_ptr {
2271 if recovery_flag.0 && recovery_flag.1.contains(&au) {
2272 self.handle_drop(ctx, goal, solver, &aplace, bidx, true);
2273 continue;
2274 }
2275 }
2276
2277 let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2278 let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2279 let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2280
2281 goal.assert(&update_a);
2282 solver.assert(&update_a);
2283 }
2284 }
2285 1 => {
2286 let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2288 let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2289 let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2290
2291 goal.assert(&update_a);
2292 solver.assert(&update_a);
2293 }
2294 _ => {
2295 self.handle_intra_var_unsupported(au);
2296 continue;
2297 }
2298 }
2299 }
2300 Operand::Constant(..) => continue,
2301 #[cfg(rapx_ge_99)]
2302 Operand::RuntimeChecks(_) => continue,
2303 }
2304 }
2305
2306 if self.icx_slice().var()[lu].is_unsupported() {
2308 self.handle_intra_var_unsupported(lu);
2309 return;
2310 }
2311
2312 let l_ori_bv: ast::BV;
2313
2314 let l_place_ty = dest.ty(&self.body.local_decls, self.tcx());
2315 let l_local_ty = self.body.local_decls[llocal].ty;
2316
2317 let mut is_ctor = true;
2318 match dest.projection.len() {
2319 0 => {
2320 let return_value_layout =
2323 self.extract_default_ty_layout(l_place_ty.ty, l_place_ty.variant_index);
2324 if return_value_layout.is_empty() || !return_value_layout.get_requirement() {
2325 return;
2326 }
2327
2328 let int_for_gen = if source_flag {
2329 let modified_layout_bv =
2330 self.generate_ptr_layout(l_place_ty.ty, l_place_ty.variant_index);
2331 let merge_layout_bv = rustbv_merge(
2332 &heap_layout_to_rustbv(return_value_layout.layout()),
2333 &modified_layout_bv,
2334 );
2335 rustbv_to_int(&merge_layout_bv)
2336 } else {
2337 rustbv_to_int(&heap_layout_to_rustbv(return_value_layout.layout()))
2338 };
2339
2340 let mut llen = self.icx_slice().len()[lu];
2341
2342 if self.icx_slice().var()[lu].is_init() {
2343 if llen == 0 {
2344 rap_debug!(
2345 "handle_call: lvalue length is 0 for local {:?}, skipping\n",
2346 lu
2347 );
2348 return;
2349 }
2350 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
2351 let l_zero_const = ast::BV::from_u64(ctx, 0, llen as u32);
2352 let constraint_l_ori_zero = l_ori_bv._safe_eq(&l_zero_const).unwrap();
2353 goal.assert(&constraint_l_ori_zero);
2354 solver.assert(&constraint_l_ori_zero);
2355 is_ctor = false;
2356 } else {
2357 let ty_with_vidx = TyWithIndex::new(l_place_ty.ty, l_place_ty.variant_index);
2359 match ty_with_vidx.get_priority() {
2360 0 => {
2361 self.handle_intra_var_unsupported(lu);
2363 return;
2364 }
2365 1 => {
2366 return;
2367 }
2368 2 => {
2369 self.icx_slice_mut().ty_mut()[lu] = ty_with_vidx;
2371 self.icx_slice_mut().layout_mut()[lu] =
2372 return_value_layout.layout().clone();
2373 }
2374 _ => unreachable!(),
2375 }
2376 }
2377
2378 llen = return_value_layout.layout().len();
2379
2380 let l_name = if is_ctor {
2381 new_local_name(lu, bidx, 0).add("_ctor_fn")
2382 } else {
2383 new_local_name(lu, bidx, 0).add("_cover_fn")
2384 };
2385
2386 let l_layout_bv = ast::BV::from_u64(ctx, int_for_gen, llen as u32);
2387 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
2388
2389 let constraint_new_owning = l_new_bv._safe_eq(&l_layout_bv).unwrap();
2390
2391 goal.assert(&constraint_new_owning);
2392 solver.assert(&constraint_new_owning);
2393
2394 self.icx_slice_mut().len_mut()[lu] = llen;
2395 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
2396 }
2397 1 => {
2398 let return_value_layout = self.extract_default_ty_layout(l_local_ty, None);
2401 if return_value_layout.is_empty() || !return_value_layout.get_requirement() {
2402 return;
2403 }
2404
2405 let llen = self.icx_slice().len()[lu];
2408
2409 let lpj_fields = self.extract_projection(dest, None);
2410 let index_needed = lpj_fields.index_needed();
2411
2412 if self.icx_slice().var()[lu].is_init() {
2413 l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
2414 let extract_from_field =
2415 l_ori_bv.extract(index_needed as u32, index_needed as u32);
2416 let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
2417 let constraint_l_f_ori_zero =
2418 extract_from_field._safe_eq(&l_f_zero_const).unwrap();
2419
2420 goal.assert(&constraint_l_f_ori_zero);
2421 solver.assert(&constraint_l_f_ori_zero);
2422 } else {
2423 let l_ori_name_ctor = new_local_name(lu, bidx, 0).add("_ctor_fn");
2424 let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
2425 let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
2426 let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
2427
2428 goal.assert(&constraint_l_ctor_zero);
2429 solver.assert(&constraint_l_ctor_zero);
2430
2431 l_ori_bv = l_ori_zero;
2432 self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, None);
2433 self.icx_slice_mut().layout_mut()[lu] = return_value_layout.layout().clone();
2434 }
2435
2436 let l_name = new_local_name(lu, bidx, 0);
2437 let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
2438
2439 let update_field = if source_flag {
2440 ast::BV::from_u64(ctx, 1, 1)
2441 } else {
2442 if return_value_layout.layout()[index_needed] == OwnedHeap::True {
2443 ast::BV::from_u64(ctx, 1, 1)
2444 } else {
2445 ast::BV::from_u64(ctx, 0, 1)
2446 }
2447 };
2448
2449 let mut final_bv: ast::BV;
2450 if index_needed < llen - 1 {
2451 let end_part = l_ori_bv.extract((llen - 1) as u32, (index_needed + 1) as u32);
2452 final_bv = end_part.concat(&update_field);
2453 } else {
2454 final_bv = update_field;
2455 }
2456 if index_needed > 0 {
2457 let begin_part = l_ori_bv.extract((index_needed - 1) as u32, 0);
2458 final_bv = final_bv.concat(&begin_part);
2459 }
2460 let update_filed_using_func = l_new_bv._safe_eq(&final_bv).unwrap();
2461
2462 goal.assert(&update_filed_using_func);
2463 solver.assert(&update_filed_using_func);
2464
2465 self.icx_slice_mut().len_mut()[lu] = return_value_layout.layout().len();
2466 self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
2467 }
2468 _ => {
2469 self.handle_intra_var_unsupported(lu);
2470 return;
2471 }
2472 }
2473 }
2474
2475 pub(crate) fn handle_return(
2476 &mut self,
2477 ctx: &'ctx z3::Context,
2478 goal: &'ctx z3::Goal<'ctx>,
2479 solver: &'ctx z3::Solver<'ctx>,
2480 bidx: usize,
2481 ) {
2482 let place_0 = Place::from(Local::from_usize(0));
2483 self.handle_drop(ctx, goal, solver, &place_0, bidx, false);
2484
2485 for (iidx, var) in self.icx_slice().var.iter().enumerate() {
2487 let len = self.icx_slice().len()[iidx];
2488 if len == 0 {
2489 continue;
2490 }
2491 if iidx <= self.body.arg_count {
2492 continue;
2493 }
2494
2495 if var.is_init() {
2496 let var_ori_bv = var.extract();
2497
2498 let return_name = new_local_name(iidx, bidx, 0).add("_return");
2499 let var_return_bv = ast::BV::new_const(ctx, return_name, len as u32);
2500
2501 let zero_const = ast::BV::from_u64(ctx, 0, len as u32);
2502
2503 let var_update = var_return_bv._safe_eq(&var_ori_bv).unwrap();
2504 let var_freed = var_return_bv._safe_eq(&zero_const).unwrap();
2505
2506 let args = &[&var_update, &var_freed];
2507 let constraint_return = ast::Bool::and(ctx, args);
2508
2509 goal.assert(&constraint_return);
2510 solver.assert(&constraint_return);
2511 }
2512 }
2513
2514 let result = solver.check();
2515 let model = solver.get_model();
2516
2517 if is_z3_goal_verbose() {
2518 let g = format!("{}", goal);
2519 rap_trace!("{}\n", g);
2520 if model.is_some() {
2521 rap_trace!("{}", format!("{}", model.unwrap()));
2522 }
2523 }
2524
2525 if result == z3::SatResult::Unsat && self.taint_flag {
2531 let fn_name = get_name(self.tcx(), self.def_id)
2532 .unwrap_or_else(|| Symbol::intern("no symbol available"));
2533
2534 rap_warn!("Memory Leak detected in function {:}", fn_name);
2535 let source = span_to_source_code(self.body.span);
2536 let file = span_to_filename(self.body.span);
2537 let mut snippet = Snippet::source(&source)
2538 .line_start(span_to_line_number(self.body.span))
2539 .origin(&file)
2540 .fold(false);
2541
2542 for source in self.taint_source.iter() {
2543 if are_spans_in_same_file(self.body.span, source.source_info.span) {
2544 snippet = snippet.annotation(
2545 Level::Warning
2546 .span(relative_pos_range(self.body.span, source.source_info.span))
2547 .label("Memory Leak Candidates."),
2548 );
2549 }
2550 }
2558
2559 let message = Level::Warning
2560 .title("Memory Leak detected.")
2561 .snippet(snippet);
2562 let renderer = Renderer::styled();
2563 rap_warn!("{}", renderer.render(message));
2564 }
2565 }
2566
2567 pub(crate) fn handle_drop(
2568 &mut self,
2569 ctx: &'ctx z3::Context,
2570 goal: &'ctx z3::Goal<'ctx>,
2571 solver: &'ctx z3::Solver<'ctx>,
2572 dest: &Place<'tcx>,
2573 bidx: usize,
2574 recovery: bool,
2575 ) {
2576 let local = dest.local;
2577 let u: usize = local.as_usize();
2578
2579 if self.icx_slice().len()[u] == 0 {
2580 return;
2581 }
2582
2583 if self.icx_slice().var()[u].is_declared() || self.icx_slice().var()[u].is_unsupported() {
2584 return;
2585 }
2586
2587 let len = self.icx_slice().len()[u];
2588 let rust_bv = reverse_heap_layout_to_rustbv(&self.icx_slice().layout()[u]);
2589 let ori_bv = self.icx_slice().var()[u].extract();
2590
2591 let f = self.extract_projection(dest, None);
2592 if f.is_unsupported() {
2593 self.handle_intra_var_unsupported(u);
2594 return;
2595 }
2596
2597 match f.has_field() {
2598 false => {
2599 if recovery {
2602 let name = new_local_name(u, bidx, 0).add("_drop_recovery");
2604 let new_bv = ast::BV::new_const(ctx, name, len as u32);
2605 let zero_bv = ast::BV::from_u64(ctx, 0, len as u32);
2606
2607 let and_bv = ori_bv.bvand(&zero_bv);
2608
2609 let constraint_recovery = new_bv._eq(&and_bv);
2610
2611 goal.assert(&constraint_recovery);
2612 solver.assert(&constraint_recovery);
2613
2614 self.icx_slice_mut().var_mut()[u] = IntraVar::Init(new_bv);
2615 } else {
2616 let name = new_local_name(u, bidx, 0).add("_drop_all");
2618 let new_bv = ast::BV::new_const(ctx, name, len as u32);
2619 let int_for_rust_bv = rustbv_to_int(&rust_bv);
2620 let int_bv_const = ast::BV::from_u64(ctx, int_for_rust_bv, len as u32);
2621
2622 let and_bv = ori_bv.bvand(&int_bv_const);
2623
2624 let constraint_reverse = new_bv._eq(&and_bv);
2625
2626 goal.assert(&constraint_reverse);
2627 solver.assert(&constraint_reverse);
2628
2629 self.icx_slice_mut().var_mut()[u] = IntraVar::Init(new_bv);
2630 }
2631 }
2632 true => {
2633 let index_needed = f.index_needed();
2635
2636 if index_needed >= rust_bv.len() {
2637 return;
2638 }
2639
2640 let name = if recovery {
2641 new_local_name(u, bidx, 0).add("_drop_f_recovery")
2642 } else {
2643 new_local_name(u, bidx, 0).add("_drop_f")
2644 };
2645 let new_bv = ast::BV::new_const(ctx, name, len as u32);
2646
2647 if (rust_bv[index_needed] && !recovery) || (!rust_bv[index_needed] && recovery) {
2648 let constraint_update = new_bv._eq(&ori_bv);
2651
2652 goal.assert(&constraint_update);
2653 solver.assert(&constraint_update);
2654
2655 self.icx_slice_mut().var_mut()[u] = IntraVar::Init(new_bv);
2656 } else {
2657 let f_free = ast::BV::from_u64(ctx, 0, 1);
2658 let mut final_bv: ast::BV;
2659 if index_needed < len - 1 {
2660 let end_part = ori_bv.extract((len - 1) as u32, (index_needed + 1) as u32);
2661 final_bv = end_part.concat(&f_free);
2662 } else {
2663 final_bv = f_free;
2664 }
2665 if index_needed > 0 {
2666 let begin_part = ori_bv.extract((index_needed - 1) as u32, 0);
2667 final_bv = final_bv.concat(&begin_part);
2668 }
2669
2670 let constraint_free_f = new_bv._safe_eq(&final_bv).unwrap();
2671
2672 goal.assert(&constraint_free_f);
2673 solver.assert(&constraint_free_f);
2674
2675 self.icx_slice_mut().var_mut()[u] = IntraVar::Init(new_bv);
2676 }
2677 }
2678 }
2679 }
2680
2681 pub(crate) fn handle_intra_var_unsupported(&mut self, idx: usize) {
2682 match self.icx_slice_mut().var_mut()[idx] {
2683 IntraVar::Unsupported => return,
2684 IntraVar::Declared | IntraVar::Init(_) => {
2685 self.icx_slice_mut().var_mut()[idx] = IntraVar::Unsupported;
2687 self.icx_slice_mut().len_mut()[idx] = 0;
2688 return;
2689 }
2690 }
2691 }
2692
2693 pub(crate) fn handle_taint(&mut self, l: usize, r: usize) {
2694 if self.icx_slice().taint()[r].is_untainted() {
2695 return;
2696 }
2697
2698 if self.icx_slice().taint()[l].is_untainted() {
2699 self.icx_slice_mut().taint_mut()[l] = self.icx_slice().taint()[r].clone();
2700 } else {
2701 for elem in self.icx_slice().taint()[r].set().clone() {
2702 self.icx_slice_mut().taint_mut()[l].insert(elem);
2703 }
2704 }
2705 }
2706
2707 pub(crate) fn extract_default_ty_layout(
2708 &mut self,
2709 ty: Ty<'tcx>,
2710 variant: Option<VariantIdx>,
2711 ) -> OwnershipLayoutResult {
2712 match ty.kind() {
2713 TyKind::Array(..) => {
2714 let mut res = OwnershipLayoutResult::new();
2715 let mut default_heap = DefaultOwnership::new(self.tcx(), self.owner());
2716
2717 let _ = ty.visit_with(&mut default_heap);
2718 res.update_from_default_heap_visitor(&mut default_heap);
2719
2720 res
2721 }
2722 TyKind::Tuple(tuple_ty_list) => {
2723 let mut res = OwnershipLayoutResult::new();
2724
2725 for tuple_ty in tuple_ty_list.iter() {
2726 let mut default_heap = DefaultOwnership::new(self.tcx(), self.owner());
2727
2728 let _ = tuple_ty.visit_with(&mut default_heap);
2729 res.update_from_default_heap_visitor(&mut default_heap);
2730 }
2731
2732 res
2733 }
2734 TyKind::Adt(adtdef, substs) => {
2735 if adtdef.is_enum() && variant.is_none() {
2737 return OwnershipLayoutResult::new();
2738 }
2739
2740 let mut res = OwnershipLayoutResult::new();
2741
2742 if adtdef.is_struct() || adtdef.is_union() {
2744 for field in adtdef.all_fields() {
2745 let field_ty = field.ty(self.tcx(), substs);
2746
2747 let mut default_heap = DefaultOwnership::new(self.tcx(), self.owner());
2748
2749 let _ = field_ty.visit_with(&mut default_heap);
2750 res.update_from_default_heap_visitor(&mut default_heap);
2751 }
2752 }
2753 else if adtdef.is_enum() {
2755 let vidx = variant.unwrap();
2756
2757 for field in &adtdef.variants()[vidx].fields {
2758 let field_ty = field.ty(self.tcx(), substs);
2759
2760 let mut default_heap = DefaultOwnership::new(self.tcx(), self.owner());
2761
2762 let _ = field_ty.visit_with(&mut default_heap);
2763 res.update_from_default_heap_visitor(&mut default_heap);
2764 }
2765 }
2766 res
2767 }
2768 TyKind::Param(..) => {
2769 let mut res = OwnershipLayoutResult::new();
2770 res.set_requirement(true);
2771 res.set_param(true);
2772 res.set_owned(true);
2773 res.layout_mut().push(OwnedHeap::True);
2774 res
2775 }
2776 TyKind::RawPtr(..) => {
2777 let mut res = OwnershipLayoutResult::new();
2778 res.set_requirement(true);
2779 res.layout_mut().push(OwnedHeap::False);
2780 res
2781 }
2782 TyKind::Ref(..) => {
2783 let mut res = OwnershipLayoutResult::new();
2784 res.set_requirement(true);
2785 res.layout_mut().push(OwnedHeap::False);
2786 res
2787 }
2788 _ => OwnershipLayoutResult::new(),
2789 }
2790 }
2791
2792 pub(crate) fn generate_ptr_layout(
2793 &mut self,
2794 ty: Ty<'tcx>,
2795 variant: Option<VariantIdx>,
2796 ) -> Vec<bool> {
2797 let mut res = Vec::new();
2798 match ty.kind() {
2799 TyKind::Array(..) => {
2800 res.push(false);
2801 res
2802 }
2803 TyKind::Tuple(tuple_ty_list) => {
2804 for tuple_ty in tuple_ty_list.iter() {
2805 if tuple_ty.is_any_ptr() {
2806 res.push(true);
2807 } else {
2808 res.push(false);
2809 }
2810 }
2811
2812 res
2813 }
2814 TyKind::Adt(adtdef, _substs) => {
2815 if adtdef.is_enum() && variant.is_none() {
2817 return res;
2818 }
2819
2820 if adtdef.is_struct() || adtdef.is_union() {
2822 for _field in adtdef.all_fields() {
2823 res.push(false);
2824 }
2825 }
2826 else if adtdef.is_enum() {
2828 let vidx = variant.unwrap();
2829
2830 for _field in &adtdef.variants()[vidx].fields {
2831 res.push(false);
2832 }
2833 }
2834 res
2835 }
2836 TyKind::Param(..) => {
2837 res.push(false);
2838 res
2839 }
2840 TyKind::RawPtr(..) => {
2841 res.push(true);
2842 res
2843 }
2844 TyKind::Ref(..) => {
2845 res.push(true);
2846 res
2847 }
2848 _ => res,
2849 }
2850 }
2851
2852 fn extract_projection(&self, place: &Place<'tcx>, aggre: Aggre) -> ProjectionSupport<'tcx> {
2853 let mut prj: ProjectionSupport<'tcx> = ProjectionSupport::default();
2857 if aggre.is_some() {
2858 let ty = place.ty(&self.body.local_decls, self.tcx());
2863 prj.pf_vec.push((aggre.unwrap(), ty.ty));
2864 return prj;
2865 }
2866 for (idx, each_pj) in place.projection.iter().enumerate() {
2867 match each_pj {
2868 ProjectionElem::Field(field, ty) => {
2869 prj.pf_push(field.index(), ty);
2870 if prj.pf_vec.len() > 1 {
2871 prj.unsupport = true;
2872 break;
2873 }
2874 if prj.deref {
2875 prj.unsupport = true;
2876 break;
2877 }
2878 }
2879 ProjectionElem::Deref => {
2880 prj.deref = true;
2881 if idx > 0 {
2882 prj.unsupport = true;
2883 break;
2884 }
2885 }
2886 ProjectionElem::Downcast(.., ref vidx) => {
2887 prj.downcast = Some(*vidx);
2888 if idx > 0 {
2889 prj.unsupport = true;
2890 break;
2891 }
2892 }
2893 ProjectionElem::ConstantIndex { .. }
2894 | ProjectionElem::Subslice { .. }
2895 | ProjectionElem::Index(..)
2896 | ProjectionElem::OpaqueCast(..) => {
2897 prj.unsupport = true;
2898 break;
2899 }
2900 _ => todo!(),
2901 }
2902 }
2903 prj
2904 }
2905}
2906
2907fn new_local_name(local: usize, bidx: usize, sidx: usize) -> String {
2908 let s = bidx
2909 .to_string()
2910 .add("_")
2911 .add(&sidx.to_string())
2912 .add("_")
2913 .add(&local.to_string());
2914 s
2915}
2916
2917fn is_place_containing_ptr(ty: &Ty) -> bool {
2918 match ty.kind() {
2919 TyKind::Tuple(tuple_ty_list) => {
2920 for tuple_ty in tuple_ty_list.iter() {
2921 if tuple_ty.is_any_ptr() {
2922 return true;
2923 }
2924 }
2925 false
2926 }
2927 TyKind::RawPtr(..) => true,
2928 TyKind::Ref(..) => true,
2929 _ => false,
2930 }
2931}
2932
2933#[derive(Debug)]
2934struct ProjectionSupport<'tcx> {
2935 pf_vec: Vec<(usize, Ty<'tcx>)>,
2936 deref: bool,
2937 downcast: Disc,
2938 unsupport: bool,
2939}
2940
2941impl<'tcx> Default for ProjectionSupport<'tcx> {
2942 fn default() -> Self {
2943 Self {
2944 pf_vec: Vec::default(),
2945 deref: false,
2946 downcast: None,
2947 unsupport: false,
2948 }
2949 }
2950}
2951
2952impl<'tcx> ProjectionSupport<'tcx> {
2953 pub fn pf_push(&mut self, index: usize, ty: Ty<'tcx>) {
2954 self.pf_vec.push((index, ty));
2955 }
2956
2957 pub fn is_unsupported(&self) -> bool {
2958 self.unsupport == true
2959 }
2960
2961 pub fn has_field(&self) -> bool {
2962 self.pf_vec.len() > 0
2963 }
2964
2965 pub fn has_downcast(&self) -> bool {
2966 self.downcast.is_some()
2967 }
2968
2969 pub fn downcast(&self) -> Disc {
2970 self.downcast
2971 }
2972
2973 pub fn index_needed(&self) -> usize {
2974 self.pf_vec[0].0
2975 }
2976}
2977
2978fn has_projection(place: &Place) -> bool {
2979 return if place.projection.len() > 0 {
2980 true
2981 } else {
2982 false
2983 };
2984}
2985
2986fn heap_layout_to_rustbv(layout: &Vec<OwnedHeap>) -> Vec<bool> {
2987 let mut v = Vec::default();
2988 for item in layout.iter() {
2989 match item {
2990 OwnedHeap::Unknown => rap_error!("item of raw type owner is uninit"),
2991 OwnedHeap::False => v.push(false),
2992 OwnedHeap::True => v.push(true),
2993 }
2994 }
2995 v
2996}
2997
2998fn reverse_heap_layout_to_rustbv(layout: &Vec<OwnedHeap>) -> Vec<bool> {
2999 let mut v = Vec::default();
3000 for item in layout.iter() {
3001 match item {
3002 OwnedHeap::Unknown => rap_error!("item of raw type owner is uninit"),
3003 OwnedHeap::False => v.push(true),
3004 OwnedHeap::True => v.push(false),
3005 }
3006 }
3007 v
3008}
3009
3010fn rustbv_merge(a: &Vec<bool>, b: &Vec<bool>) -> Vec<bool> {
3011 assert_eq!(a.len(), b.len());
3012 let mut bv = Vec::new();
3013 for idx in 0..a.len() {
3014 bv.push(a[idx] || b[idx]);
3015 }
3016 bv
3017}
3018
3019fn rustbv_to_int(bv: &Vec<bool>) -> u64 {
3023 let mut ans = 0;
3024 let mut base = 1;
3025 for tf in bv.iter() {
3026 ans = ans + base * (*tf as u64);
3027 base = base * 2;
3028 }
3029 ans
3030}
3031
3032fn help_debug_goal_stmt<'tcx, 'ctx>(
3033 ctx: &'ctx z3::Context,
3034 goal: &'ctx z3::Goal<'ctx>,
3035 bidx: usize,
3036 sidx: usize,
3037) {
3038 let debug_name = format!("CONSTRAINTS: S {} {}", bidx, sidx);
3039 let dbg_bool = ast::Bool::new_const(ctx, debug_name);
3040 goal.assert(&dbg_bool);
3041}
3042
3043fn help_debug_goal_term<'tcx, 'ctx>(
3044 ctx: &'ctx z3::Context,
3045 goal: &'ctx z3::Goal<'ctx>,
3046 bidx: usize,
3047) {
3048 let debug_name = format!("CONSTRAINTS: T {}", bidx);
3049 let dbg_bool = ast::Bool::new_const(ctx, debug_name);
3050 goal.assert(&dbg_bool);
3051}