Skip to content

Commit

Permalink
also do not add noalias on not-Unpin Box
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Feb 6, 2023
1 parent 8e1bc87 commit c9f136b
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 16 deletions.
33 changes: 27 additions & 6 deletions src/borrow_tracker/stacked_borrows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,32 @@ impl NewPermission {
}
}

fn from_box_ty<'tcx>(
ty: Ty<'tcx>,
kind: RetagKind,
cx: &crate::MiriInterpCx<'_, 'tcx>,
) -> Self {
// `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling).
let pointee = ty.builtin_deref(true).unwrap().ty;
if pointee.is_unpin(*cx.tcx, cx.param_env()) {
// A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only
// a weak protector).
NewPermission::Uniform {
perm: Permission::Unique,
access: Some(AccessKind::Write),
protector: (kind == RetagKind::FnEntry)
.then_some(ProtectorKind::WeakProtector),
}
} else {
// `!Unpin` boxes do not get `noalias` nor `dereferenceable`.
NewPermission::Uniform {
perm: Permission::SharedReadWrite,
access: None,
protector: None,
}
}
}

fn protector(&self) -> Option<ProtectorKind> {
match self {
NewPermission::Uniform { protector, .. } => *protector,
Expand Down Expand Up @@ -914,12 +940,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
// Boxes get a weak protectors, since they may be deallocated.
let new_perm = NewPermission::Uniform {
perm: Permission::Unique,
access: Some(AccessKind::Write),
protector: (self.kind == RetagKind::FnEntry)
.then_some(ProtectorKind::WeakProtector),
};
let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
self.retag_ptr_inplace(place, new_perm, self.retag_cause)
}

Expand Down
54 changes: 44 additions & 10 deletions tests/pass/stacked-borrows/future-self-referential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ impl Future for Delay {
}
}

fn mk_waker() -> Waker {
use std::sync::Arc;

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

Waker::from(Arc::new(MyWaker))
}

async fn do_stuff() {
(&mut Delay::new(1)).await;
}
Expand Down Expand Up @@ -73,16 +86,7 @@ impl Future for DoStuff {
}

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 waker = mk_waker();
let mut context = Context::from_waker(&waker);

let mut pinned = pin!(fut);
Expand All @@ -94,7 +98,37 @@ fn run_fut<T>(fut: impl Future<Output = T>) -> T {
}
}

fn self_referential_box() {
let waker = mk_waker();
let cx = &mut Context::from_waker(&waker);

async fn my_fut() -> i32 {
let val = 10;
let val_ref = &val;

let _ = Delay::new(1).await;

*val_ref
}

fn box_poll<F: Future>(
mut f: Pin<Box<F>>,
cx: &mut Context<'_>,
) -> (Pin<Box<F>>, Poll<F::Output>) {
let p = f.as_mut().poll(cx);
(f, p)
}

let my_fut = Box::pin(my_fut());
let (my_fut, p1) = box_poll(my_fut, cx);
assert!(p1.is_pending());
let (my_fut, p2) = box_poll(my_fut, cx);
assert!(p2.is_ready());
drop(my_fut);
}

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

0 comments on commit c9f136b

Please sign in to comment.