Improve information sharing across SB diagnostics

Previous Stacked Borrows diagnostics were missing a lot of information
about the state of the interpreter, and it was difficult to add
additional state because it was threaded through all the intervening
function signatures.

This change factors a lot of the arguments which used to be passed
individually to many stacked borrows functions into a single
`DiagnosticCx`, which is built in `Stacks::for_each`, and since it
wraps a handle to `AllocHistory`, we can now handle more nuanced
things like heterogeneous borrow of `!Freeze` types.
This commit is contained in:
Ben Kimock 2022-05-22 19:39:09 -04:00 committed by Ralf Jung
parent 46da748502
commit 14e72e7ffa
77 changed files with 877 additions and 522 deletions

View File

@ -178,20 +178,15 @@ pub fn report_error<'tcx, 'mir>(
(None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental")),
(None, format!("see {url} for further information")),
];
match history {
Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => {
let msg = format!("{tag:?} was created by a retag at offsets {created_range:?}");
helps.push((Some(*created_span), msg));
if let Some((invalidated_range, invalidated_span)) = invalidated {
let msg = format!("{tag:?} was later invalidated at offsets {invalidated_range:?}");
helps.push((Some(*invalidated_span), msg));
}
if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected {
helps.push((Some(*protecting_tag_span), format!("{tag:?} was protected due to {protecting_tag:?} which was created here")));
helps.push((Some(*protection_span), format!("this protector is live for this call")));
}
if let Some(TagHistory {created, invalidated, protected}) = history.clone() {
helps.push((Some(created.1), created.0));
if let Some((msg, span)) = invalidated {
helps.push((Some(span), msg));
}
if let Some([(protector_msg, protector_span), (protection_msg, protection_span)]) = protected {
helps.push((Some(protector_span), protector_msg));
helps.push((Some(protection_span), protection_msg));
}
None => {}
}
helps
}

View File

@ -876,8 +876,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
pub fn current_span(&self) -> CurrentSpan<'_, 'mir, 'tcx> {
CurrentSpan { span: None, machine: self }
pub fn current_span(&self, tcx: TyCtxt<'tcx>) -> CurrentSpan<'_, 'mir, 'tcx> {
CurrentSpan { span: None, machine: self, tcx }
}
}
@ -888,27 +888,61 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
#[derive(Clone)]
pub struct CurrentSpan<'a, 'mir, 'tcx> {
span: Option<Span>,
tcx: TyCtxt<'tcx>,
machine: &'a Evaluator<'mir, 'tcx>,
}
impl<'a, 'mir, 'tcx> CurrentSpan<'a, 'mir, 'tcx> {
impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> {
/// Get the current span, skipping non-local frames.
/// This function is backed by a cache, and can be assumed to be very fast.
pub fn get(&mut self) -> Span {
*self.span.get_or_insert_with(|| Self::current_span(self.machine))
*self.span.get_or_insert_with(|| Self::current_span(self.tcx, self.machine))
}
/// Similar to `CurrentSpan::get`, but retrieves the parent frame of the first non-local frame.
/// This is useful when we are processing something which occurs on function-entry and we want
/// to point at the call to the function, not the function definition generally.
#[inline(never)]
pub fn get_parent(&mut self) -> Span {
let idx = Self::current_span_index(self.tcx, self.machine);
Self::nth_span(self.machine, idx.wrapping_sub(1))
}
#[inline(never)]
fn current_span(machine: &Evaluator<'_, '_>) -> Span {
fn current_span(tcx: TyCtxt<'_>, machine: &Evaluator<'_, '_>) -> Span {
let idx = Self::current_span_index(tcx, machine);
Self::nth_span(machine, idx)
}
fn nth_span(machine: &Evaluator<'_, '_>, idx: usize) -> Span {
machine
.threads
.active_thread_stack()
.get(idx)
.map(Frame::current_span)
.unwrap_or(rustc_span::DUMMY_SP)
}
// Find the position of the inner-most frame which is part of the crate being
// compiled/executed, part of the Cargo workspace, and is also not #[track_caller].
fn current_span_index(tcx: TyCtxt<'_>, machine: &Evaluator<'_, '_>) -> usize {
machine
.threads
.active_thread_stack()
.iter()
.enumerate()
.rev()
.find(|frame| {
.find_map(|(idx, frame)| {
let def_id = frame.instance.def_id();
def_id.is_local() || machine.local_crates.contains(&def_id.krate)
if (def_id.is_local() || machine.local_crates.contains(&def_id.krate))
&& !frame.instance.def.requires_caller_location(tcx)
{
Some(idx)
} else {
None
}
})
.map(|frame| frame.current_span())
.unwrap_or(rustc_span::DUMMY_SP)
.unwrap_or(0)
}
}

View File

@ -137,7 +137,7 @@ pub enum Provenance {
}
/// The "extra" information a pointer has over a regular AllocId.
#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq)]
pub enum ProvenanceExtra {
Concrete(SbTag),
Wildcard,
@ -706,15 +706,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
}
let alloc = alloc.into_owned();
let stacks = ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| {
Stacks::new_allocation(
id,
alloc.size(),
stacked_borrows,
kind,
ecx.machine.current_span(),
)
});
let stacks =
ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| {
Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind)
});
let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| {
data_race::AllocExtra::new_allocation(
data_race,
@ -808,7 +803,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
#[inline(always)]
fn before_memory_read(
_tcx: TyCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
machine: &Self,
alloc_extra: &AllocExtra,
(alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
@ -828,7 +823,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
prov_extra,
range,
machine.stacked_borrows.as_ref().unwrap(),
machine.current_span(),
machine.current_span(tcx),
&machine.threads,
)?;
}
@ -840,7 +835,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
#[inline(always)]
fn before_memory_write(
_tcx: TyCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
machine: &mut Self,
alloc_extra: &mut AllocExtra,
(alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
@ -860,7 +855,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
prov_extra,
range,
machine.stacked_borrows.as_ref().unwrap(),
machine.current_span(),
machine.current_span(tcx),
&machine.threads,
)?;
}
@ -872,7 +867,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
#[inline(always)]
fn before_memory_deallocation(
_tcx: TyCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
machine: &mut Self,
alloc_extra: &mut AllocExtra,
(alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra),
@ -895,6 +890,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
prove_extra,
range,
machine.stacked_borrows.as_ref().unwrap(),
machine.current_span(tcx),
&machine.threads,
)
} else {

View File

@ -1,91 +1,294 @@
use smallvec::SmallVec;
use std::fmt;
use rustc_middle::mir::interpret::{AllocId, AllocRange};
use rustc_middle::mir::interpret::{alloc_range, AllocId, AllocRange};
use rustc_span::{Span, SpanData};
use rustc_target::abi::Size;
use crate::helpers::CurrentSpan;
use crate::stacked_borrows::{err_sb_ub, AccessKind};
use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission};
use crate::*;
use rustc_middle::mir::interpret::InterpError;
#[derive(Clone, Debug)]
pub struct AllocHistory {
// The time tags can be compressed down to one bit per event, by just storing a Vec<u8>
// where each bit is set to indicate if the event was a creation or a retag
current_time: usize,
creations: smallvec::SmallVec<[Event; 2]>,
invalidations: smallvec::SmallVec<[Event; 1]>,
id: AllocId,
creations: smallvec::SmallVec<[Creation; 1]>,
invalidations: smallvec::SmallVec<[Invalidation; 1]>,
protectors: smallvec::SmallVec<[Protection; 1]>,
}
#[derive(Clone, Debug)]
struct Protection {
orig_tag: SbTag,
tag: SbTag,
struct Creation {
retag: RetagOp,
span: Span,
}
impl Creation {
fn generate_diagnostic(&self) -> (String, SpanData) {
let tag = self.retag.new_tag;
if let Some(perm) = self.retag.permission {
(
format!(
"{tag:?} was created by a {:?} retag at offsets {:?}",
perm, self.retag.range,
),
self.span.data(),
)
} else {
assert!(self.retag.range.size == Size::ZERO);
(
format!(
"{tag:?} would have been created here, but this is a zero-size retag ({:?}) so the tag in question does not exist anywhere",
self.retag.range,
),
self.span.data(),
)
}
}
}
#[derive(Clone, Debug)]
struct Event {
parent: Option<SbTag>,
struct Invalidation {
tag: SbTag,
range: AllocRange,
span: Span,
cause: InvalidationCause,
}
pub enum TagHistory {
Tagged {
tag: SbTag,
created: (AllocRange, SpanData),
invalidated: Option<(AllocRange, SpanData)>,
protected: Option<(SbTag, SpanData, SpanData)>,
},
#[derive(Clone, Debug)]
enum InvalidationCause {
Access(AccessKind),
Retag(Permission, RetagCause),
}
impl Invalidation {
fn generate_diagnostic(&self) -> (String, SpanData) {
(
format!(
"{:?} was later invalidated at offsets {:?} by a {}",
self.tag, self.range, self.cause
),
self.span.data(),
)
}
}
impl fmt::Display for InvalidationCause {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InvalidationCause::Access(kind) => write!(f, "{}", kind),
InvalidationCause::Retag(perm, kind) =>
if *kind == RetagCause::FnEntry {
write!(f, "{:?} FnEntry retag", perm)
} else {
write!(f, "{:?} retag", perm)
},
}
}
}
#[derive(Clone, Debug)]
struct Protection {
orig_tag: ProvenanceExtra,
tag: SbTag,
span: Span,
}
#[derive(Clone)]
pub struct TagHistory {
pub created: (String, SpanData),
pub invalidated: Option<(String, SpanData)>,
pub protected: Option<([(String, SpanData); 2])>,
}
pub struct DiagnosticCxBuilder<'ecx, 'mir, 'tcx> {
operation: Operation,
current_span: CurrentSpan<'ecx, 'mir, 'tcx>,
threads: &'ecx ThreadManager<'mir, 'tcx>,
}
pub struct DiagnosticCx<'ecx, 'mir, 'tcx, 'history> {
operation: Operation,
current_span: CurrentSpan<'ecx, 'mir, 'tcx>,
threads: &'ecx ThreadManager<'mir, 'tcx>,
history: &'history mut AllocHistory,
offset: Size,
}
impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> {
pub fn build(
self,
history: &'history mut AllocHistory,
offset: Size,
) -> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> {
DiagnosticCx {
operation: self.operation,
current_span: self.current_span,
threads: self.threads,
history,
offset,
}
}
pub fn retag(
current_span: CurrentSpan<'ecx, 'mir, 'tcx>,
threads: &'ecx ThreadManager<'mir, 'tcx>,
cause: RetagCause,
new_tag: SbTag,
orig_tag: ProvenanceExtra,
range: AllocRange,
) -> Self {
let operation =
Operation::Retag(RetagOp { cause, new_tag, orig_tag, range, permission: None });
DiagnosticCxBuilder { current_span, threads, operation }
}
pub fn read(
current_span: CurrentSpan<'ecx, 'mir, 'tcx>,
threads: &'ecx ThreadManager<'mir, 'tcx>,
tag: ProvenanceExtra,
range: AllocRange,
) -> Self {
let operation = Operation::Access(AccessOp { kind: AccessKind::Read, tag, range });
DiagnosticCxBuilder { current_span, threads, operation }
}
pub fn write(
current_span: CurrentSpan<'ecx, 'mir, 'tcx>,
threads: &'ecx ThreadManager<'mir, 'tcx>,
tag: ProvenanceExtra,
range: AllocRange,
) -> Self {
let operation = Operation::Access(AccessOp { kind: AccessKind::Write, tag, range });
DiagnosticCxBuilder { current_span, threads, operation }
}
pub fn dealloc(
current_span: CurrentSpan<'ecx, 'mir, 'tcx>,
threads: &'ecx ThreadManager<'mir, 'tcx>,
tag: ProvenanceExtra,
) -> Self {
let operation = Operation::Dealloc(DeallocOp { tag });
DiagnosticCxBuilder { current_span, threads, operation }
}
}
impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> {
pub fn unbuild(self) -> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> {
DiagnosticCxBuilder {
operation: self.operation,
current_span: self.current_span,
threads: self.threads,
}
}
}
#[derive(Debug, Clone)]
enum Operation {
Retag(RetagOp),
Access(AccessOp),
Dealloc(DeallocOp),
}
#[derive(Debug, Clone)]
struct RetagOp {
cause: RetagCause,
new_tag: SbTag,
orig_tag: ProvenanceExtra,
range: AllocRange,
permission: Option<Permission>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum RetagCause {
Normal,
FnReturn,
FnEntry,
TwoPhase,
}
#[derive(Debug, Clone)]
struct AccessOp {
kind: AccessKind,
tag: ProvenanceExtra,
range: AllocRange,
}
#[derive(Debug, Clone)]
struct DeallocOp {
tag: ProvenanceExtra,
}
impl AllocHistory {
pub fn new() -> Self {
pub fn new(id: AllocId) -> Self {
Self {
current_time: 0,
id,
creations: SmallVec::new(),
invalidations: SmallVec::new(),
protectors: SmallVec::new(),
}
}
}
pub fn log_creation(
&mut self,
parent: Option<SbTag>,
tag: SbTag,
range: AllocRange,
current_span: &mut CurrentSpan<'_, '_, '_>,
) {
let span = current_span.get();
self.creations.push(Event { parent, tag, range, span });
self.current_time += 1;
impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> {
pub fn start_grant(&mut self, perm: Permission) {
let Operation::Retag(op) = &mut self.operation else {
unreachable!("start_grant must only be called during a retag, this is: {:?}", self.operation)
};
op.permission = Some(perm);
let last_creation = &mut self.history.creations.last_mut().unwrap();
match last_creation.retag.permission {
None => {
last_creation.retag.permission = Some(perm);
}
Some(previous) =>
if previous != perm {
let previous_range = last_creation.retag.range;
last_creation.retag.range = alloc_range(previous_range.start, self.offset);
let mut new_event = last_creation.clone();
new_event.retag.range = alloc_range(self.offset, previous_range.end());
new_event.retag.permission = Some(perm);
self.history.creations.push(new_event);
},
}
}
pub fn log_invalidation(
&mut self,
tag: SbTag,
range: AllocRange,
current_span: &mut CurrentSpan<'_, '_, '_>,
) {
let span = current_span.get();
self.invalidations.push(Event { parent: None, tag, range, span });
self.current_time += 1;
pub fn log_creation(&mut self) {
let Operation::Retag(op) = &self.operation else {
unreachable!("log_creation must only be called during a retag")
};
self.history.creations.push(Creation { retag: op.clone(), span: self.current_span.get() });
}
pub fn log_protector(
&mut self,
orig_tag: SbTag,
tag: SbTag,
current_span: &mut CurrentSpan<'_, '_, '_>,
) {
let span = current_span.get();
self.protectors.push(Protection { orig_tag, tag, span });
self.current_time += 1;
pub fn log_invalidation(&mut self, tag: SbTag) {
let mut span = self.current_span.get();
let (range, cause) = match &self.operation {
Operation::Retag(RetagOp { cause, range, permission, .. }) => {
if *cause == RetagCause::FnEntry {
span = self.current_span.get_parent();
}
(*range, InvalidationCause::Retag(permission.unwrap(), *cause))
}
Operation::Access(AccessOp { kind, range, .. }) =>
(*range, InvalidationCause::Access(*kind)),
_ => unreachable!("Tags can only be invalidated during a retag or access"),
};
self.history.invalidations.push(Invalidation { tag, range, span, cause });
}
pub fn log_protector(&mut self) {
let Operation::Retag(op) = &self.operation else {
unreachable!("Protectors can only be created during a retag")
};
self.history.protectors.push(Protection {
orig_tag: op.orig_tag,
tag: op.new_tag,
span: self.current_span.get(),
});
}
pub fn get_logs_relevant_to(
@ -93,9 +296,48 @@ impl AllocHistory {
tag: SbTag,
protector_tag: Option<SbTag>,
) -> Option<TagHistory> {
let Some(created) = self.history
.creations
.iter()
.rev()
.find_map(|event| {
// First, look for a Creation event where the tag and the offset matches. This
// ensrues that we pick the right Creation event when a retag isn't uniform due to
// Freeze.
let range = event.retag.range;
if event.retag.new_tag == tag
&& self.offset >= range.start
&& self.offset < (range.start + range.size)
{
Some(event.generate_diagnostic())
} else {
None
}
})
.or_else(|| {
// If we didn't find anything with a matching offset, just return the event where
// the tag was created. This branch is hit when we use a tag at an offset that
// doesn't have the tag.
self.history.creations.iter().rev().find_map(|event| {
if event.retag.new_tag == tag {
Some(event.generate_diagnostic())
} else {
None
}
})
}) else {
// But if we don't have a creation event, this is related to a wildcard, and there
// is really nothing we can do to help.
return None;
};
let invalidated = self.history.invalidations.iter().rev().find_map(|event| {
if event.tag == tag { Some(event.generate_diagnostic()) } else { None }
});
let protected = protector_tag
.and_then(|protector| {
self.protectors.iter().find_map(|protection| {
self.history.protectors.iter().find_map(|protection| {
if protection.tag == protector {
Some((protection.orig_tag, protection.span.data()))
} else {
@ -104,77 +346,141 @@ impl AllocHistory {
})
})
.and_then(|(tag, call_span)| {
self.creations.iter().rev().find_map(|event| {
if event.tag == tag {
Some((event.parent?, event.span.data(), call_span))
self.history.creations.iter().rev().find_map(|event| {
if ProvenanceExtra::Concrete(event.retag.new_tag) == tag {
Some((event.retag.orig_tag, event.span.data(), call_span))
} else {
None
}
})
})
.map(|(protecting_tag, protecting_tag_span, protection_span)| {
[
(
format!(
"{tag:?} was protected due to {protecting_tag:?} which was created here"
),
protecting_tag_span,
),
(format!("this protector is live for this call"), protection_span),
]
});
let get_matching = |events: &[Event]| {
events.iter().rev().find_map(|event| {
if event.tag == tag { Some((event.range, event.span.data())) } else { None }
})
};
Some(TagHistory::Tagged {
tag,
created: get_matching(&self.creations)?,
invalidated: get_matching(&self.invalidations),
protected,
})
Some(TagHistory { created, invalidated, protected })
}
/// Report a descriptive error when `new` could not be granted from `derived_from`.
pub fn grant_error<'tcx>(
&self,
derived_from: ProvenanceExtra,
new: Item,
alloc_id: AllocId,
alloc_range: AllocRange,
error_offset: Size,
stack: &Stack,
) -> InterpError<'tcx> {
pub fn grant_error(&self, perm: Permission, stack: &Stack) -> InterpError<'tcx> {
let Operation::Retag(op) = &self.operation else {
unreachable!("grant_error should only be called during a retag")
};
let action = format!(
"trying to reborrow from {derived_from:?} for {new_perm:?} permission at {alloc_id:?}[{offset:#x}]",
new_perm = new.perm(),
offset = error_offset.bytes(),
"trying to retag from {:?} for {:?} permission at {:?}[{:#x}]",
op.orig_tag,
perm,
self.history.id,
self.offset.bytes(),
);
err_sb_ub(
format!("{}{}", action, error_cause(stack, derived_from)),
Some(operation_summary("a reborrow", alloc_id, alloc_range)),
derived_from.and_then(|derived_from| self.get_logs_relevant_to(derived_from, None)),
format!("{}{}", action, error_cause(stack, op.orig_tag)),
Some(operation_summary(&op.cause.summary(), self.history.id, op.range)),
op.orig_tag.and_then(|orig_tag| self.get_logs_relevant_to(orig_tag, None)),
)
}
/// Report a descriptive error when `access` is not permitted based on `tag`.
pub fn access_error<'tcx>(
&self,
access: AccessKind,
tag: ProvenanceExtra,
alloc_id: AllocId,
alloc_range: AllocRange,
error_offset: Size,
stack: &Stack,
) -> InterpError<'tcx> {
pub fn access_error(&self, stack: &Stack) -> InterpError<'tcx> {
let Operation::Access(op) = &self.operation else {
unreachable!("access_error should only be called during an access")
};
let action = format!(
"attempting a {access} using {tag:?} at {alloc_id:?}[{offset:#x}]",
offset = error_offset.bytes(),
access = op.kind,
tag = op.tag,
alloc_id = self.history.id,
offset = self.offset.bytes(),
);
err_sb_ub(
format!("{}{}", action, error_cause(stack, tag)),
Some(operation_summary("an access", alloc_id, alloc_range)),
tag.and_then(|tag| self.get_logs_relevant_to(tag, None)),
format!("{}{}", action, error_cause(stack, op.tag)),
Some(operation_summary("an access", self.history.id, op.range)),
op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)),
)
}
pub fn protector_error(&self, item: &Item) -> InterpError<'tcx> {
let call_id = self
.threads
.all_stacks()
.flatten()
.map(|frame| {
frame.extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data")
})
.find(|frame| frame.protected_tags.contains(&item.tag()))
.map(|frame| frame.call_id)
.unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here?
match self.operation {
Operation::Dealloc(_) =>
err_sb_ub(
format!(
"deallocating while item {:?} is protected by call {:?}",
item, call_id
),
None,
None,
),
Operation::Retag(RetagOp { orig_tag: tag, .. })
| Operation::Access(AccessOp { tag, .. }) =>
err_sb_ub(
format!(
"not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}",
tag, item, call_id
),
None,
tag.and_then(|tag| self.get_logs_relevant_to(tag, Some(item.tag()))),
),
}
}
pub fn dealloc_error(&self) -> InterpError<'tcx> {
let Operation::Dealloc(op) = &self.operation else {
unreachable!("dealloc_error should only be called during a deallocation")
};
err_sb_ub(
format!(
"no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack",
op.tag, self.history.id,
),
None,
op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)),
)
}
#[inline(never)]
pub fn check_tracked_tag_popped(&self, item: &Item, global: &GlobalStateInner) {
if !global.tracked_pointer_tags.contains(&item.tag()) {
return;
}
let summary = match self.operation {
Operation::Dealloc(_) => None,
Operation::Access(AccessOp { kind, tag, .. }) => Some((tag, kind)),
Operation::Retag(RetagOp { orig_tag, permission, .. }) => {
let kind = match permission
.expect("start_grant should set the current permission before popping a tag")
{
Permission::SharedReadOnly => AccessKind::Read,
Permission::Unique => AccessKind::Write,
Permission::SharedReadWrite | Permission::Disabled => {
panic!("Only SharedReadOnly and Unique retags can pop tags");
}
};
Some((orig_tag, kind))
}
};
register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(*item, summary));
}
}
fn operation_summary(
operation: &'static str,
alloc_id: AllocId,
alloc_range: AllocRange,
) -> String {
fn operation_summary(operation: &str, alloc_id: AllocId, alloc_range: AllocRange) -> String {
format!("this error occurs as part of {operation} at {alloc_id:?}{alloc_range:?}")
}
@ -192,3 +498,15 @@ fn error_cause(stack: &Stack, prov_extra: ProvenanceExtra) -> &'static str {
", but no exposed tags have suitable permission in the borrow stack for this location"
}
}
impl RetagCause {
fn summary(&self) -> String {
match self {
RetagCause::Normal => "retag",
RetagCause::FnEntry => "FnEntry retag",
RetagCause::FnReturn => "FnReturn retag",
RetagCause::TwoPhase => "two-phase retag",
}
.to_string()
}
}

View File

@ -22,7 +22,7 @@ use smallvec::SmallVec;
use crate::*;
pub mod diagnostics;
use diagnostics::{AllocHistory, TagHistory};
use diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder, RetagCause, TagHistory};
mod item;
pub use item::{Item, Permission};
@ -142,11 +142,11 @@ pub enum RefKind {
impl fmt::Display for RefKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RefKind::Unique { two_phase: false } => write!(f, "unique"),
RefKind::Unique { two_phase: true } => write!(f, "unique (two-phase)"),
RefKind::Shared => write!(f, "shared"),
RefKind::Raw { mutable: true } => write!(f, "raw (mutable)"),
RefKind::Raw { mutable: false } => write!(f, "raw (constant)"),
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"),
RefKind::Raw { mutable: true } => write!(f, "raw (mutable) pointer"),
RefKind::Raw { mutable: false } => write!(f, "raw (constant) pointer"),
}
}
}
@ -285,94 +285,19 @@ impl<'tcx> Stack {
/// currently checking.
fn item_popped(
item: &Item,
provoking_access: Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages
global: &GlobalStateInner,
alloc_history: &mut AllocHistory,
threads: &ThreadManager<'_, 'tcx>,
dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>,
) -> InterpResult<'tcx> {
if !global.tracked_pointer_tags.is_empty() {
check_tracked(item, &provoking_access, global);
#[inline(never)] // cold path
fn check_tracked(
item: &Item,
provoking_access: &Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>,
global: &GlobalStateInner,
) {
if global.tracked_pointer_tags.contains(&item.tag()) {
register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(
*item,
provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)),
));
}
}
dcx.check_tracked_tag_popped(item, global);
}
if !item.protected() {
return Ok(());
}
// We store tags twice, once in global.protected_tags and once in each call frame.
// We do this because consulting a single global set in this function is faster
// than attempting to search all call frames in the program for the `FrameExtra`
// (if any) which is protecting the popped tag.
//
// This duplication trades off making `end_call` slower to make this function faster. This
// trade-off is profitable in practice for a combination of two reasons.
// 1. A single protected tag can (and does in some programs) protect thousands of `Item`s.
// Therefore, adding overhead to in function call/return is profitable even if it only
// saves a little work in this function.
// 2. Most frames protect only one or two tags. So this duplicative global turns a search
// which ends up about linear in the number of protected tags in the program into a
// constant time check (and a slow linear, because the tags in the frames aren't contiguous).
if global.protected_tags.contains(&item.tag()) {
return Err(protector_error(item, &provoking_access, alloc_history, threads));
#[inline(never)] // cold path
fn protector_error<'tcx>(
item: &Item,
provoking_access: &Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>,
alloc_history: &mut AllocHistory,
threads: &ThreadManager<'_, 'tcx>,
) -> InterpErrorInfo<'tcx> {
// This path is cold because it is fatal to the program. So here it is fine to do the
// more expensive search to figure out which call is responsible for protecting this
// tag.
let call_id = threads
.all_stacks()
.flatten()
.map(|frame| {
frame
.extra
.stacked_borrows
.as_ref()
.expect("we should have Stacked Borrows data")
})
.find(|frame| frame.protected_tags.contains(&item.tag()))
.map(|frame| frame.call_id)
.unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here?
if let Some((tag, _alloc_range, _offset, _access)) = provoking_access {
err_sb_ub(
format!(
"not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}",
tag, item, call_id
),
None,
tag.and_then(|tag| {
alloc_history.get_logs_relevant_to(tag, Some(item.tag()))
}),
)
} else {
err_sb_ub(
format!(
"deallocating while item {:?} is protected by call {:?}",
item, call_id
),
None,
None,
)
}.into()
}
return Err(dcx.protector_error(item).into());
}
Ok(())
}
@ -385,19 +310,15 @@ impl<'tcx> Stack {
&mut self,
access: AccessKind,
tag: ProvenanceExtra,
(alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages
global: &mut GlobalStateInner,
current_span: &mut CurrentSpan<'_, '_, 'tcx>,
alloc_history: &mut AllocHistory,
dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>,
exposed_tags: &FxHashSet<SbTag>,
threads: &ThreadManager<'_, 'tcx>,
) -> InterpResult<'tcx> {
// Two main steps: Find granting item, remove incompatible items above.
// Step 1: Find granting item.
let granting_idx = self.find_granting(access, tag, exposed_tags).map_err(|_| {
alloc_history.access_error(access, tag, alloc_id, alloc_range, offset, self)
})?;
let granting_idx =
self.find_granting(access, tag, exposed_tags).map_err(|_| dcx.access_error(self))?;
// Step 2: Remove incompatible items above them. Make sure we do not remove protected
// items. Behavior differs for reads and writes.
@ -416,14 +337,8 @@ impl<'tcx> Stack {
0
};
self.pop_items_after(first_incompatible_idx, |item| {
Stack::item_popped(
&item,
Some((tag, alloc_range, offset, access)),
global,
alloc_history,
threads,
)?;
alloc_history.log_invalidation(item.tag(), alloc_range, current_span);
Stack::item_popped(&item, global, dcx)?;
dcx.log_invalidation(item.tag());
Ok(())
})?;
} else {
@ -443,14 +358,8 @@ impl<'tcx> Stack {
0
};
self.disable_uniques_starting_at(first_incompatible_idx, |item| {
Stack::item_popped(
&item,
Some((tag, alloc_range, offset, access)),
global,
alloc_history,
threads,
)?;
alloc_history.log_invalidation(item.tag(), alloc_range, current_span);
Stack::item_popped(&item, global, dcx)?;
dcx.log_invalidation(item.tag());
Ok(())
})?;
}
@ -487,27 +396,18 @@ impl<'tcx> Stack {
fn dealloc(
&mut self,
tag: ProvenanceExtra,
(alloc_id, _alloc_range, _offset): (AllocId, AllocRange, Size), // just for debug printing and error messages
global: &GlobalStateInner,
alloc_history: &mut AllocHistory,
dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>,
exposed_tags: &FxHashSet<SbTag>,
threads: &ThreadManager<'_, 'tcx>,
) -> InterpResult<'tcx> {
// Step 1: Make sure there is a granting item.
self.find_granting(AccessKind::Write, tag, exposed_tags).map_err(|_| {
err_sb_ub(format!(
"no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack",
tag, alloc_id,
),
None,
tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, None)),
)
})?;
self.find_granting(AccessKind::Write, tag, exposed_tags)
.map_err(|_| dcx.dealloc_error())?;
// Step 2: Consider all items removed. This checks for protectors.
for idx in (0..self.len()).rev() {
let item = self.get(idx).unwrap();
Stack::item_popped(&item, None, global, alloc_history, threads)?;
Stack::item_popped(&item, global, dcx)?;
}
Ok(())
}
@ -522,23 +422,21 @@ impl<'tcx> Stack {
&mut self,
derived_from: ProvenanceExtra,
new: Item,
(alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages
global: &mut GlobalStateInner,
current_span: &mut CurrentSpan<'_, '_, 'tcx>,
alloc_history: &mut AllocHistory,
dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>,
exposed_tags: &FxHashSet<SbTag>,
threads: &ThreadManager<'_, 'tcx>,
) -> InterpResult<'tcx> {
dcx.start_grant(new.perm());
// Figure out which access `perm` corresponds to.
let access =
if new.perm().grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read };
// Now we figure out which item grants our parent (`derived_from`) this kind of access.
// We use that to determine where to put the new item.
let granting_idx =
self.find_granting(access, derived_from, exposed_tags).map_err(|_| {
alloc_history.grant_error(derived_from, new, alloc_id, alloc_range, offset, self)
})?;
let granting_idx = self
.find_granting(access, derived_from, exposed_tags)
.map_err(|_| dcx.grant_error(new.perm(), self))?;
// Compute where to put the new item.
// Either way, we ensure that we insert the new item in a way such that between
@ -568,16 +466,7 @@ impl<'tcx> Stack {
// A "safe" reborrow for a pointer that actually expects some aliasing guarantees.
// Here, creating a reference actually counts as an access.
// This ensures F2b for `Unique`, by removing offending `SharedReadOnly`.
self.access(
access,
derived_from,
(alloc_id, alloc_range, offset),
global,
current_span,
alloc_history,
exposed_tags,
threads,
)?;
self.access(access, derived_from, global, dcx, exposed_tags)?;
// We insert "as far up as possible": We know only compatible items are remaining
// on top of `derived_from`, and we want the new item at the top so that we
@ -596,14 +485,15 @@ impl<'tcx> Stack {
/// Map per-stack operations to higher-level per-location-range operations.
impl<'tcx> Stacks {
/// Creates new stack with initial tag.
fn new(size: Size, perm: Permission, tag: SbTag) -> Self {
/// Creates a new stack with an initial tag. For diagnostic purposes, we also need to know
/// the [`AllocId`] of the allocation this is associated with.
fn new(size: Size, perm: Permission, tag: SbTag, id: AllocId) -> Self {
let item = Item::new(tag, perm, false);
let stack = Stack::new(item);
Stacks {
stacks: RangeMap::new(size, stack),
history: AllocHistory::new(),
history: AllocHistory::new(id),
exposed_tags: FxHashSet::default(),
}
}
@ -612,15 +502,17 @@ impl<'tcx> Stacks {
fn for_each(
&mut self,
range: AllocRange,
mut dcx_builder: DiagnosticCxBuilder<'_, '_, 'tcx>,
mut f: impl FnMut(
Size,
&mut Stack,
&mut AllocHistory,
&mut DiagnosticCx<'_, '_, 'tcx, '_>,
&mut FxHashSet<SbTag>,
) -> InterpResult<'tcx>,
) -> InterpResult<'tcx> {
for (offset, stack) in self.stacks.iter_mut(range.start, range.size) {
f(offset, stack, &mut self.history, &mut self.exposed_tags)?;
let mut dcx = dcx_builder.build(&mut self.history, offset);
f(stack, &mut dcx, &mut self.exposed_tags)?;
dcx_builder = dcx.unbuild();
}
Ok(())
}
@ -633,7 +525,6 @@ impl Stacks {
size: Size,
state: &GlobalState,
kind: MemoryKind<MiriMemoryKind>,
mut current_span: CurrentSpan<'_, '_, '_>,
) -> Self {
let mut extra = state.borrow_mut();
let (base_tag, perm) = match kind {
@ -646,25 +537,18 @@ impl Stacks {
// Everything else is shared by default.
_ => (extra.base_ptr_tag(id), Permission::SharedReadWrite),
};
let mut stacks = Stacks::new(size, perm, base_tag);
stacks.history.log_creation(
None,
base_tag,
alloc_range(Size::ZERO, size),
&mut current_span,
);
stacks
Stacks::new(size, perm, base_tag, id)
}
#[inline(always)]
pub fn before_memory_read<'tcx>(
pub fn before_memory_read<'tcx, 'mir>(
&mut self,
alloc_id: AllocId,
tag: ProvenanceExtra,
range: AllocRange,
state: &GlobalState,
mut current_span: CurrentSpan<'_, '_, 'tcx>,
threads: &ThreadManager<'_, 'tcx>,
current_span: CurrentSpan<'_, 'mir, 'tcx>,
threads: &ThreadManager<'mir, 'tcx>,
) -> InterpResult<'tcx> {
trace!(
"read access with tag {:?}: {:?}, size {}",
@ -672,30 +556,22 @@ impl Stacks {
Pointer::new(alloc_id, range.start),
range.size.bytes()
);
let dcx = DiagnosticCxBuilder::read(current_span, threads, tag, range);
let mut state = state.borrow_mut();
self.for_each(range, |offset, stack, history, exposed_tags| {
stack.access(
AccessKind::Read,
tag,
(alloc_id, range, offset),
&mut state,
&mut current_span,
history,
exposed_tags,
threads,
)
self.for_each(range, dcx, |stack, dcx, exposed_tags| {
stack.access(AccessKind::Read, tag, &mut state, dcx, exposed_tags)
})
}
#[inline(always)]
pub fn before_memory_write<'tcx>(
pub fn before_memory_write<'tcx, 'mir>(
&mut self,
alloc_id: AllocId,
tag: ProvenanceExtra,
range: AllocRange,
state: &GlobalState,
mut current_span: CurrentSpan<'_, '_, 'tcx>,
threads: &ThreadManager<'_, 'tcx>,
current_span: CurrentSpan<'_, 'mir, 'tcx>,
threads: &ThreadManager<'mir, 'tcx>,
) -> InterpResult<'tcx> {
trace!(
"write access with tag {:?}: {:?}, size {}",
@ -703,34 +579,28 @@ impl Stacks {
Pointer::new(alloc_id, range.start),
range.size.bytes()
);
let dcx = DiagnosticCxBuilder::write(current_span, threads, tag, range);
let mut state = state.borrow_mut();
self.for_each(range, |offset, stack, history, exposed_tags| {
stack.access(
AccessKind::Write,
tag,
(alloc_id, range, offset),
&mut state,
&mut current_span,
history,
exposed_tags,
threads,
)
self.for_each(range, dcx, |stack, dcx, exposed_tags| {
stack.access(AccessKind::Write, tag, &mut state, dcx, exposed_tags)
})
}
#[inline(always)]
pub fn before_memory_deallocation<'tcx>(
pub fn before_memory_deallocation<'tcx, 'mir>(
&mut self,
alloc_id: AllocId,
tag: ProvenanceExtra,
range: AllocRange,
state: &GlobalState,
threads: &ThreadManager<'_, 'tcx>,
current_span: CurrentSpan<'_, 'mir, 'tcx>,
threads: &ThreadManager<'mir, 'tcx>,
) -> InterpResult<'tcx> {
trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes());
let dcx = DiagnosticCxBuilder::dealloc(current_span, threads, tag);
let state = state.borrow();
self.for_each(range, |offset, stack, history, exposed_tags| {
stack.dealloc(tag, (alloc_id, range, offset), &state, history, exposed_tags, threads)
self.for_each(range, dcx, |stack, dcx, exposed_tags| {
stack.dealloc(tag, &state, dcx, exposed_tags)
})?;
Ok(())
}
@ -747,15 +617,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
place: &MPlaceTy<'tcx, Provenance>,
size: Size,
kind: RefKind,
retag_cause: RetagCause, // What caused this retag, for diagnostics only
new_tag: SbTag,
protect: bool,
) -> InterpResult<'tcx, Option<AllocId>> {
let this = self.eval_context_mut();
let current_span = &mut this.machine.current_span();
// It is crucial that this gets called on all code paths, to ensure we track tag creation.
let log_creation = |this: &MiriEvalContext<'mir, 'tcx>,
current_span: &mut CurrentSpan<'_, 'mir, 'tcx>,
current_span: CurrentSpan<'_, 'mir, 'tcx>,
loc: Option<(AllocId, Size, ProvenanceExtra)>| // alloc_id, base_offset, orig_tag
-> InterpResult<'tcx> {
let global = this.machine.stacked_borrows.as_ref().unwrap().borrow();
@ -771,14 +641,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
return Ok(())
};
// The SB history tracking needs a parent tag, so skip if we come from a wildcard.
let ProvenanceExtra::Concrete(orig_tag) = orig_tag else {
// FIXME: should we log this?
return Ok(())
};
let (_size, _align, kind) = this.get_alloc_info(alloc_id);
match kind {
let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id);
match alloc_kind {
AllocKind::LiveData => {
// This should have alloc_extra data, but `get_alloc_extra` can still fail
// if converting this alloc_id from a global to a local one
@ -789,14 +653,18 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
.as_ref()
.expect("we should have Stacked Borrows data")
.borrow_mut();
stacked_borrows.history.log_creation(
Some(orig_tag),
new_tag,
alloc_range(base_offset, size),
let dcx = DiagnosticCxBuilder::retag(
current_span,
&this.machine.threads,
retag_cause,
new_tag,
orig_tag,
alloc_range(base_offset, size),
);
let mut dcx = dcx.build(&mut stacked_borrows.history, base_offset);
dcx.log_creation();
if protect {
stacked_borrows.history.log_protector(orig_tag, new_tag, current_span);
dcx.log_protector();
}
}
AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
@ -806,6 +674,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
Ok(())
};
let current_span = this.machine.current_span(*this.tcx);
if size == Size::ZERO {
trace!(
"reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})",
@ -829,6 +699,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
log_creation(this, current_span, None)?;
return Ok(None);
}
let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?;
log_creation(this, current_span, Some((alloc_id, base_offset, orig_tag)))?;
@ -855,11 +726,22 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
);
if protect {
// We store tags twice, once in global.protected_tags and once in each call frame.
// We do this because consulting a single global set in this function is faster
// than attempting to search all call frames in the program for the `FrameExtra`
// (if any) which is protecting the popped tag.
//
// This duplication trades off making `end_call` slower to make this function faster. This
// trade-off is profitable in practice for a combination of two reasons.
// 1. A single protected tag can (and does in some programs) protect thousands of `Item`s.
// Therefore, adding overhead to in function call/return is profitable even if it only
// saves a little work in this function.
// 2. Most frames protect only one or two tags. So this duplicative global turns a search
// which ends up about linear in the number of protected tags in the program into a
// constant time check (and a slow linear, because the tags in the frames aren't contiguous).
this.frame_mut().extra.stacked_borrows.as_mut().unwrap().protected_tags.push(new_tag);
this.machine.stacked_borrows.as_mut().unwrap().get_mut().protected_tags.insert(new_tag);
}
// FIXME: can't hold the current span handle across the borrows of self above
let current_span = &mut this.machine.current_span();
// Update the stacks.
// Make sure that raw pointers and mutable shared references are reborrowed "weak":
@ -906,26 +788,26 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
};
let item = Item::new(new_tag, perm, protected);
let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut();
let threads = &this.machine.threads;
stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| {
stack.grant(
orig_tag,
item,
(alloc_id, range, offset),
&mut global,
current_span,
history,
exposed_tags,
threads,
)
let dcx = DiagnosticCxBuilder::retag(
this.machine.current_span(*this.tcx),
&this.machine.threads,
retag_cause,
new_tag,
orig_tag,
alloc_range(base_offset, size),
);
stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| {
stack.grant(orig_tag, item, &mut global, dcx, exposed_tags)
})
})?;
return Ok(Some(alloc_id));
}
};
// Here we can avoid `borrow()` calls because we have mutable references.
// Note that this asserts that the allocation is mutable -- but since we are creating a
// mutable pointer, that seems reasonable.
let tcx = *this.tcx;
let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc_id)?;
let mut stacked_borrows = alloc_extra
.stacked_borrows
@ -935,19 +817,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let item = Item::new(new_tag, perm, protect);
let range = alloc_range(base_offset, size);
let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut();
let threads = &machine.threads;
let current_span = &mut machine.current_span(); // `get_alloc_extra_mut` invalidated our old `current_span`
stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| {
stack.grant(
orig_tag,
item,
(alloc_id, range, offset),
&mut global,
current_span,
history,
exposed_tags,
threads,
)
let dcx = DiagnosticCxBuilder::retag(
machine.current_span(tcx),
&machine.threads,
retag_cause,
new_tag,
orig_tag,
alloc_range(base_offset, size),
);
stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| {
stack.grant(orig_tag, item, &mut global, dcx, exposed_tags)
})?;
Ok(Some(alloc_id))
@ -959,6 +838,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
&mut self,
val: &ImmTy<'tcx, Provenance>,
kind: RefKind,
retag_cause: RetagCause, // What caused this retag, for diagnostics only
protect: bool,
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
let this = self.eval_context_mut();
@ -977,7 +857,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let new_tag = this.machine.stacked_borrows.as_mut().unwrap().get_mut().new_ptr();
// Reborrow.
let alloc_id = this.reborrow(&place, size, kind, new_tag, protect)?;
let alloc_id = this.reborrow(&place, size, kind, retag_cause, new_tag, protect)?;
// Adjust pointer.
let new_place = place.map_provenance(|p| {
@ -1007,7 +887,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let retag_fields = this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields;
let mut visitor = RetagVisitor { ecx: this, kind, retag_fields };
let retag_cause = match kind {
RetagKind::TwoPhase { .. } => RetagCause::TwoPhase,
RetagKind::FnEntry => RetagCause::FnEntry,
RetagKind::Raw | RetagKind::Default => RetagCause::Normal,
};
let mut visitor = RetagVisitor { ecx: this, kind, retag_cause, retag_fields };
return visitor.visit_value(place);
// Determine mutability and whether to add a protector.
@ -1036,6 +921,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
struct RetagVisitor<'ecx, 'mir, 'tcx> {
ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>,
kind: RetagKind,
retag_cause: RetagCause,
retag_fields: bool,
}
impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> {
@ -1044,10 +930,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
&mut self,
place: &PlaceTy<'tcx, Provenance>,
ref_kind: RefKind,
retag_cause: RetagCause,
protector: bool,
) -> InterpResult<'tcx> {
let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?;
let val = self.ecx.retag_reference(&val, ref_kind, protector)?;
let val = self.ecx.retag_reference(&val, ref_kind, retag_cause, protector)?;
self.ecx.write_immediate(*val, place)?;
Ok(())
}
@ -1068,13 +955,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
self.retag_place(
place,
RefKind::Unique { two_phase: false },
self.retag_cause,
/*protector*/ false,
)
}
fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) {
self.retag_place(place, ref_kind, protector)?;
self.retag_place(place, ref_kind, self.retag_cause, protector)?;
} else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) {
// Wide raw pointers *do* have fields and their types are strange.
// vtables have a type like `&[*const (); 3]` or so!
@ -1117,6 +1005,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let val = this.retag_reference(
&val,
RefKind::Unique { two_phase: false },
RetagCause::FnReturn,
/*protector*/ true,
)?;
// And use reborrowed pointer for return place.

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/box-cell-alias.rs:LL:CC
|
LL | unsafe { (*ptr).set(20) };
| ^^^^^^^^^^^^^^
| |
| trying to reborrow from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x0..0x1]
| trying to retag from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x0..0x1]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x1]
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x1]
--> $DIR/box-cell-alias.rs:LL:CC
|
LL | let ptr: *const Cell<u8> = &*val;
| ^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x1]
help: <TAG> was later invalidated at offsets [0x0..0x1] by a Unique retag
--> $DIR/box-cell-alias.rs:LL:CC
|
LL | let res = helper(val, ptr);

