diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d492a565a72..2eba3511838 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -706,7 +706,26 @@ fn reborrow( ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if size == Size::ZERO { - // Nothing to do for zero-sized accesses. + // Don't update any stacks for a zero-sized access; borrow stacks are per-byte and this + // touches no bytes so there is no stack to put this tag in. + // However, if the pointer for this operation points at a real allocation we still + // record where it was created so that we can issue a helpful diagnostic if there is an + // attempt to use it for a non-zero-sized access. + // Dangling slices are a common case here; it's valid to get their length but with raw + // pointer tagging for example all calls to get_unchecked on them are invalid. + if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { + let extra = this.get_alloc_extra(alloc_id)?; + let stacked_borrows = + extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let mut alloc_history = stacked_borrows.history.borrow_mut(); + alloc_history.log_creation( + Some(orig_tag), + new_tag, + alloc_range(base_offset, Size::ZERO), + &mut this.machine.current_span(), + ); + } + trace!( "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", kind, diff --git a/tests/compile-fail/stacked_borrows/zst_slice.stderr b/tests/compile-fail/stacked_borrows/zst_slice.stderr index f9d8b024e98..c6b4dc16b79 100644 --- a/tests/compile-fail/stacked_borrows/zst_slice.stderr +++ b/tests/compile-fail/stacked_borrows/zst_slice.stderr @@ -2,7 +2,11 @@ error: Undefined Behavior: trying to reborrow for SharedReadOnly permissio | = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - +help: was created by a retag at offsets [0x0..0x0] + --> $DIR/zst_slice.rs:LL:CC + | +LL | assert_eq!(*s.get_unchecked(1), 2); + | ^^^^^^^^^^^^^^^^^^ = note: inside `core::slice::::get_unchecked::` at rustc_src/src/slice/mod.rs:LL:CC note: inside `main` at $DIR/zst_slice.rs:LL:CC --> $DIR/zst_slice.rs:LL:CC