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