rapx/analysis/range/domain/
interproc.rs1use crate::analysis::range::domain::ConstraintGraph;
2use crate::analysis::range::domain::domain::CallOp;
3use crate::analysis::range::domain::domain::{ConstConvert, IntervalArithmetic, VarNodes};
4use crate::analysis::range::{Range, RangeType};
5use crate::compat::FxHashMap;
6use rustc_hir::def_id::DefId;
7use rustc_middle::mir::Operand;
8use rustc_middle::mir::Place;
9use std::cell::RefCell;
10use std::fmt::Debug;
11use std::rc::Rc;
12
13impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> CallOp<'tcx, T> {
14 pub fn eval_call(
15 &self,
16 caller_vars: &VarNodes<'tcx, T>,
17 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
18 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
19 ) -> Range<T> {
20 match self.fun_path.as_str() {
21 "std::iter::IntoIterator::into_iter" => match self.args.first() {
22 Some(Operand::Copy(place)) | Some(Operand::Move(place)) => {
23 rap_trace!(
24 "Iterator detected on place {:?}, returning its range",
25 place
26 );
27 if let Some(var_node) = caller_vars.get(place) {
28 let range = var_node.get_range().clone();
29 rap_trace!(
30 "Iterator detected on place {:?}, returning its range: {:?}",
31 place,
32 range
33 );
34 return range;
35 }
36 }
37 _ => {}
38 },
39 "std::iter::Iterator::next" => match self.args.first() {
40 Some(Operand::Copy(place)) | Some(Operand::Move(place)) => {
41 rap_trace!(
42 "Iterator next detected on place {:?}, returning its range",
43 place
44 );
45 if let Some(var_node) = caller_vars.get(place) {
46 let range = var_node.get_range().clone();
47 rap_trace!(
48 "Iterator next detected on place {:?}, returning its range: {:?}",
49 place,
50 range
51 );
52 return range;
53 }
54 }
55 _ => {}
56 },
57 "core::slice::<impl [T]>::len" => {
58 let mut result = Range::bottom();
59 match self.args.last() {
60 Some(Operand::Copy(place)) | Some(Operand::Move(place)) => {
61 let range = caller_vars[place].get_range().clone();
62 let len = range
63 .get_upper()
64 .clone()
65 .checked_sub(&range.get_lower().clone())
66 .unwrap_or_else(|| {
67 rap_trace!(
68 "len() subtraction overflow for range {:?}, returning [0, max]",
69 range
70 );
71 T::max_value()
72 });
73 result = Range::exact(len.clone());
74 }
75 Some(Operand::Constant(c)) => {}
76 None => {}
77 #[cfg(rapx_ge_99)]
78 _ => {}
79 }
80 rap_trace!(
81 "len() detected on place {:?}, returning its range: {:?}",
82 self.sink,
83 result
84 );
85 return result;
86 }
87 "std::ops::IndexMut::index_mut" => {
88 let mut result = Range::bottom();
89
90 match self.args.last() {
91 Some(Operand::Copy(place)) | Some(Operand::Move(place)) => {
92 result = caller_vars[place].get_range().clone();
93 }
94 Some(Operand::Constant(c)) => {}
95 None => {}
96 #[cfg(rapx_ge_99)]
97 _ => {}
98 }
99
100 rap_trace!(
101 "IndexMut detected on place {:?}, returning its range: {:?}",
102 self.sink,
103 result
104 );
105 return result;
106 }
107 "std::ops::Index::index" => {
108 let mut result = Range::bottom();
109
110 match self.args.last() {
111 Some(Operand::Copy(place)) | Some(Operand::Move(place)) => {
112 result = caller_vars[place].get_range().clone();
113 }
114 Some(Operand::Constant(c)) => {}
115 None => {}
116 #[cfg(rapx_ge_99)]
117 _ => {}
118 }
119
120 rap_trace!(
121 "Index detected on place {:?}, returning its range: {:?}",
122 self.sink,
123 result
124 );
125 return result;
126 }
127 "core::panicking::panic" | "std::panicking::panic" => {
128 rap_trace!("Panic call detected, returning bottom range.");
129 return Range::new(T::max_value(), T::min_value(), RangeType::Empty);
130 }
131 _ => {}
132 }
133 if let Some(rc_callee_cg_cell) = cg_map.get(&self.def_id) {
135 rap_debug!(
136 "Evaluating call to {:?} with args {:?}",
137 self.def_id,
138 self.args
139 );
140 if let Ok(mut callee_cg) = rc_callee_cg_cell.try_borrow_mut() {
143 for (i, caller_arg_operand) in self.args.iter().enumerate() {
146 rap_debug!(
147 "Processing argument {}: {:?} to callee {:?}",
148 i,
149 caller_arg_operand,
150 self.def_id
151 );
152 match caller_arg_operand {
153 Operand::Copy(caller_arg_place) | Operand::Move(caller_arg_place) => {
154 let callee_arg_local = rustc_middle::mir::Local::from_usize(i + 1);
157
158 if let Some(callee_arg_node) = callee_cg.vars.values_mut().find(|v| {
160 v.v.local == callee_arg_local && v.v.projection.is_empty()
161 }) {
162 if let Some(caller_arg_node) = caller_vars.get(&caller_arg_place) {
164 let arg_range = caller_arg_node.get_range().clone();
165 callee_arg_node.set_range(arg_range);
166 rap_debug!(
167 "Passing argument from {:?} to callee {:?} : {:?} {:?} -> {:?}",
168 caller_arg_place,
169 self.def_id,
170 callee_arg_node.get_value(),
171 caller_arg_node.get_range(),
172 callee_arg_node.get_range()
173 );
174 }
175 }
176 }
177 Operand::Constant(const_operand) => {
178 rap_debug!(
179 "constant argument {:?} to callee {:?}",
180 const_operand,
181 self.def_id
182 );
183 let callee_arg_local = rustc_middle::mir::Local::from_usize(i + 1);
184 if let Some(const_value) = T::from_const(&const_operand.const_) {
185 if let Some(callee_arg_node) =
186 callee_cg.vars.values_mut().find(|v| {
187 v.v.local == callee_arg_local && v.v.projection.is_empty()
188 })
189 {
190 let arg_range = Range::new(
193 const_value.clone(),
194 const_value.clone(),
195 RangeType::Regular,
196 );
197 callee_arg_node.set_range(arg_range.clone());
198 rap_debug!(
199 "Passing argument from {:?} to callee {:?} : {:?} {:?} -> {:?}",
200 const_value,
201 self.def_id,
202 callee_arg_node.get_value(),
203 arg_range,
204 callee_arg_node.get_range()
205 );
206 }
207 }
208 }
210 #[cfg(rapx_ge_99)]
211 Operand::RuntimeChecks(_) => {}
212 }
213 }
214
215 callee_cg.find_intervals(cg_map, vars_map);
220
221 let return_place_local = 0 as usize; if let Some(return_node) = callee_cg.vars.get_mut(&Place::return_place()) {
228 let return_range = return_node.get_range().clone();
229 rap_debug!(" final return range {:?} ", return_range);
230 return return_range;
231 }
232 let Some(callee_varnodes_vec) = vars_map.get_mut(&self.def_id) else {
233 panic!(
234 "No variable map entry for this function {:?}, skipping Nuutila\n",
235 self.def_id
236 );
237 };
238 callee_cg.reset_vars(callee_varnodes_vec);
239 } else {
240 rap_trace!(
243 "Recursive call or existing borrow for {:?}, returning top.",
244 self.def_id
245 );
246 return Range::top();
247 }
248 }
249
250 rap_trace!(
253 "Callee ConstraintGraph for {:?} not found, returning top.",
254 self.def_id
255 );
256 Range::top()
257}
258}