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:
parent
46da748502
commit
14e72e7ffa
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) };
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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()) }
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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),
|
||||
|
20
tests/fail/stacked_borrows/fnentry_invalidation.rs
Normal file
20
tests/fail/stacked_borrows/fnentry_invalidation.rs
Normal 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 {}
|
28
tests/fail/stacked_borrows/fnentry_invalidation.stderr
Normal file
28
tests/fail/stacked_borrows/fnentry_invalidation.stderr
Normal 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
|
||||
|
@ -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 };
|
||||
|
@ -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 };
|
||||
|
@ -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 };
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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`
|
||||
|
@ -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/
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 _;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 };
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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/
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 _;
|
||||
|
@ -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 _;
|
||||
|
@ -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/
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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 => {}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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 => {}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
17
tests/fail/stacked_borrows/track_caller.rs
Normal file
17
tests/fail/stacked_borrows/track_caller.rs
Normal 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 };
|
||||
}
|
28
tests/fail/stacked_borrows/track_caller.stderr
Normal file
28
tests/fail/stacked_borrows/track_caller.stderr
Normal 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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user