Skip to main content

rapx/analysis/alias/default/
mod.rs

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