Skip to content

Commit 84b66f0

Browse files
authored
Merge pull request #572 from solson/rustup
Treat ref-to-raw cast like a reborrow: do a special kind of retag
2 parents 8359898 + 2c2587b commit 84b66f0

File tree

4 files changed

+32
-61
lines changed

4 files changed

+32
-61
lines changed

rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
nightly-2018-12-18
1+
nightly-2018-12-21

src/lib.rs

+2-28
Original file line numberDiff line numberDiff line change
@@ -526,36 +526,10 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
526526
}
527527
}
528528

529-
#[inline]
530-
fn escape_to_raw(
531-
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
532-
ptr: OpTy<'tcx, Self::PointerTag>,
533-
) -> EvalResult<'tcx> {
534-
// It is tempting to check the type here, but drop glue does EscapeToRaw
535-
// on a raw pointer.
536-
// This is deliberately NOT `deref_operand` as we do not want `tag_dereference`
537-
// to be called! That would kill the original tag if we got a raw ptr.
538-
let place = ecx.ref_to_mplace(ecx.read_immediate(ptr)?)?;
539-
let size = ecx.size_and_align_of_mplace(place)?.map(|(size, _)| size)
540-
// for extern types, just cover what we can
541-
.unwrap_or_else(|| place.layout.size);
542-
if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag ||
543-
!ecx.machine.validate || size == Size::ZERO
544-
{
545-
// No tracking, or no retagging. The latter is possible because a dependency of ours
546-
// might be called with different flags than we are, so there are `Retag`
547-
// statements but we do not want to execute them.
548-
Ok(())
549-
} else {
550-
ecx.escape_to_raw(place, size)
551-
}
552-
}
553-
554529
#[inline(always)]
555530
fn retag(
556531
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
557-
fn_entry: bool,
558-
two_phase: bool,
532+
kind: mir::RetagKind,
559533
place: PlaceTy<'tcx, Borrow>,
560534
) -> EvalResult<'tcx> {
561535
if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) {
@@ -566,7 +540,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
566540
// uninitialized data.
567541
Ok(())
568542
} else {
569-
ecx.retag(fn_entry, two_phase, place)
543+
ecx.retag(kind, place)
570544
}
571545
}
572546

src/stacked_borrows.rs

+24-28
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::rc::Rc;
44

55
use rustc::ty::{self, layout::Size};
66
use rustc::hir::{Mutability, MutMutable, MutImmutable};
7+
use rustc::mir::RetagKind;
78

89
use crate::{
910
EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor,
@@ -550,10 +551,11 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
550551
}
551552

552553
/// Retag an indidual pointer, returning the retagged version.
554+
/// `mutbl` can be `None` to make this a raw pointer.
553555
fn retag_reference(
554556
&mut self,
555557
val: ImmTy<'tcx, Borrow>,
556-
mutbl: Mutability,
558+
mutbl: Option<Mutability>,
557559
fn_barrier: bool,
558560
two_phase: bool,
559561
) -> EvalResult<'tcx, Immediate<Borrow>> {
@@ -571,16 +573,17 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
571573
// Compute new borrow.
572574
let time = this.machine.stacked_borrows.increment_clock();
573575
let new_bor = match mutbl {
574-
MutMutable => Borrow::Uniq(time),
575-
MutImmutable => Borrow::Shr(Some(time)),
576+
Some(MutMutable) => Borrow::Uniq(time),
577+
Some(MutImmutable) => Borrow::Shr(Some(time)),
578+
None => Borrow::default(),
576579
};
577580

578581
// Reborrow.
579582
this.reborrow(place, size, fn_barrier, new_bor)?;
580583
let new_place = place.with_tag(new_bor);
581584
// Handle two-phase borrows.
582585
if two_phase {
583-
assert!(mutbl == MutMutable, "two-phase shared borrows make no sense");
586+
assert!(mutbl == Some(MutMutable), "two-phase shared borrows make no sense");
584587
// We immediately share it, to allow read accesses
585588
let two_phase_time = this.machine.stacked_borrows.increment_clock();
586589
let two_phase_bor = Borrow::Shr(Some(two_phase_time));
@@ -665,59 +668,47 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
665668
Ok(())
666669
}
667670

