rapx/analysis/alias_analysis/default/
mod.rs1pub mod alias;
2pub mod assign;
3pub mod block;
4pub mod graph;
5pub mod mop;
6pub mod types;
7pub mod value;
8
9use super::{AliasAnalysis, AliasPair, FnAliasMap, FnAliasPairs};
10use crate::compat::FxHashMap;
11use crate::{
12 analysis::{Analysis, path_analysis::default::PathAnalyzer},
13 def_id::*,
14 utils::source::*,
15};
16use graph::AliasGraph;
17use rustc_hir::def_id::DefId;
18use rustc_middle::ty::TyCtxt;
19use std::{collections::HashSet, convert::From, fmt};
20
21pub const VISIT_LIMIT: usize = 80;
22
23#[derive(Debug, Clone, Hash, PartialEq, Eq)]
24pub struct MopAliasPair {
25 pub fact: AliasPair,
26 pub lhs_may_drop: bool,
27 pub lhs_need_drop: bool,
28 pub rhs_may_drop: bool,
29 pub rhs_need_drop: bool,
30}
31
32impl MopAliasPair {
33 pub fn new(
34 left_local: usize,
35 lhs_may_drop: bool,
36 lhs_need_drop: bool,
37 right_local: usize,
38 rhs_may_drop: bool,
39 rhs_need_drop: bool,
40 ) -> MopAliasPair {
41 MopAliasPair {
42 fact: AliasPair::new(left_local, right_local),
43 lhs_may_drop,
44 lhs_need_drop,
45 rhs_may_drop,
46 rhs_need_drop,
47 }
48 }
49
50 pub fn valuable(&self) -> bool {
51 return self.lhs_may_drop && self.rhs_may_drop;
52 }
53
54 pub fn swap(&mut self) {
55 self.fact.swap();
56 std::mem::swap(&mut self.lhs_may_drop, &mut self.rhs_may_drop);
57 std::mem::swap(&mut self.lhs_need_drop, &mut self.rhs_need_drop);
58 }
59
60 pub fn left_local(&self) -> usize {
61 self.fact.left_local
62 }
63
64 pub fn right_local(&self) -> usize {
65 self.fact.right_local
66 }
67
68 pub fn lhs_fields(&self) -> &[usize] {
69 &self.fact.lhs_fields
70 }
71
72 pub fn rhs_fields(&self) -> &[usize] {
73 &self.fact.rhs_fields
74 }
75}
76
77impl From<MopAliasPair> for AliasPair {
78 fn from(m: MopAliasPair) -> Self {
79 m.fact
80 }
81}
82
83impl From<MopFnAliasPairs> for FnAliasPairs {
84 fn from(m: MopFnAliasPairs) -> Self {
85 let alias_set = m.alias_set.into_iter().map(Into::into).collect(); FnAliasPairs {
87 arg_size: m.arg_size,
88 alias_set,
89 }
90 }
91}
92
93#[derive(Debug, Clone)]
94pub struct MopFnAliasPairs {
95 arg_size: usize,
96 alias_set: HashSet<MopAliasPair>,
97}
98
99impl fmt::Display for MopFnAliasPairs {
100 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101 write!(
102 f,
103 "{{{}}}",
104 self.aliases()
105 .iter()
106 .map(|alias| format!("{}", alias.fact))
107 .collect::<Vec<String>>()
108 .join(",")
109 )
110 }
111}
112
113impl MopFnAliasPairs {
114 pub fn new(arg_size: usize) -> MopFnAliasPairs {
115 Self {
116 arg_size,
117 alias_set: HashSet::new(),
118 }
119 }
120
121 pub fn arg_size(&self) -> usize {
122 self.arg_size
123 }
124
125 pub fn aliases(&self) -> &HashSet<MopAliasPair> {
126 &self.alias_set
127 }
128
129 pub fn add_alias(&mut self, alias: MopAliasPair) {
130 self.alias_set.insert(alias);
131 }
132
133 pub fn len(&self) -> usize {
134 self.alias_set.len()
135 }
136
137 pub fn sort_alias_index(&mut self) {
138 let alias_set = std::mem::take(&mut self.alias_set);
139 let mut new_alias_set = HashSet::with_capacity(alias_set.len());
140
141 for mut ra in alias_set.into_iter() {
142 if ra.left_local() >= ra.right_local() {
143 ra.swap();
144 }
145 new_alias_set.insert(ra);
146 }
147 self.alias_set = new_alias_set;
148 }
149}
150
151pub type MopFnAliasMap = FxHashMap<DefId, MopFnAliasPairs>;
153
154pub struct AliasAnalyzer<'tcx> {
155 pub tcx: TyCtxt<'tcx>,
156 pub fn_map: FxHashMap<DefId, MopFnAliasPairs>,
157 path_analyzer: PathAnalyzer<'tcx>,
158}
159
160impl<'tcx> Analysis for AliasAnalyzer<'tcx> {
161 fn name(&self) -> &'static str {
162 "Alias Analysis (MoP)"
163 }
164
165 fn run(&mut self) {
166 rap_debug!("Start alias analysis via MoP.");
167 let mir_keys = self.tcx.mir_keys(());
168 for local_def_id in mir_keys {
169 self.query_alias_graph(local_def_id.to_def_id());
170 }
171 for (fn_id, fn_alias) in &mut self.fn_map {
173 let fn_name = get_fn_name(self.tcx, *fn_id);
174 fn_alias.sort_alias_index();
175 if fn_alias.len() > 0 {
176 rap_debug!("Alias found in {:?}: {}", fn_name, fn_alias);
177 }
178 }
179 self.handle_conor_cases();
180 }
181
182 fn reset(&mut self) {
183 todo!();
184 }
185}
186
187impl<'tcx> AliasAnalysis for AliasAnalyzer<'tcx> {
188 fn get_fn_alias(&self, def_id: DefId) -> Option<FnAliasPairs> {
189 self.fn_map.get(&def_id).cloned().map(Into::into)
190 }
191
192 fn get_all_fn_alias(&self) -> FnAliasMap {
193 self.fn_map
194 .iter()
195 .map(|(k, v)| (*k, FnAliasPairs::from(v.clone())))
196 .collect()
197 }
198}
199
200impl<'tcx> AliasAnalyzer<'tcx> {
201 pub fn new(tcx: TyCtxt<'tcx>) -> Self {
202 Self {
203 tcx,
204 fn_map: FxHashMap::default(),
205 path_analyzer: PathAnalyzer::new(tcx, false),
206 }
207 }
208
209 fn handle_conor_cases(&mut self) {
210 let cases = [
211 copy_from_nonoverlapping_opt(),
212 copy_to_nonoverlapping_opt(),
213 copy_to_opt(),
214 copy_from_opt(),
215 ];
216 let alias = MopAliasPair::new(1, true, true, 2, true, true);
217 for (key, value) in self.fn_map.iter_mut() {
218 if contains(&cases, *key) {
219 value.alias_set.clear();
220 value.alias_set.insert(alias.clone());
221 }
222 }
223 }
224
225 fn query_alias_graph(&mut self, def_id: DefId) {
226 let fn_name = get_fn_name(self.tcx, def_id);
227 if fn_name
228 .as_ref()
229 .map_or(false, |s| s.contains("__raw_ptr_deref_dummy"))
230 {
231 return;
232 }
233 rap_trace!("query_alias_graph: {:?}", fn_name);
234 if let Some(_other) = self.tcx.hir_body_const_context(def_id.expect_local()) {
236 return;
237 }
238
239 if self.tcx.is_mir_available(def_id) {
240 let paths = self.path_analyzer.analyze(def_id);
241 let path_graph = self
242 .path_analyzer
243 .graphs
244 .get(&def_id)
245 .cloned()
246 .unwrap_or_else(|| {
247 let mut g =
248 crate::analysis::path_analysis::graph::PathGraph::new(self.tcx, def_id);
249 g.find_scc();
250 g
251 });
252 let mut alias_graph = AliasGraph::from_path_graph(self.tcx, def_id, path_graph);
253 rap_debug!("Alias graph created: {}", alias_graph);
254 rap_debug!("Search scc components in the graph.");
255 alias_graph.find_scc();
256 rap_trace!("After searching scc: {}", alias_graph);
257 let mut recursion_set = HashSet::default();
258 alias_graph.process_function_paths_opt(paths, &mut self.fn_map, &mut recursion_set);
259 if alias_graph.visit_times() > VISIT_LIMIT {
260 rap_trace!("Over visited: {:?}", def_id);
261 }
262 self.fn_map.insert(def_id, alias_graph.ret_alias);
263 } else {
264 rap_trace!("Mir is not available at {}", self.tcx.def_path_str(def_id));
265 }
266 }
267
268 pub fn get_all_fn_alias_raw(&mut self) -> MopFnAliasMap {
269 self.fn_map.clone()
270 }
271
272 pub fn take_path_analyzer(&mut self) -> PathAnalyzer<'tcx> {
273 std::mem::replace(&mut self.path_analyzer, PathAnalyzer::new(self.tcx, false))
274 }
275}