1pub mod default;
2pub mod mfp;
3pub mod observer;
4use crate::utils::source::get_fn_name_byid;
5
6use super::super::Analysis;
7use crate::compat::FxHashMap;
8use rustc_hir::def_id::DefId;
9use rustc_middle::{
10 mir::{Local, Place, StatementKind},
11 ty::{GenericArgsRef, Ty, TyCtxt, TyKind},
12};
13use rustc_span::def_id::LOCAL_CRATE;
14use std::{collections::HashSet, fmt};
15
16pub type FnAliasMap = FxHashMap<DefId, FnAliasPairs>;
18
19pub struct FnAliasMapWrapper(pub FnAliasMap);
21
22pub trait AliasAnalysis: Analysis {
24 fn get_fn_alias(&self, def_id: DefId) -> Option<FnAliasPairs>;
26 fn get_all_fn_alias(&self) -> FnAliasMap;
28 fn get_local_fn_alias(&self) -> FnAliasMap {
31 self.get_all_fn_alias()
32 .iter()
33 .filter(|(def_id, _)| def_id.krate == LOCAL_CRATE)
34 .map(|(k, v)| (*k, v.clone()))
35 .collect()
36 }
37
38 fn get_local_origins(&self, _def_id: DefId) -> LocalOriginMap {
42 LocalOriginMap::default()
43 }
44
45 fn get_self_field_origin(
48 &self,
49 _def_id: DefId,
50 _local: usize,
51 _fields: &[usize],
52 ) -> Option<FieldOrigin> {
53 None
54 }
55}
56
57#[derive(Debug, Clone)]
60pub struct FnAliasPairs {
61 arg_size: usize,
62 alias_set: HashSet<AliasPair>,
63}
64
65impl FnAliasPairs {
66 pub fn new(arg_size: usize) -> FnAliasPairs {
67 Self {
68 arg_size,
69 alias_set: HashSet::new(),
70 }
71 }
72
73 pub fn arg_size(&self) -> usize {
74 self.arg_size
75 }
76
77 pub fn aliases(&self) -> &HashSet<AliasPair> {
78 &self.alias_set
79 }
80
81 pub fn add_alias(&mut self, alias: AliasPair) {
82 self.alias_set.insert(alias);
83 }
84
85 pub fn len(&self) -> usize {
86 self.alias_set.len()
87 }
88
89 pub fn sort_alias_index(&mut self) {
90 let alias_set = std::mem::take(&mut self.alias_set);
91 let mut new_alias_set = HashSet::with_capacity(alias_set.len());
92
93 for mut ra in alias_set.into_iter() {
94 if ra.left_local() >= ra.right_local() {
95 ra.swap();
96 }
97 new_alias_set.insert(ra);
98 }
99 self.alias_set = new_alias_set;
100 }
101
102 pub fn compress_fields(&mut self) {
106 let alias_set = std::mem::take(&mut self.alias_set);
107 let mut compressed = HashSet::with_capacity(alias_set.len());
108 for mut ra in alias_set.into_iter() {
109 if !ra.lhs_fields.is_empty() {
110 ra.lhs_fields = vec![ra.lhs_fields[0]];
111 }
112 if !ra.rhs_fields.is_empty() {
113 ra.rhs_fields = vec![ra.rhs_fields[0]];
114 }
115 compressed.insert(ra);
116 }
117 self.alias_set = compressed;
118 }
119}
120
121impl fmt::Display for FnAliasPairs {
122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123 if self.aliases().is_empty() {
124 write!(f, "null")?;
125 } else {
126 let mut facts: Vec<_> = self.aliases().iter().collect();
127 facts.sort_by(|a, b| {
128 a.left_local
129 .cmp(&b.left_local)
130 .then(a.right_local.cmp(&b.right_local))
131 .then(a.lhs_fields.cmp(&b.lhs_fields))
132 .then(a.rhs_fields.cmp(&b.rhs_fields))
133 });
134 let joined = facts
135 .into_iter()
136 .map(|fact| format!("{}", fact))
137 .collect::<Vec<_>>()
138 .join(", ");
139 write!(f, "{}", joined)?;
140 }
141 Ok(())
142 }
143}
144
145impl fmt::Display for FnAliasMapWrapper {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 writeln!(f, "=== Print alias analysis results ===")?;
148 for (def_id, result) in &self.0 {
149 let fn_name = get_fn_name_byid(def_id);
150 writeln!(f, "Alias of {:?}: {}", fn_name, result)?;
151 }
152 Ok(())
153 }
154}
155
156pub type LocalOriginMap = FxHashMap<usize, (usize, Vec<usize>)>;
159
160#[derive(Clone, Debug)]
162pub struct FieldOrigin {
163 pub struct_def_id: DefId,
164 pub field_index: usize,
165 pub field_name: String,
166}
167
168pub fn adt_from_ty<'tcx>(ty: Ty<'tcx>) -> Option<(DefId, GenericArgsRef<'tcx>)> {
170 match ty.kind() {
171 TyKind::Ref(_, inner, _) | TyKind::RawPtr(inner, _) => adt_from_ty(*inner),
172 TyKind::Adt(adt, args) => Some((adt.did(), *args)),
173 _ => None,
174 }
175}
176
177pub fn collect_local_origins<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> LocalOriginMap {
181 let body = tcx.optimized_mir(def_id);
182 let mut origins = LocalOriginMap::default();
183
184 for block in body.basic_blocks.iter() {
185 for statement in &block.statements {
186 let StatementKind::Assign(assign) = &statement.kind else {
187 continue;
188 };
189 let (target, rvalue) = assign.as_ref();
190 if let Some(origin) = rvalue_origin(rvalue, &origins) {
191 origins.insert(target.local.as_usize(), origin);
192 }
193 }
194 if let rustc_middle::mir::TerminatorKind::Call { func, args, destination, .. } = &block.terminator().kind {
195 if let rustc_middle::mir::Operand::Constant(c) = func {
196 if let rustc_middle::ty::FnDef(_, _) = c.const_.ty().kind() {
197 if let Some(first_arg) = args.first() {
198 if let Some(place) = first_arg.node.place() {
199 let origin = resolve_place(&place, &origins);
200 origins.insert(destination.local.as_usize(), origin);
201 }
202 }
203 }
204 }
205 }
206 }
207 origins
208}
209
210fn rvalue_origin(
212 rvalue: &rustc_middle::mir::Rvalue<'_>,
213 origins: &LocalOriginMap,
214) -> Option<(usize, Vec<usize>)> {
215 if let Some(place) = crate::helpers::mir_utils::rvalue_source_place(rvalue) {
216 return Some(resolve_place(place, origins));
217 }
218 if let rustc_middle::mir::Rvalue::Cast(_, operand, _) = rvalue {
219 if let Some(place) = operand.place() {
220 return Some(resolve_place(&place, origins));
221 }
222 }
223 None
224}
225
226pub fn resolve_place(place: &Place<'_>, origins: &LocalOriginMap) -> (usize, Vec<usize>) {
230 let local = place.local.as_usize();
231 let fields: Vec<usize> = place
232 .projection
233 .iter()
234 .filter_map(|elem| match elem {
235 rustc_middle::mir::ProjectionElem::Field(idx, _) => Some(idx.as_usize()),
236 _ => None,
237 })
238 .collect();
239 if !fields.is_empty() {
240 return (local, fields);
241 }
242 origins.get(&local).cloned().unwrap_or((local, fields))
243}
244
245pub fn resolve_self_field_origin<'tcx>(
248 tcx: TyCtxt<'tcx>,
249 def_id: DefId,
250 local: usize,
251 fields: &[usize],
252) -> Option<FieldOrigin> {
253 if local != 1 || fields.is_empty() {
254 return None;
255 }
256 let body = tcx.optimized_mir(def_id);
257 let self_ty = body.local_decls[Local::from_usize(1)].ty;
258 let (struct_def_id, _) = adt_from_ty(self_ty)?;
259 let field_index = fields[0];
260 let adt = tcx.adt_def(struct_def_id);
261 let field = adt.all_fields().nth(field_index)?;
262 Some(FieldOrigin {
263 struct_def_id,
264 field_index,
265 field_name: field.name.to_string(),
266 })
267}
268
269pub fn resolve_any_field_origin<'tcx>(
272 tcx: TyCtxt<'tcx>,
273 def_id: DefId,
274 local: usize,
275 fields: &[usize],
276) -> Option<FieldOrigin> {
277 if fields.is_empty() {
278 return None;
279 }
280 let body = tcx.optimized_mir(def_id);
281 let self_ty = body.local_decls[Local::from_usize(local)].ty;
282 let (struct_def_id, _) = adt_from_ty(self_ty)?;
283 let field_index = fields[0];
284 let adt = tcx.adt_def(struct_def_id);
285 let field = adt.all_fields().nth(field_index)?;
286 Some(FieldOrigin {
287 struct_def_id,
288 field_index,
289 field_name: field.name.to_string(),
290 })
291}
292
293#[derive(Debug, Clone, Hash, PartialEq, Eq)]
296pub struct AliasPair {
297 pub left_local: usize,
298 pub lhs_fields: Vec<usize>,
299 pub right_local: usize,
300 pub rhs_fields: Vec<usize>,
301}
302
303impl AliasPair {
304 pub fn new(left_local: usize, right_local: usize) -> AliasPair {
305 AliasPair {
306 left_local,
307 lhs_fields: Vec::<usize>::new(),
308 right_local,
309 rhs_fields: Vec::<usize>::new(),
310 }
311 }
312
313 pub fn swap(&mut self) {
315 std::mem::swap(&mut self.left_local, &mut self.right_local);
316 std::mem::swap(&mut self.lhs_fields, &mut self.rhs_fields);
317 }
318
319 pub fn left_local(&self) -> usize {
320 self.left_local
321 }
322
323 pub fn right_local(&self) -> usize {
324 self.right_local
325 }
326
327 pub fn lhs_fields(&self) -> &[usize] {
328 &self.lhs_fields
329 }
330
331 pub fn rhs_fields(&self) -> &[usize] {
332 &self.rhs_fields
333 }
334}
335
336impl fmt::Display for AliasPair {
337 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
338 write!(
339 f,
340 "({},{})",
341 aa_place_desc_str(self.left_local, &self.lhs_fields, true),
342 aa_place_desc_str(self.right_local, &self.rhs_fields, true)
343 )
344 }
345}
346
347fn aa_place_desc_str(no: usize, fields: &[usize], field_sensitive: bool) -> String {
348 let mut result = String::new();
349 result.push_str(&no.to_string());
350 if !field_sensitive {
351 return result;
352 }
353 for num in fields.iter() {
354 result.push('.');
355 result.push_str(&num.to_string());
356 }
357 result
358}