View File

@ -9,12 +9,12 @@ LL | let _val = *target_alias;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/alias_through_mutation.rs:LL:CC
|
LL | *x = &mut *(target as *mut _);
| ^^^^^^^^^^^^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a write access
--> $DIR/alias_through_mutation.rs:LL:CC
|
LL | *target = 13;

View File

@ -6,7 +6,7 @@ LL | pub fn safe(_x: &mut i32, _y: &mut i32) {}
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/aliasing_mut1.rs:LL:CC
|
LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) };

View File

@ -6,7 +6,7 @@ LL | pub fn safe(_x: &i32, _y: &mut i32) {}
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/aliasing_mut2.rs:LL:CC
|
LL | let xref = &mut x;

View File

@ -1,24 +1,24 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/aliasing_mut3.rs:LL:CC
|
LL | pub fn safe(_x: &mut i32, _y: &i32) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x0..0x4]
| trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of FnEntry retag at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/aliasing_mut3.rs:LL:CC
|
LL | safe_raw(xraw, xshr);
| ^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag
--> $DIR/aliasing_mut3.rs:LL:CC
|
LL | pub fn safe(_x: &mut i32, _y: &i32) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | safe_raw(xraw, xshr);
| ^^^^^^^^^^^^^^^^^^^^
= note: backtrace:
= note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC
note: inside `main` at $DIR/aliasing_mut3.rs:LL:CC

