rapx/analysis/rcanary/ranalyzer/
intra_visitor.rs

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