1use rustc_hir::def_id::DefId;
9use rustc_middle::mir::{Local, Operand, ProjectionElem, Rvalue, StatementKind};
10use crate::verify::{
11 alias_hazard::{self, AliasProducer, HazardKind},
12 contract::Property,
13 def_use::PlaceKey,
14};
15use crate::helpers::mir_scan::Checkpoint;
16use crate::helpers::api_classify;
17use crate::analysis::alias::collect_local_origins;
18
19use super::state::{AllocId, VmState, VmValue};
20
21#[derive(Clone, Debug)]
23pub struct VmOrigin {
24 pub local: Local,
26 pub alloc_id: AllocId,
28 pub kind: VmOriginKind,
30}
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub enum VmOriginKind {
34 MutRef,
35 SharedRef,
36 RawMutPtr,
37 RawConstPtr,
38 Owned(DefId),
39 Unknown,
40}
41
42impl VmOrigin {
43 pub fn is_mut_ref(&self) -> bool {
45 matches!(self.kind, VmOriginKind::MutRef)
46 }
47
48 pub fn is_shared_ref(&self) -> bool {
50 matches!(self.kind, VmOriginKind::SharedRef)
51 }
52
53 pub fn is_owned(&self) -> bool {
56 matches!(self.kind, VmOriginKind::Owned(_))
57 }
58}
59
60impl<'ctx, 'tcx> VmState<'ctx, 'tcx> {
61 pub fn resolve_origin(&self, value: &VmValue<'ctx, 'tcx>) -> Option<VmOrigin> {
66 let Some(prov) = &value.provenance else {
67 return None;
68 };
69
70 let alloc_id = prov.alloc_id;
71
72 let mut best: Option<VmOrigin> = None;
75
76 for (local, val) in &self.locals {
77 let Some(val_prov) = &val.provenance else {
78 continue;
79 };
80 if val_prov.alloc_id != alloc_id {
81 continue;
82 }
83
84 let kind = self.classify_local(local);
85 let candidate = VmOrigin {
86 local: *local,
87 alloc_id,
88 kind,
89 };
90
91 let is_param = local.as_usize() <= self.body.arg_count;
93 let is_owned = candidate.is_owned();
94
95 match &best {
96 None => best = Some(candidate),
97 Some(existing) => {
98 let ex_is_param = existing.local.as_usize() <= self.body.arg_count;
99 let ex_is_owned = existing.is_owned();
100 if is_param && !ex_is_param {
102 best = Some(candidate);
103 } else if is_owned && !ex_is_owned {
104 best = Some(candidate);
105 } else if is_param == ex_is_param && is_owned == ex_is_owned {
106 if local.as_usize() < existing.local.as_usize() {
108 best = Some(candidate);
109 }
110 }
111 }
112 }
113 }
114
115 best
116 }
117
118 fn classify_local(&self, local: &Local) -> VmOriginKind {
120 let ty = self.body.local_decls[*local].ty;
121 match ty.kind() {
122 rustc_middle::ty::TyKind::Ref(_, _, rustc_middle::ty::Mutability::Mut) => {
123 VmOriginKind::MutRef
124 }
125 rustc_middle::ty::TyKind::Ref(_, _, rustc_middle::ty::Mutability::Not) => {
126 VmOriginKind::SharedRef
127 }
128 rustc_middle::ty::TyKind::RawPtr(inner_ty, rustc_middle::ty::Mutability::Mut) => {
129 let _ = inner_ty;
130 VmOriginKind::RawMutPtr
131 }
132 rustc_middle::ty::TyKind::RawPtr(..) => VmOriginKind::RawConstPtr,
133 rustc_middle::ty::TyKind::Adt(adt_def, _) => {
134 VmOriginKind::Owned(adt_def.did())
135 }
136 _ => VmOriginKind::Unknown,
137 }
138 }
139}
140
141pub enum VmAliasResult {
145 Proved,
146 Failed(String),
147 Unknown,
148}
149
150pub fn check_alias_vm<'ctx, 'tcx>(
154 vm_state: &VmState<'ctx, 'tcx>,
155 checkpoint: &Checkpoint<'tcx>,
156 _property: &Property<'tcx>,
157) -> VmAliasResult {
158 let callee = match checkpoint.callee {
159 Some(c) => c,
160 None => {
162 let Some(origin_arg) = checkpoint.args.first() else {
163 return VmAliasResult::Unknown;
164 };
165 let origin_val = vm_state.value_of_operand(origin_arg);
166 if let Some(origin) = vm_state.resolve_origin(&origin_val) {
167 if origin.is_mut_ref() || origin.is_shared_ref() {
168 return VmAliasResult::Proved;
169 }
170 if origin.is_owned() {
171 return VmAliasResult::Proved;
172 }
173 }
174 if vm_state.body.arg_count >= 1 {
178 let self_ty = vm_state.body.local_decls[Local::from_usize(1)].ty;
179 if let rustc_middle::ty::TyKind::Adt(adt_def, _) = self_ty.kind() {
180 if api_classify::is_std_nonnull(&vm_state.tcx.def_path_str(adt_def.did())) {
181 return VmAliasResult::Proved;
182 }
183 }
184 }
185 if let Some(prov) = &origin_val.provenance {
187 let is_external = vm_state.alloc(prov.alloc_id).is_external;
188 if !is_external {
189 return VmAliasResult::Proved;
190 }
191 let has_shared_ref = vm_state.body.local_decls.iter().any(|d| {
193 matches!(d.ty.kind(), rustc_middle::ty::TyKind::Ref(_, _, rustc_middle::ty::Mutability::Not))
194 });
195 if has_shared_ref {
196 return VmAliasResult::Proved;
197 }
198 }
199 if origin_val.provenance.is_none() {
201 for decl in &vm_state.body.local_decls {
202 if matches!(decl.ty.kind(), rustc_middle::ty::TyKind::Ref(..)) {
203 return VmAliasResult::Proved;
204 }
205 }
206 }
207 let tcx = vm_state.tcx;
210 let caller = checkpoint.caller;
211 let arg_place = alias_hazard::operand_mir_place(origin_arg)
212 .map(|p| PlaceKey::from_mir_place(p));
213 if let Some(mir_place) = arg_place {
214 let origin_map = collect_local_origins(tcx, caller);
215 let (root, fields) = alias_hazard::deep_resolve_place(
216 mir_place.local().map(|l| l.as_usize()).unwrap_or(1),
217 &origin_map,
218 );
219 if !fields.is_empty() {
220 let resolved = PlaceKey::from_origin(root, fields);
221 let sfo = alias_hazard::self_field_origin(tcx, caller, &resolved);
222 if let Some(sfo) = sfo {
223 if let Some(is_shared) = is_self_field_shared_ref(tcx, caller, &sfo) {
224 if is_shared {
225 return VmAliasResult::Proved;
226 }
227 }
228 }
229 }
230 }
231 return VmAliasResult::Unknown;
232 }
233 };
234 let callee_name = vm_state.tcx.def_path_str(callee);
235
236 if callee_name.contains("::NonNull::")
242 && (callee_name.ends_with("::as_ref") || callee_name.ends_with("::as_mut"))
243 {
244 let ret_ty = vm_state.body.local_decls[rustc_middle::mir::RETURN_PLACE].ty;
245 if crate::helpers::mir_utils::type_contains_reference(ret_ty) {
246 return VmAliasResult::Unknown;
247 }
248 return VmAliasResult::Proved;
249 }
250
251 let Some(producer) = alias_hazard::alias_producer(&callee_name) else {
253 return VmAliasResult::Unknown;
254 };
255
256 match producer {
257 AliasProducer::View(kind) => {
258 check_view_alias(vm_state, checkpoint, callee_name, kind)
259 }
260 AliasProducer::OwnershipTransfer => {
261 check_ownership_transfer_alias(vm_state, checkpoint)
262 }
263 AliasProducer::ReadMemory => {
264 check_read_memory_alias(vm_state, checkpoint)
265 }
266 }
267}
268
269fn check_view_alias<'ctx, 'tcx>(
270 vm_state: &VmState<'ctx, 'tcx>,
271 checkpoint: &Checkpoint<'tcx>,
272 _callee_name: String,
273 kind: HazardKind,
274) -> VmAliasResult {
275 let Some(origin_arg) = checkpoint.args.first() else {
276 return VmAliasResult::Unknown;
277 };
278 let origin_val = vm_state.value_of_operand(origin_arg);
279
280 let tcx = vm_state.tcx;
281 let caller = checkpoint.caller;
282 let call_block = checkpoint.block;
283 let destination = alias_hazard::call_destination(tcx, checkpoint);
284
285 let origin_place = alias_hazard::operand_place(origin_arg)
287 .or_else(|| alias_hazard::operand_mir_place(origin_arg)
288 .map(|p| PlaceKey::from_mir_place(p)))
289 .unwrap_or_else(|| {
290 PlaceKey::from_origin(
292 crate::helpers::mir_utils::extract_local(origin_arg).map(|l| l.as_usize()).unwrap_or(1),
293 vec![],
294 )
295 });
296
297 let resolved_origin = resolve_origin_place_mir(tcx, caller, &origin_place);
300 let mut origins = vec![origin_place.clone()];
301 if resolved_origin != origin_place {
302 origins.push(resolved_origin.clone());
303 }
304
305 let mir_place_from_arg = checkpoint.args.first()
308 .and_then(|a| alias_hazard::operand_mir_place(a));
309 if let Some(place) = mir_place_from_arg {
310 if !place.projection.is_empty() && place.local == Local::from_usize(1) {
311 let field_key = PlaceKey::from_mir_place(place);
312 if !field_key.fields.is_empty() && !origins.contains(&field_key) {
313 origins.push(field_key);
314 }
315 }
316 }
317
318 if let Some(origin) = vm_state.resolve_origin(&origin_val) {
320 match (kind, origin.kind) {
321 (HazardKind::UniqueView, VmOriginKind::MutRef) => return VmAliasResult::Proved,
322 (HazardKind::SharedView, VmOriginKind::SharedRef) => return VmAliasResult::Proved,
323 (HazardKind::SharedView, VmOriginKind::RawConstPtr) => return VmAliasResult::Proved,
325 (HazardKind::UniqueView, VmOriginKind::RawConstPtr) => {
326 return VmAliasResult::Failed(
327 "const raw pointer cannot safely create a unique mutable view".into(),
328 );
329 }
330 (HazardKind::UniqueView, VmOriginKind::SharedRef) => {
331 }
334 _ => {}
335 }
336 if origin.is_owned() {
337 let check = alias_hazard::alias_proved_for_param_local(
338 tcx, caller, origin.local.as_usize(), kind,
339 );
340 let is_reallocatable = match &origin.kind {
343 VmOriginKind::Owned(def_id) => {
344 let def_path = tcx.def_path_str(*def_id);
345 api_classify::is_std_vec(&def_path)
346 || api_classify::is_std_cstring(&def_path)
347 }
348 _ => false,
349 };
350 if matches!(check, alias_hazard::HazardCheck::Safe(_)) && !is_reallocatable {
351 return VmAliasResult::Proved;
352 }
353 }
354 }
355
356 let view_len_place =
358 checkpoint.args.get(1).and_then(|a| alias_hazard::operand_place(a));
359
360 if let Some(reason) = alias_hazard::local_hazard_violation(
362 tcx, caller, call_block, destination, &origins, kind, view_len_place,
363 ) {
364 return VmAliasResult::Failed(reason);
365 }
366
367 let origin_pk = alias_hazard::resolve_param_origin(tcx, caller, &origin_place);
369 if let Some(local_index) = origin_pk {
370 match alias_hazard::alias_proved_for_param_local(tcx, caller, local_index, kind) {
371 alias_hazard::HazardCheck::Safe(_) => return VmAliasResult::Proved,
372 alias_hazard::HazardCheck::Violation(_) => {
373 }
376 alias_hazard::HazardCheck::Inconclusive => {}
377 }
378 }
379 let origin_local_place = if origin_place.fields.is_empty() {
381 PlaceKey::from_origin(
382 origin_place.local().map(|l| l.as_usize()).unwrap_or(1),
383 vec![],
384 )
385 } else {
386 origin_place.clone()
387 };
388 match alias_hazard::alias_proved_for_param_local_from_origin(
389 tcx, caller, &origin_local_place, kind,
390 ) {
391 alias_hazard::HazardCheck::Violation(_) => {} alias_hazard::HazardCheck::Safe(_) => {}
393 alias_hazard::HazardCheck::Inconclusive => {}
394 }
395
396 let dest_escapes = alias_hazard::destination_flows_to_return(tcx, caller, destination);
398 if dest_escapes {
399 let field_origin = alias_hazard::self_field_origin(tcx, caller, &resolved_origin)
401 .or_else(|| alias_hazard::self_field_origin(tcx, caller, &origin_place))
402 .or_else(|| find_struct_field_origin_for_param(tcx, caller, checkpoint));
405 if let Some(sfo) = field_origin {
406 if let Some(reason) = alias_hazard::escaped_self_field_violation(tcx, caller, &sfo) {
407 return VmAliasResult::Failed(reason);
408 }
409 return VmAliasResult::Proved;
410 }
411 let any_field = alias_hazard::any_struct_field_origin(tcx, caller, &resolved_origin)
412 .or_else(|| alias_hazard::any_struct_field_origin(tcx, caller, &origin_place));
413 if let Some(sfo) = any_field {
414 if let Some(reason) = alias_hazard::escaped_self_field_violation(tcx, caller, &sfo) {
415 return VmAliasResult::Failed(reason);
416 }
417 return VmAliasResult::Proved;
418 }
419 if let Some(reason) = alias_hazard::private_fn_callsite_delegation(
420 tcx, caller, &origin_place, kind,
421 ) {
422 return VmAliasResult::Failed(reason);
423 }
424 if kind == HazardKind::SharedView {
425 let param_origin = alias_hazard::resolve_param_origin(tcx, caller, &origin_place);
426 if let Some(local) = param_origin
427 && alias_hazard::is_origin_a_reference(tcx, caller, &PlaceKey::from_origin(local, vec![]))
428 {
429 return VmAliasResult::Proved;
430 }
431 }
432 }
433
434 if !dest_escapes {
436 return VmAliasResult::Proved;
437 }
438
439 if kind == HazardKind::UniqueView {
442 if let Some(sfo) = infer_self_field_from_type(tcx, caller, checkpoint)
446 .or_else(|| find_struct_field_origin_for_param(tcx, caller, checkpoint))
447 {
448 if alias_hazard::escaped_self_field_violation(tcx, caller, &sfo).is_none() {
449 return VmAliasResult::Proved;
450 }
451 }
452 let body = tcx.optimized_mir(caller);
455 if body.arg_count >= 1 {
456 let self_ty = body.local_decls[Local::from_usize(1)].ty;
457 if matches!(self_ty.kind(), rustc_middle::ty::TyKind::Ref(..)) {
458 return VmAliasResult::Proved;
459 }
460 if let rustc_middle::ty::TyKind::Adt(adt_def, _) = self_ty.kind() {
464 if api_classify::is_std_nonnull(&tcx.def_path_str(adt_def.did())) {
465 return VmAliasResult::Proved;
466 }
467 }
468 }
469 return VmAliasResult::Failed(format!(
470 "returned unique view escapes while the original pointer is not owned by a private self field [origin={:?}]",
471 origin_place
472 ));
473 }
474
475 VmAliasResult::Proved
477}
478
479fn find_struct_field_origin_for_param<'tcx>(
484 tcx: rustc_middle::ty::TyCtxt<'tcx>,
485 caller: DefId,
486 checkpoint: &Checkpoint<'tcx>,
487) -> Option<alias_hazard::SelfFieldOrigin> {
488 let body = tcx.optimized_mir(caller);
489
490 let self_ty = body.local_decls[Local::from_usize(1)].ty;
491 let inner_adt = match self_ty.kind() {
492 rustc_middle::ty::TyKind::Ref(_, inner, _)
493 if matches!(inner.kind(), rustc_middle::ty::TyKind::Adt(..)) => *inner,
494 _ => return None,
495 };
496 let (adt_def, _) = crate::analysis::alias::adt_from_ty(inner_adt)?;
497
498 let Some(arg0) = checkpoint.args.first() else { return None; };
500 let arg_place = match arg0 {
501 Operand::Copy(p) | Operand::Move(p) => p,
502 _ => return None,
503 };
504
505 if !arg_place.projection.is_empty() && arg_place.local == Local::from_usize(1) {
507 let fields: Vec<usize> = arg_place.projection.iter()
508 .filter_map(|p| match p {
509 ProjectionElem::Field(idx, _) => Some(idx.as_usize()),
510 _ => None,
511 })
512 .collect();
513 if !fields.is_empty() {
514 let field_index = fields[0];
515 let adt = tcx.adt_def(adt_def);
516 let field = adt.all_fields().nth(field_index)?;
517 return Some(alias_hazard::SelfFieldOrigin {
518 struct_def_id: adt_def,
519 field_index,
520 field_name: field.name.to_string(),
521 });
522 }
523 }
524
525 let arg_local = arg_place.local;
527 if arg_place.projection.is_empty() && arg_local != Local::from_usize(1) {
528 for block in body.basic_blocks.iter() {
529 for stmt in &block.statements {
530 let StatementKind::Assign(assign) = &stmt.kind else { continue };
531 let (target, rvalue) = assign.as_ref();
532 if target.local != arg_local { continue; }
533 let source = match rvalue {
534 #[cfg(rapx_rvalue_use_with_retag)]
535 Rvalue::Use(operand, _) => match operand {
536 Operand::Copy(p) | Operand::Move(p) => p,
537 _ => continue,
538 },
539 #[cfg(not(rapx_rvalue_use_with_retag))]
540 Rvalue::Use(operand) => match operand {
541 Operand::Copy(p) | Operand::Move(p) => p,
542 _ => continue,
543 },
544 Rvalue::CopyForDeref(p) => p,
545 _ => continue,
546 };
547 if source.local != Local::from_usize(1) { continue; }
548 let fields: Vec<usize> = source.projection.iter()
549 .filter_map(|p| match p {
550 ProjectionElem::Field(idx, _) => Some(idx.as_usize()),
551 _ => None,
552 })
553 .collect();
554 if fields.is_empty() { continue; }
555 let field_index = fields[0];
556 let adt = tcx.adt_def(adt_def);
557 let field = adt.all_fields().nth(field_index)?;
558 return Some(alias_hazard::SelfFieldOrigin {
559 struct_def_id: adt_def,
560 field_index,
561 field_name: field.name.to_string(),
562 });
563 }
564 }
565 }
566
567 None
568}
569
570fn infer_self_field_from_type<'tcx>(
574 tcx: rustc_middle::ty::TyCtxt<'tcx>,
575 caller: DefId,
576 checkpoint: &Checkpoint<'tcx>,
577) -> Option<alias_hazard::SelfFieldOrigin> {
578 let body = tcx.optimized_mir(caller);
579 if body.arg_count == 0 {
580 return None;
581 }
582 let self_ty = body.local_decls[Local::from_usize(1)].ty;
583 let inner = match self_ty.kind() {
584 rustc_middle::ty::TyKind::Ref(_, inner, _) => *inner,
585 _ => return None,
586 };
587 let Some((adt_def, _)) = crate::analysis::alias::adt_from_ty(inner) else {
588 return None;
589 };
590
591 let adt = tcx.adt_def(adt_def);
592 let mut raw_ptr_fields: Vec<(usize, String)> = Vec::new();
593 let variant = adt.non_enum_variant();
594 for (idx, field) in variant.fields.iter().enumerate() {
595 #[cfg(not(rapx_ge_99))]
596 let field_ty = field.ty(tcx, rustc_middle::ty::GenericArgs::identity_for_item(tcx, adt_def));
597 #[cfg(rapx_ge_99)]
598 let field_ty = field.ty(tcx, rustc_middle::ty::GenericArgs::identity_for_item(tcx, adt_def)).skip_norm_wip();
599 if matches!(field_ty.kind(), rustc_middle::ty::TyKind::RawPtr(..)) {
600 raw_ptr_fields.push((idx, field.name.to_string()));
601 }
602 }
603
604 if raw_ptr_fields.len() == 1 {
605 let (field_index, field_name) = raw_ptr_fields.into_iter().next().unwrap();
606 return Some(alias_hazard::SelfFieldOrigin {
607 struct_def_id: adt_def,
608 field_index,
609 field_name,
610 });
611 }
612
613 if let Some(arg0) = checkpoint.args.first()
616 && let Some(place) = alias_hazard::operand_mir_place(arg0)
617 {
618 let fields: Vec<usize> = place.projection.iter()
619 .filter_map(|p| match p {
620 ProjectionElem::Field(idx, _) => Some(idx.as_usize()),
621 _ => None,
622 })
623 .collect();
624 if let Some(&idx) = fields.first() {
625 if let Some(field) = adt.all_fields().nth(idx) {
626 return Some(alias_hazard::SelfFieldOrigin {
627 struct_def_id: adt_def,
628 field_index: idx,
629 field_name: field.name.to_string(),
630 });
631 }
632 }
633 }
634
635 None
636}
637fn is_self_field_shared_ref(
641 tcx: rustc_middle::ty::TyCtxt<'_>,
642 caller: DefId,
643 origin: &alias_hazard::SelfFieldOrigin,
644) -> Option<bool> {
645 let body = tcx.optimized_mir(caller);
646 let self_ty = body.local_decls[Local::from_usize(1)].ty;
647 let ((adt_def, args), _) = match self_ty.kind() {
648 rustc_middle::ty::TyKind::Ref(_, inner, _)
649 if matches!(inner.kind(), rustc_middle::ty::TyKind::Adt(..)) =>
650 {
651 let (did, a) = crate::analysis::alias::adt_from_ty(*inner)?;
652 ((did, a), Some(inner))
653 }
654 _ => return None,
655 };
656 if adt_def != origin.struct_def_id {
657 return Some(false);
658 }
659 let adt = tcx.adt_def(adt_def);
660 let field = adt.all_fields().nth(origin.field_index)?;
661 #[cfg(not(rapx_ge_99))]
662 let field_ty = field.ty(tcx, args);
663 #[cfg(rapx_ge_99)]
664 let field_ty = field.ty(tcx, args).skip_norm_wip();
665 Some(matches!(
666 field_ty.kind(),
667 rustc_middle::ty::TyKind::Ref(_, _, rustc_middle::ty::Mutability::Not)
668 ))
669}
670
671fn resolve_origin_place_mir(tcx: rustc_middle::ty::TyCtxt<'_>, caller: DefId, place: &PlaceKey) -> PlaceKey {
673 let Some(local) = place.local() else {
674 return place.clone();
675 };
676 let origins = crate::analysis::alias::collect_local_origins(tcx, caller);
677 let (root_local, mut root_fields) =
678 crate::verify::alias_hazard::deep_resolve_place(local.as_usize(), &origins);
679
680 if root_local == local.as_usize() && root_fields.is_empty() && !place.fields.is_empty() {
682 root_fields = place.fields.clone();
683 }
684
685 if root_fields.is_empty() && !place.fields.is_empty() {
688 return place.clone();
689 }
690
691 PlaceKey::from_origin(root_local, root_fields)
692}
693
694fn check_ownership_transfer_alias<'ctx, 'tcx>(
695 vm_state: &VmState<'ctx, 'tcx>,
696 checkpoint: &Checkpoint<'tcx>,
697) -> VmAliasResult {
698 let Some(origin_arg) = checkpoint.args.first() else {
699 return VmAliasResult::Unknown;
700 };
701
702 let tcx = vm_state.tcx;
703 let caller = checkpoint.caller;
704 let call_block = checkpoint.block;
705 let destination = alias_hazard::call_destination(tcx, checkpoint);
706
707 let origin_place = alias_hazard::operand_place(origin_arg);
708 let Some(origin_place) = origin_place else {
709 return VmAliasResult::Unknown;
710 };
711
712 if let Some(reason) = alias_hazard::ownership_transfer_violation(
713 tcx, caller, call_block, destination, &origin_place,
714 ) {
715 return VmAliasResult::Failed(reason);
716 }
717
718 VmAliasResult::Proved
719}
720
721fn check_read_memory_alias<'ctx, 'tcx>(
722 vm_state: &VmState<'ctx, 'tcx>,
723 checkpoint: &Checkpoint<'tcx>,
724) -> VmAliasResult {
725 let Some(origin_arg) = checkpoint.args.first() else {
726 return VmAliasResult::Unknown;
727 };
728
729 let origin_val = vm_state.value_of_operand(origin_arg);
730
731 if vm_state.contract_flags.alias_hazard_accepted {
735 return VmAliasResult::Proved;
736 }
737
738 if let rustc_middle::ty::TyKind::RawPtr(pointee, _) = origin_val.ty.kind() {
740 let tcx = vm_state.tcx;
741 let typing_env = rustc_middle::ty::TypingEnv::post_analysis(tcx, checkpoint.caller);
742 if tcx.type_is_copy_modulo_regions(typing_env, *pointee) {
743 return VmAliasResult::Proved;
744 }
745 }
746
747 let tcx = vm_state.tcx;
749 let destination = alias_hazard::call_destination(tcx, checkpoint);
750 if !alias_hazard::destination_flows_to_return(tcx, checkpoint.caller, destination) {
751 return VmAliasResult::Proved;
752 }
753
754 VmAliasResult::Failed(
755 "read API value escapes while the source pointer persists — structural alias hazard"
756 .into(),
757 )
758}