Skip to main content

rapx/check/rcanary/ranalyzer/
intra_visitor.rs

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