diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 0d91f52461..a28418e749 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -7,6 +7,7 @@ use log::trace; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; +use crate::stacked_borrows::{AccessKind, SbTag}; use crate::*; /// Details of premature program termination. @@ -58,7 +59,9 @@ impl MachineStopType for TerminationInfo {} /// Miri specific diagnostics pub enum NonHaltingDiagnostic { CreatedPointerTag(NonZeroU64), - PoppedPointerTag(Item), + /// This `Item` was popped from the borrow stack, either due to a grant of + /// `AccessKind` to `SbTag` or a deallocation when the second argument is `None`. + PoppedPointerTag(Item, Option<(SbTag, AccessKind)>), CreatedCallId(CallId), CreatedAlloc(AllocId), FreedAlloc(AllocId), @@ -321,7 +324,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use NonHaltingDiagnostic::*; let msg = match e { CreatedPointerTag(tag) => format!("created tag {:?}", tag), - PoppedPointerTag(item) => format!("popped tracked tag for item {:?}", item), + PoppedPointerTag(item, tag) => + match tag { + None => + format!( + "popped tracked tag for item {:?} due to deallocation", + item + ), + Some((tag, access)) => { + format!( + "popped tracked tag for item {:?} due to {:?} access for {:?}", + item, access, tag + ) + } + }, CreatedCallId(id) => format!("function call with id {}", id), CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 57c09ea40b..2919ce919a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -111,7 +111,7 @@ pub struct GlobalState { pub type MemoryExtra = RefCell; /// Indicates which kind of access is being performed. -#[derive(Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] pub enum AccessKind { Read, Write, @@ -296,19 +296,26 @@ impl<'tcx> Stack { } /// Check if the given item is protected. + /// + /// The `provoking_access` argument is only used to produce diagnostics. + /// It is `Some` when we are granting the contained access for said tag, and it is + /// `None` during a deallocation. fn check_protector( item: &Item, - tag: Option, + provoking_access: Option<(SbTag, AccessKind)>, global: &GlobalState, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(item.clone())); + register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( + item.clone(), + provoking_access, + )); } } if let Some(call) = item.protector { if global.is_active(call) { - if let Some(tag) = tag { + if let Some((tag, _)) = provoking_access { Err(err_sb_ub(format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item @@ -348,7 +355,7 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector(&item, Some(tag), global)?; + Stack::check_protector(&item, Some((tag, access)), global)?; } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -363,7 +370,7 @@ impl<'tcx> Stack { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); - Stack::check_protector(item, Some(tag), global)?; + Stack::check_protector(item, Some((tag, access)), global)?; item.perm = Permission::Disabled; } }