rapx/analysis/range_analysis/domain/
SymbolicExpr.rs

1#![allow(unused_imports)]
2#![allow(unused_variables)]
3#![allow(dead_code)]
4#![allow(unused_assignments)]
5#![allow(unused_parens)]
6#![allow(non_snake_case)]
7use rust_intervals::NothingBetween;
8
9use crate::analysis::range_analysis::domain::ConstraintGraph::ConstraintGraph;
10use crate::analysis::range_analysis::domain::domain::{
11    ConstConvert, IntervalArithmetic, VarNode, VarNodes,
12};
13use crate::analysis::range_analysis::{Range, RangeType};
14use crate::compat::FxHashMap;
15use crate::{rap_debug, rap_trace};
16use num_traits::{Bounded, CheckedAdd, CheckedSub, One, ToPrimitive, Zero, ops};
17use rustc_abi::Size;
18use rustc_hir::def_id::DefId;
19use rustc_middle::mir::coverage::Op;
20use rustc_middle::mir::{
21    BasicBlock, BinOp, BorrowKind, CastKind, Const, Local, LocalDecl, Operand, Place, Rvalue,
22    Statement, StatementKind, Terminator, UnOp,
23};
24use rustc_middle::ty::{ScalarInt, Ty};
25use rustc_span::sym::no_default_passes;
26use std::cell::RefCell;
27use std::cmp::PartialEq;
28use std::collections::{HashMap, HashSet};
29use std::fmt::Debug;
30use std::hash::Hash;
31use std::ops::{Add, Mul, Sub};
32use std::rc::Rc;
33use std::{fmt, mem};
34#[derive(Debug, Clone, Copy, PartialEq)]
35pub enum BoundMode {
36    Lower,
37    Upper,
38}
39
40impl BoundMode {
41    fn flip(self) -> Self {
42        match self {
43            BoundMode::Lower => BoundMode::Upper,
44            BoundMode::Upper => BoundMode::Lower,
45        }
46    }
47}
48#[derive(Debug, Clone, PartialEq, Eq)]
49pub enum SymbExpr<'tcx> {
50    Constant(Const<'tcx>),
51
52    Place(&'tcx Place<'tcx>),
53
54    Binary(BinOp, Box<SymbExpr<'tcx>>, Box<SymbExpr<'tcx>>),
55
56    Unary(UnOp, Box<SymbExpr<'tcx>>),
57
58    Cast(CastKind, Box<SymbExpr<'tcx>>, Ty<'tcx>),
59
60    Unknown,
61}
62impl<'tcx> fmt::Display for SymbExpr<'tcx> {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        write!(f, "{:?}", self)
65    }
66}
67impl<'tcx> SymbExpr<'tcx> {
68    pub fn from_operand(op: &'tcx Operand<'tcx>, place_ctx: &Vec<&'tcx Place<'tcx>>) -> Self {
69        match op {
70            Operand::Copy(place) | Operand::Move(place) => {
71                let found_base = place_ctx
72                    .iter()
73                    .find(|&&p| p.local == place.local && p.projection.is_empty());
74
75                match found_base {
76                    Some(&base_place) => SymbExpr::Place(base_place),
77
78                    None => SymbExpr::Place(place),
79                }
80            }
81            Operand::Constant(c) => SymbExpr::Constant(c.const_),
82            #[cfg(rapx_rustc_ge_196)]
83            Operand::RuntimeChecks(_) => SymbExpr::Unknown,
84        }
85    }
86
87    pub fn from_rvalue(rvalue: &'tcx Rvalue<'tcx>, place_ctx: Vec<&'tcx Place<'tcx>>) -> Self {
88        match rvalue {
89            Rvalue::Use(op, ..) => Self::from_operand(op, &place_ctx),
90            Rvalue::BinaryOp(bin_op, pair) => {
91                let (lhs, rhs) = &**pair;
92                let left = Self::from_operand(lhs, &place_ctx);
93                let right = Self::from_operand(rhs, &place_ctx);
94
95                if matches!(left, SymbExpr::Unknown) || matches!(right, SymbExpr::Unknown) {
96                    return SymbExpr::Unknown;
97                }
98
99                SymbExpr::Binary(*bin_op, Box::new(left), Box::new(right))
100            }
101            Rvalue::UnaryOp(un_op, op) => {
102                let expr = Self::from_operand(op, &place_ctx);
103                if matches!(expr, SymbExpr::Unknown) {
104                    return SymbExpr::Unknown;
105                }
106                SymbExpr::Unary(*un_op, Box::new(expr))
107            }
108            Rvalue::Cast(kind, op, ty) => {
109                let expr = Self::from_operand(op, &place_ctx);
110                if matches!(expr, SymbExpr::Unknown) {
111                    return SymbExpr::Unknown;
112                }
113                SymbExpr::Cast(*kind, Box::new(expr), *ty)
114            }
115            Rvalue::Ref(..)
116            | Rvalue::ThreadLocalRef(..)
117            | Rvalue::Aggregate(..)
118            | Rvalue::Repeat(..)
119            | Rvalue::Discriminant(..)
120            | Rvalue::CopyForDeref(..) => SymbExpr::Unknown,
121            #[cfg(not(rapx_rustc_ge_196))]
122            Rvalue::ShallowInitBox(..) | Rvalue::NullaryOp(..) => SymbExpr::Unknown,
123            #[cfg(rapx_rustc_ge_198)]
124            Rvalue::Reborrow(..) => SymbExpr::Unknown,
125            Rvalue::RawPtr(raw_ptr_kind, place) => todo!(),
126            Rvalue::WrapUnsafeBinder(operand, ty) => todo!(),
127        }
128    }
129
130    // pub fn eval<T: IntervalArithmetic + ConstConvert + Debug>(
131    //     &self,
132    //     vars: &VarNodes<'tcx, T>,
133    // ) -> Range<T> {
134    //     match self {
135    //         SymbExpr::Unknown => Range::new(T::min_value(), T::max_value(), RangeType::Regular),
136
137    //         SymbExpr::Constant(c) => {
138    //             if let Some(val) = T::from_const(c) {
139    //                 Range::new(val, val, RangeType::Regular)
140    //             } else {
141    //                 Range::new(T::min_value(), T::max_value(), RangeType::Regular)
142    //             }
143    //         }
144
145    //         SymbExpr::Place(place) => {
146    //             if let Some(node) = vars.get(place) {
147    //                 node.get_range().clone()
148    //             } else {
149    //                 Range::new(T::min_value(), T::max_value(), RangeType::Regular)
150    //             }
151    //         }
152
153    //         SymbExpr::Binary(op, lhs, rhs) => {
154    //             let l_range = lhs.eval(vars);
155    //             let r_range = rhs.eval(vars);
156
157    //             match op {
158    //                 BinOp::Add | BinOp::AddUnchecked | BinOp::AddWithOverflow => {
159    //                     l_range.add(&r_range)
160    //                 }
161    //                 BinOp::Sub | BinOp::SubUnchecked | BinOp::SubWithOverflow => {
162    //                     l_range.sub(&r_range)
163    //                 }
164    //                 BinOp::Mul | BinOp::MulUnchecked | BinOp::MulWithOverflow => {
165    //                     l_range.mul(&r_range)
166    //                 }
167
168    //                 _ => Range::new(T::min_value(), T::max_value(), RangeType::Regular),
169    //             }
170    //         }
171
172    //         SymbExpr::Unary(op, inner) => {
173    //             let _inner_range = inner.eval(vars);
174    //             match op {
175    //                 UnOp::Neg => Range::new(T::min_value(), T::max_value(), RangeType::Regular),
176    //                 UnOp::Not | UnOp::PtrMetadata => {
177    //                     Range::new(T::min_value(), T::max_value(), RangeType::Regular)
178    //                 }
179    //             }
180    //         }
181
182    //         SymbExpr::Cast(kind, inner, _target_ty) => {
183    //             let inner_range = inner.eval(vars);
184    //             match kind {
185    //                 CastKind::IntToInt => inner_range,
186
187    //                 _ => Range::new(T::min_value(), T::max_value(), RangeType::Regular),
188    //             }
189    //         }
190    //     }
191    // }
192    pub fn resolve_upper_bound<T: IntervalArithmetic + ConstConvert + Debug + Clone + PartialEq>(
193        &mut self,
194        vars: &VarNodes<'tcx, T>,
195    ) {
196        self.resolve_recursive(vars, 0, BoundMode::Upper);
197    }
198    pub fn resolve_lower_bound<T: IntervalArithmetic + ConstConvert + Debug + Clone + PartialEq>(
199        &mut self,
200        vars: &VarNodes<'tcx, T>,
201    ) {
202        self.resolve_recursive(vars, 0, BoundMode::Lower);
203    }
204
205    fn resolve_recursive<T: IntervalArithmetic + ConstConvert + Debug + Clone + PartialEq>(
206        &mut self,
207        vars: &VarNodes<'tcx, T>,
208        depth: usize,
209        mode: BoundMode,
210    ) {
211        const MAX_DEPTH: usize = 10;
212        if depth > MAX_DEPTH {
213            *self = SymbExpr::Unknown;
214            return;
215        }
216
217        match self {
218            SymbExpr::Binary(op, lhs, rhs) => {
219                lhs.resolve_recursive(vars, depth + 1, mode);
220
221                match op {
222                    BinOp::Add | BinOp::AddUnchecked | BinOp::AddWithOverflow => {
223                        rhs.resolve_recursive(vars, depth + 1, mode);
224                    }
225                    BinOp::Sub | BinOp::SubUnchecked | BinOp::SubWithOverflow => {
226                        rhs.resolve_recursive(vars, depth + 1, mode.flip());
227                    }
228                    _ => rhs.resolve_recursive(vars, depth + 1, mode),
229                }
230            }
231            SymbExpr::Unary(op, inner) => match op {
232                UnOp::Neg => {
233                    inner.resolve_recursive(vars, depth + 1, mode.flip());
234                }
235                _ => inner.resolve_recursive(vars, depth + 1, mode),
236            },
237            SymbExpr::Cast(_, inner, _) => {
238                inner.resolve_recursive(vars, depth + 1, mode);
239            }
240            _ => {}
241        }
242
243        // self.try_fold_constants::<T>();
244        rap_trace!("symexpr {}", self);
245        if let SymbExpr::Place(place) = self {
246            if let Some(node) = vars.get(place) {
247                if let IntervalType::Basic(basic) = &node.interval {
248                    rap_trace!("node {:?}", *node);
249
250                    let target_expr = if basic.lower == basic.upper {
251                        &basic.upper
252                    } else {
253                        match mode {
254                            BoundMode::Upper => &basic.upper,
255                            BoundMode::Lower => &basic.lower,
256                        }
257                    };
258
259                    match target_expr {
260                        SymbExpr::Unknown => *self = SymbExpr::Unknown,
261                        SymbExpr::Constant(c) => *self = SymbExpr::Constant(c.clone()),
262                        expr => {
263                            if let SymbExpr::Place(target_place) = expr {
264                                if target_place == place {
265                                    return;
266                                }
267                            }
268
269                            *self = expr.clone();
270                            self.resolve_recursive(vars, depth + 1, mode);
271                        }
272                    }
273                }
274            }
275        }
276    }
277    pub fn simplify(&mut self) {
278        match self {
279            SymbExpr::Binary(_, lhs, rhs) => {
280                lhs.simplify();
281                rhs.simplify();
282            }
283            SymbExpr::Unary(_, inner) => {
284                inner.simplify();
285            }
286            SymbExpr::Cast(_, inner, _) => {
287                inner.simplify();
288            }
289            _ => {}
290        }
291
292        if let SymbExpr::Binary(op, lhs, rhs) = self {
293            match op {
294                BinOp::Sub | BinOp::SubUnchecked | BinOp::SubWithOverflow => {
295                    if let SymbExpr::Binary(inner_op, inner_lhs, inner_rhs) = lhs.as_ref() {
296                        match inner_op {
297                            BinOp::Add | BinOp::AddUnchecked | BinOp::AddWithOverflow => {
298                                if inner_lhs == rhs {
299                                    *self = *inner_rhs.clone();
300                                } else if inner_rhs == rhs {
301                                    *self = *inner_lhs.clone();
302                                }
303                            }
304                            _ => {}
305                        }
306                    }
307                }
308                BinOp::Add | BinOp::AddUnchecked | BinOp::AddWithOverflow => {
309                    if let SymbExpr::Binary(inner_op, inner_lhs, inner_rhs) = lhs.as_ref() {
310                        match inner_op {
311                            BinOp::Sub | BinOp::SubUnchecked | BinOp::SubWithOverflow => {
312                                if inner_rhs == rhs {
313                                    *self = *inner_lhs.clone();
314                                }
315                            }
316                            _ => {}
317                        }
318                    }
319                }
320                _ => {}
321            }
322        }
323    }
324}
325#[derive(Debug, Clone)]
326pub enum IntervalType<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
327    Basic(BasicInterval<'tcx, T>),
328    Symb(SymbInterval<'tcx, T>),
329}
330
331impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> fmt::Display for IntervalType<'tcx, T> {
332    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
333        match self {
334            IntervalType::Basic(b) => write!(
335                f,
336                "BasicInterval: {:?} {:?} {:?} ",
337                b.get_range(),
338                b.lower,
339                b.upper
340            ),
341            IntervalType::Symb(b) => write!(
342                f,
343                "SymbInterval: {:?} {:?} {:?} ",
344                b.get_range(),
345                b.lower,
346                b.upper
347            ),
348        }
349    }
350}
351pub trait IntervalTypeTrait<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
352    fn get_range(&self) -> &Range<T>;
353    fn set_range(&mut self, new_range: Range<T>);
354    fn get_lower_expr(&self) -> &SymbExpr<'tcx>;
355    fn get_upper_expr(&self) -> &SymbExpr<'tcx>;
356}
357impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> IntervalTypeTrait<'tcx, T>
358    for IntervalType<'tcx, T>
359{
360    fn get_range(&self) -> &Range<T> {
361        match self {
362            IntervalType::Basic(b) => b.get_range(),
363            IntervalType::Symb(s) => s.get_range(),
364        }
365    }
366
367    fn set_range(&mut self, new_range: Range<T>) {
368        match self {
369            IntervalType::Basic(b) => b.set_range(new_range),
370            IntervalType::Symb(s) => s.set_range(new_range),
371        }
372    }
373    fn get_lower_expr(&self) -> &SymbExpr<'tcx> {
374        match self {
375            IntervalType::Basic(b) => b.get_lower_expr(),
376            IntervalType::Symb(s) => s.get_lower_expr(),
377        }
378    }
379
380    fn get_upper_expr(&self) -> &SymbExpr<'tcx> {
381        match self {
382            IntervalType::Basic(b) => b.get_upper_expr(),
383            IntervalType::Symb(s) => s.get_upper_expr(),
384        }
385    }
386}
387#[derive(Debug, Clone)]
388
389pub struct BasicInterval<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
390    pub range: Range<T>,
391    pub lower: SymbExpr<'tcx>,
392    pub upper: SymbExpr<'tcx>,
393}
394
395impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> BasicInterval<'tcx, T> {
396    pub fn new(range: Range<T>) -> Self {
397        Self {
398            range,
399            lower: SymbExpr::Unknown,
400            upper: SymbExpr::Unknown,
401        }
402    }
403    pub fn new_symb(range: Range<T>, lower: SymbExpr<'tcx>, upper: SymbExpr<'tcx>) -> Self {
404        Self {
405            range,
406            lower,
407            upper,
408        }
409    }
410    pub fn default() -> Self {
411        Self {
412            range: Range::default(T::min_value()),
413            lower: SymbExpr::Unknown,
414            upper: SymbExpr::Unknown,
415        }
416    }
417}
418
419impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> IntervalTypeTrait<'tcx, T>
420    for BasicInterval<'tcx, T>
421{
422    // fn get_value_id(&self) -> IntervalId {
423    //     IntervalId::BasicIntervalId
424    // }
425
426    fn get_range(&self) -> &Range<T> {
427        &self.range
428    }
429
430    fn set_range(&mut self, new_range: Range<T>) {
431        self.range = new_range;
432        if self.range.get_lower() > self.range.get_upper() {
433            self.range.set_empty();
434        }
435    }
436    fn get_lower_expr(&self) -> &SymbExpr<'tcx> {
437        &self.lower
438    }
439
440    fn get_upper_expr(&self) -> &SymbExpr<'tcx> {
441        &self.upper
442    }
443}
444
445#[derive(Debug, Clone)]
446
447pub struct SymbInterval<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
448    range: Range<T>,
449    symbound: &'tcx Place<'tcx>,
450    predicate: BinOp,
451    lower: SymbExpr<'tcx>,
452    upper: SymbExpr<'tcx>,
453}
454
455impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> SymbInterval<'tcx, T> {
456    pub fn new(range: Range<T>, symbound: &'tcx Place<'tcx>, predicate: BinOp) -> Self {
457        Self {
458            range,
459            symbound,
460            predicate,
461            lower: SymbExpr::Unknown,
462            upper: SymbExpr::Unknown,
463        }
464    }
465
466    // pub fn refine(&mut self, vars: &VarNodes<'tcx, T>) {
467    //     if let SymbExpr::Unknown = self.lower {
468    //     } else {
469    //         let low_range = self.lower.eval(vars);
470    //         if low_range.get_lower() > self.range.get_lower() {
471    //             let new_range = Range::new(
472    //                 low_range.get_lower(),
473    //                 self.range.get_upper(),
474    //                 RangeType::Regular,
475    //             );
476    //             self.range = new_range;
477    //         }
478    //     }
479
480    //     if let SymbExpr::Unknown = self.upper {
481    //         // Do nothing
482    //     } else {
483    //         let high_range = self.upper.eval(vars);
484    //         if high_range.get_upper() < self.range.get_upper() {
485    //             let new_range = Range::new(
486    //                 self.range.get_lower(),
487    //                 high_range.get_upper(),
488    //                 RangeType::Regular,
489    //             );
490    //             self.range = new_range;
491    //         }
492    //     }
493    // }
494
495    pub fn get_operation(&self) -> BinOp {
496        self.predicate
497    }
498
499    pub fn get_bound(&self) -> &'tcx Place<'tcx> {
500        self.symbound
501    }
502
503    pub fn sym_fix_intersects(
504        &self,
505        bound: &VarNode<'tcx, T>,
506        sink: &VarNode<'tcx, T>,
507    ) -> Range<T> {
508        let l = bound.get_range().get_lower().clone();
509        let u = bound.get_range().get_upper().clone();
510
511        let lower = sink.get_range().get_lower().clone();
512        let upper = sink.get_range().get_upper().clone();
513
514        match self.predicate {
515            BinOp::Eq => Range::new(l, u, RangeType::Regular),
516
517            BinOp::Le => Range::new(lower, u, RangeType::Regular),
518
519            BinOp::Lt => {
520                if u != T::max_value() {
521                    let u_minus_1 = u.checked_sub(&T::one()).unwrap_or(u);
522                    Range::new(lower, u_minus_1, RangeType::Regular)
523                } else {
524                    Range::new(lower, u, RangeType::Regular)
525                }
526            }
527
528            BinOp::Ge => Range::new(l, upper, RangeType::Regular),
529
530            BinOp::Gt => {
531                if l != T::min_value() {
532                    let l_plus_1 = l.checked_add(&T::one()).unwrap_or(l);
533                    Range::new(l_plus_1, upper, RangeType::Regular)
534                } else {
535                    Range::new(l, upper, RangeType::Regular)
536                }
537            }
538
539            BinOp::Ne => Range::new(T::min_value(), T::max_value(), RangeType::Regular),
540
541            _ => Range::new(T::min_value(), T::max_value(), RangeType::Regular),
542        }
543    }
544}
545
546impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> IntervalTypeTrait<'tcx, T>
547    for SymbInterval<'tcx, T>
548{
549    // fn get_value_id(&self) -> IntervalId {
550    //     IntervalId::SymbIntervalId
551    // }
552
553    fn get_range(&self) -> &Range<T> {
554        &self.range
555    }
556
557    fn set_range(&mut self, new_range: Range<T>) {
558        self.range = new_range;
559    }
560    fn get_lower_expr(&self) -> &SymbExpr<'tcx> {
561        &self.lower
562    }
563
564    fn get_upper_expr(&self) -> &SymbExpr<'tcx> {
565        &self.upper
566    }
567}