View File

@ -6,7 +6,7 @@ LL | pub fn safe(_x: &i32, _y: &mut Cell<i32>) {}
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/aliasing_mut4.rs:LL:CC
|
LL | let xref = &mut x;

View File

@ -9,12 +9,12 @@ LL | *LEAK = 7;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/box_exclusive_violation1.rs:LL:CC
|
LL | LEAK = x as *const _ as *mut _;
| ^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a write access
--> $DIR/box_exclusive_violation1.rs:LL:CC
|
LL | *our = 5;

View File

@ -9,12 +9,12 @@ LL | v1[1] = 5;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0xc]
help: <TAG> was created by a Unique retag at offsets [0x0..0xc]
--> $DIR/buggy_as_mut_slice.rs:LL:CC
|
LL | let v1 = safe::as_mut_slice(&v);
| ^^^^^^^^^^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0xc]
help: <TAG> was later invalidated at offsets [0x0..0xc] by a Unique retag
--> $DIR/buggy_as_mut_slice.rs:LL:CC
|
LL | unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) }

View File

@ -19,7 +19,7 @@ mod safe {
fn main() {
let mut array = [1, 2, 3, 4];
let (a, b) = safe::split_at_mut(&mut array, 0);
//~^ ERROR: /reborrow .* tag does not exist in the borrow stack/
//~^ ERROR: /retag .* tag does not exist in the borrow stack/
a[1] = 5;
b[1] = 6;
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/buggy_split_at_mut.rs:LL:CC
|
LL | let (a, b) = safe::split_at_mut(&mut array, 0);
| ^
| |
| trying to reborrow from <TAG> for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x0..0x10]
| trying to retag from <TAG> for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x0..0x10]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x10]
help: <TAG> was created by a Unique retag at offsets [0x0..0x10]
--> $DIR/buggy_split_at_mut.rs:LL:CC
|
LL | from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x10]
help: <TAG> was later invalidated at offsets [0x0..0x10] by a Unique retag
--> $DIR/buggy_split_at_mut.rs:LL:CC
|
LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid),

