add a weak form of protection that justifies Box noalias
This commit is contained in:
parent
c043a0e7d6
commit
7225524744
20 changed files with 146 additions and 65 deletions
|
@ -6,7 +6,7 @@ use rustc_span::{Span, SpanData};
|
||||||
use rustc_target::abi::Size;
|
use rustc_target::abi::Size;
|
||||||
|
|
||||||
use crate::helpers::CurrentSpan;
|
use crate::helpers::CurrentSpan;
|
||||||
use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission};
|
use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission, ProtectorKind};
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
use rustc_middle::mir::interpret::InterpError;
|
use rustc_middle::mir::interpret::InterpError;
|
||||||
|
@ -288,7 +288,11 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir
|
||||||
}
|
}
|
||||||
Operation::Access(AccessOp { kind, range, .. }) =>
|
Operation::Access(AccessOp { kind, range, .. }) =>
|
||||||
(*range, InvalidationCause::Access(*kind)),
|
(*range, InvalidationCause::Access(*kind)),
|
||||||
_ => unreachable!("Tags can only be invalidated during a retag or access"),
|
_ => {
|
||||||
|
// This can be reached, but never be relevant later since the entire allocation is
|
||||||
|
// gone now.
|
||||||
|
return;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self.history.invalidations.push(Invalidation { tag, range, span, cause });
|
self.history.invalidations.push(Invalidation { tag, range, span, cause });
|
||||||
}
|
}
|
||||||
|
@ -369,7 +373,7 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir
|
||||||
|
|
||||||
/// Report a descriptive error when `new` could not be granted from `derived_from`.
|
/// Report a descriptive error when `new` could not be granted from `derived_from`.
|
||||||
#[inline(never)] // This is only called on fatal code paths
|
#[inline(never)] // This is only called on fatal code paths
|
||||||
pub fn grant_error(&self, perm: Permission, stack: &Stack) -> InterpError<'tcx> {
|
pub(super) fn grant_error(&self, perm: Permission, stack: &Stack) -> InterpError<'tcx> {
|
||||||
let Operation::Retag(op) = &self.operation else {
|
let Operation::Retag(op) = &self.operation else {
|
||||||
unreachable!("grant_error should only be called during a retag")
|
unreachable!("grant_error should only be called during a retag")
|
||||||
};
|
};
|
||||||
|
@ -389,7 +393,7 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir
|
||||||
|
|
||||||
/// Report a descriptive error when `access` is not permitted based on `tag`.
|
/// Report a descriptive error when `access` is not permitted based on `tag`.
|
||||||
#[inline(never)] // This is only called on fatal code paths
|
#[inline(never)] // This is only called on fatal code paths
|
||||||
pub fn access_error(&self, stack: &Stack) -> InterpError<'tcx> {
|
pub(super) fn access_error(&self, stack: &Stack) -> InterpError<'tcx> {
|
||||||
let Operation::Access(op) = &self.operation else {
|
let Operation::Access(op) = &self.operation else {
|
||||||
unreachable!("access_error should only be called during an access")
|
unreachable!("access_error should only be called during an access")
|
||||||
};
|
};
|
||||||
|
@ -408,7 +412,11 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)] // This is only called on fatal code paths
|
#[inline(never)] // This is only called on fatal code paths
|
||||||
pub fn protector_error(&self, item: &Item) -> InterpError<'tcx> {
|
pub(super) fn protector_error(&self, item: &Item, kind: ProtectorKind) -> InterpError<'tcx> {
|
||||||
|
let protected = match kind {
|
||||||
|
ProtectorKind::WeakProtector => "weakly protected",
|
||||||
|
ProtectorKind::StrongProtector => "strongly protected",
|
||||||
|
};
|
||||||
let call_id = self
|
let call_id = self
|
||||||
.threads
|
.threads
|
||||||
.all_stacks()
|
.all_stacks()
|
||||||
|
@ -422,10 +430,7 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir
|
||||||
match self.operation {
|
match self.operation {
|
||||||
Operation::Dealloc(_) =>
|
Operation::Dealloc(_) =>
|
||||||
err_sb_ub(
|
err_sb_ub(
|
||||||
format!(
|
format!("deallocating while item {item:?} is {protected} by call {call_id:?}",),
|
||||||
"deallocating while item {:?} is protected by call {:?}",
|
|
||||||
item, call_id
|
|
||||||
),
|
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
|
@ -433,8 +438,7 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir
|
||||||
| Operation::Access(AccessOp { tag, .. }) =>
|
| Operation::Access(AccessOp { tag, .. }) =>
|
||||||
err_sb_ub(
|
err_sb_ub(
|
||||||
format!(
|
format!(
|
||||||
"not granting access to tag {:?} because that would remove {:?} which is protected because it is an argument of call {:?}",
|
"not granting access to tag {tag:?} because that would remove {item:?} which is {protected} because it is an argument of call {call_id:?}",
|
||||||
tag, item, call_id
|
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
tag.and_then(|tag| self.get_logs_relevant_to(tag, Some(item.tag()))),
|
tag.and_then(|tag| self.get_logs_relevant_to(tag, Some(item.tag()))),
|
||||||
|
|
|
@ -91,6 +91,26 @@ pub struct Stacks {
|
||||||
modified_since_last_gc: bool,
|
modified_since_last_gc: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The flavor of the protector.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
enum ProtectorKind {
|
||||||
|
/// Protected against aliasing violations from other pointers.
|
||||||
|
///
|
||||||
|
/// Items protected like this cause UB when they are invalidated, *but* the pointer itself may
|
||||||
|
/// still be used to issue a deallocation.
|
||||||
|
///
|
||||||
|
/// This is required for LLVM IR pointers that are `noalias` but *not* `dereferenceable`.
|
||||||
|
WeakProtector,
|
||||||
|
|
||||||
|
/// Protected against any kind of invalidation.
|
||||||
|
///
|
||||||
|
/// Items protected like this cause UB when they are invalidated or the memory is deallocated.
|
||||||
|
/// This is strictly stronger protection than `WeakProtector`.
|
||||||
|
///
|
||||||
|
/// This is required for LLVM IR pointers that are `dereferenceable` (and also allows `noalias`).
|
||||||
|
StrongProtector,
|
||||||
|
}
|
||||||
|
|
||||||
/// Extra global state, available to the memory access hooks.
|
/// Extra global state, available to the memory access hooks.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GlobalStateInner {
|
pub struct GlobalStateInner {
|
||||||
|
@ -102,12 +122,12 @@ pub struct GlobalStateInner {
|
||||||
base_ptr_tags: FxHashMap<AllocId, SbTag>,
|
base_ptr_tags: FxHashMap<AllocId, SbTag>,
|
||||||
/// Next unused call ID (for protectors).
|
/// Next unused call ID (for protectors).
|
||||||
next_call_id: CallId,
|
next_call_id: CallId,
|
||||||
/// All currently protected tags.
|
/// All currently protected tags, and the status of their protection.
|
||||||
/// An item is protected if its tag is in this set, *and* it has the "protected" bit set.
|
/// An item is protected if its tag is in this set, *and* it has the "protected" bit set.
|
||||||
/// We add tags to this when they are created with a protector in `reborrow`, and
|
/// We add tags to this when they are created with a protector in `reborrow`, and
|
||||||
/// we remove tags from this when the call which is protecting them returns, in
|
/// we remove tags from this when the call which is protecting them returns, in
|
||||||
/// `GlobalStateInner::end_call`. See `Stack::item_popped` for more details.
|
/// `GlobalStateInner::end_call`. See `Stack::item_popped` for more details.
|
||||||
protected_tags: FxHashSet<SbTag>,
|
protected_tags: FxHashMap<SbTag, ProtectorKind>,
|
||||||
/// The pointer ids to trace
|
/// The pointer ids to trace
|
||||||
tracked_pointer_tags: FxHashSet<SbTag>,
|
tracked_pointer_tags: FxHashSet<SbTag>,
|
||||||
/// The call ids to trace
|
/// The call ids to trace
|
||||||
|
@ -189,7 +209,7 @@ impl GlobalStateInner {
|
||||||
next_ptr_tag: SbTag(NonZeroU64::new(1).unwrap()),
|
next_ptr_tag: SbTag(NonZeroU64::new(1).unwrap()),
|
||||||
base_ptr_tags: FxHashMap::default(),
|
base_ptr_tags: FxHashMap::default(),
|
||||||
next_call_id: NonZeroU64::new(1).unwrap(),
|
next_call_id: NonZeroU64::new(1).unwrap(),
|
||||||
protected_tags: FxHashSet::default(),
|
protected_tags: FxHashMap::default(),
|
||||||
tracked_pointer_tags,
|
tracked_pointer_tags,
|
||||||
tracked_call_ids,
|
tracked_call_ids,
|
||||||
retag_fields,
|
retag_fields,
|
||||||
|
@ -314,6 +334,7 @@ impl<'tcx> Stack {
|
||||||
item: &Item,
|
item: &Item,
|
||||||
global: &GlobalStateInner,
|
global: &GlobalStateInner,
|
||||||
dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>,
|
dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>,
|
||||||
|
deallocation: bool,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
if !global.tracked_pointer_tags.is_empty() {
|
if !global.tracked_pointer_tags.is_empty() {
|
||||||
dcx.check_tracked_tag_popped(item, global);
|
dcx.check_tracked_tag_popped(item, global);
|
||||||
|
@ -336,8 +357,11 @@ impl<'tcx> Stack {
|
||||||
// 2. Most frames protect only one or two tags. So this duplicative global turns a search
|
// 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
|
// 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).
|
// constant time check (and a slow linear, because the tags in the frames aren't contiguous).
|
||||||
if global.protected_tags.contains(&item.tag()) {
|
if let Some(&protector_kind) = global.protected_tags.get(&item.tag()) {
|
||||||
return Err(dcx.protector_error(item).into());
|
let allowed = deallocation && matches!(protector_kind, ProtectorKind::WeakProtector);
|
||||||
|
if !allowed {
|
||||||
|
return Err(dcx.protector_error(item, protector_kind).into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -350,7 +374,7 @@ impl<'tcx> Stack {
|
||||||
&mut self,
|
&mut self,
|
||||||
access: AccessKind,
|
access: AccessKind,
|
||||||
tag: ProvenanceExtra,
|
tag: ProvenanceExtra,
|
||||||
global: &mut GlobalStateInner,
|
global: &GlobalStateInner,
|
||||||
dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>,
|
dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>,
|
||||||
exposed_tags: &FxHashSet<SbTag>,
|
exposed_tags: &FxHashSet<SbTag>,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
|
@ -377,7 +401,7 @@ impl<'tcx> Stack {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
self.pop_items_after(first_incompatible_idx, |item| {
|
self.pop_items_after(first_incompatible_idx, |item| {
|
||||||
Stack::item_popped(&item, global, dcx)?;
|
Stack::item_popped(&item, global, dcx, /* deallocation */ false)?;
|
||||||
dcx.log_invalidation(item.tag());
|
dcx.log_invalidation(item.tag());
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
@ -398,7 +422,7 @@ impl<'tcx> Stack {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
self.disable_uniques_starting_at(first_incompatible_idx, |item| {
|
self.disable_uniques_starting_at(first_incompatible_idx, |item| {
|
||||||
Stack::item_popped(&item, global, dcx)?;
|
Stack::item_popped(&item, global, dcx, /* deallocation */ false)?;
|
||||||
dcx.log_invalidation(item.tag());
|
dcx.log_invalidation(item.tag());
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
@ -440,14 +464,15 @@ impl<'tcx> Stack {
|
||||||
dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>,
|
dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>,
|
||||||
exposed_tags: &FxHashSet<SbTag>,
|
exposed_tags: &FxHashSet<SbTag>,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
// Step 1: Make sure there is a granting item.
|
// Step 1: Make a write access.
|
||||||
self.find_granting(AccessKind::Write, tag, exposed_tags)
|
// As part of this we do regular protector checking, i.e. even weakly protected items cause UB when popped.
|
||||||
|
self.access(AccessKind::Write, tag, global, dcx, exposed_tags)
|
||||||
.map_err(|_| dcx.dealloc_error())?;
|
.map_err(|_| dcx.dealloc_error())?;
|
||||||
|
|
||||||
// Step 2: Consider all items removed. This checks for protectors.
|
// Step 2: Pretend we remove the remaining items, checking if any are strongly protected.
|
||||||
for idx in (0..self.len()).rev() {
|
for idx in (0..self.len()).rev() {
|
||||||
let item = self.get(idx).unwrap();
|
let item = self.get(idx).unwrap();
|
||||||
Stack::item_popped(&item, global, dcx)?;
|
Stack::item_popped(&item, global, dcx, /* deallocation */ true)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -698,7 +723,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||||
kind: RefKind,
|
kind: RefKind,
|
||||||
retag_cause: RetagCause, // What caused this retag, for diagnostics only
|
retag_cause: RetagCause, // What caused this retag, for diagnostics only
|
||||||
new_tag: SbTag,
|
new_tag: SbTag,
|
||||||
protect: bool,
|
protect: Option<ProtectorKind>,
|
||||||
) -> InterpResult<'tcx, Option<AllocId>> {
|
) -> InterpResult<'tcx, Option<AllocId>> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
|
@ -761,7 +786,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||||
);
|
);
|
||||||
let mut dcx = dcx.build(&mut stacked_borrows.history, base_offset);
|
let mut dcx = dcx.build(&mut stacked_borrows.history, base_offset);
|
||||||
dcx.log_creation();
|
dcx.log_creation();
|
||||||
if protect {
|
if protect.is_some() {
|
||||||
dcx.log_protector();
|
dcx.log_protector();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -821,10 +846,16 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||||
size.bytes()
|
size.bytes()
|
||||||
);
|
);
|
||||||
|
|
||||||
if protect {
|
if let Some(protect) = protect {
|
||||||
// See comment in `Stack::item_popped` for why we store the tag twice.
|
// See comment in `Stack::item_popped` for why we store the tag twice.
|
||||||
this.frame_mut().extra.stacked_borrows.as_mut().unwrap().protected_tags.push(new_tag);
|
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);
|
this.machine
|
||||||
|
.stacked_borrows
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.get_mut()
|
||||||
|
.protected_tags
|
||||||
|
.insert(new_tag, protect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the stacks.
|
// Update the stacks.
|
||||||
|
@ -866,7 +897,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||||
Permission::SharedReadWrite
|
Permission::SharedReadWrite
|
||||||
};
|
};
|
||||||
let protected = if frozen {
|
let protected = if frozen {
|
||||||
protect
|
protect.is_some()
|
||||||
} else {
|
} else {
|
||||||
// We do not protect inside UnsafeCell.
|
// We do not protect inside UnsafeCell.
|
||||||
// This fixes https://github.com/rust-lang/rust/issues/55005.
|
// This fixes https://github.com/rust-lang/rust/issues/55005.
|
||||||
|
@ -899,7 +930,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.expect("we should have Stacked Borrows data")
|
.expect("we should have Stacked Borrows data")
|
||||||
.borrow_mut();
|
.borrow_mut();
|
||||||
let item = Item::new(new_tag, perm, protect);
|
let item = Item::new(new_tag, perm, protect.is_some());
|
||||||
let range = alloc_range(base_offset, size);
|
let range = alloc_range(base_offset, size);
|
||||||
let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut();
|
let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut();
|
||||||
// FIXME: can't share this with the current_span inside log_creation
|
// FIXME: can't share this with the current_span inside log_creation
|
||||||
|
@ -926,7 +957,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||||
val: &ImmTy<'tcx, Provenance>,
|
val: &ImmTy<'tcx, Provenance>,
|
||||||
kind: RefKind,
|
kind: RefKind,
|
||||||
retag_cause: RetagCause, // What caused this retag, for diagnostics only
|
retag_cause: RetagCause, // What caused this retag, for diagnostics only
|
||||||
protect: bool,
|
protect: Option<ProtectorKind>,
|
||||||
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
|
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
// We want a place for where the ptr *points to*, so we get one.
|
// We want a place for where the ptr *points to*, so we get one.
|
||||||
|
@ -996,7 +1027,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
place: &PlaceTy<'tcx, Provenance>,
|
place: &PlaceTy<'tcx, Provenance>,
|
||||||
ref_kind: RefKind,
|
ref_kind: RefKind,
|
||||||
retag_cause: RetagCause,
|
retag_cause: RetagCause,
|
||||||
protector: bool,
|
protector: Option<ProtectorKind>,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?;
|
let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?;
|
||||||
let val = self.ecx.retag_reference(&val, ref_kind, retag_cause, protector)?;
|
let val = self.ecx.retag_reference(&val, ref_kind, retag_cause, protector)?;
|
||||||
|
@ -1015,13 +1046,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
||||||
// Boxes do not get a protector: protectors reflect that references outlive the call
|
// Boxes get a weak protectors, since they may be deallocated.
|
||||||
// they were passed in to; that's just not the case for boxes.
|
|
||||||
self.retag_place(
|
self.retag_place(
|
||||||
place,
|
place,
|
||||||
RefKind::Unique { two_phase: false },
|
RefKind::Unique { two_phase: false },
|
||||||
self.retag_cause,
|
self.retag_cause,
|
||||||
/*protector*/ false,
|
/*protector*/
|
||||||
|
(self.kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1046,7 +1077,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
place,
|
place,
|
||||||
ref_kind,
|
ref_kind,
|
||||||
self.retag_cause,
|
self.retag_cause,
|
||||||
/*protector*/ self.kind == RetagKind::FnEntry,
|
/*protector*/
|
||||||
|
(self.kind == RetagKind::FnEntry)
|
||||||
|
.then_some(ProtectorKind::StrongProtector),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
ty::RawPtr(tym) => {
|
ty::RawPtr(tym) => {
|
||||||
|
@ -1059,7 +1092,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
place,
|
place,
|
||||||
RefKind::Raw { mutable: tym.mutbl == Mutability::Mut },
|
RefKind::Raw { mutable: tym.mutbl == Mutability::Mut },
|
||||||
self.retag_cause,
|
self.retag_cause,
|
||||||
/*protector*/ false,
|
/*protector*/ None,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1110,12 +1143,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
// (The pointer type does not matter, so we use a raw pointer.)
|
// (The pointer type does not matter, so we use a raw pointer.)
|
||||||
let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?;
|
let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?;
|
||||||
let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout);
|
let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout);
|
||||||
// Reborrow it.
|
// Reborrow it. With protection! That is part of the point.
|
||||||
let val = this.retag_reference(
|
let val = this.retag_reference(
|
||||||
&val,
|
&val,
|
||||||
RefKind::Unique { two_phase: false },
|
RefKind::Unique { two_phase: false },
|
||||||
RetagCause::FnReturn,
|
RetagCause::FnReturn,
|
||||||
/*protector*/ true,
|
/*protector*/ Some(ProtectorKind::StrongProtector),
|
||||||
)?;
|
)?;
|
||||||
// And use reborrowed pointer for return place.
|
// And use reborrowed pointer for return place.
|
||||||
let return_place = this.ref_to_mplace(&val)?;
|
let return_place = this.ref_to_mplace(&val)?;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is protected because it is an argument of call ID
|
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
--> $DIR/aliasing_mut1.rs:LL:CC
|
--> $DIR/aliasing_mut1.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | pub fn safe(_x: &mut i32, _y: &mut i32) {}
|
LL | pub fn safe(_x: &mut i32, _y: &mut i32) {}
|
||||||
| ^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is protected because it is an argument of call ID
|
| ^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
|
|
|
|
||||||
= 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: 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is protected because it is an argument of call ID
|
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
--> $DIR/aliasing_mut2.rs:LL:CC
|
--> $DIR/aliasing_mut2.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | pub fn safe(_x: &i32, _y: &mut i32) {}
|
LL | pub fn safe(_x: &i32, _y: &mut i32) {}
|
||||||
| ^^ not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is protected because it is an argument of call ID
|
| ^^ not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
|
|
|
|
||||||
= 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: 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is protected because it is an argument of call ID
|
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
--> $DIR/aliasing_mut4.rs:LL:CC
|
--> $DIR/aliasing_mut4.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | pub fn safe(_x: &i32, _y: &mut Cell<i32>) {}
|
LL | pub fn safe(_x: &i32, _y: &mut Cell<i32>) {}
|
||||||
| ^^ not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is protected because it is an argument of call ID
|
| ^^ not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
|
|
|
|
||||||
= 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: 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
unsafe fn test(mut x: Box<i32>, y: *const i32) -> i32 {
|
||||||
|
// We will call this in a way that x and y alias.
|
||||||
|
*x = 5;
|
||||||
|
std::mem::forget(x);
|
||||||
|
*y //~ERROR: weakly protected
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
unsafe {
|
||||||
|
let mut v = 42;
|
||||||
|
let ptr = &mut v as *mut i32;
|
||||||
|
test(Box::from_raw(ptr), ptr);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is weakly protected because it is an argument of call ID
|
||||||
|
--> $DIR/box_noalias_violation.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | *y
|
||||||
|
| ^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is weakly protected because it is an argument of call ID
|
||||||
|
|
|
||||||
|
= 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/box_noalias_violation.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | let ptr = &mut v as *mut i32;
|
||||||
|
| ^^^^^^
|
||||||
|
help: <TAG> is this argument
|
||||||
|
--> $DIR/box_noalias_violation.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | unsafe fn test(mut x: Box<i32>, y: *const i32) -> i32 {
|
||||||
|
| ^^^^^
|
||||||
|
= note: BACKTRACE:
|
||||||
|
= note: inside `test` at $DIR/box_noalias_violation.rs:LL:CC
|
||||||
|
note: inside `main` at $DIR/box_noalias_violation.rs:LL:CC
|
||||||
|
--> $DIR/box_noalias_violation.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | test(Box::from_raw(ptr), ptr);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//@error-pattern: /deallocating while item \[Unique for .*\] is protected/
|
//@error-pattern: /deallocating while item \[Unique for .*\] is strongly protected/
|
||||||
|
|
||||||
fn inner(x: &mut i32, f: fn(&mut i32)) {
|
fn inner(x: &mut i32, f: fn(&mut i32)) {
|
||||||
// `f` may mutate, but it may not deallocate!
|
// `f` may mutate, but it may not deallocate!
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: Undefined Behavior: deallocating while item [Unique for <TAG>] is protected by call ID
|
error: Undefined Behavior: deallocating while item [Unique for <TAG>] is strongly protected by call ID
|
||||||
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
|
LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [Unique for <TAG>] is protected by call ID
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [Unique for <TAG>] is strongly protected by call ID
|
||||||
|
|
|
|
||||||
= 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: 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//@error-pattern: /deallocating while item \[SharedReadWrite for .*\] is protected/
|
//@error-pattern: /deallocating while item \[SharedReadWrite for .*\] is strongly protected/
|
||||||
use std::marker::PhantomPinned;
|
use std::marker::PhantomPinned;
|
||||||
|
|
||||||
pub struct NotUnpin(i32, PhantomPinned);
|
pub struct NotUnpin(i32, PhantomPinned);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: Undefined Behavior: deallocating while item [SharedReadWrite for <TAG>] is protected by call ID
|
error: Undefined Behavior: deallocating while item [SharedReadWrite for <TAG>] is strongly protected by call ID
|
||||||
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
|
LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [SharedReadWrite for <TAG>] is protected by call ID
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [SharedReadWrite for <TAG>] is strongly protected by call ID
|
||||||
|
|
|
|
||||||
= 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: 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
|
|
|
@ -7,6 +7,6 @@ fn main() {
|
||||||
fn foo(a: &mut u32, y: *mut u32) -> u32 {
|
fn foo(a: &mut u32, y: *mut u32) -> u32 {
|
||||||
*a = 1;
|
*a = 1;
|
||||||
let _b = &*a;
|
let _b = &*a;
|
||||||
unsafe { *y = 2 }; //~ ERROR: /not granting access .* because that would remove .* which is protected/
|
unsafe { *y = 2 }; //~ ERROR: /not granting access .* because that would remove .* which is strongly protected/
|
||||||
return *a;
|
return *a;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is protected because it is an argument of call ID
|
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
--> $DIR/illegal_write6.rs:LL:CC
|
--> $DIR/illegal_write6.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | unsafe { *y = 2 };
|
LL | unsafe { *y = 2 };
|
||||||
| ^^^^^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is protected because it is an argument of call ID
|
| ^^^^^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
|
|
|
|
||||||
= 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: 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is protected because it is an argument of call ID
|
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
--> $DIR/invalidate_against_protector1.rs:LL:CC
|
--> $DIR/invalidate_against_protector1.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | let _val = unsafe { *x };
|
LL | let _val = unsafe { *x };
|
||||||
| ^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is protected because it is an argument of call ID
|
| ^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
|
|
|
|
||||||
= 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: 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is protected because it is an argument of call ID
|
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
--> $DIR/invalidate_against_protector2.rs:LL:CC
|
--> $DIR/invalidate_against_protector2.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | unsafe { *x = 0 };
|
LL | unsafe { *x = 0 };
|
||||||
| ^^^^^^ not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is protected because it is an argument of call ID
|
| ^^^^^^ not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
|
|
|
|
||||||
= 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: 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is protected because it is an argument of call ID
|
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
--> $DIR/invalidate_against_protector3.rs:LL:CC
|
--> $DIR/invalidate_against_protector3.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | unsafe { *x = 0 };
|
LL | unsafe { *x = 0 };
|
||||||
| ^^^^^^ not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is protected because it is an argument of call ID
|
| ^^^^^^ not granting access to tag <TAG> because that would remove [SharedReadOnly for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
|
|
|
|
||||||
= 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: 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//@error-pattern: which is protected
|
//@error-pattern: which is strongly protected
|
||||||
struct Newtype<'a>(&'a mut i32, i32);
|
struct Newtype<'a>(&'a mut i32, i32);
|
||||||
|
|
||||||
fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) {
|
fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is protected because it is an argument of call ID
|
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
--> RUSTLIB/alloc/src/boxed.rs:LL:CC
|
--> RUSTLIB/alloc/src/boxed.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc)
|
LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is protected because it is an argument of call ID
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
|
|
|
|
||||||
= 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: 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//@error-pattern: which is protected
|
//@error-pattern: which is strongly protected
|
||||||
struct Newtype<'a>(&'a mut i32);
|
struct Newtype<'a>(&'a mut i32);
|
||||||
|
|
||||||
fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) {
|
fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is protected because it is an argument of call ID
|
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
--> RUSTLIB/alloc/src/boxed.rs:LL:CC
|
--> RUSTLIB/alloc/src/boxed.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc)
|
LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is protected because it is an argument of call ID
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID
|
||||||
|
|
|
|
||||||
= 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: 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue