diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs | 33 | ||||
| -rw-r--r-- | src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs | 54 |
2 files changed, 71 insertions, 16 deletions
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 3b3a41c2f03..106e93751d2 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -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, @@ -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) } diff --git a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs index 96fc0be344d..6994def16a1 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs @@ -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; } @@ -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); @@ -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(); } |