View File

@ -0,0 +1,20 @@
// Test that spans displayed in diagnostics identify the function call, not the function
// definition, as the location of invalidation due to FnEntry retag. Technically the FnEntry retag
// occurs inside the function, but what the user wants to know is which call produced the
// invalidation.
fn main() {
let mut x = 0i32;
let z = &mut x as *mut i32;
x.do_bad();
unsafe {
let _oof = *z; //~ ERROR: /read access .* tag does not exist in the borrow stack/
}
}
trait Bad {
fn do_bad(&mut self) {
// who knows
}
}
impl Bad for i32 {}

View File

@ -0,0 +1,28 @@
error: Undefined Behavior: attempting a read access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/fnentry_invalidation.rs:LL:CC
|
LL | let _oof = *z;
| ^^
| |
| attempting a read access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of an access at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> $DIR/fnentry_invalidation.rs:LL:CC
|
LL | let z = &mut x as *mut i32;
| ^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag
--> $DIR/fnentry_invalidation.rs:LL:CC
|
LL | x.do_bad();
| ^^^^^^^^^^
= note: backtrace:
= note: inside `main` at $DIR/fnentry_invalidation.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error

View File

@ -9,12 +9,12 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref.
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/illegal_read1.rs:LL:CC
|
LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok...
| ^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a read access
--> $DIR/illegal_read1.rs:LL:CC
|
LL | let _val = unsafe { *xraw };

