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 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 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_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 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_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}