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::domain::ConstraintGraph;
10use crate::analysis::range::domain::domain::{
11 ConstConvert, IntervalArithmetic, VarNode, VarNodes,
12};
13use crate::analysis::range::{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_ge_99)]
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_ge_99))]
122 Rvalue::ShallowInitBox(..) | Rvalue::NullaryOp(..) => SymbExpr::Unknown,
123 #[cfg(rapx_ge_99)]
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 resolve_upper_bound<T: IntervalArithmetic + ConstConvert + Debug + Clone + PartialEq>(
131 &mut self,
132 vars: &VarNodes<'tcx, T>,
133 ) {
134 self.resolve_recursive(vars, 0, BoundMode::Upper);
135 }
136 pub fn resolve_lower_bound<T: IntervalArithmetic + ConstConvert + Debug + Clone + PartialEq>(
137 &mut self,
138 vars: &VarNodes<'tcx, T>,
139 ) {
140 self.resolve_recursive(vars, 0, BoundMode::Lower);
141 }
142
143 fn resolve_recursive<T: IntervalArithmetic + ConstConvert + Debug + Clone + PartialEq>(
144 &mut self,
145 vars: &VarNodes<'tcx, T>,
146 depth: usize,
147 mode: BoundMode,
148 ) {
149 const MAX_DEPTH: usize = 10;
150 if depth > MAX_DEPTH {
151 *self = SymbExpr::Unknown;
152 return;
153 }
154
155 match self {
156 SymbExpr::Binary(op, lhs, rhs) => {
157 lhs.resolve_recursive(vars, depth + 1, mode);
158
159 match op {
160 BinOp::Add | BinOp::AddUnchecked | BinOp::AddWithOverflow => {
161 rhs.resolve_recursive(vars, depth + 1, mode);
162 }
163 BinOp::Sub | BinOp::SubUnchecked | BinOp::SubWithOverflow => {
164 rhs.resolve_recursive(vars, depth + 1, mode.flip());
165 }
166 _ => rhs.resolve_recursive(vars, depth + 1, mode),
167 }
168 }
169 SymbExpr::Unary(op, inner) => match op {
170 UnOp::Neg => {
171 inner.resolve_recursive(vars, depth + 1, mode.flip());
172 }
173 _ => inner.resolve_recursive(vars, depth + 1, mode),
174 },
175 SymbExpr::Cast(_, inner, _) => {
176 inner.resolve_recursive(vars, depth + 1, mode);
177 }
178 _ => {}
179 }
180
181 rap_trace!("symexpr {}", self);
182 if let SymbExpr::Place(place) = self {
183 if let Some(node) = vars.get(place) {
184 if let IntervalType::Basic(basic) = &node.interval {
185 rap_trace!("node {:?}", *node);
186
187 let target_expr = if basic.lower == basic.upper {
188 &basic.upper
189 } else {
190 match mode {
191 BoundMode::Upper => &basic.upper,
192 BoundMode::Lower => &basic.lower,
193 }
194 };
195
196 match target_expr {
197 SymbExpr::Unknown => *self = SymbExpr::Unknown,
198 SymbExpr::Constant(c) => *self = SymbExpr::Constant(c.clone()),
199 expr => {
200 if let SymbExpr::Place(target_place) = expr {
201 if target_place == place {
202 return;
203 }
204 }
205
206 *self = expr.clone();
207 self.resolve_recursive(vars, depth + 1, mode);
208 }
209 }
210 }
211 }
212 }
213 }
214 pub fn simplify(&mut self) {
215 match self {
216 SymbExpr::Binary(_, lhs, rhs) => {
217 lhs.simplify();
218 rhs.simplify();
219 }
220 SymbExpr::Unary(_, inner) => {
221 inner.simplify();
222 }
223 SymbExpr::Cast(_, inner, _) => {
224 inner.simplify();
225 }
226 _ => {}
227 }
228
229 if let SymbExpr::Binary(op, lhs, rhs) = self {
230 match op {
231 BinOp::Sub | BinOp::SubUnchecked | BinOp::SubWithOverflow => {
232 if let SymbExpr::Binary(inner_op, inner_lhs, inner_rhs) = lhs.as_ref() {
233 match inner_op {
234 BinOp::Add | BinOp::AddUnchecked | BinOp::AddWithOverflow => {
235 if inner_lhs == rhs {
236 *self = *inner_rhs.clone();
237 } else if inner_rhs == rhs {
238 *self = *inner_lhs.clone();
239 }
240 }
241 _ => {}
242 }
243 }
244 }
245 BinOp::Add | BinOp::AddUnchecked | BinOp::AddWithOverflow => {
246 if let SymbExpr::Binary(inner_op, inner_lhs, inner_rhs) = lhs.as_ref() {
247 match inner_op {
248 BinOp::Sub | BinOp::SubUnchecked | BinOp::SubWithOverflow => {
249 if inner_rhs == rhs {
250 *self = *inner_lhs.clone();
251 }
252 }
253 _ => {}
254 }
255 }
256 }
257 _ => {}
258 }
259 }
260 }
261}
262#[derive(Debug, Clone)]
263pub enum IntervalType<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
264 Basic(BasicInterval<'tcx, T>),
265 Symb(SymbInterval<'tcx, T>),
266}
267
268impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> fmt::Display for IntervalType<'tcx, T> {
269 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270 match self {
271 IntervalType::Basic(b) => write!(
272 f,
273 "BasicInterval: {:?} {:?} {:?} ",
274 b.get_range(),
275 b.lower,
276 b.upper
277 ),
278 IntervalType::Symb(b) => write!(
279 f,
280 "SymbInterval: {:?} {:?} {:?} ",
281 b.get_range(),
282 b.lower,
283 b.upper
284 ),
285 }
286 }
287}
288pub trait IntervalTypeTrait<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
289 fn get_range(&self) -> &Range<T>;
290 fn set_range(&mut self, new_range: Range<T>);
291 fn get_lower_expr(&self) -> &SymbExpr<'tcx>;
292 fn get_upper_expr(&self) -> &SymbExpr<'tcx>;
293}
294impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> IntervalTypeTrait<'tcx, T>
295 for IntervalType<'tcx, T>
296{
297 fn get_range(&self) -> &Range<T> {
298 match self {
299 IntervalType::Basic(b) => b.get_range(),
300 IntervalType::Symb(s) => s.get_range(),
301 }
302 }
303
304 fn set_range(&mut self, new_range: Range<T>) {
305 match self {
306 IntervalType::Basic(b) => b.set_range(new_range),
307 IntervalType::Symb(s) => s.set_range(new_range),
308 }
309 }
310 fn get_lower_expr(&self) -> &SymbExpr<'tcx> {
311 match self {
312 IntervalType::Basic(b) => b.get_lower_expr(),
313 IntervalType::Symb(s) => s.get_lower_expr(),
314 }
315 }
316
317 fn get_upper_expr(&self) -> &SymbExpr<'tcx> {
318 match self {
319 IntervalType::Basic(b) => b.get_upper_expr(),
320 IntervalType::Symb(s) => s.get_upper_expr(),
321 }
322 }
323}
324#[derive(Debug, Clone)]
325
326pub struct BasicInterval<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
327 pub range: Range<T>,
328 pub lower: SymbExpr<'tcx>,
329 pub upper: SymbExpr<'tcx>,
330}
331
332impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> BasicInterval<'tcx, T> {
333 pub fn new(range: Range<T>) -> Self {
334 Self {
335 range,
336 lower: SymbExpr::Unknown,
337 upper: SymbExpr::Unknown,
338 }
339 }
340 pub fn new_symb(range: Range<T>, lower: SymbExpr<'tcx>, upper: SymbExpr<'tcx>) -> Self {
341 Self {
342 range,
343 lower,
344 upper,
345 }
346 }
347 pub fn default() -> Self {
348 Self {
349 range: Range::bottom(),
350 lower: SymbExpr::Unknown,
351 upper: SymbExpr::Unknown,
352 }
353 }
354}
355
356impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> IntervalTypeTrait<'tcx, T>
357 for BasicInterval<'tcx, T>
358{
359 fn get_range(&self) -> &Range<T> {
360 &self.range
361 }
362
363 fn set_range(&mut self, new_range: Range<T>) {
364 self.range = new_range;
365 if self.range.get_lower() > self.range.get_upper() {
366 self.range.set_empty();
367 }
368 }
369 fn get_lower_expr(&self) -> &SymbExpr<'tcx> {
370 &self.lower
371 }
372
373 fn get_upper_expr(&self) -> &SymbExpr<'tcx> {
374 &self.upper
375 }
376}
377
378#[derive(Debug, Clone)]
379
380pub struct SymbInterval<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
381 range: Range<T>,
382 symbound: &'tcx Place<'tcx>,
383 predicate: BinOp,
384 lower: SymbExpr<'tcx>,
385 upper: SymbExpr<'tcx>,
386}
387
388impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> SymbInterval<'tcx, T> {
389 pub fn new(range: Range<T>, symbound: &'tcx Place<'tcx>, predicate: BinOp) -> Self {
390 Self {
391 range,
392 symbound,
393 predicate,
394 lower: SymbExpr::Unknown,
395 upper: SymbExpr::Unknown,
396 }
397 }
398
399 pub fn get_operation(&self) -> BinOp {
400 self.predicate
401 }
402
403 pub fn get_bound(&self) -> &'tcx Place<'tcx> {
404 self.symbound
405 }
406
407 pub fn sym_fix_intersects(
408 &self,
409 bound: &VarNode<'tcx, T>,
410 sink: &VarNode<'tcx, T>,
411 ) -> Range<T> {
412 let l = bound.get_range().get_lower().clone();
413 let u = bound.get_range().get_upper().clone();
414
415 let lower = sink.get_range().get_lower().clone();
416 let upper = sink.get_range().get_upper().clone();
417
418 match self.predicate {
419 BinOp::Eq => Range::new(l, u, RangeType::Regular),
420
421 BinOp::Le => Range::new(lower, u, RangeType::Regular),
422
423 BinOp::Lt => {
424 if u != T::max_value() {
425 let u_minus_1 = u.checked_sub(&T::one()).unwrap_or(u);
426 Range::new(lower, u_minus_1, RangeType::Regular)
427 } else {
428 Range::new(lower, u, RangeType::Regular)
429 }
430 }
431
432 BinOp::Ge => Range::new(l, upper, RangeType::Regular),
433
434 BinOp::Gt => {
435 if l != T::min_value() {
436 let l_plus_1 = l.checked_add(&T::one()).unwrap_or(l);
437 Range::new(l_plus_1, upper, RangeType::Regular)
438 } else {
439 Range::new(l, upper, RangeType::Regular)
440 }
441 }
442
443 BinOp::Ne => Range::top(),
444
445 _ => Range::top(),
446 }
447 }
448}
449
450impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> IntervalTypeTrait<'tcx, T>
451 for SymbInterval<'tcx, T>
452{
453 fn get_range(&self) -> &Range<T> {
454 &self.range
455 }
456
457 fn set_range(&mut self, new_range: Range<T>) {
458 self.range = new_range;
459 }
460 fn get_lower_expr(&self) -> &SymbExpr<'tcx> {
461 &self.lower
462 }
463
464 fn get_upper_expr(&self) -> &SymbExpr<'tcx> {
465 &self.upper
466 }
467}