View File

@ -9,12 +9,12 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref.
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/illegal_read2.rs:LL:CC
|
LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok...
| ^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a SharedReadOnly retag
--> $DIR/illegal_read2.rs:LL:CC
|
LL | let shr = unsafe { &*xraw };

View File

@ -9,12 +9,12 @@ LL | let _val = *xref2;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/illegal_read3.rs:LL:CC
|
LL | let xref2 = &mut *xref1;
| ^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a read access
--> $DIR/illegal_read3.rs:LL:CC
|
LL | let _val = unsafe { *xref1.r };

View File

@ -9,12 +9,12 @@ LL | let _illegal = *xref2;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/illegal_read4.rs:LL:CC
|
LL | let xref2 = unsafe { &mut *xraw };
| ^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a read access
--> $DIR/illegal_read4.rs:LL:CC
|
LL | let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs

View File

@ -9,12 +9,12 @@ LL | let _val = *xref; // the mutable one is dead and gone
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [$HEX..$HEX]
help: <TAG> was created by a Unique retag at offsets [$HEX..$HEX]
--> $DIR/illegal_read5.rs:LL:CC
|
LL | let xref: &mut i32 = &mut *refmut;
| ^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [$HEX..$HEX]
help: <TAG> was later invalidated at offsets [$HEX..$HEX] by a read access
--> $DIR/illegal_read5.rs:LL:CC
|
LL | mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref

