Skip to main content

rapx/check/rcanary/ranalyzer/
intra_visitor.rs

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        // For node 0 there is no pre node existed!
115        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            // collect all pre nodes and generate their icx slice into a vector
162            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            // the result icx slice for updating the icx
168            let mut ans_icx_slice = v_pre_collect[0].clone();
169            let var_len = v_pre_collect[0].len().len();
170
171            // for all variables
172            for var_idx in 0..var_len {
173                // the bv and len is using to generate new constrain
174                // the ty is to check the consistency among the branches
175                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 one variable in all pre basic blocks
181                for idx in 0..v_pre_collect.len() {
182                    // merge: ty = ty, len = len
183                    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                    // for now the len must not be zero and the var must not be decl/un..
195                    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                    // use bv and to generate new bv
214                    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        // rap_debug!("{:?} in {}", self.icx_slice(), bidx);
244    }
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                // if l_local_ty.is_enum() {
269                //     let stmt_disc = sidx + 1;
270                //     if stmt_disc < data.statements.len() {
271                //         match &data.statements[stmt_disc].kind {
272                //             StatementKind::SetDiscriminant { place: disc_place, variant_index: vidx, }
273                //             => {
274                //                 let disc_local = disc_place.local;
275                //                 if disc_local == l_local {
276                //                     match extract_projection(disc_place) {
277                //                         Some(prj) => {
278                //                             if prj.is_unsupported() {
279                //                                 self.handle_Intra_var_unsupported(l_local.as_usize());
280                //                                 return;
281                //                             }
282                //                             disc = Some(*vidx);
283                //                         },
284                //                         None => (),
285                //                     }
286                //                 }
287                //             },
288                //             _ => (),
289                //         }
290                //     };
291                // }
292
293                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 any rvalue or lplace is unsupported, then make them all unsupported and exit
617        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 the current layout of rvalue is 0, avoid the following analysis
628        // e.g., a = b, b:[]
629        if self.icx_slice().len()[ru] == 0 {
630            // the len is 0 and ty is None which do not need update
631            return;
632        }
633
634        // get the length of current variable to generate bit vector in the future
635        let mut llen = self.icx_slice().len()[lu];
636        let rlen = self.icx_slice().len()[ru];
637
638        // extract the original z3 ast of the variable needed to prepare generating new
639        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 the lvalue is not initialized for the first time (already initialized)
652            // the constraint that promise the original value of lvalue that does not hold the heap
653            // e.g., y=x ,that y is non-owning => l=0
654            // check the pointee layout (of) is same
655            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            // this branch means that the assignment is the constructor of the lvalue
668            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                    // cannot identify the ty (unsupported like fn ptr ...)
673                    self.handle_intra_var_unsupported(lu);
674                    self.handle_intra_var_unsupported(ru);
675                    return;
676                }
677                1 => {
678                    return;
679                }
680                2 => {
681                    // update the layout of lvalue due to it is an instance
682                    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        // update the lvalue length that is equal to rvalue
690        llen = rlen;
691        self.icx_slice_mut().len_mut()[lu] = llen;
692
693        // produce the name of lvalue and rvalue in this program point
694        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        // generate new bit vectors for variables
702        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        // the constraint that promise the unique heap in transformation of y=x, l=r
709        // the exactly constraint is that (r'=r && l'=0) || (l'=r && r'=0)
710        // this is for (r'=r && l'=0)
711        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        // this is for (l'=r && r'=0)
717        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        // the final constraint and add the constraint to the goal of this function
723        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        // update the Intra var value in current basic block (exactly, the statement)
730        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 any rvalue or lplace is unsupported, then make them all unsupported and exit
753        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 the current layout of rvalue is 0, avoid any following analysis
764        // e.g., a = b, b:[]
765        if self.icx_slice().len()[ru] == 0 {
766            // the len is 0 and ty is None which do not need update
767            return;
768        }
769
770        // get the length of current variable to generate bit vector in the future
771        let mut llen = self.icx_slice().len()[lu];
772        let rlen = self.icx_slice().len()[ru];
773
774        // extract the original z3 ast of the variable needed to prepare generating new
775        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 the lvalue is not initialized for the first time
788            // the constraint that promise the original value of lvalue that does not hold the heap
789            // e.g., y=move x ,that y (l) is non-owning
790            // check the pointee layout (of) is same
791            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            // this branch means that the assignment is the constructor of the lvalue
804            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                    // cannot identify the ty (unsupported like fn ptr ...)
809                    self.handle_intra_var_unsupported(lu);
810                    self.handle_intra_var_unsupported(ru);
811                    return;
812                }
813                1 => {
814                    return;
815                }
816                2 => {
817                    // update the layout of lvalue due to it is an instance
818                    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        // update the lvalue length that is equal to rvalue
826        llen = rlen;
827        self.icx_slice_mut().len_mut()[lu] = llen;
828
829        // produce the name of lvalue and rvalue in this program point
830        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        // generate new bit vectors for variables
838        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        // the constraint that promise the unique heap in transformation of y=move x, l=move r
844        // the exactly constraint is that r'=0 && l'=r
845        // this is for r'=0
846        let r_non_owning = r_new_bv._safe_eq(&r_zero_const).unwrap();
847        // this is for l'=r
848        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        // update the Intra var value in current basic block (exactly, the statement)
856        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        // y=x.f => l=r.f
873        // this local of rvalue is not x.f
874        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 any rvalue or lplace is unsupported, then make them all unsupported and exit
881        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 the current layout of the father in rvalue is 0, avoid the following analysis
892        // e.g., a = b, b:[]
893        if self.icx_slice().len[ru] == 0 {
894            // the len is 0 and ty is None which do not need update
895            return;
896        }
897
898        // extract the ty of the rplace, the rplace has projection like _1.0
899        // rpj ty is the exact ty of rplace, the first field ty of rplace
900        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            // we only support that the field depth is 1 in max
904            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        // get the length of current variable and the rplace projection to generate bit vector in the future
920        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        // extract the original z3 ast of the variable needed to prepare generating new
925        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            // if the lvalue is not initialized for the first time
938            // the constraint that promise the original value of lvalue that does not hold the heap
939            // e.g., y=move x.f ,that y (l) is non-owning
940            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            // this branch means that the assignment is the constructor of the lvalue
948            // Note : l = r.f => l's len must be 1 if l is a pointer
949            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                    // cannot identify the ty (unsupported like fn ptr ...)
954                    self.handle_intra_var_unsupported(lu);
955                    self.handle_intra_var_unsupported(ru);
956                    return;
957                }
958                1 => {
959                    return;
960                }
961                2 => {
962                    // update the layout of lvalue due to it is an instance
963                    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        // update the lvalue length that is equal to rvalue
971        llen = rpj_len;
972        self.icx_slice_mut().len_mut()[lu] = llen;
973
974        // produce the name of lvalue and rvalue in this program point
975        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        // generate new bit vectors for variables
983        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        // the constraint that promise the unique heap in transformation of y=x.f, l=r.f
987        // the exactly constraint is that ( r.f'=r.f && l'=0 ) || ( l'=extend(r.f) && r.f'=0 )
988        // this is for r.f'=r.f (no change) && l'=0
989        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        // this is for l'=extend(r.f) && r.f'=0
996        // this is for l'=extend(r.f)
997        // note that we extract the heap of the ori r.f and apply (extend) it to new lvalue
998        // like l'=r.f=1 => l' [1111] and default layout [****]
999        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        // this is for r.f'=0
1027        // like r.1'=0 => ori and new => [0110] and [1011] => [0010]
1028        // note that we calculate the index of r.f and use bit vector 'and' to update the heap
1029        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        // the final constraint and add the constraint to the goal of this function
1040        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        // update the Intra var value in current basic block (exactly, the statement)
1047        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        // y=move x.f => l=move r.f
1064        // this local of rvalue is not x.f
1065        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 any rvalue or lplace is unsupported, then make them all unsupported and exit
1072        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        // extract the ty of the rplace, the rplace has projection like _1.0
1083        // rpj ty is the exact ty of rplace, the first field ty of rplace
1084        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            // we only support that the field depth is 1 in max
1088            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        // get the length of current variable and the rplace projection to generate bit vector in the future
1104        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 the current layout of the father in rvalue is 0, avoid the following analysis
1109        // e.g., a = b, b:[]
1110        if self.icx_slice().len[ru] == 0 {
1111            // the len is 0 and ty is None which do not need update
1112            return;
1113        }
1114
1115        // extract the original z3 ast of the variable needed to prepare generating new
1116        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            // if the lvalue is not initialized for the first time
1129            // the constraint that promise the original value of lvalue that does not hold the heap
1130            // e.g., y=move x.f ,that y (l) is non-owning
1131            // do not check the ty l = ty r due to field operation
1132            // if self.icx_slice().ty()[lu] != self.icx_slice().ty[ru] {
1133            //     self.handle_intra_var_unsupported(lu);
1134            //     self.handle_intra_var_unsupported(ru);
1135            //     return;
1136            // }
1137            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            // this branch means that the assignment is the constructor of the lvalue
1145            // Note : l = r.f => l's len must be 1 if l is a pointer
1146            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                    // cannot identify the ty (unsupported like fn ptr ...)
1151                    self.handle_intra_var_unsupported(lu);
1152                    self.handle_intra_var_unsupported(ru);
1153                    return;
1154                }
1155                1 => {
1156                    return;
1157                }
1158                2 => {
1159                    // update the layout of lvalue due to it is an instance
1160                    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        // update the lvalue length that is equal to rvalue
1168        llen = rpj_len;
1169        self.icx_slice_mut().len_mut()[lu] = llen;
1170
1171        // produce the name of lvalue and rvalue in this program point
1172        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        // generate new bit vectors for variables
1180        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        // the constraint that promise the unique heap in transformation of y=move x.f, l=move r.f
1184        // the exactly constraint is that l'=extend(r.f) && r.f'=0
1185        // this is for l'=extend(r.f)
1186        // note that we extract the heap of the ori r.f and apply (extend) it to new lvalue
1187        // like l'=r.f=1 => l' [1111] and default layout [****]
1188        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        // this is for r.f'=0
1217        // like r.1'=0 => ori and new => [0110] and [1011] => [0010]
1218        // note that we calculate the index of r.f and use bit vector 'and' to update the heap
1219        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        // update the Intra var value in current basic block (exactly, the statement)
1232        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        // y.f= x => l.f= r
1292        // this local of lvalue is not y.f
1293        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 any rvalue or lplace is unsupported, then make them all unsupported and exit
1300        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        // extract the ty of the rvalue
1311        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            // we only support that the field depth is 1 in max
1315            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                // .f .v => judge
1323                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                // variant.len = 1 && field[0]
1331                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                // .f => normal field access
1338            }
1339            (false, true) => {
1340                // .v => not
1341                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        // get the length of current variable and the lplace projection to generate bit vector in the future
1357        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 the current layout of the father in rvalue is 0, avoid the following analysis
1362        // e.g., a = b, b:[]
1363        if self.icx_slice().len[ru] == 0 {
1364            // the len is 0 and ty is None which do not need update
1365            return;
1366        }
1367
1368        // extract the original z3 ast of the variable needed to prepare generating new
1369        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            // if the lvalue is not initialized for the first time
1374            // the constraint that promise the original value of lvalue that does not hold the heap
1375            // e.g., y.f= x ,that y.f (l) is non-owning
1376            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            // this branch means that the assignment is the constructor of the lvalue (either l and l.f)
1386            // this constraint promise before the struct is [0;field]
1387            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        // we no not need to update the lvalue length that is equal to rvalue
1399        // llen = rlen;
1400        // self.icx_slice_mut().len_mut()[lu] = llen;
1401
1402        // produce the name of lvalue and rvalue in this program point
1403        let l_name = new_local_name(lu, bidx, sidx);
1404        let r_name = new_local_name(ru, bidx, sidx);
1405
1406        // generate new bit vectors for variables
1407        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        // the constraint that promise the unique heap in transformation of y.f=x, l.f=r
1413        // the exactly constraint is that (r'=r && l.f'=0) || (r'=0 && l.f'=shrink(r))
1414        // this is for r'=r && l.f'=0
1415        // this is for r'=r
1416        let r_owning = r_new_bv._safe_eq(&r_ori_bv).unwrap();
1417        //this is for l.f'=0
1418        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        // this is for r'=0 && l.f'=shrink(r)
1429        // this is for r'=0
1430        let r_non_owning = r_new_bv._safe_eq(&r_zero_const).unwrap();
1431        // this is for l.f'=shrink(r)
1432        // to achieve this goal would be kind of complicated
1433        // first we take the disjunction of whole rvalue into point as *
1434        // then, the we contact 3 bit vector [1;begin] [*] [1;end]
1435        // at last, we use and operation to simulate shrink from e.g., [0010] to [11*1]
1436        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        // the final constraint and add the constraint to the goal of this function
1456        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        // update the Intra var value in current basic block (exactly, the statement)
1463        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        // y.f=move x => l.f=move r
1482        // this local of lvalue is not y.f
1483        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 any rvalue or lplace is unsupported, then make them all unsupported and exit
1490        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        // extract the ty of the rvalue
1501        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            // we only support that the field depth is 1 in max
1505            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                // .f .v => judge
1513                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                // variant.len = 1 && field[0]
1521                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                // .f => normal field access
1528            }
1529            (false, true) => {
1530                // .v => not
1531                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        // get the length of current variable and the lplace projection to generate bit vector in the future
1547        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 the current layout of the father in rvalue is 0, avoid the following analysis
1552        // e.g., a = b, b:[]
1553        if self.icx_slice().len[ru] == 0 {
1554            // the len is 0 and ty is None which do not need update
1555            return;
1556        }
1557
1558        // extract the original z3 ast of the variable needed to prepare generating new
1559        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            // if the lvalue is not initialized for the first time
1564            // the constraint that promise the original value of lvalue that does not hold the heap
1565            // e.g., y.f=move x ,that y.f (l) is non-owning
1566            // add: y.f -> y is not argument e.g., fn(arg1) arg1.1 = 0, cause arg is init as 1
1567            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            // this branch means that the assignment is the constructor of the lvalue (either l and l.f)
1577            // this constraint promise before the struct is [0;field]
1578            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        // we no not need to update the lvalue length that is equal to rvalue
1590        // llen = rlen;
1591        // self.icx_slice_mut().len_mut()[lu] = llen;
1592
1593        // produce the name of lvalue and rvalue in this program point
1594        let l_name = new_local_name(lu, bidx, sidx);
1595        let r_name = new_local_name(ru, bidx, sidx);
1596
1597        // generate new bit vectors for variables
1598        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        // the constraint that promise the unique heap in transformation of y.f=move x, l.f=move r
1604        // the exactly constraint is that r'=0 && l.f'=shrink(r)
1605        // this is for r'=0
1606        let r_non_owning = r_new_bv._safe_eq(&r_zero_const).unwrap();
1607
1608        // this is for l.f'=shrink(r)
1609        // to achieve this goal would be kind of complicated
1610        // first we take the disjunction of whole rvalue into point as *
1611        // then, the we contact 3 bit vector [1;begin] [*] [1;end]
1612        // at last, we use or operation to simulate shrink from e.g., [1010] to [00*0]
1613        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        // update the Intra var value in current basic block (exactly, the statement)
1633        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        // y.f= x.f => l.f= r.f
1652        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 any rvalue or lplace is unsupported, then make them all unsupported and exit
1659        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        // extract the ty of the rplace, the rplace has projection like _1.0
1672        // rpj ty is the exact ty of rplace, the first field ty of rplace
1673        let rpj_fields = self.extract_projection(rplace, None);
1674        if rpj_fields.is_unsupported() {
1675            // we only support that the field depth is 1 in max
1676            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            // we only support that the field depth is 1 in max
1684            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        // get the length of current variable and the rplace projection to generate bit vector in the future
1716        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 the current layout of the father in rvalue is 0, avoid the following analysis
1721        // e.g., a = b, b:[]
1722        if self.icx_slice().len[ru] == 0 {
1723            // the len is 0 and ty is None which do not need update
1724            return;
1725        }
1726
1727        // extract the original z3 ast of the variable needed to prepare generating new
1728        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            // if the lvalue is not initialized for the first time
1733            // the constraint that promise the original value of lvalue that does not hold the heap
1734            // e.g., y.f= move x.f ,that y.f (l) is non-owning
1735            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            // this branch means that the assignment is the constructor of the lvalue (either l and l.f)
1745            // this constraint promise before the struct is [0;field]
1746            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        // produce the name of lvalue and rvalue in this program point
1758        let l_name = new_local_name(lu, bidx, sidx);
1759        let r_name = new_local_name(ru, bidx, sidx);
1760
1761        // generate new bit vectors for variables
1762        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        // the constraint that promise the unique heap in transformation of y.f= x.f, l.f= r.f
1766        // the exactly constraint is that (r.f'=0 && l.f'=r.f) || (l.f'=0 && r.f'=r.f)
1767        // this is for r.f'=0 && l.f'=r.f
1768        // this is for r.f'=0
1769        // like r.1'=0 => ori and new => [0110] and [1011] => [0010]
1770        // note that we calculate the index of r.f and use bit vector 'and' to update the heap
1771        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        // this is for l.f'=r.f
1778        // to achieve this goal would be kind of complicated
1779        // first we extract the field from the rvalue into point as *
1780        // then, the we contact 3 bit vector [1;begin] [*] [1;end]
1781        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        // this is for l.f'=0 && r.f'=r.f
1799        // this is for l.f'=0
1800        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        // this is for r.f'=r.f
1807        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        // the final constraint and add the constraint to the goal of this function
1813        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        // update the Intra var value in current basic block (exactly, the statement)
1820        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        // y.f=move x.f => l.f=move r.f
1839        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 any rvalue or lplace is unsupported, then make them all unsupported and exit
1846        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        // extract the ty of the rplace, the rplace has projection like _1.0
1859        // rpj ty is the exact ty of rplace, the first field ty of rplace
1860        //let rpj_ty = rplace.ty(&self.body.local_decls, self.tcx);
1861        let rpj_fields = self.extract_projection(rplace, None);
1862        if rpj_fields.is_unsupported() {
1863            // we only support that the field depth is 1 in max
1864            self.handle_intra_var_unsupported(lu);
1865            self.handle_intra_var_unsupported(ru);
1866            return;
1867        }
1868
1869        // extract the ty of the lplace, the lplace has projection like _1.0
1870        // lpj ty is the exact ty of lplace, the first field ty of lplace
1871        //let lpj_ty = lplace.ty(&self.body.local_decls, self.tcx);
1872        let lpj_fields = self.extract_projection(lplace, aggre);
1873        if lpj_fields.is_unsupported() {
1874            // we only support that the field depth is 1 in max
1875            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        // get the length of current variable and the rplace projection to generate bit vector in the future
1906        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 the current layout of the father in rvalue is 0, avoid the following analysis
1911        // e.g., a = b, b:[]
1912        if self.icx_slice().len[ru] == 0 {
1913            // the len is 0 and ty is None which do not need update
1914            return;
1915        }
1916
1917        // extract the original z3 ast of the variable needed to prepare generating new
1918        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            // if the lvalue is not initialized for the first time
1923            // the constraint that promise the original value of lvalue that does not hold the heap
1924            // e.g., y.f= move x.f ,that y.f (l) is non-owning
1925            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            // this branch means that the assignment is the constructor of the lvalue (either l and l.f)
1935            // this constraint promise before the struct is [0;field]
1936            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        // produce the name of lvalue and rvalue in this program point
1948        let l_name = new_local_name(lu, bidx, sidx);
1949        let r_name = new_local_name(ru, bidx, sidx);
1950
1951        // generate new bit vectors for variables
1952        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        // the constraint that promise the unique heap in transformation of y.f=move x.f, l.f=move r.f
1956        // the exactly constraint is that r.f'=0 && l.f'=r.f
1957        // this is for r.f'=0
1958        // like r.1'=0 => ori and new => [0110] and [1011] => [0010]
1959        // note that we calculate the index of r.f and use bit vector 'and' to update the heap
1960        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        // this is for l.f'=r.f
1968        // to achieve this goal would be kind of complicated
1969        // first we extract the field from the rvalue into point as *
1970        // then, the we contact 3 bit vector [1;begin] [*] [1;end]
1971        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        // update the Intra var value in current basic block (exactly, the statement)
1992        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: &Vec<Operand<'tcx>>,
2000        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: &Vec<Operand<'tcx>>,
2031        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: &Vec<Operand<'tcx>>,
2080        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                        //rap_debug!("{:?}", id);
2089                        //rap_debug!("{:?}", mir_body(self.tcx, *id));
2090                        match id.index.as_usize() {
2091                            2171 => {
2092                                // this for calling std::mem::drop(TY)
2093                                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        // for return value
2118        let llocal = dest.local;
2119        let lu: usize = llocal.as_usize();
2120
2121        // the source flag is for fn(self) -> */&
2122        // we will tag the lvalue as tainted and change the default ctor to modified one
2123        let source_flag = self.check_fn_source(args, dest);
2124        // the recovery flag is for fn(*) -> Self
2125        // the return value should have the same layout as tainted one
2126        // we will take the heap of the args if the arg is a pointer
2127        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 the current layout of the father in rvalue is 0, avoid the following analysis
2139                    // e.g., a = b, b:[]
2140                    if self.icx_slice().len()[au] == 0 {
2141                        // the len is 0 and ty is None which do not need update
2142                        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                            // this indicates that the operand is move without projection
2164                            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                                // if the aplace is a pointer (move ptr => still hold)
2171                                // the exact constraint is a=0, a'=a
2172                                // this is for a=0
2173                                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                                // this is for a'=a
2177                                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                                // if the aplace is a instance (move i => drop)
2189                                self.handle_drop(ctx, goal, solver, &aplace, bidx, false);
2190                            }
2191                        }
2192                        1 => {
2193                            // this indicates that the operand is move without projection
2194                            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                                // if the aplace in field is a pointer (move a.f (ptr) => still hold)
2200                                // the exact constraint is a'=a
2201                                // this is for a'=a
2202                                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                                // if the aplace is a instance (move i.f => i.f=0)
2210                                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 the current layout of the father in rvalue is 0, avoid the following analysis
2224                    // e.g., a = b, b:[]
2225                    if self.icx_slice().len()[au] == 0 {
2226                        // the len is 0 and ty is None which do not need update
2227                        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                            // this indicates that the operand is move without projection
2243                            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                                // if the aplace is a pointer (ptr => still hold)
2250                                // the exact constraint is a=0, a'=a
2251                                // this is for a=0
2252                                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                                // this is for a'=a
2256                                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 the aplace is a instance (i => Copy)
2268                                // for Instance Copy => No need to change
2269
2270                                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                            // this indicates that the operand is move without projection
2287                            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        // establish constraints for return value
2307        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                // alike move instance
2321
2322                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                    // this branch means that the assignment is the constructor of the lvalue
2358                    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                            // cannot identify the ty (unsupported like fn ptr ...)
2362                            self.handle_intra_var_unsupported(lu);
2363                            return;
2364                        }
2365                        1 => {
2366                            return;
2367                        }
2368                        2 => {
2369                            // update the layout of lvalue due to it is an instance
2370                            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                // alike move to field
2399
2400                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 int_for_gen = rustbv_to_int(&heap_layout_to_rustbv(return_value_layout.layout()));
2406
2407                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        // when whole function return => we need to check every variable is freed
2486        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        // rap_debug!("{}", self.body.local_decls.display());
2526        // rap_debug!("{}", self.body.basic_blocks.display());
2527        // let g = format!("{}", goal);
2528        // rap_debug!("{}\n", g.color(Color::LightGray).bold());
2529
2530        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                // rap_warn!(
2551                //     "{}",
2552                //     format!(
2553                //         "RCanary: LeakItem Candidates: {:?}, {:?}",
2554                //         source.kind, source.source_info.span
2555                //     )
2556                // );
2557            }
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                // drop the entire owning item
2600                // reverse the heap layout and using and operator
2601                if recovery {
2602                    // recovery for pointer, clear all
2603                    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                    // is not recovery for pointer, just normal drop
2617                    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                // drop the field
2634                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                    // not actually drop, just update the idx
2649                    // the default heap is false (non-owning) somehow, we just reverse it before
2650                    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                // turns into the unsupported
2686                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                // check the ty is or is not an enum and the variant of this enum is or is not given
2736                if adtdef.is_enum() && variant.is_none() {
2737                    return OwnershipLayoutResult::new();
2738                }
2739
2740                let mut res = OwnershipLayoutResult::new();
2741
2742                // check the ty if it is a struct or union
2743                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                // check the ty which is an enum with a exact variant idx
2754                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                // check the ty is or is not an enum and the variant of this enum is or is not given
2816                if adtdef.is_enum() && variant.is_none() {
2817                    return res;
2818                }
2819
2820                // check the ty if it is a struct or union
2821                if adtdef.is_struct() || adtdef.is_union() {
2822                    for _field in adtdef.all_fields() {
2823                        res.push(false);
2824                    }
2825                }
2826                // check the ty which is an enum with a exact variant idx
2827                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        // Extract the field index of the place:
2854        // If the ProjectionElem finds the variant is not Field, stop and exit!
2855        // This method is used for field sensitivity analysis only!
2856        let mut prj: ProjectionSupport<'tcx> = ProjectionSupport::default();
2857        if aggre.is_some() {
2858            // if the 'Aggregate' is Some, that means ProjectionSupport is used for a local constructor.
2859            // Therefore, we do not need to record the ty of such field, instead, the projection
2860            // records the ty of the place, it is correct, because for local constructor, we do
2861            // not use the type information of the filed, but only need the index to init them one by one.
2862            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
3019// Create an unsigned integer from bit bit-vector.
3020// The bit-vector has n bits
3021// the i'th bit (counting from 0 to n-1) is 1 if ans div 2^i mod 2 is 1.
3022fn 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}