1use crate::analysis::alias::default::types::ValueKind;
2use crate::analysis::alias::observer::AliasObserver;
3use crate::analysis::points_to::slot::{AbstractLoc, Slot};
4use rustc_abi::FieldIdx;
5use rustc_hir::def_id::DefId;
6use rustc_middle::mir::{AggregateKind, Operand, Rvalue, StatementKind, TerminatorKind};
7use rustc_span::Span;
8
9use super::graph::AliasGraph;
10use super::MopFnAliasMap;
11
12impl<'tcx> AliasGraph<'tcx> {
13 pub fn init_pts_graph(&mut self) {
14 self.pts_graph = crate::analysis::points_to::builder::from_body(self.tcx(), self.def_id());
15 for val in self.values.iter_mut() {
16 let slot = crate::analysis::points_to::slot::Slot::new(val.local);
17 if let Some(si) = self.pts_graph.get_slot_idx(&slot) {
18 val.slot_idx = Some(si);
19 }
20 }
21 }
22
23 pub fn alias_bb(&mut self, bb_index: usize, obs: &mut dyn AliasObserver) {
25 let body = self.tcx().optimized_mir(self.def_id());
26 let bb = &body.basic_blocks[rustc_middle::mir::BasicBlock::from(bb_index)];
27
28 for stmt in &bb.statements {
29 let span = stmt.source_info.span;
30 match &stmt.kind {
31 StatementKind::Assign(assign) => {
32 let (place, rvalue) = &**assign;
33 self.process_assignment(place, rvalue, span, obs);
34 }
35 _ => {}
36 }
37 }
38 }
39
40 fn process_assignment(
41 &mut self,
42 place: &rustc_middle::mir::Place<'tcx>,
43 rvalue: &rustc_middle::mir::Rvalue<'tcx>,
44 span: Span,
45 obs: &mut dyn AliasObserver,
46 ) {
47 let lv_slot = Slot::from_mir_place(place);
48 let lv_pts = self.pts_graph.ensure_slot(lv_slot.clone(), false, false);
49 if !self.pts_graph.may_drop(lv_pts) {
50 return;
51 }
52 let lv_val = self.projection(*place);
53
54 match rvalue {
55 Rvalue::Use(operand, ..) => match operand {
56 Operand::Copy(rv_place) => {
57 if let Some((rv_val, rv_pts)) = self.resolve_operand(rv_place) {
58 obs.on_value_use(self, rv_val, span, false);
59 self.pts_graph.assign_value(lv_pts, rv_pts);
60 obs.on_value_assign(self, lv_val);
61 }
62 }
63 Operand::Move(rv_place) => {
64 if let Some((rv_val, rv_pts)) = self.resolve_operand(rv_place) {
65 self.move_sources.insert(lv_val, rv_val);
66 obs.on_value_use(self, rv_val, span, false);
67 if obs.track_all_moves() || self.pts_graph.slot_kind(rv_pts) == ValueKind::RawPtr {
68 self.pts_graph.assign_value(lv_pts, rv_pts);
69 }
70 obs.on_value_assign(self, lv_val);
71 }
72 }
73 Operand::Constant(_) => {}
74 #[cfg(rapx_ge_99)]
75 Operand::RuntimeChecks(_) => {}
76 },
77 Rvalue::Ref(_, _, rv_place)
78 | Rvalue::RawPtr(_, rv_place)
79 | Rvalue::CopyForDeref(rv_place) => {
80 let rv_slot = Slot::from_mir_place(rv_place);
81 if let Some(rv_val) = self.place_to_value_idx(rv_place) {
82 obs.on_value_use(self, rv_val, span, false);
83 }
84 let rv_slot_clone = rv_slot.clone();
85 self.pts_graph.assign_pointee(lv_pts, AbstractLoc::Slot(rv_slot));
86 if let Some(rv_pts) = self.pts_graph.get_slot_idx(&rv_slot_clone) {
87 self.pts_graph.merge_equivalence(lv_pts, rv_pts);
88 }
89 obs.on_value_assign(self, lv_val);
90 }
91 Rvalue::Cast(_, operand, _) => match operand {
92 Operand::Copy(rv_place) | Operand::Move(rv_place) => {
93 if let Some((rv_val, rv_pts)) = self.resolve_operand(rv_place) {
94 obs.on_value_use(self, rv_val, span, false);
95 self.pts_graph.assign_value(lv_pts, rv_pts);
96 obs.on_value_assign(self, lv_val);
97 }
98 }
99 _ => {}
100 },
101 Rvalue::Aggregate(kind, operands) => {
102 match kind.as_ref() {
103 AggregateKind::Tuple | AggregateKind::Adt(..) => {
104 for (field_idx, operand) in operands.iter_enumerated() {
105 match operand {
106 Operand::Copy(rv_place) | Operand::Move(rv_place) => {
107 if let Some((rv_val, rv_pts)) = self.resolve_operand(rv_place) {
108 let field_slot = lv_slot.project(field_idx.as_usize());
109 let field_pts = self.pts_graph.ensure_slot(field_slot, false, false);
110 let field_val = self.projection_field(place, field_idx);
112 obs.on_value_use(self, rv_val, span, false);
113 self.pts_graph.assign_value(field_pts, rv_pts);
114 obs.on_value_assign(self, field_val);
115 }
116 }
117 _ => {}
118 }
119 }
120 }
121 _ => {
122 for operand in operands {
123 match operand {
124 Operand::Copy(rv_place) | Operand::Move(rv_place) => {
125 if let Some((rv_val, rv_pts)) = self.resolve_operand(rv_place) {
126 obs.on_value_use(self, rv_val, span, false);
127 self.pts_graph.assign_value(lv_pts, rv_pts);
128 obs.on_value_assign(self, lv_val);
129 }
130 }
131 _ => {}
132 }
133 }
134 }
135 }
136 }
137 #[cfg(not(rapx_ge_99))]
138 Rvalue::ShallowInitBox(operand, _) => match operand {
139 Operand::Copy(rv_place) | Operand::Move(rv_place) => {
140 if let Some((rv_val, rv_pts)) = self.resolve_operand(rv_place) {
141 obs.on_value_use(self, rv_val, span, false);
142 self.pts_graph.assign_value(lv_pts, rv_pts);
143 obs.on_value_assign(self, lv_val);
144 }
145 }
146 _ => {}
147 },
148 Rvalue::Discriminant(rv_place) => {
149 if let Some((rv_val, rv_pts)) = self.resolve_operand(rv_place) {
150 obs.on_value_use(self, rv_val, span, false);
151 self.pts_graph.assign_value(lv_pts, rv_pts);
152 obs.on_value_assign(self, lv_val);
153 }
154 }
155 _ => {}
156 }
157 }
158
159 fn resolve_operand(&mut self, place: &rustc_middle::mir::Place<'tcx>) -> Option<(usize, usize)> {
161 let slot = Slot::from_mir_place(place);
162 let pts_idx = self.pts_graph.ensure_slot(slot, false, false);
163 if !self.pts_graph.may_drop(pts_idx) {
164 return None;
165 }
166 let val_idx = self.projection(*place);
167 Some((val_idx, pts_idx))
168 }
169
170 fn place_to_value_idx(&self, place: &rustc_middle::mir::Place<'tcx>) -> Option<usize> {
172 let slot = Slot::from_mir_place(place);
173 self.slot_to_value_idx(&slot)
174 }
175
176 fn projection_field(
178 &mut self,
179 base: &rustc_middle::mir::Place<'tcx>,
180 field_idx: FieldIdx,
181 ) -> usize {
182 let body = self.tcx().optimized_mir(self.def_id());
183 let base_ty = base.ty(&body.local_decls, self.tcx()).ty;
184 let field_ty = match base_ty.kind() {
185 rustc_middle::ty::TyKind::Tuple(fields) => fields.get(field_idx.as_usize()).copied().unwrap_or(base_ty),
186 rustc_middle::ty::TyKind::Adt(..) => base_ty,
187 _ => base_ty,
188 };
189 let field_place = self.tcx().mk_place_field(*base, field_idx, field_ty);
190 self.projection(field_place)
191 }
192
193 pub fn slot_to_value_idx(&self, slot: &Slot) -> Option<usize> {
195 if slot.fields.is_empty() {
196 let local = slot.local;
197 if local < self.values.len() {
198 return Some(local);
199 }
200 return None;
201 }
202 let mut cur = slot.local;
203 if cur >= self.values.len() {
204 return None;
205 }
206 for &field_id in &slot.fields {
207 cur = *self.values[cur].fields.get(&field_id)?;
208 }
209 Some(cur)
210 }
211
212 pub fn alias_bbcall(
214 &mut self,
215 bb_index: usize,
216 fn_map: &MopFnAliasMap,
217 obs: &mut dyn AliasObserver,
218 ) {
219 let (merge_slots, ret_local, may_drop_count, target_id, span) =
220 self.parse_call_slots(bb_index);
221 if merge_slots.is_empty() {
222 return;
223 }
224
225 for &(val_idx, _) in merge_slots.iter().skip(1) {
227 if val_idx != 0 {
228 obs.on_value_use(self, val_idx, span, true);
229 }
230 }
231
232 if may_drop_count <= 1 {
233 let (ret_val, ret_slot) = merge_slots[0];
234 if ret_val != 0 && self.pts_graph.may_drop(ret_slot) {
235 self.pts_graph.reset_partition(ret_slot);
236 obs.on_value_assign(self, ret_val);
237 }
238 return;
239 }
240
241 match target_id {
242 Some(id) => {
243 if super::alias::is_no_alias_intrinsic(id) {
244 return;
245 }
246 if !self.tcx().is_mir_available(id) {
247 let (ret_val, _) = merge_slots[0];
248 if ret_val != 0 && self.value_is_ptr(ret_val) {
249 let slot_args: Vec<usize> = merge_slots.iter().map(|&(_, s)| s).collect();
250 self.pts_graph.conservative_call_merge(&slot_args);
251 obs.on_value_assign(self, ret_val);
252 }
253 return;
254 }
255 self.apply_fn_alias_results_pts(id, &merge_slots, fn_map, obs);
256 }
257 None => {
258 let (ret_val, _) = merge_slots[0];
259 if ret_val != 0 && self.pts_graph.get_slot_idx(&Slot::new(ret_local)).map_or(false, |si| self.pts_graph.slot_is_ptr(si)) {
260 let slot_args: Vec<usize> = merge_slots.iter().map(|&(_, s)| s).collect();
261 self.pts_graph.conservative_call_merge(&slot_args);
262 obs.on_value_assign(self, ret_val);
263 }
264 }
265 }
266
267 let (ret_val, _) = merge_slots[0];
268 if ret_val != 0 && self.pts_graph.may_drop(merge_slots[0].1) {
269 obs.on_value_assign(self, ret_val);
270 }
271 }
272
273 fn parse_call_slots(
275 &mut self,
276 bb_index: usize,
277 ) -> (Vec<(usize, usize)>, usize, usize, Option<DefId>, Span) {
278 let terminator = match self.terminator(bb_index) {
279 Some(t) => t.clone(),
280 None => return (vec![], 0, 0, None, rustc_span::DUMMY_SP),
281 };
282 let TerminatorKind::Call {
283 func: ref func_op, ref args, ref destination, ..
284 } = terminator.kind else { return (vec![], 0, 0, None, rustc_span::DUMMY_SP); };
285 let span = terminator.source_info.span;
286
287 let target_id = match func_op {
288 Operand::Constant(c) => match c.ty().kind() {
289 rustc_middle::ty::FnDef(id, _) => Some(*id),
290 _ => None,
291 },
292 _ => None,
293 };
294
295 let ret_local = destination.local.as_usize();
296 let ret_slot = Slot::new(ret_local);
297 let ret_pts = self.pts_graph.ensure_slot(ret_slot, false, false);
298 let ret_val = self.projection(*destination);
299 let mut result = vec![(ret_val, ret_pts)];
300 let mut may_drop_count: usize = if self.pts_graph.may_drop(ret_pts) { 1 } else { 0 };
301
302 for arg in args {
303 match arg.node {
304 Operand::Copy(ref p) | Operand::Move(ref p) => {
305 let arg_local = p.local.as_usize();
306 let arg_slot = Slot::new(arg_local);
307 let arg_pts = self.pts_graph.ensure_slot(arg_slot, false, false);
308 let arg_val = self.projection(*p);
309 if self.pts_graph.may_drop(arg_pts) {
310 may_drop_count += 1;
311 }
312 result.push((arg_val, arg_pts));
313 }
314 Operand::Constant(_) => { result.push((0, 0)); }
315 #[cfg(rapx_ge_99)]
316 Operand::RuntimeChecks(_) => {}
317 }
318 }
319
320 (result, ret_local, may_drop_count, target_id, span)
321 }
322
323 fn apply_fn_alias_results_pts(
324 &mut self,
325 target_id: DefId,
326 merge_vec: &[(usize, usize)],
327 fn_map: &MopFnAliasMap,
328 obs: &mut dyn AliasObserver,
329 ) {
330 let Some(fn_aliases) = fn_map.get(&target_id) else { return };
331 if fn_aliases.aliases().is_empty() { return; }
332 let unified: crate::analysis::alias::FnAliasPairs = From::from(fn_aliases.clone());
333 let slot_args: Vec<usize> = merge_vec.iter().map(|&(_, s)| s).collect();
334 self.pts_graph.apply_callee_summary(&unified, &slot_args);
335 obs.on_state_change(self);
336 }
337
338 pub fn merge_results_pts(&mut self) {
339 let pairs = self.pts_graph.fn_alias_pairs(self.arg_size());
340 for alias in pairs.aliases() {
341 let lv_local = alias.left_local();
342 let rv_local = alias.right_local();
343 let lv_slot = self.value_to_slot_idx(lv_local).unwrap_or(lv_local);
344 let rv_slot = self.value_to_slot_idx(rv_local).unwrap_or(rv_local);
345 let mut mop_alias = super::MopAliasPair::new(
346 alias.left_local(),
347 self.pts_graph.may_drop(lv_slot),
348 self.pts_graph.need_drop(lv_slot),
349 alias.right_local(),
350 self.pts_graph.may_drop(rv_slot),
351 self.pts_graph.need_drop(rv_slot),
352 );
353 mop_alias.fact = alias.clone();
354 self.ret_alias.add_alias(mop_alias);
355 }
356 }
357}