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::ownedheap_analysis::{default::*, *},
24    utils::{
25        log::{
26            are_spans_in_same_file, relative_pos_range, span_to_filename, span_to_line_number,
27            span_to_source_code,
28        },
29        source::get_name,
30    },
31};
32
33type Disc = Option<VariantIdx>;
34type Aggre = Option<usize>;
35
36#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
37pub enum AsgnKind {
38    Assign,
39    Reference,
40    Pointer,
41    Cast,
42    Aggregate,
43}
44
45impl<'tcx, 'a> FlowAnalysis<'tcx, 'a> {
46    pub fn intra_run(&mut self) {
47        let tcx = self.tcx();
48        let mir_keys = tcx.mir_keys(());
49
50        for each_mir in mir_keys {
51            let def_id = each_mir.to_def_id();
52            let body = tcx.instance_mir(Item(def_id));
53            if graph::is_cyclic(&body.basic_blocks) {
54                continue;
55            }
56            if format!("{:?}", def_id).contains("syscall_dispatch") {
57                continue;
58            }
59
60            let mut cfg = z3::Config::new();
61            cfg.set_model_generation(true);
62            cfg.set_timeout_msec(1000);
63            let ctx = z3::Context::new(&cfg);
64            let goal = z3::Goal::new(&ctx, true, false, false);
65            let solver = z3::Solver::new(&ctx);
66
67            let mut intra_visitor = IntraFlowAnalysis::new(self.rcx, def_id);
68            intra_visitor.visit_body(&ctx, &goal, &solver, body);
69        }
70    }
71}
72
73impl<'tcx, 'ctx, 'a> IntraFlowAnalysis<'tcx, 'ctx, 'a> {
74    pub(crate) fn visit_body(
75        &mut self,
76        ctx: &'ctx z3::Context,
77        goal: &'ctx z3::Goal<'ctx>,
78        solver: &'ctx z3::Solver<'ctx>,
79        body: &'tcx Body<'tcx>,
80    ) {
81        let topo: Vec<usize> = self.graph.get_topo().iter().map(|id| *id).collect();
82        for bidx in topo {
83            let data = &body.basic_blocks[BasicBlock::from(bidx)];
84            self.visit_block_data(ctx, goal, solver, data, bidx);
85        }
86    }
87
88    pub(crate) fn visit_block_data(
89        &mut self,
90        ctx: &'ctx z3::Context,
91        goal: &'ctx z3::Goal<'ctx>,
92        solver: &'ctx z3::Solver<'ctx>,
93        data: &'tcx BasicBlockData<'tcx>,
94        bidx: usize,
95    ) {
96        self.preprocess_for_basic_block(ctx, goal, solver, bidx);
97
98        for (sidx, stmt) in data.statements.iter().enumerate() {
99            self.visit_statement(ctx, goal, solver, stmt, bidx, sidx);
100        }
101
102        self.visit_terminator(ctx, goal, solver, data.terminator(), bidx);
103
104        self.reprocess_for_basic_block(bidx);
105    }
106
107    pub(crate) fn preprocess_for_basic_block(
108        &mut self,
109        ctx: &'ctx z3::Context,
110        goal: &'ctx z3::Goal<'ctx>,
111        solver: &'ctx z3::Solver<'ctx>,
112        bidx: usize,
113    ) {
114        // 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().var_mut()[lu] = IntraVar::Init(l_ori_bv_ctor);
1274        }
1275    }
1276
1277    pub(crate) fn handle_copy_to_field(
1278        &mut self,
1279        ctx: &'ctx z3::Context,
1280        goal: &'ctx z3::Goal<'ctx>,
1281        solver: &'ctx z3::Solver<'ctx>,
1282        _kind: AsgnKind,
1283        lplace: &Place<'tcx>,
1284        rplace: &Place<'tcx>,
1285        mut disc: Disc,
1286        aggre: Aggre,
1287        bidx: usize,
1288        sidx: usize,
1289    ) {
1290        // y.f= x => l.f= r
1291        // this local of lvalue is not y.f
1292        let llocal = lplace.local;
1293        let rlocal = rplace.local;
1294
1295        let lu: usize = llocal.as_usize();
1296        let ru: usize = rlocal.as_usize();
1297
1298        // if any rvalue or lplace is unsupported, then make them all unsupported and exit
1299        if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1300        {
1301            self.handle_intra_var_unsupported(lu);
1302            self.handle_intra_var_unsupported(ru);
1303            return;
1304        }
1305        if !self.icx_slice().var()[ru].is_init() {
1306            return;
1307        }
1308
1309        // extract the ty of the rvalue
1310        let l_local_ty = self.body.local_decls[llocal].ty;
1311        let lpj_fields = self.extract_projection(lplace, aggre);
1312        if lpj_fields.is_unsupported() {
1313            // we only support that the field depth is 1 in max
1314            self.handle_intra_var_unsupported(lu);
1315            self.handle_intra_var_unsupported(ru);
1316            return;
1317        }
1318
1319        match (lpj_fields.has_field(), lpj_fields.has_downcast()) {
1320            (true, true) => {
1321                // .f .v => judge
1322                disc = lpj_fields.downcast();
1323                let ty_with_index = TyWithIndex::new(l_local_ty, disc);
1324
1325                if ty_with_index.0.is_none() {
1326                    return;
1327                }
1328
1329                // variant.len = 1 && field[0]
1330                if lpj_fields.index_needed() == 0 && ty_with_index.0.unwrap().0 == 1 {
1331                    self.handle_copy(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1332                    return;
1333                }
1334            }
1335            (true, false) => {
1336                // .f => normal field access
1337            }
1338            (false, true) => {
1339                // .v => not
1340                return;
1341            }
1342            (false, false) => {
1343                self.handle_copy(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1344                return;
1345            }
1346        }
1347
1348        let index_needed = lpj_fields.index_needed();
1349
1350        let default_heap = self.extract_default_ty_layout(l_local_ty, disc);
1351        if !default_heap.get_requirement() || default_heap.is_empty() {
1352            return;
1353        }
1354
1355        // get the length of current variable and the lplace projection to generate bit vector in the future
1356        let llen = default_heap.layout().len();
1357        self.icx_slice_mut().len_mut()[lu] = llen;
1358        let rlen = self.icx_slice().len()[ru];
1359
1360        // if the current layout of the father in rvalue is 0, avoid the following analysis
1361        // e.g., a = b, b:[]
1362        if self.icx_slice().len[ru] == 0 {
1363            // the len is 0 and ty is None which do not need update
1364            return;
1365        }
1366
1367        // extract the original z3 ast of the variable needed to prepare generating new
1368        let l_ori_bv: ast::BV;
1369        let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1370
1371        if self.icx_slice().var()[lu].is_init() {
1372            // if the lvalue is not initialized for the first time
1373            // the constraint that promise the original value of lvalue that does not hold the heap
1374            // e.g., y.f= x ,that y.f (l) is non-owning
1375            l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1376            let extract_from_field = l_ori_bv.extract(index_needed as u32, index_needed as u32);
1377            if lu > self.body.arg_count {
1378                let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
1379                let constraint_l_f_ori_zero = extract_from_field._safe_eq(&l_f_zero_const).unwrap();
1380                goal.assert(&constraint_l_f_ori_zero);
1381                solver.assert(&constraint_l_f_ori_zero);
1382            }
1383        } else {
1384            // this branch means that the assignment is the constructor of the lvalue (either l and l.f)
1385            // this constraint promise before the struct is [0;field]
1386            let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1387            let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1388            let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1389            let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1390            goal.assert(&constraint_l_ctor_zero);
1391            solver.assert(&constraint_l_ctor_zero);
1392            l_ori_bv = l_ori_zero;
1393            self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1394            self.icx_slice_mut().layout_mut()[lu] = default_heap.layout().clone();
1395        }
1396
1397        // we no not need to update the lvalue length that is equal to rvalue
1398        // llen = rlen;
1399        // self.icx_slice_mut().len_mut()[lu] = llen;
1400
1401        // produce the name of lvalue and rvalue in this program point
1402        let l_name = new_local_name(lu, bidx, sidx);
1403        let r_name = new_local_name(ru, bidx, sidx);
1404
1405        // generate new bit vectors for variables
1406        let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1407        let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1408
1409        let r_zero_const = ast::BV::from_u64(ctx, 0, rlen as u32);
1410
1411        // the constraint that promise the unique heap in transformation of y.f=x, l.f=r
1412        // the exactly constraint is that (r'=r && l.f'=0) || (r'=0 && l.f'=shrink(r))
1413        // this is for r'=r && l.f'=0
1414        // this is for r'=r
1415        let r_owning = r_new_bv._safe_eq(&r_ori_bv).unwrap();
1416        //this is for l.f'=0
1417        let mut rust_bv_for_op_and = vec![true; llen];
1418        rust_bv_for_op_and[index_needed] = false;
1419        let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1420        let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, llen as u32);
1421        let after_op_and = l_ori_bv.bvand(&z3_bv_for_op_and);
1422        let lpj_non_owning = l_new_bv._safe_eq(&after_op_and).unwrap();
1423
1424        let args1 = &[&r_owning, &lpj_non_owning];
1425        let summary_1 = ast::Bool::and(ctx, args1);
1426
1427        // this is for r'=0 && l.f'=shrink(r)
1428        // this is for r'=0
1429        let r_non_owning = r_new_bv._safe_eq(&r_zero_const).unwrap();
1430        // this is for l.f'=shrink(r)
1431        // to achieve this goal would be kind of complicated
1432        // first we take the disjunction of whole rvalue into point as *
1433        // then, the we contact 3 bit vector [1;begin] [*] [1;end]
1434        // at last, we use and operation to simulate shrink from e.g., [0010] to [11*1]
1435        let disjunction_r = r_ori_bv.bvredor();
1436        let mut final_bv: ast::BV;
1437
1438        if index_needed < llen - 1 {
1439            let end_part = l_ori_bv.extract((llen - 1) as u32, (index_needed + 1) as u32);
1440            final_bv = end_part.concat(&disjunction_r);
1441        } else {
1442            final_bv = disjunction_r;
1443        }
1444        if index_needed > 0 {
1445            let begin_part = l_ori_bv.extract((index_needed - 1) as u32, 0);
1446            final_bv = final_bv.concat(&begin_part);
1447        }
1448
1449        let lpj_shrink_owning = l_new_bv._safe_eq(&final_bv).unwrap();
1450
1451        let args2 = &[&r_non_owning, &lpj_shrink_owning];
1452        let summary_2 = ast::Bool::and(ctx, args2);
1453
1454        // the final constraint and add the constraint to the goal of this function
1455        let args3 = &[&summary_1, &summary_2];
1456        let constraint_owning_now = ast::Bool::or(ctx, args3);
1457
1458        goal.assert(&constraint_owning_now);
1459        solver.assert(&constraint_owning_now);
1460
1461        // update the Intra var value in current basic block (exactly, the statement)
1462        self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1463        self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1464        self.handle_taint(lu, ru);
1465    }
1466
1467    pub(crate) fn handle_move_to_field(
1468        &mut self,
1469        ctx: &'ctx z3::Context,
1470        goal: &'ctx z3::Goal<'ctx>,
1471        solver: &'ctx z3::Solver<'ctx>,
1472        _kind: AsgnKind,
1473        lplace: &Place<'tcx>,
1474        rplace: &Place<'tcx>,
1475        mut disc: Disc,
1476        aggre: Aggre,
1477        bidx: usize,
1478        sidx: usize,
1479    ) {
1480        // y.f=move x => l.f=move r
1481        // this local of lvalue is not y.f
1482        let llocal = lplace.local;
1483        let rlocal = rplace.local;
1484
1485        let lu: usize = llocal.as_usize();
1486        let ru: usize = rlocal.as_usize();
1487
1488        // if any rvalue or lplace is unsupported, then make them all unsupported and exit
1489        if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1490        {
1491            self.handle_intra_var_unsupported(lu);
1492            self.handle_intra_var_unsupported(ru);
1493            return;
1494        }
1495        if !self.icx_slice().var()[ru].is_init() {
1496            return;
1497        }
1498
1499        // extract the ty of the rvalue
1500        let l_local_ty = self.body.local_decls[llocal].ty;
1501        let lpj_fields = self.extract_projection(lplace, aggre);
1502        if lpj_fields.is_unsupported() {
1503            // we only support that the field depth is 1 in max
1504            self.handle_intra_var_unsupported(lu);
1505            self.handle_intra_var_unsupported(ru);
1506            return;
1507        }
1508
1509        match (lpj_fields.has_field(), lpj_fields.has_downcast()) {
1510            (true, true) => {
1511                // .f .v => judge
1512                disc = lpj_fields.downcast();
1513                let ty_with_index = TyWithIndex::new(l_local_ty, disc);
1514
1515                if ty_with_index.0.is_none() {
1516                    return;
1517                }
1518
1519                // variant.len = 1 && field[0]
1520                if lpj_fields.index_needed() == 0 && ty_with_index.0.unwrap().0 == 1 {
1521                    self.handle_move(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1522                    return;
1523                }
1524            }
1525            (true, false) => {
1526                // .f => normal field access
1527            }
1528            (false, true) => {
1529                // .v => not
1530                return;
1531            }
1532            (false, false) => {
1533                self.handle_move(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1534                return;
1535            }
1536        }
1537
1538        let index_needed = lpj_fields.index_needed();
1539
1540        let mut default_heap = self.extract_default_ty_layout(l_local_ty, disc);
1541        if !default_heap.get_requirement() || default_heap.is_empty() {
1542            return;
1543        }
1544
1545        // get the length of current variable and the lplace projection to generate bit vector in the future
1546        let llen = default_heap.layout().len();
1547        self.icx_slice_mut().len_mut()[lu] = llen;
1548        let rlen = self.icx_slice().len()[ru];
1549
1550        // if the current layout of the father in rvalue is 0, avoid the following analysis
1551        // e.g., a = b, b:[]
1552        if self.icx_slice().len[ru] == 0 {
1553            // the len is 0 and ty is None which do not need update
1554            return;
1555        }
1556
1557        // extract the original z3 ast of the variable needed to prepare generating new
1558        let l_ori_bv: ast::BV;
1559        let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1560
1561        if self.icx_slice().var()[lu].is_init() {
1562            // if the lvalue is not initialized for the first time
1563            // the constraint that promise the original value of lvalue that does not hold the heap
1564            // e.g., y.f=move x ,that y.f (l) is non-owning
1565            // add: y.f -> y is not argument e.g., fn(arg1) arg1.1 = 0, cause arg is init as 1
1566            l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1567            let extract_from_field = l_ori_bv.extract(index_needed as u32, index_needed as u32);
1568            if lu > self.body.arg_count {
1569                let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
1570                let constraint_l_f_ori_zero = extract_from_field._safe_eq(&l_f_zero_const).unwrap();
1571                goal.assert(&constraint_l_f_ori_zero);
1572                solver.assert(&constraint_l_f_ori_zero);
1573            }
1574        } else {
1575            // this branch means that the assignment is the constructor of the lvalue (either l and l.f)
1576            // this constraint promise before the struct is [0;field]
1577            let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1578            let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1579            let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1580            let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1581            goal.assert(&constraint_l_ctor_zero);
1582            solver.assert(&constraint_l_ctor_zero);
1583            l_ori_bv = l_ori_zero;
1584            self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1585            self.icx_slice_mut().layout_mut()[lu] = default_heap.layout_mut().clone();
1586        }
1587
1588        // we no not need to update the lvalue length that is equal to rvalue
1589        // llen = rlen;
1590        // self.icx_slice_mut().len_mut()[lu] = llen;
1591
1592        // produce the name of lvalue and rvalue in this program point
1593        let l_name = new_local_name(lu, bidx, sidx);
1594        let r_name = new_local_name(ru, bidx, sidx);
1595
1596        // generate new bit vectors for variables
1597        let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1598        let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1599
1600        let r_zero_const = ast::BV::from_u64(ctx, 0, rlen as u32);
1601
1602        // the constraint that promise the unique heap in transformation of y.f=move x, l.f=move r
1603        // the exactly constraint is that r'=0 && l.f'=shrink(r)
1604        // this is for r'=0
1605        let r_non_owning = r_new_bv._safe_eq(&r_zero_const).unwrap();
1606
1607        // this is for l.f'=shrink(r)
1608        // to achieve this goal would be kind of complicated
1609        // first we take the disjunction of whole rvalue into point as *
1610        // then, the we contact 3 bit vector [1;begin] [*] [1;end]
1611        // at last, we use or operation to simulate shrink from e.g., [1010] to [00*0]
1612        let disjunction_r = r_ori_bv.bvredor();
1613        let mut final_bv: ast::BV;
1614        if index_needed < llen - 1 {
1615            let end_part = l_ori_bv.extract((llen - 1) as u32, (index_needed + 1) as u32);
1616            final_bv = end_part.concat(&disjunction_r);
1617        } else {
1618            final_bv = disjunction_r;
1619        }
1620        if index_needed > 0 {
1621            let begin_part = l_ori_bv.extract((index_needed - 1) as u32, 0);
1622            final_bv = final_bv.concat(&begin_part);
1623        }
1624        let lpj_shrink_owning = l_new_bv._safe_eq(&final_bv).unwrap();
1625
1626        goal.assert(&r_non_owning);
1627        goal.assert(&lpj_shrink_owning);
1628        solver.assert(&r_non_owning);
1629        solver.assert(&lpj_shrink_owning);
1630
1631        // update the Intra var value in current basic block (exactly, the statement)
1632        self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1633        self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1634        self.handle_taint(lu, ru);
1635    }
1636
1637    pub(crate) fn handle_copy_field_to_field(
1638        &mut self,
1639        ctx: &'ctx z3::Context,
1640        goal: &'ctx z3::Goal<'ctx>,
1641        solver: &'ctx z3::Solver<'ctx>,
1642        _kind: AsgnKind,
1643        lplace: &Place<'tcx>,
1644        rplace: &Place<'tcx>,
1645        disc: Disc,
1646        aggre: Aggre,
1647        bidx: usize,
1648        sidx: usize,
1649    ) {
1650        // y.f= x.f => l.f= r.f
1651        let llocal = lplace.local;
1652        let rlocal = rplace.local;
1653
1654        let lu: usize = llocal.as_usize();
1655        let ru: usize = rlocal.as_usize();
1656
1657        // if any rvalue or lplace is unsupported, then make them all unsupported and exit
1658        if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1659        {
1660            self.handle_intra_var_unsupported(lu);
1661            self.handle_intra_var_unsupported(ru);
1662            return;
1663        }
1664        if !self.icx_slice().var()[ru].is_init() {
1665            return;
1666        }
1667
1668        let l_local_ty = self.body.local_decls[llocal].ty;
1669
1670        // extract the ty of the rplace, the rplace has projection like _1.0
1671        // rpj ty is the exact ty of rplace, the first field ty of rplace
1672        let rpj_fields = self.extract_projection(rplace, None);
1673        if rpj_fields.is_unsupported() {
1674            // we only support that the field depth is 1 in max
1675            self.handle_intra_var_unsupported(lu);
1676            self.handle_intra_var_unsupported(ru);
1677            return;
1678        }
1679
1680        let lpj_fields = self.extract_projection(lplace, aggre);
1681        if lpj_fields.is_unsupported() {
1682            // we only support that the field depth is 1 in max
1683            self.handle_intra_var_unsupported(lu);
1684            self.handle_intra_var_unsupported(ru);
1685            return;
1686        }
1687
1688        match (rpj_fields.has_field(), lpj_fields.has_field()) {
1689            (true, true) => (),
1690            (true, false) => {
1691                self.handle_copy_from_field(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1692                return;
1693            }
1694            (false, true) => {
1695                self.handle_copy_to_field(
1696                    ctx, goal, solver, _kind, lplace, rplace, disc, aggre, bidx, sidx,
1697                );
1698                return;
1699            }
1700            (false, false) => {
1701                self.handle_copy(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1702                return;
1703            }
1704        }
1705
1706        let r_index_needed = rpj_fields.index_needed();
1707        let l_index_needed = lpj_fields.index_needed();
1708
1709        let default_heap = self.extract_default_ty_layout(l_local_ty, disc);
1710        if !default_heap.get_requirement() || default_heap.is_empty() {
1711            return;
1712        }
1713
1714        // get the length of current variable and the rplace projection to generate bit vector in the future
1715        let llen = default_heap.layout().len();
1716        let rlen = self.icx_slice().len()[ru];
1717        self.icx_slice_mut().len_mut()[lu] = llen;
1718
1719        // if the current layout of the father in rvalue is 0, avoid the following analysis
1720        // e.g., a = b, b:[]
1721        if self.icx_slice().len[ru] == 0 {
1722            // the len is 0 and ty is None which do not need update
1723            return;
1724        }
1725
1726        // extract the original z3 ast of the variable needed to prepare generating new
1727        let l_ori_bv: ast::BV;
1728        let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1729
1730        if self.icx_slice().var()[lu].is_init() {
1731            // if the lvalue is not initialized for the first time
1732            // the constraint that promise the original value of lvalue that does not hold the heap
1733            // e.g., y.f= move x.f ,that y.f (l) is non-owning
1734            l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1735            let extract_from_field = l_ori_bv.extract(l_index_needed as u32, l_index_needed as u32);
1736            if lu > self.body.arg_count {
1737                let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
1738                let constraint_l_f_ori_zero = extract_from_field._safe_eq(&l_f_zero_const).unwrap();
1739                goal.assert(&constraint_l_f_ori_zero);
1740                solver.assert(&constraint_l_f_ori_zero);
1741            }
1742        } else {
1743            // this branch means that the assignment is the constructor of the lvalue (either l and l.f)
1744            // this constraint promise before the struct is [0;field]
1745            let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1746            let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1747            let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1748            let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1749            goal.assert(&constraint_l_ctor_zero);
1750            solver.assert(&constraint_l_ctor_zero);
1751            l_ori_bv = l_ori_zero;
1752            self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1753            self.icx_slice_mut().layout_mut()[lu] = default_heap.layout().clone();
1754        }
1755
1756        // produce the name of lvalue and rvalue in this program point
1757        let l_name = new_local_name(lu, bidx, sidx);
1758        let r_name = new_local_name(ru, bidx, sidx);
1759
1760        // generate new bit vectors for variables
1761        let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1762        let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1763
1764        // the constraint that promise the unique heap in transformation of y.f= x.f, l.f= r.f
1765        // the exactly constraint is that (r.f'=0 && l.f'=r.f) || (l.f'=0 && r.f'=r.f)
1766        // this is for r.f'=0 && l.f'=r.f
1767        // this is for r.f'=0
1768        // like r.1'=0 => ori and new => [0110] and [1011] => [0010]
1769        // note that we calculate the index of r.f and use bit vector 'and' to update the heap
1770        let mut rust_bv_for_op_and = vec![true; rlen];
1771        rust_bv_for_op_and[r_index_needed] = false;
1772        let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1773        let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, rlen as u32);
1774        let after_op_and = r_ori_bv.bvand(&z3_bv_for_op_and);
1775        let rpj_non_owning = r_new_bv._safe_eq(&after_op_and).unwrap();
1776        // this is for l.f'=r.f
1777        // to achieve this goal would be kind of complicated
1778        // first we extract the field from the rvalue into point as *
1779        // then, the we contact 3 bit vector [1;begin] [*] [1;end]
1780        let extract_field_r = r_ori_bv.extract(r_index_needed as u32, r_index_needed as u32);
1781        let mut final_bv: ast::BV;
1782        if l_index_needed < llen - 1 {
1783            let end_part = l_ori_bv.extract((llen - 1) as u32, (l_index_needed + 1) as u32);
1784            final_bv = end_part.concat(&extract_field_r);
1785        } else {
1786            final_bv = extract_field_r;
1787        }
1788        if l_index_needed > 0 {
1789            let begin_part = l_ori_bv.extract((l_index_needed - 1) as u32, 0);
1790            final_bv = final_bv.concat(&begin_part);
1791        }
1792        let lpj_owning = l_new_bv._safe_eq(&final_bv).unwrap();
1793
1794        let args1 = &[&rpj_non_owning, &lpj_owning];
1795        let summary_1 = ast::Bool::and(ctx, args1);
1796
1797        // this is for l.f'=0 && r.f'=r.f
1798        // this is for l.f'=0
1799        let mut rust_bv_for_op_and = vec![true; llen];
1800        rust_bv_for_op_and[l_index_needed] = false;
1801        let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1802        let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, llen as u32);
1803        let after_op_and = l_ori_bv.bvand(&z3_bv_for_op_and);
1804        let lpj_non_owning = l_new_bv._safe_eq(&after_op_and).unwrap();
1805        // this is for r.f'=r.f
1806        let rpj_owning = r_new_bv._safe_eq(&r_ori_bv).unwrap();
1807
1808        let args2 = &[&lpj_non_owning, &rpj_owning];
1809        let summary_2 = ast::Bool::and(ctx, args2);
1810
1811        // the final constraint and add the constraint to the goal of this function
1812        let args3 = &[&summary_1, &summary_2];
1813        let constraint_owning_now = ast::Bool::or(ctx, args3);
1814
1815        goal.assert(&constraint_owning_now);
1816        solver.assert(&constraint_owning_now);
1817
1818        // update the Intra var value in current basic block (exactly, the statement)
1819        self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1820        self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1821        self.handle_taint(lu, ru);
1822    }
1823
1824    pub(crate) fn handle_move_field_to_field(
1825        &mut self,
1826        ctx: &'ctx z3::Context,
1827        goal: &'ctx z3::Goal<'ctx>,
1828        solver: &'ctx z3::Solver<'ctx>,
1829        _kind: AsgnKind,
1830        lplace: &Place<'tcx>,
1831        rplace: &Place<'tcx>,
1832        disc: Disc,
1833        aggre: Aggre,
1834        bidx: usize,
1835        sidx: usize,
1836    ) {
1837        // y.f=move x.f => l.f=move r.f
1838        let llocal = lplace.local;
1839        let rlocal = rplace.local;
1840
1841        let lu: usize = llocal.as_usize();
1842        let ru: usize = rlocal.as_usize();
1843
1844        // if any rvalue or lplace is unsupported, then make them all unsupported and exit
1845        if self.icx_slice().var()[lu].is_unsupported() || self.icx_slice.var()[ru].is_unsupported()
1846        {
1847            self.handle_intra_var_unsupported(lu);
1848            self.handle_intra_var_unsupported(ru);
1849            return;
1850        }
1851        if !self.icx_slice().var()[ru].is_init() {
1852            return;
1853        }
1854
1855        let l_local_ty = self.body.local_decls[llocal].ty;
1856
1857        // extract the ty of the rplace, the rplace has projection like _1.0
1858        // rpj ty is the exact ty of rplace, the first field ty of rplace
1859        //let rpj_ty = rplace.ty(&self.body.local_decls, self.tcx);
1860        let rpj_fields = self.extract_projection(rplace, None);
1861        if rpj_fields.is_unsupported() {
1862            // we only support that the field depth is 1 in max
1863            self.handle_intra_var_unsupported(lu);
1864            self.handle_intra_var_unsupported(ru);
1865            return;
1866        }
1867
1868        // extract the ty of the lplace, the lplace has projection like _1.0
1869        // lpj ty is the exact ty of lplace, the first field ty of lplace
1870        //let lpj_ty = lplace.ty(&self.body.local_decls, self.tcx);
1871        let lpj_fields = self.extract_projection(lplace, aggre);
1872        if lpj_fields.is_unsupported() {
1873            // we only support that the field depth is 1 in max
1874            self.handle_intra_var_unsupported(lu);
1875            self.handle_intra_var_unsupported(ru);
1876            return;
1877        }
1878
1879        match (rpj_fields.has_field(), lpj_fields.has_field()) {
1880            (true, true) => (),
1881            (true, false) => {
1882                self.handle_move_from_field(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1883                return;
1884            }
1885            (false, true) => {
1886                self.handle_move_to_field(
1887                    ctx, goal, solver, _kind, lplace, rplace, disc, aggre, bidx, sidx,
1888                );
1889            }
1890            (false, false) => {
1891                self.handle_move(ctx, goal, solver, _kind, lplace, rplace, bidx, sidx);
1892                return;
1893            }
1894        }
1895
1896        let r_index_needed = rpj_fields.index_needed();
1897        let l_index_needed = lpj_fields.index_needed();
1898
1899        let default_heap = self.extract_default_ty_layout(l_local_ty, disc);
1900        if !default_heap.get_requirement() || default_heap.is_empty() {
1901            return;
1902        }
1903
1904        // get the length of current variable and the rplace projection to generate bit vector in the future
1905        let llen = default_heap.layout().len();
1906        let rlen = self.icx_slice().len()[ru];
1907        self.icx_slice_mut().len_mut()[lu] = llen;
1908
1909        // if the current layout of the father in rvalue is 0, avoid the following analysis
1910        // e.g., a = b, b:[]
1911        if self.icx_slice().len[ru] == 0 {
1912            // the len is 0 and ty is None which do not need update
1913            return;
1914        }
1915
1916        // extract the original z3 ast of the variable needed to prepare generating new
1917        let l_ori_bv: ast::BV;
1918        let r_ori_bv = self.icx_slice_mut().var_mut()[ru].extract();
1919
1920        if self.icx_slice().var()[lu].is_init() {
1921            // if the lvalue is not initialized for the first time
1922            // the constraint that promise the original value of lvalue that does not hold the heap
1923            // e.g., y.f= move x.f ,that y.f (l) is non-owning
1924            l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
1925            let extract_from_field = l_ori_bv.extract(l_index_needed as u32, l_index_needed as u32);
1926            if lu > self.body.arg_count {
1927                let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
1928                let constraint_l_f_ori_zero = extract_from_field._safe_eq(&l_f_zero_const).unwrap();
1929                goal.assert(&constraint_l_f_ori_zero);
1930                solver.assert(&constraint_l_f_ori_zero);
1931            }
1932        } else {
1933            // this branch means that the assignment is the constructor of the lvalue (either l and l.f)
1934            // this constraint promise before the struct is [0;field]
1935            let l_ori_name_ctor = new_local_name(lu, bidx, sidx).add("_ctor_asgn");
1936            let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
1937            let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
1938            let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
1939            goal.assert(&constraint_l_ctor_zero);
1940            solver.assert(&constraint_l_ctor_zero);
1941            l_ori_bv = l_ori_zero;
1942            self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, disc);
1943            self.icx_slice_mut().layout_mut()[lu] = default_heap.layout().clone();
1944        }
1945
1946        // produce the name of lvalue and rvalue in this program point
1947        let l_name = new_local_name(lu, bidx, sidx);
1948        let r_name = new_local_name(ru, bidx, sidx);
1949
1950        // generate new bit vectors for variables
1951        let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
1952        let r_new_bv = ast::BV::new_const(ctx, r_name, rlen as u32);
1953
1954        // the constraint that promise the unique heap in transformation of y.f=move x.f, l.f=move r.f
1955        // the exactly constraint is that r.f'=0 && l.f'=r.f
1956        // this is for r.f'=0
1957        // like r.1'=0 => ori and new => [0110] and [1011] => [0010]
1958        // note that we calculate the index of r.f and use bit vector 'and' to update the heap
1959        let mut rust_bv_for_op_and = vec![true; rlen];
1960        rust_bv_for_op_and[r_index_needed] = false;
1961        let int_for_op_and = rustbv_to_int(&rust_bv_for_op_and);
1962        let z3_bv_for_op_and = ast::BV::from_u64(ctx, int_for_op_and, rlen as u32);
1963        let after_op_and = r_ori_bv.bvand(&z3_bv_for_op_and);
1964        let rpj_non_owning = r_new_bv._safe_eq(&after_op_and).unwrap();
1965
1966        // this is for l.f'=r.f
1967        // to achieve this goal would be kind of complicated
1968        // first we extract the field from the rvalue into point as *
1969        // then, the we contact 3 bit vector [1;begin] [*] [1;end]
1970        let extract_field_r = r_ori_bv.extract(r_index_needed as u32, r_index_needed as u32);
1971        let mut final_bv: ast::BV;
1972
1973        if l_index_needed < llen - 1 {
1974            let end_part = l_ori_bv.extract((llen - 1) as u32, (l_index_needed + 1) as u32);
1975            final_bv = end_part.concat(&extract_field_r);
1976        } else {
1977            final_bv = extract_field_r;
1978        }
1979        if l_index_needed > 0 {
1980            let begin_part = l_ori_bv.extract((l_index_needed - 1) as u32, 0);
1981            final_bv = final_bv.concat(&begin_part);
1982        }
1983        let lpj_owning = l_new_bv._safe_eq(&final_bv).unwrap();
1984
1985        goal.assert(&rpj_non_owning);
1986        goal.assert(&lpj_owning);
1987        solver.assert(&rpj_non_owning);
1988        solver.assert(&lpj_owning);
1989
1990        // update the Intra var value in current basic block (exactly, the statement)
1991        self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
1992        self.icx_slice_mut().var_mut()[ru] = IntraVar::Init(r_new_bv);
1993        self.handle_taint(lu, ru);
1994    }
1995
1996    pub(crate) fn check_fn_source(
1997        &mut self,
1998        //args: &Vec<Operand<'tcx>>,
1999        args: &Box<[Spanned<Operand<'tcx>>]>,
2000        dest: &Place<'tcx>,
2001    ) -> bool {
2002        if args.len() != 1 {
2003            return false;
2004        }
2005
2006        let l_place_ty = dest.ty(&self.body.local_decls, self.tcx());
2007        if !is_place_containing_ptr(&l_place_ty.ty) {
2008            return false;
2009        }
2010
2011        match args[0].node {
2012            Operand::Move(aplace) => {
2013                let a_place_ty = aplace.ty(&self.body.local_decls, self.tcx());
2014                let default_layout =
2015                    self.extract_default_ty_layout(a_place_ty.ty, a_place_ty.variant_index);
2016                if default_layout.is_owned() {
2017                    self.taint_flag = true;
2018                    true
2019                } else {
2020                    false
2021                }
2022            }
2023            _ => false,
2024        }
2025    }
2026
2027    pub(crate) fn check_fn_recovery(
2028        &mut self,
2029        //args: &Vec<Operand<'tcx>>,
2030        args: &Box<[Spanned<Operand<'tcx>>]>,
2031        dest: &Place<'tcx>,
2032    ) -> (bool, Vec<usize>) {
2033        let mut ans: (bool, Vec<usize>) = (false, Vec::new());
2034
2035        if args.len() == 0 {
2036            return ans;
2037        }
2038
2039        let l_place_ty = dest.ty(&self.body.local_decls, self.tcx());
2040        let default_layout =
2041            self.extract_default_ty_layout(l_place_ty.ty, l_place_ty.variant_index);
2042        if !default_layout.get_requirement() || default_layout.is_empty() {
2043            return ans;
2044        }
2045        let ty_with_idx = TyWithIndex::new(l_place_ty.ty, l_place_ty.variant_index);
2046
2047        for arg in args {
2048            match arg.node {
2049                Operand::Move(aplace) => {
2050                    let au: usize = aplace.local.as_usize();
2051                    let taint = &self.icx_slice().taint()[au];
2052                    if taint.is_tainted() && taint.contains(&ty_with_idx) {
2053                        ans.0 = true;
2054                        ans.1.push(au);
2055                    }
2056                }
2057                Operand::Copy(aplace) => {
2058                    let au: usize = aplace.local.as_usize();
2059                    let taint = &self.icx_slice().taint()[au];
2060                    if taint.is_tainted() && taint.contains(&ty_with_idx) {
2061                        ans.0 = true;
2062                        ans.1.push(au);
2063                    }
2064                }
2065                _ => (),
2066            }
2067        }
2068        ans
2069    }
2070
2071    pub(crate) fn handle_call(
2072        &mut self,
2073        ctx: &'ctx z3::Context,
2074        goal: &'ctx z3::Goal<'ctx>,
2075        solver: &'ctx z3::Solver<'ctx>,
2076        term: Terminator<'tcx>,
2077        func: &Operand<'tcx>,
2078        //args: &Vec<Operand<'tcx>>,
2079        args: &Box<[Spanned<Operand<'tcx>>]>,
2080        dest: &Place<'tcx>,
2081        bidx: usize,
2082    ) {
2083        match func {
2084            Operand::Constant(constant) => {
2085                match constant.ty().kind() {
2086                    ty::FnDef(id, ..) => {
2087                        //rap_debug!("{:?}", id);
2088                        //rap_debug!("{:?}", mir_body(self.tcx, *id));
2089                        match id.index.as_usize() {
2090                            2171 => {
2091                                // this for calling std::mem::drop(TY)
2092                                match args[0].node {
2093                                    Operand::Move(aplace) => {
2094                                        let a_place_ty =
2095                                            dest.ty(&self.body.local_decls, self.tcx());
2096                                        let a_ty = a_place_ty.ty;
2097                                        if a_ty.is_adt() {
2098                                            self.handle_drop(
2099                                                ctx, goal, solver, &aplace, bidx, false,
2100                                            );
2101                                            return;
2102                                        }
2103                                    }
2104                                    _ => (),
2105                                }
2106                            }
2107                            _ => (),
2108                        }
2109                    }
2110                    _ => (),
2111                }
2112            }
2113            _ => (),
2114        }
2115
2116        // for return value
2117        let llocal = dest.local;
2118        let lu: usize = llocal.as_usize();
2119
2120        // the source flag is for fn(self) -> */&
2121        // we will tag the lvalue as tainted and change the default ctor to modified one
2122        let source_flag = self.check_fn_source(args, dest);
2123        // the recovery flag is for fn(*) -> Self
2124        // the return value should have the same layout as tainted one
2125        // we will take the heap of the args if the arg is a pointer
2126        let recovery_flag = self.check_fn_recovery(args, dest);
2127        if source_flag {
2128            self.add_taint(term);
2129        }
2130
2131        for arg in args {
2132            match arg.node {
2133                Operand::Move(aplace) => {
2134                    let alocal = aplace.local;
2135                    let au: usize = alocal.as_usize();
2136
2137                    // if the current layout of the father in rvalue is 0, avoid the following analysis
2138                    // e.g., a = b, b:[]
2139                    if self.icx_slice().len()[au] == 0 {
2140                        // the len is 0 and ty is None which do not need update
2141                        continue;
2142                    }
2143
2144                    if !self.icx_slice().var()[au].is_init() {
2145                        continue;
2146                    }
2147
2148                    let a_place_ty = aplace.ty(&self.body.local_decls, self.tcx());
2149                    let a_ty = a_place_ty.ty;
2150                    let is_a_ptr = a_ty.is_any_ptr();
2151
2152                    let a_ori_bv = self.icx_slice_mut().var_mut()[au].extract();
2153                    let alen = self.icx_slice().len()[au];
2154
2155                    if source_flag {
2156                        self.icx_slice_mut().taint_mut()[lu]
2157                            .insert(TyWithIndex::new(a_place_ty.ty, a_place_ty.variant_index));
2158                    }
2159
2160                    match aplace.projection.len() {
2161                        0 => {
2162                            // this indicates that the operand is move without projection
2163                            if is_a_ptr {
2164                                if recovery_flag.0 && recovery_flag.1.contains(&au) {
2165                                    self.handle_drop(ctx, goal, solver, &aplace, bidx, true);
2166                                    continue;
2167                                }
2168
2169                                // if the aplace is a pointer (move ptr => still hold)
2170                                // the exact constraint is a=0, a'=a
2171                                // this is for a=0
2172                                let a_zero_const = ast::BV::from_u64(ctx, 0, alen as u32);
2173                                let a_ori_non_owing = a_ori_bv._safe_eq(&a_zero_const).unwrap();
2174
2175                                // this is for a'=a
2176                                let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2177                                let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2178                                let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2179
2180                                goal.assert(&a_ori_non_owing);
2181                                goal.assert(&update_a);
2182                                solver.assert(&a_ori_non_owing);
2183                                solver.assert(&update_a);
2184
2185                                self.icx_slice_mut().var_mut()[au] = IntraVar::Init(a_new_bv);
2186                            } else {
2187                                // if the aplace is a instance (move i => drop)
2188                                self.handle_drop(ctx, goal, solver, &aplace, bidx, false);
2189                            }
2190                        }
2191                        1 => {
2192                            // this indicates that the operand is move without projection
2193                            if is_a_ptr {
2194                                if recovery_flag.0 && recovery_flag.1.contains(&au) {
2195                                    self.handle_drop(ctx, goal, solver, &aplace, bidx, true);
2196                                    continue;
2197                                }
2198                                // if the aplace in field is a pointer (move a.f (ptr) => still hold)
2199                                // the exact constraint is a'=a
2200                                // this is for a'=a
2201                                let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2202                                let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2203                                let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2204
2205                                goal.assert(&update_a);
2206                                solver.assert(&update_a);
2207                            } else {
2208                                // if the aplace is a instance (move i.f => i.f=0)
2209                                self.handle_drop(ctx, goal, solver, &aplace, bidx, false);
2210                            }
2211                        }
2212                        _ => {
2213                            self.handle_intra_var_unsupported(au);
2214                            continue;
2215                        }
2216                    }
2217                }
2218                Operand::Copy(aplace) => {
2219                    let alocal = aplace.local;
2220                    let au: usize = alocal.as_usize();
2221
2222                    // if the current layout of the father in rvalue is 0, avoid the following analysis
2223                    // e.g., a = b, b:[]
2224                    if self.icx_slice().len()[au] == 0 {
2225                        // the len is 0 and ty is None which do not need update
2226                        continue;
2227                    }
2228
2229                    if !self.icx_slice().var()[au].is_init() {
2230                        continue;
2231                    }
2232
2233                    let a_ty = aplace.ty(&self.body.local_decls, self.tcx()).ty;
2234                    let is_a_ptr = a_ty.is_any_ptr();
2235
2236                    let a_ori_bv = self.icx_slice_mut().var_mut()[au].extract();
2237                    let alen = self.icx_slice().len()[au];
2238
2239                    match aplace.projection.len() {
2240                        0 => {
2241                            // this indicates that the operand is move without projection
2242                            if is_a_ptr {
2243                                if recovery_flag.0 && recovery_flag.1.contains(&au) {
2244                                    self.handle_drop(ctx, goal, solver, &aplace, bidx, true);
2245                                    continue;
2246                                }
2247
2248                                // if the aplace is a pointer (ptr => still hold)
2249                                // the exact constraint is a=0, a'=a
2250                                // this is for a=0
2251                                let a_zero_const = ast::BV::from_u64(ctx, 0, alen as u32);
2252                                let a_ori_non_owing = a_ori_bv._safe_eq(&a_zero_const).unwrap();
2253
2254                                // this is for a'=a
2255                                let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2256                                let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2257                                let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2258
2259                                goal.assert(&a_ori_non_owing);
2260                                goal.assert(&update_a);
2261                                solver.assert(&a_ori_non_owing);
2262                                solver.assert(&update_a);
2263
2264                                self.icx_slice_mut().var_mut()[au] = IntraVar::Init(a_new_bv);
2265                            } else {
2266                                // if the aplace is a instance (i => Copy)
2267                                // for Instance Copy => No need to change
2268
2269                                if is_a_ptr {
2270                                    if recovery_flag.0 && recovery_flag.1.contains(&au) {
2271                                        self.handle_drop(ctx, goal, solver, &aplace, bidx, true);
2272                                        continue;
2273                                    }
2274                                }
2275
2276                                let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2277                                let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2278                                let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2279
2280                                goal.assert(&update_a);
2281                                solver.assert(&update_a);
2282                            }
2283                        }
2284                        1 => {
2285                            // this indicates that the operand is move without projection
2286                            let a_name = new_local_name(au, bidx, 0).add("_param_pass");
2287                            let a_new_bv = ast::BV::new_const(ctx, a_name, alen as u32);
2288                            let update_a = a_new_bv._safe_eq(&a_ori_bv).unwrap();
2289
2290                            goal.assert(&update_a);
2291                            solver.assert(&update_a);
2292                        }
2293                        _ => {
2294                            self.handle_intra_var_unsupported(au);
2295                            continue;
2296                        }
2297                    }
2298                }
2299                Operand::Constant(..) => continue,
2300                #[cfg(rapx_rustc_ge_196)]
2301                Operand::RuntimeChecks(_) => continue,
2302            }
2303        }
2304
2305        // establish constraints for return value
2306        if self.icx_slice().var()[lu].is_unsupported() {
2307            self.handle_intra_var_unsupported(lu);
2308            return;
2309        }
2310
2311        let l_ori_bv: ast::BV;
2312
2313        let l_place_ty = dest.ty(&self.body.local_decls, self.tcx());
2314        let l_local_ty = self.body.local_decls[llocal].ty;
2315
2316        let mut is_ctor = true;
2317        match dest.projection.len() {
2318            0 => {
2319                // alike move instance
2320
2321                let return_value_layout =
2322                    self.extract_default_ty_layout(l_place_ty.ty, l_place_ty.variant_index);
2323                if return_value_layout.is_empty() || !return_value_layout.get_requirement() {
2324                    return;
2325                }
2326
2327                let int_for_gen = if source_flag {
2328                    let modified_layout_bv =
2329                        self.generate_ptr_layout(l_place_ty.ty, l_place_ty.variant_index);
2330                    let merge_layout_bv = rustbv_merge(
2331                        &heap_layout_to_rustbv(return_value_layout.layout()),
2332                        &modified_layout_bv,
2333                    );
2334                    rustbv_to_int(&merge_layout_bv)
2335                } else {
2336                    rustbv_to_int(&heap_layout_to_rustbv(return_value_layout.layout()))
2337                };
2338
2339                let mut llen = self.icx_slice().len()[lu];
2340
2341                if self.icx_slice().var()[lu].is_init() {
2342                    if llen == 0 {
2343                        rap_debug!(
2344                            "handle_call: lvalue length is 0 for local {:?}, skipping\n",
2345                            lu
2346                        );
2347                        return;
2348                    }
2349                    l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
2350                    let l_zero_const = ast::BV::from_u64(ctx, 0, llen as u32);
2351                    let constraint_l_ori_zero = l_ori_bv._safe_eq(&l_zero_const).unwrap();
2352                    goal.assert(&constraint_l_ori_zero);
2353                    solver.assert(&constraint_l_ori_zero);
2354                    is_ctor = false;
2355                } else {
2356                    // this branch means that the assignment is the constructor of the lvalue
2357                    let ty_with_vidx = TyWithIndex::new(l_place_ty.ty, l_place_ty.variant_index);
2358                    match ty_with_vidx.get_priority() {
2359                        0 => {
2360                            // cannot identify the ty (unsupported like fn ptr ...)
2361                            self.handle_intra_var_unsupported(lu);
2362                            return;
2363                        }
2364                        1 => {
2365                            return;
2366                        }
2367                        2 => {
2368                            // update the layout of lvalue due to it is an instance
2369                            self.icx_slice_mut().ty_mut()[lu] = ty_with_vidx;
2370                            self.icx_slice_mut().layout_mut()[lu] =
2371                                return_value_layout.layout().clone();
2372                        }
2373                        _ => unreachable!(),
2374                    }
2375                }
2376
2377                llen = return_value_layout.layout().len();
2378
2379                let l_name = if is_ctor {
2380                    new_local_name(lu, bidx, 0).add("_ctor_fn")
2381                } else {
2382                    new_local_name(lu, bidx, 0).add("_cover_fn")
2383                };
2384
2385                let l_layout_bv = ast::BV::from_u64(ctx, int_for_gen, llen as u32);
2386                let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
2387
2388                let constraint_new_owning = l_new_bv._safe_eq(&l_layout_bv).unwrap();
2389
2390                goal.assert(&constraint_new_owning);
2391                solver.assert(&constraint_new_owning);
2392
2393                self.icx_slice_mut().len_mut()[lu] = llen;
2394                self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
2395            }
2396            1 => {
2397                // alike move to field
2398
2399                let return_value_layout = self.extract_default_ty_layout(l_local_ty, None);
2400                if return_value_layout.is_empty() || !return_value_layout.get_requirement() {
2401                    return;
2402                }
2403
2404                //let int_for_gen = rustbv_to_int(&heap_layout_to_rustbv(return_value_layout.layout()));
2405
2406                let llen = self.icx_slice().len()[lu];
2407
2408                let lpj_fields = self.extract_projection(dest, None);
2409                let index_needed = lpj_fields.index_needed();
2410
2411                if self.icx_slice().var()[lu].is_init() {
2412                    l_ori_bv = self.icx_slice_mut().var_mut()[lu].extract();
2413                    let extract_from_field =
2414                        l_ori_bv.extract(index_needed as u32, index_needed as u32);
2415                    let l_f_zero_const = ast::BV::from_u64(ctx, 0, 1);
2416                    let constraint_l_f_ori_zero =
2417                        extract_from_field._safe_eq(&l_f_zero_const).unwrap();
2418
2419                    goal.assert(&constraint_l_f_ori_zero);
2420                    solver.assert(&constraint_l_f_ori_zero);
2421                } else {
2422                    let l_ori_name_ctor = new_local_name(lu, bidx, 0).add("_ctor_fn");
2423                    let l_ori_bv_ctor = ast::BV::new_const(ctx, l_ori_name_ctor, llen as u32);
2424                    let l_ori_zero = ast::BV::from_u64(ctx, 0, llen as u32);
2425                    let constraint_l_ctor_zero = l_ori_bv_ctor._safe_eq(&l_ori_zero).unwrap();
2426
2427                    goal.assert(&constraint_l_ctor_zero);
2428                    solver.assert(&constraint_l_ctor_zero);
2429
2430                    l_ori_bv = l_ori_zero;
2431                    self.icx_slice_mut().ty_mut()[lu] = TyWithIndex::new(l_local_ty, None);
2432                    self.icx_slice_mut().layout_mut()[lu] = return_value_layout.layout().clone();
2433                }
2434
2435                let l_name = new_local_name(lu, bidx, 0);
2436                let l_new_bv = ast::BV::new_const(ctx, l_name, llen as u32);
2437
2438                let update_field = if source_flag {
2439                    ast::BV::from_u64(ctx, 1, 1)
2440                } else {
2441                    if return_value_layout.layout()[index_needed] == OwnedHeap::True {
2442                        ast::BV::from_u64(ctx, 1, 1)
2443                    } else {
2444                        ast::BV::from_u64(ctx, 0, 1)
2445                    }
2446                };
2447
2448                let mut final_bv: ast::BV;
2449                if index_needed < llen - 1 {
2450                    let end_part = l_ori_bv.extract((llen - 1) as u32, (index_needed + 1) as u32);
2451                    final_bv = end_part.concat(&update_field);
2452                } else {
2453                    final_bv = update_field;
2454                }
2455                if index_needed > 0 {
2456                    let begin_part = l_ori_bv.extract((index_needed - 1) as u32, 0);
2457                    final_bv = final_bv.concat(&begin_part);
2458                }
2459                let update_filed_using_func = l_new_bv._safe_eq(&final_bv).unwrap();
2460
2461                goal.assert(&update_filed_using_func);
2462                solver.assert(&update_filed_using_func);
2463
2464                self.icx_slice_mut().len_mut()[lu] = return_value_layout.layout().len();
2465                self.icx_slice_mut().var_mut()[lu] = IntraVar::Init(l_new_bv);
2466            }
2467            _ => {
2468                self.handle_intra_var_unsupported(lu);
2469                return;
2470            }
2471        }
2472    }
2473
2474    pub(crate) fn handle_return(
2475        &mut self,
2476        ctx: &'ctx z3::Context,
2477        goal: &'ctx z3::Goal<'ctx>,
2478        solver: &'ctx z3::Solver<'ctx>,
2479        bidx: usize,
2480    ) {
2481        let place_0 = Place::from(Local::from_usize(0));
2482        self.handle_drop(ctx, goal, solver, &place_0, bidx, false);
2483
2484        // when whole function return => we need to check every variable is freed
2485        for (iidx, var) in self.icx_slice().var.iter().enumerate() {
2486            let len = self.icx_slice().len()[iidx];
2487            if len == 0 {
2488                continue;
2489            }
2490            if iidx <= self.body.arg_count {
2491                continue;
2492            }
2493
2494            if var.is_init() {
2495                let var_ori_bv = var.extract();
2496
2497                let return_name = new_local_name(iidx, bidx, 0).add("_return");
2498                let var_return_bv = ast::BV::new_const(ctx, return_name, len as u32);
2499
2500                let zero_const = ast::BV::from_u64(ctx, 0, len as u32);
2501
2502                let var_update = var_return_bv._safe_eq(&var_ori_bv).unwrap();
2503                let var_freed = var_return_bv._safe_eq(&zero_const).unwrap();
2504
2505                let args = &[&var_update, &var_freed];
2506                let constraint_return = ast::Bool::and(ctx, args);
2507
2508                goal.assert(&constraint_return);
2509                solver.assert(&constraint_return);
2510            }
2511        }
2512
2513        let result = solver.check();
2514        let model = solver.get_model();
2515
2516        if is_z3_goal_verbose() {
2517            let g = format!("{}", goal);
2518            rap_trace!("{}\n", g);
2519            if model.is_some() {
2520                rap_trace!("{}", format!("{}", model.unwrap()));
2521            }
2522        }
2523
2524        // rap_debug!("{}", self.body.local_decls.display());
2525        // rap_debug!("{}", self.body.basic_blocks.display());
2526        // let g = format!("{}", goal);
2527        // rap_debug!("{}\n", g.color(Color::LightGray).bold());
2528
2529        if result == z3::SatResult::Unsat && self.taint_flag {
2530            let fn_name = get_name(self.tcx(), self.def_id)
2531                .unwrap_or_else(|| Symbol::intern("no symbol available"));
2532
2533            rap_warn!("Memory Leak detected in function {:}", fn_name);
2534            let source = span_to_source_code(self.body.span);
2535            let file = span_to_filename(self.body.span);
2536            let mut snippet = Snippet::source(&source)
2537                .line_start(span_to_line_number(self.body.span))
2538                .origin(&file)
2539                .fold(false);
2540
2541            for source in self.taint_source.iter() {
2542                if are_spans_in_same_file(self.body.span, source.source_info.span) {
2543                    snippet = snippet.annotation(
2544                        Level::Warning
2545                            .span(relative_pos_range(self.body.span, source.source_info.span))
2546                            .label("Memory Leak Candidates."),
2547                    );
2548                }
2549                // rap_warn!(
2550                //     "{}",
2551                //     format!(
2552                //         "RCanary: LeakItem Candidates: {:?}, {:?}",
2553                //         source.kind, source.source_info.span
2554                //     )
2555                // );
2556            }
2557
2558            let message = Level::Warning
2559                .title("Memory Leak detected.")
2560                .snippet(snippet);
2561            let renderer = Renderer::styled();
2562            rap_warn!("{}", renderer.render(message));
2563        }
2564    }
2565
2566    pub(crate) fn handle_drop(
2567        &mut self,
2568        ctx: &'ctx z3::Context,
2569        goal: &'ctx z3::Goal<'ctx>,
2570        solver: &'ctx z3::Solver<'ctx>,
2571        dest: &Place<'tcx>,
2572        bidx: usize,
2573        recovery: bool,
2574    ) {
2575        let local = dest.local;
2576        let u: usize = local.as_usize();
2577
2578        if self.icx_slice().len()[u] == 0 {
2579            return;
2580        }
2581
2582        if self.icx_slice().var()[u].is_declared() || self.icx_slice().var()[u].is_unsupported() {
2583            return;
2584        }
2585
2586        let len = self.icx_slice().len()[u];
2587        let rust_bv = reverse_heap_layout_to_rustbv(&self.icx_slice().layout()[u]);
2588        let ori_bv = self.icx_slice().var()[u].extract();
2589
2590        let f = self.extract_projection(dest, None);
2591        if f.is_unsupported() {
2592            self.handle_intra_var_unsupported(u);
2593            return;
2594        }
2595
2596        match f.has_field() {
2597            false => {
2598                // drop the entire owning item
2599                // reverse the heap layout and using and operator
2600                if recovery {
2601                    // recovery for pointer, clear all
2602                    let name = new_local_name(u, bidx, 0).add("_drop_recovery");
2603                    let new_bv = ast::BV::new_const(ctx, name, len as u32);
2604                    let zero_bv = ast::BV::from_u64(ctx, 0, len as u32);
2605
2606                    let and_bv = ori_bv.bvand(&zero_bv);
2607
2608                    let constraint_recovery = new_bv._eq(&and_bv);
2609
2610                    goal.assert(&constraint_recovery);
2611                    solver.assert(&constraint_recovery);
2612
2613                    self.icx_slice_mut().var_mut()[u] = IntraVar::Init(new_bv);
2614                } else {
2615                    // is not recovery for pointer, just normal drop
2616                    let name = new_local_name(u, bidx, 0).add("_drop_all");
2617                    let new_bv = ast::BV::new_const(ctx, name, len as u32);
2618                    let int_for_rust_bv = rustbv_to_int(&rust_bv);
2619                    let int_bv_const = ast::BV::from_u64(ctx, int_for_rust_bv, len as u32);
2620
2621                    let and_bv = ori_bv.bvand(&int_bv_const);
2622
2623                    let constraint_reverse = new_bv._eq(&and_bv);
2624
2625                    goal.assert(&constraint_reverse);
2626                    solver.assert(&constraint_reverse);
2627
2628                    self.icx_slice_mut().var_mut()[u] = IntraVar::Init(new_bv);
2629                }
2630            }
2631            true => {
2632                // drop the field
2633                let index_needed = f.index_needed();
2634
2635                if index_needed >= rust_bv.len() {
2636                    return;
2637                }
2638
2639                let name = if recovery {
2640                    new_local_name(u, bidx, 0).add("_drop_f_recovery")
2641                } else {
2642                    new_local_name(u, bidx, 0).add("_drop_f")
2643                };
2644                let new_bv = ast::BV::new_const(ctx, name, len as u32);
2645
2646                if (rust_bv[index_needed] && !recovery) || (!rust_bv[index_needed] && recovery) {
2647                    // not actually drop, just update the idx
2648                    // the default heap is false (non-owning) somehow, we just reverse it before
2649                    let constraint_update = new_bv._eq(&ori_bv);
2650
2651                    goal.assert(&constraint_update);
2652                    solver.assert(&constraint_update);
2653
2654                    self.icx_slice_mut().var_mut()[u] = IntraVar::Init(new_bv);
2655                } else {
2656                    let f_free = ast::BV::from_u64(ctx, 0, 1);
2657                    let mut final_bv: ast::BV;
2658                    if index_needed < len - 1 {
2659                        let end_part = ori_bv.extract((len - 1) as u32, (index_needed + 1) as u32);
2660                        final_bv = end_part.concat(&f_free);
2661                    } else {
2662                        final_bv = f_free;
2663                    }
2664                    if index_needed > 0 {
2665                        let begin_part = ori_bv.extract((index_needed - 1) as u32, 0);
2666                        final_bv = final_bv.concat(&begin_part);
2667                    }
2668
2669                    let constraint_free_f = new_bv._safe_eq(&final_bv).unwrap();
2670
2671                    goal.assert(&constraint_free_f);
2672                    solver.assert(&constraint_free_f);
2673
2674                    self.icx_slice_mut().var_mut()[u] = IntraVar::Init(new_bv);
2675                }
2676            }
2677        }
2678    }
2679
2680    pub(crate) fn handle_intra_var_unsupported(&mut self, idx: usize) {
2681        match self.icx_slice_mut().var_mut()[idx] {
2682            IntraVar::Unsupported => return,
2683            IntraVar::Declared | IntraVar::Init(_) => {
2684                // turns into the unsupported
2685                self.icx_slice_mut().var_mut()[idx] = IntraVar::Unsupported;
2686                self.icx_slice_mut().len_mut()[idx] = 0;
2687                return;
2688            }
2689        }
2690    }
2691
2692    pub(crate) fn handle_taint(&mut self, l: usize, r: usize) {
2693        if self.icx_slice().taint()[r].is_untainted() {
2694            return;
2695        }
2696
2697        if self.icx_slice().taint()[l].is_untainted() {
2698            self.icx_slice_mut().taint_mut()[l] = self.icx_slice().taint()[r].clone();
2699        } else {
2700            for elem in self.icx_slice().taint()[r].set().clone() {
2701                self.icx_slice_mut().taint_mut()[l].insert(elem);
2702            }
2703        }
2704    }
2705
2706    pub(crate) fn extract_default_ty_layout(
2707        &mut self,
2708        ty: Ty<'tcx>,
2709        variant: Option<VariantIdx>,
2710    ) -> OwnershipLayoutResult {
2711        match ty.kind() {
2712            TyKind::Array(..) => {
2713                let mut res = OwnershipLayoutResult::new();
2714                let mut default_heap = DefaultOwnership::new(self.tcx(), self.owner());
2715
2716                let _ = ty.visit_with(&mut default_heap);
2717                res.update_from_default_heap_visitor(&mut default_heap);
2718
2719                res
2720            }
2721            TyKind::Tuple(tuple_ty_list) => {
2722                let mut res = OwnershipLayoutResult::new();
2723
2724                for tuple_ty in tuple_ty_list.iter() {
2725                    let mut default_heap = DefaultOwnership::new(self.tcx(), self.owner());
2726
2727                    let _ = tuple_ty.visit_with(&mut default_heap);
2728                    res.update_from_default_heap_visitor(&mut default_heap);
2729                }
2730
2731                res
2732            }
2733            TyKind::Adt(adtdef, substs) => {
2734                // check the ty is or is not an enum and the variant of this enum is or is not given
2735                if adtdef.is_enum() && variant.is_none() {
2736                    return OwnershipLayoutResult::new();
2737                }
2738
2739                let mut res = OwnershipLayoutResult::new();
2740
2741                // check the ty if it is a struct or union
2742                if adtdef.is_struct() || adtdef.is_union() {
2743                    for field in adtdef.all_fields() {
2744                        let field_ty = field.ty(self.tcx(), substs);
2745
2746                        let mut default_heap = DefaultOwnership::new(self.tcx(), self.owner());
2747
2748                        let _ = field_ty.visit_with(&mut default_heap);
2749                        res.update_from_default_heap_visitor(&mut default_heap);
2750                    }
2751                }
2752                // check the ty which is an enum with a exact variant idx
2753                else if adtdef.is_enum() {
2754                    let vidx = variant.unwrap();
2755
2756                    for field in &adtdef.variants()[vidx].fields {
2757                        let field_ty = field.ty(self.tcx(), substs);
2758
2759                        let mut default_heap = DefaultOwnership::new(self.tcx(), self.owner());
2760
2761                        let _ = field_ty.visit_with(&mut default_heap);
2762                        res.update_from_default_heap_visitor(&mut default_heap);
2763                    }
2764                }
2765                res
2766            }
2767            TyKind::Param(..) => {
2768                let mut res = OwnershipLayoutResult::new();
2769                res.set_requirement(true);
2770                res.set_param(true);
2771                res.set_owned(true);
2772                res.layout_mut().push(OwnedHeap::True);
2773                res
2774            }
2775            TyKind::RawPtr(..) => {
2776                let mut res = OwnershipLayoutResult::new();
2777                res.set_requirement(true);
2778                res.layout_mut().push(OwnedHeap::False);
2779                res
2780            }
2781            TyKind::Ref(..) => {
2782                let mut res = OwnershipLayoutResult::new();
2783                res.set_requirement(true);
2784                res.layout_mut().push(OwnedHeap::False);
2785                res
2786            }
2787            _ => OwnershipLayoutResult::new(),
2788        }
2789    }
2790
2791    pub(crate) fn generate_ptr_layout(
2792        &mut self,
2793        ty: Ty<'tcx>,
2794        variant: Option<VariantIdx>,
2795    ) -> Vec<bool> {
2796        let mut res = Vec::new();
2797        match ty.kind() {
2798            TyKind::Array(..) => {
2799                res.push(false);
2800                res
2801            }
2802            TyKind::Tuple(tuple_ty_list) => {
2803                for tuple_ty in tuple_ty_list.iter() {
2804                    if tuple_ty.is_any_ptr() {
2805                        res.push(true);
2806                    } else {
2807                        res.push(false);
2808                    }
2809                }
2810
2811                res
2812            }
2813            TyKind::Adt(adtdef, _substs) => {
2814                // check the ty is or is not an enum and the variant of this enum is or is not given
2815                if adtdef.is_enum() && variant.is_none() {
2816                    return res;
2817                }
2818
2819                // check the ty if it is a struct or union
2820                if adtdef.is_struct() || adtdef.is_union() {
2821                    for _field in adtdef.all_fields() {
2822                        res.push(false);
2823                    }
2824                }
2825                // check the ty which is an enum with a exact variant idx
2826                else if adtdef.is_enum() {
2827                    let vidx = variant.unwrap();
2828
2829                    for _field in &adtdef.variants()[vidx].fields {
2830                        res.push(false);
2831                    }
2832                }
2833                res
2834            }
2835            TyKind::Param(..) => {
2836                res.push(false);
2837                res
2838            }
2839            TyKind::RawPtr(..) => {
2840                res.push(true);
2841                res
2842            }
2843            TyKind::Ref(..) => {
2844                res.push(true);
2845                res
2846            }
2847            _ => res,
2848        }
2849    }
2850
2851    fn extract_projection(&self, place: &Place<'tcx>, aggre: Aggre) -> ProjectionSupport<'tcx> {
2852        // Extract the field index of the place:
2853        // If the ProjectionElem finds the variant is not Field, stop and exit!
2854        // This method is used for field sensitivity analysis only!
2855        let mut prj: ProjectionSupport<'tcx> = ProjectionSupport::default();
2856        if aggre.is_some() {
2857            // if the 'Aggregate' is Some, that means ProjectionSupport is used for a local constructor.
2858            // Therefore, we do not need to record the ty of such field, instead, the projection
2859            // records the ty of the place, it is correct, because for local constructor, we do
2860            // not use the type information of the filed, but only need the index to init them one by one.
2861            let ty = place.ty(&self.body.local_decls, self.tcx());
2862            prj.pf_vec.push((aggre.unwrap(), ty.ty));
2863            return prj;
2864        }
2865        for (idx, each_pj) in place.projection.iter().enumerate() {
2866            match each_pj {
2867                ProjectionElem::Field(field, ty) => {
2868                    prj.pf_push(field.index(), ty);
2869                    if prj.pf_vec.len() > 1 {
2870                        prj.unsupport = true;
2871                        break;
2872                    }
2873                    if prj.deref {
2874                        prj.unsupport = true;
2875                        break;
2876                    }
2877                }
2878                ProjectionElem::Deref => {
2879                    prj.deref = true;
2880                    if idx > 0 {
2881                        prj.unsupport = true;
2882                        break;
2883                    }
2884                }
2885                ProjectionElem::Downcast(.., ref vidx) => {
2886                    prj.downcast = Some(*vidx);
2887                    if idx > 0 {
2888                        prj.unsupport = true;
2889                        break;
2890                    }
2891                }
2892                ProjectionElem::ConstantIndex { .. }
2893                | ProjectionElem::Subslice { .. }
2894                | ProjectionElem::Index(..)
2895                | ProjectionElem::OpaqueCast(..) => {
2896                    prj.unsupport = true;
2897                    break;
2898                }
2899                _ => todo!(),
2900            }
2901        }
2902        prj
2903    }
2904}
2905
2906fn new_local_name(local: usize, bidx: usize, sidx: usize) -> String {
2907    let s = bidx
2908        .to_string()
2909        .add("_")
2910        .add(&sidx.to_string())
2911        .add("_")
2912        .add(&local.to_string());
2913    s
2914}
2915
2916fn is_place_containing_ptr(ty: &Ty) -> bool {
2917    match ty.kind() {
2918        TyKind::Tuple(tuple_ty_list) => {
2919            for tuple_ty in tuple_ty_list.iter() {
2920                if tuple_ty.is_any_ptr() {
2921                    return true;
2922                }
2923            }
2924            false
2925        }
2926        TyKind::RawPtr(..) => true,
2927        TyKind::Ref(..) => true,
2928        _ => false,
2929    }
2930}
2931
2932#[derive(Debug)]
2933struct ProjectionSupport<'tcx> {
2934    pf_vec: Vec<(usize, Ty<'tcx>)>,
2935    deref: bool,
2936    downcast: Disc,
2937    unsupport: bool,
2938}
2939
2940impl<'tcx> Default for ProjectionSupport<'tcx> {
2941    fn default() -> Self {
2942        Self {
2943            pf_vec: Vec::default(),
2944            deref: false,
2945            downcast: None,
2946            unsupport: false,
2947        }
2948    }
2949}
2950
2951impl<'tcx> ProjectionSupport<'tcx> {
2952    pub fn pf_push(&mut self, index: usize, ty: Ty<'tcx>) {
2953        self.pf_vec.push((index, ty));
2954    }
2955
2956    pub fn is_unsupported(&self) -> bool {
2957        self.unsupport == true
2958    }
2959
2960    pub fn has_field(&self) -> bool {
2961        self.pf_vec.len() > 0
2962    }
2963
2964    pub fn has_downcast(&self) -> bool {
2965        self.downcast.is_some()
2966    }
2967
2968    pub fn downcast(&self) -> Disc {
2969        self.downcast
2970    }
2971
2972    pub fn index_needed(&self) -> usize {
2973        self.pf_vec[0].0
2974    }
2975}
2976
2977fn has_projection(place: &Place) -> bool {
2978    return if place.projection.len() > 0 {
2979        true
2980    } else {
2981        false
2982    };
2983}
2984
2985fn heap_layout_to_rustbv(layout: &Vec<OwnedHeap>) -> Vec<bool> {
2986    let mut v = Vec::default();
2987    for item in layout.iter() {
2988        match item {
2989            OwnedHeap::Unknown => rap_error!("item of raw type owner is uninit"),
2990            OwnedHeap::False => v.push(false),
2991            OwnedHeap::True => v.push(true),
2992        }
2993    }
2994    v
2995}
2996
2997fn reverse_heap_layout_to_rustbv(layout: &Vec<OwnedHeap>) -> Vec<bool> {
2998    let mut v = Vec::default();
2999    for item in layout.iter() {
3000        match item {
3001            OwnedHeap::Unknown => rap_error!("item of raw type owner is uninit"),
3002            OwnedHeap::False => v.push(true),
3003            OwnedHeap::True => v.push(false),
3004        }
3005    }
3006    v
3007}
3008
3009fn rustbv_merge(a: &Vec<bool>, b: &Vec<bool>) -> Vec<bool> {
3010    assert_eq!(a.len(), b.len());
3011    let mut bv = Vec::new();
3012    for idx in 0..a.len() {
3013        bv.push(a[idx] || b[idx]);
3014    }
3015    bv
3016}
3017
3018// Create an unsigned integer from bit bit-vector.
3019// The bit-vector has n bits
3020// the i'th bit (counting from 0 to n-1) is 1 if ans div 2^i mod 2 is 1.
3021fn rustbv_to_int(bv: &Vec<bool>) -> u64 {
3022    let mut ans = 0;
3023    let mut base = 1;
3024    for tf in bv.iter() {
3025        ans = ans + base * (*tf as u64);
3026        base = base * 2;
3027    }
3028    ans
3029}
3030
3031fn help_debug_goal_stmt<'tcx, 'ctx>(
3032    ctx: &'ctx z3::Context,
3033    goal: &'ctx z3::Goal<'ctx>,
3034    bidx: usize,
3035    sidx: usize,
3036) {
3037    let debug_name = format!("CONSTRAINTS: S {} {}", bidx, sidx);
3038    let dbg_bool = ast::Bool::new_const(ctx, debug_name);
3039    goal.assert(&dbg_bool);
3040}
3041
3042fn help_debug_goal_term<'tcx, 'ctx>(
3043    ctx: &'ctx z3::Context,
3044    goal: &'ctx z3::Goal<'ctx>,
3045    bidx: usize,
3046) {
3047    let debug_name = format!("CONSTRAINTS: T {}", bidx);
3048    let dbg_bool = ast::Bool::new_const(ctx, debug_name);
3049    goal.assert(&dbg_bool);
3050}