View File

@ -9,12 +9,12 @@ LL | let _val = *raw;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> $DIR/illegal_read6.rs:LL:CC
|
LL | let raw = x as *mut _;
| ^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique retag
--> $DIR/illegal_read6.rs:LL:CC
|
LL | let x = &mut *x; // kill `raw`

View File

@ -17,6 +17,6 @@ fn main() {
// without invalidating `x`. That would be bad! It would mean that creating `shr`
// leaked `x` to `raw`.
let _val = ptr::read(raw);
let _val = *x.get_mut(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
let _val = *x.get_mut(); //~ ERROR: /retag .* tag does not exist in the borrow stack/
}
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/illegal_read7.rs:LL:CC
|
LL | let _val = *x.get_mut();
| ^^^^^^^^^^^
| |
| trying to reborrow from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x0..0x4]
| trying to retag from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of two-phase retag at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/illegal_read7.rs:LL:CC
|
LL | let x = &mut *raw;
| ^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a read access
--> $DIR/illegal_read7.rs:LL:CC
|
LL | let _val = ptr::read(raw);

View File

@ -9,12 +9,12 @@ LL | let _fail = *y1;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/illegal_read8.rs:LL:CC
|
LL | let y1: &i32 = mem::transmute(&*x); // launder lifetimes
| ^^^^^^^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a write access
--> $DIR/illegal_read8.rs:LL:CC
|
LL | *y2 += 1;

View File

@ -9,6 +9,16 @@ LL | let _val = *root2;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/illegal_read_despite_exposed1.rs:LL:CC
|
LL | let root2 = &mut *exposed_ptr;
| ^^^^^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4] by a write access
--> $DIR/illegal_read_despite_exposed1.rs:LL:CC
|
LL | *exposed_ptr = 0;
| ^^^^^^^^^^^^^^^^
= note: backtrace:
= note: inside `main` at $DIR/illegal_read_despite_exposed1.rs:LL:CC

View File

@ -9,6 +9,16 @@ LL | let _val = *root2;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/illegal_read_despite_exposed2.rs:LL:CC
|
LL | let root2 = &mut *exposed_ptr;
| ^^^^^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4] by a read access
--> $DIR/illegal_read_despite_exposed2.rs:LL:CC
|
LL | let _val = *exposed_ptr;
| ^^^^^^^^^^^^
= note: backtrace:
= note: inside `main` at $DIR/illegal_read_despite_exposed2.rs:LL:CC

View File

@ -9,7 +9,7 @@ LL | unsafe { *x = 42 };
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/illegal_write1.rs:LL:CC
|
LL | let x: *mut u32 = xref as *const _ as *mut _;

