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