Skip to content

Commit

Permalink
Auto merge of rust-lang#2713 - RalfJung:not-unpin-fake-read, r=RalfJung
Browse files Browse the repository at this point in the history
for now, do not do fake reads on non-Unpin mutable references

Work-around for rust-lang/unsafe-code-guidelines#381, needed to make the new test pass. Undoes parts of rust-lang/miri#2694.
  • Loading branch information
bors committed Dec 3, 2022
2 parents 9562aac + 30e3ca7 commit 5d2ee92
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 54 deletions.
23 changes: 14 additions & 9 deletions src/borrow_tracker/stacked_borrows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ pub struct Stacks {
/// new pointer.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
enum RefKind {
/// `&mut` and `Box`.
/// `Box`.
Box,
/// `&mut`.
Unique { two_phase: bool },
/// `&` with or without interior mutability.
Shared,
Expand All @@ -56,6 +58,7 @@ enum RefKind {
impl fmt::Display for RefKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RefKind::Box => write!(f, "Box"),
RefKind::Unique { two_phase: false } => write!(f, "unique reference"),
RefKind::Unique { two_phase: true } => write!(f, "unique reference (two-phase)"),
RefKind::Shared => write!(f, "shared reference"),
Expand Down Expand Up @@ -654,15 +657,17 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
let (perm, access) = match kind {
RefKind::Unique { two_phase } => {
// Permission is Unique only if the type is `Unpin` and this is not twophase
let perm = if !two_phase && place.layout.ty.is_unpin(*this.tcx, this.param_env()) {
Permission::Unique
if !two_phase && place.layout.ty.is_unpin(*this.tcx, this.param_env()) {
(Permission::Unique, Some(AccessKind::Write))
} else {
Permission::SharedReadWrite
};
// We do an access for all full borrows, even if `!Unpin`.
let access = if !two_phase { Some(AccessKind::Write) } else { None };
(perm, access)
// FIXME: We emit `dereferenceable` for `!Unpin` mutable references, so we
// should do fake accesses here. But then we run into
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>, so for now
// we don't do that.
(Permission::SharedReadWrite, None)
}
}
RefKind::Box => (Permission::Unique, Some(AccessKind::Write)),
RefKind::Raw { mutable: true } => {
// Creating a raw ptr does not count as an access
(Permission::SharedReadWrite, None)
Expand Down Expand Up @@ -853,7 +858,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Boxes get a weak protectors, since they may be deallocated.
self.retag_place(
place,
RefKind::Unique { two_phase: false },
RefKind::Box,
self.retag_cause,
/*protector*/
(self.kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector),
Expand Down
17 changes: 0 additions & 17 deletions tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.rs

This file was deleted.

This file was deleted.

102 changes: 102 additions & 0 deletions tests/pass/stacked-borrows/future-self-referential.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#![feature(pin_macro)]

use std::future::*;
use std::marker::PhantomPinned;
use std::pin::*;
use std::ptr;
use std::task::*;

struct Delay {
delay: usize,
}

impl Delay {
fn new(delay: usize) -> Self {
Delay { delay }
}
}

impl Future for Delay {
type Output = ();
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
if self.delay > 0 {
self.delay -= 1;
Poll::Pending
} else {
Poll::Ready(())
}
}
}

async fn do_stuff() {
(&mut Delay::new(1)).await;
}

// Same thing implemented by hand
struct DoStuff {
state: usize,
delay: Delay,
delay_ref: *mut Delay,
_marker: PhantomPinned,
}

impl DoStuff {
fn new() -> Self {
DoStuff {
state: 0,
delay: Delay::new(1),
delay_ref: ptr::null_mut(),
_marker: PhantomPinned,
}
}
}

impl Future for DoStuff {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
unsafe {
let this = self.get_unchecked_mut();
match this.state {
0 => {
// Set up self-ref.
this.delay_ref = &mut this.delay;
// Move to next state.
this.state = 1;
Poll::Pending
}
1 => {
let delay = &mut *this.delay_ref;
Pin::new_unchecked(delay).poll(cx)
}
_ => unreachable!(),
}
}
}
}

fn run_fut<T>(fut: impl Future<Output = T>) -> T {
use std::sync::Arc;

struct MyWaker;
impl Wake for MyWaker {
fn wake(self: Arc<Self>) {
unimplemented!()
}
}

let waker = Waker::from(Arc::new(MyWaker));
let mut context = Context::from_waker(&waker);

let mut pinned = pin!(fut);
loop {
match pinned.as_mut().poll(&mut context) {
Poll::Pending => continue,
Poll::Ready(v) => return v,
}
}
}

fn main() {
run_fut(do_stuff());
run_fut(DoStuff::new());
}

0 comments on commit 5d2ee92

Please sign in to comment.