Skip to content

Commit 0805b4b

Browse files
committed
retag return places
1 parent 90d71cd commit 0805b4b

File tree

2 files changed

+50
-9
lines changed

2 files changed

+50
-9
lines changed

src/machine.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -481,11 +481,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
481481
kind: mir::RetagKind,
482482
place: PlaceTy<'tcx, Tag>,
483483
) -> InterpResult<'tcx> {
484-
if ecx.memory.extra.stacked_borrows.is_none() {
485-
// No tracking.
486-
Ok(())
487-
} else {
484+
if ecx.memory.extra.stacked_borrows.is_some() {
488485
ecx.retag(kind, place)
486+
} else {
487+
Ok(())
489488
}
490489
}
491490

@@ -502,6 +501,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
502501
Ok(frame.with_extra(extra))
503502
}
504503

504+
#[inline(always)]
505+
fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
506+
if ecx.memory.extra.stacked_borrows.is_some() {
507+
ecx.retag_return_place()
508+
} else {
509+
Ok(())
510+
}
511+
}
512+
505513
#[inline(always)]
506514
fn after_stack_pop(
507515
ecx: &mut InterpCx<'mir, 'tcx, Self>,

src/stacked_borrows.rs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use log::trace;
1111
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1212
use rustc_middle::mir::RetagKind;
1313
use rustc_middle::ty;
14-
use rustc_target::abi::Size;
14+
use rustc_target::abi::{LayoutOf, Size};
1515
use rustc_hir::Mutability;
1616

1717
use crate::*;
@@ -569,7 +569,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
569569
val: ImmTy<'tcx, Tag>,
570570
kind: RefKind,
571571
protect: bool,
572-
) -> InterpResult<'tcx, Immediate<Tag>> {
572+
) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> {
573573
let this = self.eval_context_mut();
574574
// We want a place for where the ptr *points to*, so we get one.
575575
let place = this.ref_to_mplace(val)?;
@@ -582,7 +582,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
582582
let place = this.mplace_access_checked(place)?;
583583
if size == Size::ZERO {
584584
// Nothing to do for ZSTs.
585-
return Ok(*val);
585+
return Ok(val);
586586
}
587587

588588
// Compute new borrow.
@@ -603,7 +603,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
603603
let new_place = place.replace_tag(new_tag);
604604

605605
// Return new pointer.
606-
Ok(new_place.to_ref())
606+
Ok(ImmTy::from_immediate(new_place.to_ref(), val.layout))
607607
}
608608
}
609609

@@ -640,9 +640,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
640640
// Fast path.
641641
let val = this.read_immediate(this.place_to_op(place)?)?;
642642
let val = this.retag_reference(val, mutbl, protector)?;
643-
this.write_immediate(val, place)?;
643+
this.write_immediate(*val, place)?;
644644
}
645645

646646
Ok(())
647647
}
648+
649+
/// After a stack frame got pushed, retag the return place so that we are sure
650+
/// it does not alias with anything.
651+
///
652+
/// This is a HACK because there is nothing in MIR that would make the retag
653+
/// explicit. Also see https://github.com/rust-lang/rust/issues/71117.
654+
fn retag_return_place(&mut self) -> InterpResult<'tcx> {
655+
let this = self.eval_context_mut();
656+
let return_place = if let Some(return_place) = this.frame_mut().return_place {
657+
return_place
658+
} else {
659+
// No return place, nothing to do.
660+
return Ok(());
661+
};
662+
if return_place.layout.is_zst() {
663+
// There may not be any memory here, nothing to do.
664+
return Ok(());
665+
}
666+
// We need this to be in-memory to use tagged pointers.
667+
let return_place = this.force_allocation(return_place)?;
668+
669+
// We have to turn the place into a pointer to use the existing code.
670+
// (The pointer type does not matter, so we use a raw pointer.)
671+
let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?;
672+
let val = ImmTy::from_immediate(return_place.to_ref(), ptr_layout);
673+
// Reborrow it.
674+
let val = this.retag_reference(val, RefKind::Unique { two_phase: false }, /*protector*/ true)?;
675+
// And use reborrowed pointer for return place.
676+
let return_place = this.ref_to_mplace(val)?;
677+
this.frame_mut().return_place = Some(return_place.into());
678+
679+
Ok(())
680+
}
648681
}

0 commit comments

Comments
 (0)