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