View File

@ -9,12 +9,12 @@ LL | unsafe { *target2 = 13 };
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> $DIR/illegal_write2.rs:LL:CC
|
LL | let target2 = target as *mut _;
| ^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique retag
--> $DIR/illegal_write2.rs:LL:CC
|
LL | drop(&mut *target); // reborrow

View File

@ -9,7 +9,7 @@ LL | unsafe { *ptr = 42 };
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/illegal_write3.rs:LL:CC
|
LL | let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag

View File

@ -9,12 +9,12 @@ LL | let _val = *reference;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/illegal_write4.rs:LL:CC
|
LL | let reference = unsafe { &*raw }; // freeze
| ^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique retag
--> $DIR/illegal_write4.rs:LL:CC
|
LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag

View File

@ -9,12 +9,12 @@ LL | let _val = *xref;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/illegal_write5.rs:LL:CC
|
LL | let xref = unsafe { &mut *xraw };
| ^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a write access
--> $DIR/illegal_write5.rs:LL:CC
|
LL | unsafe { *xraw = 15 };

View File

@ -6,7 +6,7 @@ LL | unsafe { *y = 2 };
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> $DIR/illegal_write6.rs:LL:CC
|
LL | let p = x as *mut u32;

View File

@ -9,6 +9,16 @@ LL | let _val = *root2;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/illegal_write_despite_exposed1.rs:LL:CC
|
LL | let root2 = &*exposed_ptr;
| ^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4] by a write access
--> $DIR/illegal_write_despite_exposed1.rs:LL:CC
|
LL | *exposed_ptr = 0;
| ^^^^^^^^^^^^^^^^
= note: backtrace:
= note: inside `main` at $DIR/illegal_write_despite_exposed1.rs:LL:CC

View File

@ -12,6 +12,6 @@ fn main() {
*c.get() = UnsafeCell::new(1); // invalidates inner_shr
// stack: [c: SharedReadWrite]
let _val = *inner_shr.get(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
let _val = *inner_shr.get(); //~ ERROR: /retag .* tag does not exist in the borrow stack/
}
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/interior_mut1.rs:LL:CC
|
LL | let _val = *inner_shr.get();
| ^^^^^^^^^^^^^^^
| |
| trying to reborrow from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x0..0x4]
| trying to retag from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> $DIR/interior_mut1.rs:LL:CC
|
LL | let inner_shr = &*inner_uniq; // adds a SharedReadWrite
| ^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a write access
--> $DIR/interior_mut1.rs:LL:CC
|
LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr

View File

@ -25,6 +25,6 @@ fn main() {
// stack: [c: SharedReadWrite]
// now this does not work any more
let _val = *inner_shr.get(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
let _val = *inner_shr.get(); //~ ERROR: /retag .* tag does not exist in the borrow stack/
}
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/interior_mut2.rs:LL:CC
|
LL | let _val = *inner_shr.get();
| ^^^^^^^^^^^^^^^
| |
| trying to reborrow from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x0..0x4]
| trying to retag from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> $DIR/interior_mut2.rs:LL:CC
|
LL | let inner_shr = &*inner_uniq;
| ^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a write access
--> $DIR/interior_mut2.rs:LL:CC
|
LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated

View File

@ -6,7 +6,7 @@ LL | let _val = unsafe { *x };
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> $DIR/invalidate_against_barrier1.rs:LL:CC
|
LL | let xraw = &mut x as *mut _;

View File

@ -6,7 +6,7 @@ LL | unsafe { *x = 0 };
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> $DIR/invalidate_against_barrier2.rs:LL:CC
|
LL | let xraw = &mut x as *mut _;

View File

@ -8,5 +8,5 @@ fn main() {
let xref = unsafe { &mut *xraw };
let xref_in_mem = Box::new(xref);
let _val = unsafe { *xraw }; // invalidate xref
let _val = *xref_in_mem; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
let _val = *xref_in_mem; //~ ERROR: /retag .* tag does not exist in the borrow stack/
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/load_invalid_mut.rs:LL:CC
|
LL | let _val = *xref_in_mem;
| ^^^^^^^^^^^^
| |
| trying to reborrow from <TAG> for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x0..0x4]
| trying to retag from <TAG> for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/load_invalid_mut.rs:LL:CC
|
LL | let xref_in_mem = Box::new(xref);
| ^^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a read access
--> $DIR/load_invalid_mut.rs:LL:CC
|
LL | let _val = unsafe { *xraw }; // invalidate xref

View File

@ -8,5 +8,5 @@ fn main() {
let xref = unsafe { &*xraw };
let xref_in_mem = Box::new(xref);
unsafe { *xraw = 42 }; // unfreeze
let _val = *xref_in_mem; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
let _val = *xref_in_mem; //~ ERROR: /retag .* tag does not exist in the borrow stack/
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/load_invalid_shr.rs:LL:CC
|
LL | let _val = *xref_in_mem;
| ^^^^^^^^^^^^
| |
| trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x0..0x4]
| trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/load_invalid_shr.rs:LL:CC
|
LL | let xref_in_mem = Box::new(xref);
| ^^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a write access
--> $DIR/load_invalid_shr.rs:LL:CC
|
LL | unsafe { *xraw = 42 }; // unfreeze

View File

@ -9,12 +9,12 @@ LL | *LEAK = 7;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/mut_exclusive_violation1.rs:LL:CC
|
LL | LEAK = x as *const _ as *mut _;
| ^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a write access
--> $DIR/mut_exclusive_violation1.rs:LL:CC
|
LL | *our = 5;

View File

@ -9,12 +9,12 @@ LL | let _val = *raw1;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/mut_exclusive_violation2.rs:LL:CC
|
LL | let raw1 = ptr1.as_mut();
| ^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique retag
--> $DIR/mut_exclusive_violation2.rs:LL:CC
|
LL | let _raw2 = ptr2.as_mut();

View File

@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc)
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> $DIR/newtype_retagging.rs:LL:CC
|
LL | let ptr = Box::into_raw(Box::new(0i32));

View File

@ -9,12 +9,12 @@ LL | assert_eq!(unsafe { *y }, 1);
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/outdated_local.rs:LL:CC
|
LL | let y: *const i32 = &x;
| ^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a write access
--> $DIR/outdated_local.rs:LL:CC
|
LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local

View File

@ -6,5 +6,5 @@ fn main() {
let xraw = x as *mut _;
let xref = unsafe { &mut *xraw };
let _val = unsafe { *xraw }; // invalidate xref
foo(xref); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
foo(xref); //~ ERROR: /retag .* tag does not exist in the borrow stack/
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/pass_invalid_mut.rs:LL:CC
|
LL | foo(xref);
| ^^^^
| |
| trying to reborrow from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x0..0x4]
| trying to retag from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of two-phase retag at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/pass_invalid_mut.rs:LL:CC
|
LL | let xref = unsafe { &mut *xraw };
| ^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a read access
--> $DIR/pass_invalid_mut.rs:LL:CC
|
LL | let _val = unsafe { *xraw }; // invalidate xref

View File

@ -6,5 +6,5 @@ fn main() {
let xraw = x as *mut _;
let xref = unsafe { &*xraw };
unsafe { *xraw = 42 }; // unfreeze
foo(xref); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
foo(xref); //~ ERROR: /retag .* tag does not exist in the borrow stack/
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/pass_invalid_shr.rs:LL:CC
|
LL | foo(xref);
| ^^^^
| |
| trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x0..0x4]
| trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/pass_invalid_shr.rs:LL:CC
|
LL | let xref = unsafe { &*xraw };
| ^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a write access
--> $DIR/pass_invalid_shr.rs:LL:CC
|
LL | unsafe { *xraw = 42 }; // unfreeze

View File

@ -9,12 +9,12 @@ LL | let _x = unsafe { *PTR };
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x1]
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x1]
--> $DIR/pointer_smuggling.rs:LL:CC
|
LL | PTR = x;
| ^
help: <TAG> was later invalidated at offsets [0x0..0x1]
help: <TAG> was later invalidated at offsets [0x0..0x1] by a write access
--> $DIR/pointer_smuggling.rs:LL:CC
|
LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created.

View File

@ -9,12 +9,12 @@ LL | unsafe { *raw1 = 13 };
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> $DIR/raw_tracking.rs:LL:CC
|
LL | let raw1 = &mut l as *mut _;
| ^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique retag
--> $DIR/raw_tracking.rs:LL:CC
|
LL | let raw2 = &mut l as *mut _; // invalidates raw1

View File

@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 {
let xraw = x as *mut (i32, i32);
let ret = unsafe { &mut (*xraw).1 };
let _val = unsafe { *xraw }; // invalidate xref
ret //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
ret //~ ERROR: /retag .* tag does not exist in the borrow stack/
}
fn main() {

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
--> $DIR/return_invalid_mut.rs:LL:CC
|
LL | ret
| ^^^
| |
| trying to reborrow from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x4..0x8]
| trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x4..0x8]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x4..0x8]
help: <TAG> was created by a Unique retag at offsets [0x4..0x8]
--> $DIR/return_invalid_mut.rs:LL:CC
|
LL | let ret = unsafe { &mut (*xraw).1 };
| ^^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x8]
help: <TAG> was later invalidated at offsets [0x0..0x8] by a read access
--> $DIR/return_invalid_mut.rs:LL:CC
|
LL | let _val = unsafe { *xraw }; // invalidate xref