668-
/// The given place may henceforth be accessed through raw pointers.
669-
#[inline(always)]
670-
fn escape_to_raw(
671-
&mut self,
672-
place: MPlaceTy<'tcx, Borrow>,
673-
size: Size,
674-
) -> EvalResult<'tcx> {
675-
let this = self.eval_context_mut();
676-
this.reborrow(place, size, /*fn_barrier*/ false, Borrow::default())?;
677-
Ok(())
678-
}
679-
680671
fn retag(
681672
&mut self,
682-
fn_entry: bool,
683-
two_phase: bool,
673+
kind: RetagKind,
684674
place: PlaceTy<'tcx, Borrow>
685675
) -> EvalResult<'tcx> {
686676
let this = self.eval_context_mut();
687677
// Determine mutability and whether to add a barrier.
688678
// Cannot use `builtin_deref` because that reports *immutable* for `Box`,
689679
// making it useless.
690-
fn qualify(ty: ty::Ty<'_>, fn_entry: bool) -> Option<(Mutability, bool)> {
680+
fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(Option<Mutability>, bool)> {
691681
match ty.sty {
692682
// References are simple
693-
ty::Ref(_, _, mutbl) => Some((mutbl, fn_entry)),
683+
ty::Ref(_, _, mutbl) => Some((Some(mutbl), kind == RetagKind::FnEntry)),
684+
// Raw pointers need to be enabled
685+
ty::RawPtr(..) if kind == RetagKind::Raw => Some((None, false)),
694686
// Boxes do not get a barrier: Barriers reflect that references outlive the call
695687
// they were passed in to; that's just not the case for boxes.
696-
ty::Adt(..) if ty.is_box() => Some((MutMutable, false)),
688+
ty::Adt(..) if ty.is_box() => Some((Some(MutMutable), false)),
697689
_ => None,
698690
}
699691
}
700692

701693
// We need a visitor to visit all references. However, that requires
702694
// a `MemPlace`, so we have a fast path for reference types that
703695
// avoids allocating.
704-
if let Some((mutbl, barrier)) = qualify(place.layout.ty, fn_entry) {
696+
if let Some((mutbl, barrier)) = qualify(place.layout.ty, kind) {
705697
// fast path
706698
let val = this.read_immediate(this.place_to_op(place)?)?;
707-
let val = this.retag_reference(val, mutbl, barrier, two_phase)?;
699+
let val = this.retag_reference(val, mutbl, barrier, kind == RetagKind::TwoPhase)?;
708700
this.write_immediate(val, place)?;
709701
return Ok(());
710702
}
711703
let place = this.force_allocation(place)?;
712704

713-
let mut visitor = RetagVisitor { ecx: this, fn_entry, two_phase };
705+
let mut visitor = RetagVisitor { ecx: this, kind };
714706
visitor.visit_value(place)?;
715707

716708
// The actual visitor
717709
struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> {
718710
ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>,
719-
fn_entry: bool,
720-
two_phase: bool,
711+
kind: RetagKind,
721712
}
722713
impl<'ecx, 'a, 'mir, 'tcx>
723714
MutValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>>
@@ -736,9 +727,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
736727
{
737728
// Cannot use `builtin_deref` because that reports *immutable* for `Box`,
738729
// making it useless.
739-
if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.fn_entry) {
730+
if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.kind) {
740731
let val = self.ecx.read_immediate(place.into())?;
741-
let val = self.ecx.retag_reference(val, mutbl, barrier, self.two_phase)?;
732+
let val = self.ecx.retag_reference(
733+
val,
734+
mutbl,
735+
barrier,
736+
self.kind == RetagKind::TwoPhase
737+
)?;
742738
self.ecx.write_immediate(val, place.into())?;
743739
}
744740
Ok(())
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// Make sure we cannot use raw ptrs that got transmuted from mutable references
22
// (i.e, no EscapeToRaw happened).
3-
// We could, in principle, to EscapeToRaw lazily to allow this code, but that
3+
// We could, in principle, do EscapeToRaw lazily to allow this code, but that
44
// would no alleviate the need for EscapeToRaw (see `ref_raw_int_raw` in
55
// `run-pass/stacked-borrows.rs`), and thus increase overall complexity.
66
use std::mem;
77

88
fn main() {
9-
let mut x: i32 = 42;
10-
let raw: *mut i32 = unsafe { mem::transmute(&mut x) };
11-
let raw = raw as usize as *mut i32; // make sure we killed the tag
9+
let mut x: [i32; 2] = [42, 43];
10+
let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) };
11+
// `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag
12+
let raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
1213
unsafe { *raw = 13; } //~ ERROR does not exist on the stack
1314
}

0 commit comments

Comments
 (0)