rapx/analysis/core/alias_analysis/mfp/
mod.rs1pub mod interproc;
2pub mod intraproc;
3pub mod transfer;
4
5extern crate rustc_mir_dataflow;
6use rustc_data_structures::fx::{FxHashMap, FxHashSet};
7use rustc_hir::def_id::DefId;
8use rustc_middle::mir::{Operand, TerminatorKind};
9use rustc_middle::ty::{self, TyCtxt};
10use rustc_mir_dataflow::Analysis;
11use std::cell::RefCell;
12use std::rc::Rc;
13
14use super::{AliasAnalysis, FnAliasMap, FnAliasPairs};
15use crate::analysis::Analysis as RapxAnalysis;
16use intraproc::FnAliasAnalyzer;
17
18pub struct MfpAliasAnalyzer<'tcx> {
20 tcx: TyCtxt<'tcx>,
21 fn_map: FxHashMap<DefId, FnAliasPairs>,
23}
24
25impl<'tcx> MfpAliasAnalyzer<'tcx> {
26 pub fn new(tcx: TyCtxt<'tcx>) -> Self {
28 MfpAliasAnalyzer {
29 tcx,
30 fn_map: FxHashMap::default(),
31 }
32 }
33
34 fn get_arg_count(&self, def_id: DefId) -> Option<usize> {
36 if !self.tcx.is_mir_available(def_id) {
37 return None;
38 }
39 if let Some(local_def_id) = def_id.as_local() {
41 if self.tcx.hir_body_const_context(local_def_id).is_some() {
42 return None;
43 }
44 }
45 let body = self.tcx.optimized_mir(def_id);
46 Some(body.arg_count)
47 }
48
49 fn analyze_function(
51 &mut self,
52 def_id: DefId,
53 fn_summaries: &Rc<RefCell<FxHashMap<DefId, FnAliasPairs>>>,
54 ) {
55 let fn_name = self.tcx.def_path_str(def_id);
56
57 if !self.tcx.is_mir_available(def_id) {
59 return;
60 }
61
62 if let Some(local_def_id) = def_id.as_local() {
64 if self.tcx.hir_body_const_context(local_def_id).is_some() {
65 return;
66 }
67 }
68
69 if fn_name.contains("__raw_ptr_deref_dummy") {
71 return;
72 }
73
74 let body = self.tcx.optimized_mir(def_id);
76
77 let analyzer = FnAliasAnalyzer::new(self.tcx, def_id, body, fn_summaries.clone());
79
80 let mut results = analyzer
82 .iterate_to_fixpoint(self.tcx, body, None)
83 .into_results_cursor(body);
84
85 let iter_cnt = *results.analysis().bb_iter_cnt.borrow();
87 let bb_cnt = body.basic_blocks.iter().len();
88 rap_debug!(
89 "[Alias-mfp] {fn_name} {iter_cnt}/{bb_cnt}, analysis ratio: {:.2}",
90 (iter_cnt as f32) / (bb_cnt as f32)
91 );
92
93 let new_summary = interproc::extract_summary(&mut results, body, def_id);
95
96 if let Some(old_summary) = self.fn_map.get_mut(&def_id) {
99 for alias in new_summary.aliases() {
100 old_summary.add_alias(alias.clone());
101 }
102 } else {
103 self.fn_map.insert(def_id, new_summary);
104 }
105 }
106
107 fn collect_reachable_functions(&self, def_id: DefId, reachable: &mut FxHashSet<DefId>) {
109 if reachable.contains(&def_id) {
111 return;
112 }
113
114 if self.get_arg_count(def_id).is_none() {
116 return;
117 }
118
119 reachable.insert(def_id);
121
122 let body = self.tcx.optimized_mir(def_id);
124 for bb_data in body.basic_blocks.iter() {
125 if let Some(terminator) = &bb_data.terminator {
126 if let TerminatorKind::Call { func, .. } = &terminator.kind {
127 if let Operand::Constant(c) = func {
128 if let ty::FnDef(callee_def_id, _) = c.ty().kind() {
129 self.collect_reachable_functions(*callee_def_id, reachable);
131 }
132 }
133 }
134 }
135 }
136 }
137}
138
139impl<'tcx> RapxAnalysis for MfpAliasAnalyzer<'tcx> {
140 fn name(&self) -> &'static str {
141 "Alias Analysis (MFP)"
142 }
143
144 fn run(&mut self) {
145 let mir_keys = self.tcx.mir_keys(());
147
148 let fn_summaries = Rc::new(RefCell::new(FxHashMap::default()));
150
151 let mut reachable_functions = FxHashSet::default();
153
154 for local_def_id in mir_keys.iter() {
156 self.collect_reachable_functions(local_def_id.to_def_id(), &mut reachable_functions);
157 }
158
159 for def_id in reachable_functions.iter() {
161 if let Some(arg_count) = self.get_arg_count(*def_id) {
162 self.fn_map.insert(*def_id, FnAliasPairs::new(arg_count));
163 }
164 }
165
166 let reachable_vec: Vec<DefId> = reachable_functions.iter().copied().collect();
168
169 const MAX_ITERATIONS: usize = 10;
171 let mut iteration = 0;
172
173 loop {
174 iteration += 1;
175 let mut changed = false;
176
177 {
179 let mut summaries = fn_summaries.borrow_mut();
180 summaries.clear();
181 for (def_id, summary) in &self.fn_map {
182 summaries.insert(*def_id, summary.clone());
183 }
184 }
185
186 for def_id in reachable_vec.iter() {
188 if !self.fn_map.contains_key(def_id) {
190 continue;
191 }
192
193 let old_summary = self.fn_map.get(def_id).cloned().unwrap();
195
196 self.analyze_function(*def_id, &fn_summaries);
198
199 if let Some(new_summary) = self.fn_map.get(def_id) {
201 let old_aliases: std::collections::HashSet<_> =
203 old_summary.aliases().iter().cloned().collect();
204 let new_aliases: std::collections::HashSet<_> =
205 new_summary.aliases().iter().cloned().collect();
206
207 if old_aliases != new_aliases {
208 changed = true;
209 rap_trace!(
210 "Summary changed for {:?}: {} -> {}",
211 self.tcx.def_path_str(def_id),
212 old_summary.len(),
213 new_summary.len()
214 );
215 }
216 }
217 }
218
219 if !changed {
221 rap_trace!(
222 "Interprocedural analysis converged after {} iterations",
223 iteration
224 );
225 break;
226 }
227
228 if iteration >= MAX_ITERATIONS {
229 rap_warn!("Reached maximum iterations ({}), stopping", MAX_ITERATIONS);
230 break;
231 }
232 }
233
234 for (fn_id, fn_alias) in &mut self.fn_map {
236 let fn_name = self.tcx.def_path_str(fn_id);
237 fn_alias.sort_alias_index();
238 if fn_alias.len() > 0 {
239 rap_trace!("Alias found in {:?}: {}", fn_name, fn_alias);
240 }
241 }
242 }
243
244 fn reset(&mut self) {
245 self.fn_map.clear();
246 }
247}
248
249impl<'tcx> AliasAnalysis for MfpAliasAnalyzer<'tcx> {
250 fn get_fn_alias(&self, def_id: DefId) -> Option<FnAliasPairs> {
251 self.fn_map.get(&def_id).cloned()
252 }
253
254 fn get_all_fn_alias(&self) -> FnAliasMap {
255 self.fn_map.clone()
256 }
257}