View File

@ -10,7 +10,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> {
fn main() {
match foo(&mut (1, 2)) {
Some(_x) => {} //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
Some(_x) => {} //~ ERROR: /retag .* tag does not exist in the borrow stack/
None => {}
}
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
--> $DIR/return_invalid_mut_option.rs:LL:CC
|
LL | Some(_x) => {}
| ^^
| |
| trying to reborrow from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x4..0x8]
| trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x4..0x8]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x4..0x8]
help: <TAG> was created by a Unique retag at offsets [0x4..0x8]
--> $DIR/return_invalid_mut_option.rs:LL:CC
|
LL | let ret = Some(ret);
| ^^^
help: <TAG> was later invalidated at offsets [0x0..0x8]
help: <TAG> was later invalidated at offsets [0x0..0x8] by a read access
--> $DIR/return_invalid_mut_option.rs:LL:CC
|
LL | let _val = unsafe { *xraw }; // invalidate xref

View File

@ -8,5 +8,5 @@ fn foo(x: &mut (i32, i32)) -> (&mut i32,) {
}
fn main() {
foo(&mut (1, 2)).0; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
foo(&mut (1, 2)).0; //~ ERROR: /retag .* tag does not exist in the borrow stack/
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
--> $DIR/return_invalid_mut_tuple.rs:LL:CC
|
LL | foo(&mut (1, 2)).0;
| ^^^^^^^^^^^^^^^^^^
| |
| trying to reborrow from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x4..0x8]
| trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x4..0x8]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x4..0x8]
help: <TAG> was created by a Unique retag at offsets [0x4..0x8]
--> $DIR/return_invalid_mut_tuple.rs:LL:CC
|
LL | let ret = (unsafe { &mut (*xraw).1 },);
| ^^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x8]
help: <TAG> was later invalidated at offsets [0x0..0x8] by a read access
--> $DIR/return_invalid_mut_tuple.rs:LL:CC
|
LL | let _val = unsafe { *xraw }; // invalidate xref

View File

@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 {
let xraw = x as *mut (i32, i32);
let ret = unsafe { &(*xraw).1 };
unsafe { *xraw = (42, 23) }; // unfreeze
ret //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
ret //~ ERROR: /retag .* tag does not exist in the borrow stack/
}
fn main() {

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
--> $DIR/return_invalid_shr.rs:LL:CC
|
LL | ret
| ^^^
| |
| trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x4..0x8]
| trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x4..0x8]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x4..0x8]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x4..0x8]
--> $DIR/return_invalid_shr.rs:LL:CC
|
LL | let ret = unsafe { &(*xraw).1 };
| ^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x8]
help: <TAG> was later invalidated at offsets [0x0..0x8] by a write access
--> $DIR/return_invalid_shr.rs:LL:CC
|
LL | unsafe { *xraw = (42, 23) }; // unfreeze

View File

@ -9,7 +9,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&i32> {
fn main() {
match foo(&mut (1, 2)) {
Some(_x) => {} //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
Some(_x) => {} //~ ERROR: /retag .* tag does not exist in the borrow stack/
None => {}
}
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
--> $DIR/return_invalid_shr_option.rs:LL:CC
|
LL | Some(_x) => {}
| ^^
| |
| trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x4..0x8]
| trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x4..0x8]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x4..0x8]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x4..0x8]
--> $DIR/return_invalid_shr_option.rs:LL:CC
|
LL | let ret = Some(unsafe { &(*xraw).1 });
| ^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x8]
help: <TAG> was later invalidated at offsets [0x0..0x8] by a write access
--> $DIR/return_invalid_shr_option.rs:LL:CC
|
LL | unsafe { *xraw = (42, 23) }; // unfreeze

View File

@ -8,5 +8,5 @@ fn foo(x: &mut (i32, i32)) -> (&i32,) {
}
fn main() {
foo(&mut (1, 2)).0; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
foo(&mut (1, 2)).0; //~ ERROR: /retag .* tag does not exist in the borrow stack/
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
--> $DIR/return_invalid_shr_tuple.rs:LL:CC
|
LL | foo(&mut (1, 2)).0;
| ^^^^^^^^^^^^^^^^^^
| |
| trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x4..0x8]
| trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x4..0x8]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x4..0x8]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x4..0x8]
--> $DIR/return_invalid_shr_tuple.rs:LL:CC
|
LL | let ret = (unsafe { &(*xraw).1 },);
| ^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x8]
help: <TAG> was later invalidated at offsets [0x0..0x8] by a write access
--> $DIR/return_invalid_shr_tuple.rs:LL:CC
|
LL | unsafe { *xraw = (42, 23) }; // unfreeze

View File

@ -11,6 +11,6 @@ fn main() {
let y: &mut Cell<i32> = mem::transmute(&mut *x); // launder lifetime
let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite
shr_rw.set(1);
y.get_mut(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/
y.get_mut(); //~ ERROR: /retag .* tag does not exist in the borrow stack/
}
}

View File

@ -1,20 +1,20 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC
|
LL | y.get_mut();
| ^^^^^^^^^^^
| |
| trying to reborrow from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x0..0x4]
| trying to retag from <TAG> for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of two-phase retag at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC
|
LL | let y: &mut Cell<i32> = mem::transmute(&mut *x); // launder lifetime
| ^^^^^^^^^^^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4]
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique retag
--> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC
|
LL | shr_rw.set(1);

View File

@ -9,12 +9,12 @@ LL | let _val = *y;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [$HEX..$HEX]
help: <TAG> was created by a SharedReadOnly retag at offsets [$HEX..$HEX]
--> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC
|
LL | let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: <TAG> was later invalidated at offsets [$HEX..$HEX]
help: <TAG> was later invalidated at offsets [$HEX..$HEX] by a Unique retag
--> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC
|
LL | shr_rw.replace(1);

View File

@ -9,7 +9,7 @@ LL | *(x as *const i32 as *mut i32) = 7;
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x4]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> $DIR/shr_frozen_violation1.rs:LL:CC
|
LL | *(x as *const i32 as *mut i32) = 7;

View File

@ -0,0 +1,17 @@
// This is a copy of illegal_read1.rs, but with #[track_caller] on the test.
// This test only checks that our diagnostics do not display the contents of callee.
#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391
fn main() {
let mut x = 15;
let xraw = &mut x as *mut _;
let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok...
callee(xraw);
let _val = *xref; // ...but any use of raw will invalidate our ref.
//~^ ERROR: /read access .* tag does not exist in the borrow stack/
}
#[track_caller]
fn callee(xraw: *mut i32) {
let _val = unsafe { *xraw };
}

View File

@ -0,0 +1,28 @@
error: Undefined Behavior: attempting a read access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> $DIR/track_caller.rs:LL:CC
|
LL | let _val = *xref; // ...but any use of raw will invalidate our ref.
| ^^^^^
| |
| attempting a read access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of an access at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a Unique retag at offsets [0x0..0x4]
--> $DIR/track_caller.rs:LL:CC
|
LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok...
| ^^^^^^^^^^
help: <TAG> was later invalidated at offsets [0x0..0x4] by a read access
--> $DIR/track_caller.rs:LL:CC
|
LL | callee(xraw);
| ^^^^^^^^^^^^
= note: backtrace:
= note: inside `main` at $DIR/track_caller.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error

View File

@ -9,7 +9,7 @@ LL | unsafe { *raw = 13 };
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x4..0x8]
help: <TAG> was created by a SharedReadWrite retag at offsets [0x4..0x8]
--> $DIR/transmute-is-no-escape.rs:LL:CC
|
LL | let raw = (&mut x[1] as *mut i32).wrapping_offset(-1);

View File

@ -9,7 +9,7 @@ LL | let _val = unsafe { *ptr_to_first.add(1) };
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x1]
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x1]
--> $DIR/unescaped_static.rs:LL:CC
|
LL | let ptr_to_first = &ARRAY[0] as *const u8;

View File

@ -1,5 +1,5 @@
//@compile-flags: -Zmiri-strict-provenance
//@error-pattern: /reborrow .* tag does not exist in the borrow stack/
//@error-pattern: /retag .* tag does not exist in the borrow stack/
fn main() {
unsafe {

View File

@ -1,15 +1,15 @@
error: Undefined Behavior: trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
error: Undefined Behavior: trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
--> RUSTLIB/core/src/slice/mod.rs:LL:CC
|
LL | unsafe { &*index.get_unchecked(self) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| trying to reborrow from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at ALLOC[0x4..0x8]
| trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at ALLOC[0x4..0x8]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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: <TAG> was created by a retag at offsets [0x0..0x0]
help: <TAG> would have been created here, but this is a zero-size retag ([0x0..0x0]) so the tag in question does not exist anywhere
--> $DIR/zst_slice.rs:LL:CC
|
LL | assert_eq!(*s.get_unchecked(1), 2);