mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Auto merge of #2985 - RalfJung:retag-fields, r=saethlin
make full field retagging the default The 'scalar' field retagging mode is clearly a hack -- it mirrors details of the codegen backend and how various structs are represented in LLVM. This means whether code has UB or not depends on surprising aspects, such as whether a struct has 2 or 3 (non-zero-sized) fields. Now that both hashbrown and scopeguard have released fixes to be compatible with field retagging, I think it is time to enable full field retagging by default. `@saethlin` do you have an idea of how much fallout enabling full field retagging by default will cause? Do you have objections to enabling it by default? Fixes https://github.com/rust-lang/miri/issues/2528
This commit is contained in:
commit
c0de313e82
@ -407,15 +407,11 @@ to Miri failing to detect cases of undefined behavior in a program.
|
||||
application instead of raising an error within the context of Miri (and halting
|
||||
execution). Note that code might not expect these operations to ever panic, so
|
||||
this flag can lead to strange (mis)behavior.
|
||||
* `-Zmiri-retag-fields` changes Stacked Borrows retagging to recurse into *all* fields.
|
||||
This means that references in fields of structs/enums/tuples/arrays/... are retagged,
|
||||
and in particular, they are protected when passed as function arguments.
|
||||
(The default is to recurse only in cases where rustc would actually emit a `noalias` attribute.)
|
||||
* `-Zmiri-retag-fields=<all|none|scalar>` controls when Stacked Borrows retagging recurses into
|
||||
fields. `all` means it always recurses (like `-Zmiri-retag-fields`), `none` means it never
|
||||
recurses, `scalar` (the default) means it only recurses for types where we would also emit
|
||||
`noalias` annotations in the generated LLVM IR (types passed as individual scalars or pairs of
|
||||
scalars). Setting this to `none` is **unsound**.
|
||||
* `-Zmiri-retag-fields[=<all|none|scalar>]` controls when Stacked Borrows retagging recurses into
|
||||
fields. `all` means it always recurses (the default, and equivalent to `-Zmiri-retag-fields`
|
||||
without an explicit value), `none` means it never recurses, `scalar` means it only recurses for
|
||||
types where we would also emit `noalias` annotations in the generated LLVM IR (types passed as
|
||||
individual scalars or pairs of scalars). Setting this to `none` is **unsound**.
|
||||
* `-Zmiri-tag-gc=<blocks>` configures how often the pointer tag garbage collector runs. The default
|
||||
is to search for and remove unreachable tags once every `10000` basic blocks. Setting this to
|
||||
`0` disables the garbage collector, which causes some programs to have explosive memory usage
|
||||
|
@ -6,11 +6,19 @@ use rustc_span::{Span, SpanData};
|
||||
use rustc_target::abi::Size;
|
||||
|
||||
use crate::borrow_tracker::{
|
||||
stacked_borrows::{err_sb_ub, Permission},
|
||||
AccessKind, GlobalStateInner, ProtectorKind,
|
||||
stacked_borrows::Permission, AccessKind, GlobalStateInner, ProtectorKind,
|
||||
};
|
||||
use crate::*;
|
||||
|
||||
/// Error reporting
|
||||
fn err_sb_ub<'tcx>(
|
||||
msg: String,
|
||||
help: Vec<String>,
|
||||
history: Option<TagHistory>,
|
||||
) -> InterpError<'tcx> {
|
||||
err_machine_stop!(TerminationInfo::StackedBorrowsUb { msg, help, history })
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AllocHistory {
|
||||
id: AllocId,
|
||||
@ -61,12 +69,15 @@ struct Invalidation {
|
||||
#[derive(Clone, Debug)]
|
||||
enum InvalidationCause {
|
||||
Access(AccessKind),
|
||||
Retag(Permission, RetagCause),
|
||||
Retag(Permission, RetagInfo),
|
||||
}
|
||||
|
||||
impl Invalidation {
|
||||
fn generate_diagnostic(&self) -> (String, SpanData) {
|
||||
let message = if let InvalidationCause::Retag(_, RetagCause::FnEntry) = self.cause {
|
||||
let message = if matches!(
|
||||
self.cause,
|
||||
InvalidationCause::Retag(_, RetagInfo { cause: RetagCause::FnEntry, .. })
|
||||
) {
|
||||
// For a FnEntry retag, our Span points at the caller.
|
||||
// See `DiagnosticCx::log_invalidation`.
|
||||
format!(
|
||||
@ -87,8 +98,8 @@ 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) =>
|
||||
write!(f, "{perm:?} {retag}", retag = kind.summary()),
|
||||
InvalidationCause::Retag(perm, info) =>
|
||||
write!(f, "{perm:?} {retag}", retag = info.summary()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -129,13 +140,13 @@ impl<'ecx, 'mir, 'tcx> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> {
|
||||
|
||||
pub fn retag(
|
||||
machine: &'ecx MiriMachine<'mir, 'tcx>,
|
||||
cause: RetagCause,
|
||||
info: RetagInfo,
|
||||
new_tag: BorTag,
|
||||
orig_tag: ProvenanceExtra,
|
||||
range: AllocRange,
|
||||
) -> Self {
|
||||
let operation =
|
||||
Operation::Retag(RetagOp { cause, new_tag, orig_tag, range, permission: None });
|
||||
Operation::Retag(RetagOp { info, new_tag, orig_tag, range, permission: None });
|
||||
|
||||
DiagnosticCxBuilder { machine, operation }
|
||||
}
|
||||
@ -179,13 +190,19 @@ enum Operation {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct RetagOp {
|
||||
cause: RetagCause,
|
||||
info: RetagInfo,
|
||||
new_tag: BorTag,
|
||||
orig_tag: ProvenanceExtra,
|
||||
range: AllocRange,
|
||||
permission: Option<Permission>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct RetagInfo {
|
||||
pub cause: RetagCause,
|
||||
pub in_field: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum RetagCause {
|
||||
Normal,
|
||||
@ -258,11 +275,11 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
|
||||
pub fn log_invalidation(&mut self, tag: BorTag) {
|
||||
let mut span = self.machine.current_span();
|
||||
let (range, cause) = match &self.operation {
|
||||
Operation::Retag(RetagOp { cause, range, permission, .. }) => {
|
||||
if *cause == RetagCause::FnEntry {
|
||||
Operation::Retag(RetagOp { info, range, permission, .. }) => {
|
||||
if info.cause == RetagCause::FnEntry {
|
||||
span = self.machine.caller_span();
|
||||
}
|
||||
(*range, InvalidationCause::Retag(permission.unwrap(), *cause))
|
||||
(*range, InvalidationCause::Retag(permission.unwrap(), *info))
|
||||
}
|
||||
Operation::Access(AccessOp { kind, range, .. }) =>
|
||||
(*range, InvalidationCause::Access(*kind)),
|
||||
@ -372,9 +389,13 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
|
||||
self.history.id,
|
||||
self.offset.bytes(),
|
||||
);
|
||||
let mut helps = vec![operation_summary(&op.info.summary(), self.history.id, op.range)];
|
||||
if op.info.in_field {
|
||||
helps.push(format!("errors for retagging in fields are fairly new; please reach out to us (e.g. at <https://rust-lang.zulipchat.com/#narrow/stream/269128-miri>) if you find this error troubling"));
|
||||
}
|
||||
err_sb_ub(
|
||||
format!("{action}{}", error_cause(stack, op.orig_tag)),
|
||||
Some(operation_summary(&op.cause.summary(), self.history.id, op.range)),
|
||||
helps,
|
||||
op.orig_tag.and_then(|orig_tag| self.get_logs_relevant_to(orig_tag, None)),
|
||||
)
|
||||
}
|
||||
@ -397,7 +418,7 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
|
||||
);
|
||||
err_sb_ub(
|
||||
format!("{action}{}", error_cause(stack, op.tag)),
|
||||
Some(operation_summary("an access", self.history.id, op.range)),
|
||||
vec![operation_summary("an access", self.history.id, op.range)],
|
||||
op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)),
|
||||
)
|
||||
}
|
||||
@ -423,7 +444,7 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
|
||||
Operation::Dealloc(_) =>
|
||||
err_sb_ub(
|
||||
format!("deallocating while item {item:?} is {protected} by call {call_id:?}",),
|
||||
None,
|
||||
vec![],
|
||||
None,
|
||||
),
|
||||
Operation::Retag(RetagOp { orig_tag: tag, .. })
|
||||
@ -432,7 +453,7 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
|
||||
format!(
|
||||
"not granting access to tag {tag:?} because that would remove {item:?} which is {protected} because it is an argument of call {call_id:?}",
|
||||
),
|
||||
None,
|
||||
vec![],
|
||||
tag.and_then(|tag| self.get_logs_relevant_to(tag, Some(item.tag()))),
|
||||
),
|
||||
}
|
||||
@ -450,7 +471,7 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
|
||||
alloc_id = self.history.id,
|
||||
cause = error_cause(stack, op.tag),
|
||||
),
|
||||
None,
|
||||
vec![],
|
||||
op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)),
|
||||
)
|
||||
}
|
||||
@ -496,14 +517,18 @@ fn error_cause(stack: &Stack, prov_extra: ProvenanceExtra) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
impl RetagCause {
|
||||
impl RetagInfo {
|
||||
fn summary(&self) -> String {
|
||||
match self {
|
||||
let mut s = match self.cause {
|
||||
RetagCause::Normal => "retag",
|
||||
RetagCause::FnEntry => "function-entry retag",
|
||||
RetagCause::InPlaceFnPassing => "in-place function argument/return passing protection",
|
||||
RetagCause::TwoPhase => "two-phase retag",
|
||||
}
|
||||
.to_string()
|
||||
.to_string();
|
||||
if self.in_field {
|
||||
s.push_str(" (of a reference/box inside this compound value)");
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,11 @@ pub mod diagnostics;
|
||||
mod item;
|
||||
mod stack;
|
||||
|
||||
use log::trace;
|
||||
use std::cmp;
|
||||
use std::fmt::Write;
|
||||
use std::mem;
|
||||
|
||||
use log::trace;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::mir::{Mutability, RetagKind};
|
||||
@ -19,12 +21,12 @@ use rustc_middle::ty::{
|
||||
use rustc_target::abi::{Abi, Size};
|
||||
|
||||
use crate::borrow_tracker::{
|
||||
stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder, TagHistory},
|
||||
stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder},
|
||||
AccessKind, GlobalStateInner, ProtectorKind, RetagFields,
|
||||
};
|
||||
use crate::*;
|
||||
|
||||
use diagnostics::RetagCause;
|
||||
use diagnostics::{RetagCause, RetagInfo};
|
||||
pub use item::{Item, Permission};
|
||||
pub use stack::Stack;
|
||||
|
||||
@ -168,15 +170,6 @@ impl NewPermission {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error reporting
|
||||
pub fn err_sb_ub<'tcx>(
|
||||
msg: String,
|
||||
help: Option<String>,
|
||||
history: Option<TagHistory>,
|
||||
) -> InterpError<'tcx> {
|
||||
err_machine_stop!(TerminationInfo::StackedBorrowsUb { msg, help, history })
|
||||
}
|
||||
|
||||
// # Stacked Borrows Core Begin
|
||||
|
||||
/// We need to make at least the following things true:
|
||||
@ -623,7 +616,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||
size: Size,
|
||||
new_perm: NewPermission,
|
||||
new_tag: BorTag,
|
||||
retag_cause: RetagCause, // What caused this retag, for diagnostics only
|
||||
retag_info: RetagInfo, // diagnostics info about this retag
|
||||
) -> InterpResult<'tcx, Option<AllocId>> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
@ -670,7 +663,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||
// FIXME: can this be done cleaner?
|
||||
let dcx = DiagnosticCxBuilder::retag(
|
||||
&this.machine,
|
||||
retag_cause,
|
||||
retag_info,
|
||||
new_tag,
|
||||
orig_tag,
|
||||
alloc_range(base_offset, size),
|
||||
@ -761,7 +754,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||
let global = machine.borrow_tracker.as_ref().unwrap().borrow();
|
||||
let dcx = DiagnosticCxBuilder::retag(
|
||||
machine,
|
||||
retag_cause,
|
||||
retag_info,
|
||||
new_tag,
|
||||
orig_tag,
|
||||
alloc_range(base_offset, size),
|
||||
@ -804,7 +797,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||
let global = this.machine.borrow_tracker.as_ref().unwrap().borrow();
|
||||
let dcx = DiagnosticCxBuilder::retag(
|
||||
&this.machine,
|
||||
retag_cause,
|
||||
retag_info,
|
||||
new_tag,
|
||||
orig_tag,
|
||||
alloc_range(base_offset, size),
|
||||
@ -834,7 +827,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||
&mut self,
|
||||
val: &ImmTy<'tcx, Provenance>,
|
||||
new_perm: NewPermission,
|
||||
cause: RetagCause, // What caused this retag, for diagnostics only
|
||||
info: RetagInfo, // diagnostics info about this retag
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
|
||||
let this = self.eval_context_mut();
|
||||
// We want a place for where the ptr *points to*, so we get one.
|
||||
@ -852,7 +845,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||
let new_tag = this.machine.borrow_tracker.as_mut().unwrap().get_mut().new_ptr();
|
||||
|
||||
// Reborrow.
|
||||
let alloc_id = this.sb_reborrow(&place, size, new_perm, new_tag, cause)?;
|
||||
let alloc_id = this.sb_reborrow(&place, size, new_perm, new_tag, info)?;
|
||||
|
||||
// Adjust pointer.
|
||||
let new_place = place.map_provenance(|p| {
|
||||
@ -886,12 +879,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
|
||||
let this = self.eval_context_mut();
|
||||
let new_perm = NewPermission::from_ref_ty(val.layout.ty, kind, this);
|
||||
let retag_cause = match kind {
|
||||
let cause = match kind {
|
||||
RetagKind::TwoPhase { .. } => RetagCause::TwoPhase,
|
||||
RetagKind::FnEntry => unreachable!(),
|
||||
RetagKind::Raw | RetagKind::Default => RetagCause::Normal,
|
||||
};
|
||||
this.sb_retag_reference(val, new_perm, retag_cause)
|
||||
this.sb_retag_reference(val, new_perm, RetagInfo { cause, in_field: false })
|
||||
}
|
||||
|
||||
fn sb_retag_place_contents(
|
||||
@ -906,7 +899,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
RetagKind::FnEntry => RetagCause::FnEntry,
|
||||
RetagKind::Default => RetagCause::Normal,
|
||||
};
|
||||
let mut visitor = RetagVisitor { ecx: this, kind, retag_cause, retag_fields };
|
||||
let mut visitor =
|
||||
RetagVisitor { ecx: this, kind, retag_cause, retag_fields, in_field: false };
|
||||
return visitor.visit_value(place);
|
||||
|
||||
// The actual visitor.
|
||||
@ -915,6 +909,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
kind: RetagKind,
|
||||
retag_cause: RetagCause,
|
||||
retag_fields: RetagFields,
|
||||
in_field: bool,
|
||||
}
|
||||
impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> {
|
||||
#[inline(always)] // yes this helps in our benchmarks
|
||||
@ -922,10 +917,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
&mut self,
|
||||
place: &PlaceTy<'tcx, Provenance>,
|
||||
new_perm: NewPermission,
|
||||
retag_cause: RetagCause,
|
||||
) -> InterpResult<'tcx> {
|
||||
let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?;
|
||||
let val = self.ecx.sb_retag_reference(&val, new_perm, retag_cause)?;
|
||||
let val = self.ecx.sb_retag_reference(
|
||||
&val,
|
||||
new_perm,
|
||||
RetagInfo { cause: self.retag_cause, in_field: self.in_field },
|
||||
)?;
|
||||
self.ecx.write_immediate(*val, place)?;
|
||||
Ok(())
|
||||
}
|
||||
@ -943,7 +941,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
||||
// Boxes get a weak protectors, since they may be deallocated.
|
||||
let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
|
||||
self.retag_ptr_inplace(place, new_perm, self.retag_cause)
|
||||
self.retag_ptr_inplace(place, new_perm)
|
||||
}
|
||||
|
||||
fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
||||
@ -960,7 +958,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
ty::Ref(..) => {
|
||||
let new_perm =
|
||||
NewPermission::from_ref_ty(place.layout.ty, self.kind, self.ecx);
|
||||
self.retag_ptr_inplace(place, new_perm, self.retag_cause)?;
|
||||
self.retag_ptr_inplace(place, new_perm)?;
|
||||
}
|
||||
ty::RawPtr(..) => {
|
||||
// We do *not* want to recurse into raw pointers -- wide raw pointers have
|
||||
@ -984,7 +982,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
}
|
||||
};
|
||||
if recurse {
|
||||
let in_field = mem::replace(&mut self.in_field, true); // remember and restore old value
|
||||
self.walk_value(place)?;
|
||||
self.in_field = in_field;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1011,7 +1011,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
access: Some(AccessKind::Write),
|
||||
protector: Some(ProtectorKind::StrongProtector),
|
||||
};
|
||||
let _new_ptr = this.sb_retag_reference(&ptr, new_perm, RetagCause::InPlaceFnPassing)?;
|
||||
let _new_ptr = this.sb_retag_reference(
|
||||
&ptr,
|
||||
new_perm,
|
||||
RetagInfo { cause: RetagCause::InPlaceFnPassing, in_field: false },
|
||||
)?;
|
||||
// We just throw away `new_ptr`, so nobody can access this memory while it is protected.
|
||||
|
||||
Ok(())
|
||||
|
@ -22,7 +22,7 @@ pub enum TerminationInfo {
|
||||
UnsupportedInIsolation(String),
|
||||
StackedBorrowsUb {
|
||||
msg: String,
|
||||
help: Option<String>,
|
||||
help: Vec<String>,
|
||||
history: Option<TagHistory>,
|
||||
},
|
||||
TreeBorrowsUb {
|
||||
@ -224,11 +224,10 @@ pub fn report_error<'tcx, 'mir>(
|
||||
(None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")),
|
||||
],
|
||||
StackedBorrowsUb { help, history, .. } => {
|
||||
let url = "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md";
|
||||
msg.extend(help.clone());
|
||||
let mut helps = vec![
|
||||
(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")),
|
||||
(None, format!("see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information")),
|
||||
];
|
||||
if let Some(TagHistory {created, invalidated, protected}) = history.clone() {
|
||||
helps.push((Some(created.1), created.0));
|
||||
|
@ -183,7 +183,7 @@ impl Default for MiriConfig {
|
||||
mute_stdout_stderr: false,
|
||||
preemption_rate: 0.01, // 1%
|
||||
report_progress: None,
|
||||
retag_fields: RetagFields::OnlyScalar,
|
||||
retag_fields: RetagFields::Yes,
|
||||
external_so_file: None,
|
||||
gc_interval: 10_000,
|
||||
num_cpus: 1,
|
||||
|
@ -14,6 +14,7 @@ mod safe {
|
||||
from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid"
|
||||
from_raw_parts_mut(ptr.offset(mid as isize), len - mid),
|
||||
)
|
||||
//~[stack]^^^^ ERROR: /retag .* tag does not exist in the borrow stack/
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,7 +22,6 @@ mod safe {
|
||||
fn main() {
|
||||
let mut array = [1, 2, 3, 4];
|
||||
let (a, b) = safe::split_at_mut(&mut array, 0);
|
||||
//~[stack]^ ERROR: /retag .* tag does not exist in the borrow stack/
|
||||
a[1] = 5;
|
||||
b[1] = 6;
|
||||
//~[tree]^ ERROR: /write access through .* is forbidden/
|
||||
|
@ -1,11 +1,15 @@
|
||||
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 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]
|
||||
LL | / (
|
||||
LL | | from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid"
|
||||
LL | | from_raw_parts_mut(ptr.offset(mid as isize), len - mid),
|
||||
LL | | )
|
||||
| | ^
|
||||
| | |
|
||||
| | 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 (of a reference/box inside this compound value) at ALLOC[0x0..0x10]
|
||||
| errors for retagging in fields are fairly new; please reach out to us (e.g. at <https://rust-lang.zulipchat.com/#narrow/stream/269128-miri>) if you find this error troubling
|
||||
|
|
||||
= 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
|
||||
@ -20,7 +24,12 @@ help: <TAG> was later invalidated at offsets [0x0..0x10] by a Unique retag
|
||||
LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: BACKTRACE (of the first span):
|
||||
= note: inside `main` at $DIR/buggy_split_at_mut.rs:LL:CC
|
||||
= note: inside `safe::split_at_mut::<i32>` at $DIR/buggy_split_at_mut.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> $DIR/buggy_split_at_mut.rs:LL:CC
|
||||
|
|
||||
LL | let (a, b) = safe::split_at_mut(&mut array, 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -5,7 +5,8 @@ LL | foo(some_xref);
|
||||
| ^^^^^^^^^
|
||||
| |
|
||||
| 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]
|
||||
| this error occurs as part of retag (of a reference/box inside this compound value) at ALLOC[0x0..0x4]
|
||||
| errors for retagging in fields are fairly new; please reach out to us (e.g. at <https://rust-lang.zulipchat.com/#narrow/stream/269128-miri>) if you find this error troubling
|
||||
|
|
||||
= 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
|
||||
|
@ -5,7 +5,8 @@ LL | foo(pair_xref);
|
||||
| ^^^^^^^^^
|
||||
| |
|
||||
| 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]
|
||||
| this error occurs as part of retag (of a reference/box inside this compound value) at ALLOC[0x0..0x4]
|
||||
| errors for retagging in fields are fairly new; please reach out to us (e.g. at <https://rust-lang.zulipchat.com/#narrow/stream/269128-miri>) if you find this error troubling
|
||||
|
|
||||
= 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
|
||||
|
@ -5,7 +5,8 @@ LL | ret
|
||||
| ^^^
|
||||
| |
|
||||
| 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]
|
||||
| this error occurs as part of retag (of a reference/box inside this compound value) at ALLOC[0x4..0x8]
|
||||
| errors for retagging in fields are fairly new; please reach out to us (e.g. at <https://rust-lang.zulipchat.com/#narrow/stream/269128-miri>) if you find this error troubling
|
||||
|
|
||||
= 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
|
||||
|
@ -5,7 +5,8 @@ LL | ret
|
||||
| ^^^
|
||||
| |
|
||||
| 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]
|
||||
| this error occurs as part of retag (of a reference/box inside this compound value) at ALLOC[0x4..0x8]
|
||||
| errors for retagging in fields are fairly new; please reach out to us (e.g. at <https://rust-lang.zulipchat.com/#narrow/stream/269128-miri>) if you find this error troubling
|
||||
|
|
||||
= 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@compile-flags: -Zmiri-disable-validation
|
||||
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
|
||||
#![feature(generators, generator_trait)]
|
||||
|
||||
use std::{
|
||||
@ -10,9 +10,10 @@ fn firstn() -> impl Generator<Yield = u64, Return = ()> {
|
||||
static move || {
|
||||
let mut num = 0;
|
||||
let num = &mut num;
|
||||
*num += 0;
|
||||
|
||||
yield *num;
|
||||
*num += 1; //~ ERROR: dereferenced after this allocation got freed
|
||||
*num += 1; //~ERROR: dereferenced after this allocation got freed
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,8 @@ LL | ret
|
||||
| ^^^
|
||||
| |
|
||||
| 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]
|
||||
| this error occurs as part of retag (of a reference/box inside this compound value) at ALLOC[0x4..0x8]
|
||||
| errors for retagging in fields are fairly new; please reach out to us (e.g. at <https://rust-lang.zulipchat.com/#narrow/stream/269128-miri>) if you find this error troubling
|
||||
|
|
||||
= 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
|
||||
|
@ -5,7 +5,8 @@ LL | ret
|
||||
| ^^^
|
||||
| |
|
||||
| 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]
|
||||
| this error occurs as part of retag (of a reference/box inside this compound value) at ALLOC[0x4..0x8]
|
||||
| errors for retagging in fields are fairly new; please reach out to us (e.g. at <https://rust-lang.zulipchat.com/#narrow/stream/269128-miri>) if you find this error troubling
|
||||
|
|
||||
= 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
|
||||
|
@ -13,7 +13,7 @@ use std::ptr;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
fn basic() {
|
||||
fn finish<T>(mut amt: usize, mut t: T) -> T::Return
|
||||
fn finish<T>(mut amt: usize, self_referential: bool, mut t: T) -> T::Return
|
||||
where
|
||||
T: Generator<Yield = usize>,
|
||||
{
|
||||
@ -22,7 +22,10 @@ fn basic() {
|
||||
loop {
|
||||
let state = t.as_mut().resume(());
|
||||
// Test if the generator is valid (according to type invariants).
|
||||
let _ = unsafe { ManuallyDrop::new(ptr::read(t.as_mut().get_unchecked_mut())) };
|
||||
// For self-referential generators however this is UB!
|
||||
if !self_referential {
|
||||
let _ = unsafe { ManuallyDrop::new(ptr::read(t.as_mut().get_unchecked_mut())) };
|
||||
}
|
||||
match state {
|
||||
GeneratorState::Yielded(y) => {
|
||||
amt -= y;
|
||||
@ -40,9 +43,9 @@ fn basic() {
|
||||
panic!()
|
||||
}
|
||||
|
||||
finish(1, || yield 1);
|
||||
finish(1, false, || yield 1);
|
||||
|
||||
finish(3, || {
|
||||
finish(3, false, || {
|
||||
let mut x = 0;
|
||||
yield 1;
|
||||
x += 1;
|
||||
@ -52,27 +55,27 @@ fn basic() {
|
||||
assert_eq!(x, 2);
|
||||
});
|
||||
|
||||
finish(7 * 8 / 2, || {
|
||||
finish(7 * 8 / 2, false, || {
|
||||
for i in 0..8 {
|
||||
yield i;
|
||||
}
|
||||
});
|
||||
|
||||
finish(1, || {
|
||||
finish(1, false, || {
|
||||
if true {
|
||||
yield 1;
|
||||
} else {
|
||||
}
|
||||
});
|
||||
|
||||
finish(1, || {
|
||||
finish(1, false, || {
|
||||
if false {
|
||||
} else {
|
||||
yield 1;
|
||||
}
|
||||
});
|
||||
|
||||
finish(2, || {
|
||||
finish(2, false, || {
|
||||
if {
|
||||
yield 1;
|
||||
false
|
||||
@ -83,9 +86,20 @@ fn basic() {
|
||||
yield 1;
|
||||
});
|
||||
|
||||
// also test a self-referential generator
|
||||
// also test self-referential generators
|
||||
assert_eq!(
|
||||
finish(5, || {
|
||||
finish(5, true, static || {
|
||||
let mut x = 5;
|
||||
let y = &mut x;
|
||||
*y = 5;
|
||||
yield *y;
|
||||
*y = 10;
|
||||
x
|
||||
}),
|
||||
10
|
||||
);
|
||||
assert_eq!(
|
||||
finish(5, true, || {
|
||||
let mut x = Box::new(5);
|
||||
let y = &mut *x;
|
||||
*y = 5;
|
||||
@ -97,7 +111,7 @@ fn basic() {
|
||||
);
|
||||
|
||||
let b = true;
|
||||
finish(1, || {
|
||||
finish(1, false, || {
|
||||
yield 1;
|
||||
if b {
|
||||
return;
|
||||
@ -109,7 +123,7 @@ fn basic() {
|
||||
drop(x);
|
||||
});
|
||||
|
||||
finish(3, || {
|
||||
finish(3, false, || {
|
||||
yield 1;
|
||||
#[allow(unreachable_code)]
|
||||
let _x: (String, !) = (String::new(), {
|
||||
|
@ -1,4 +1,3 @@
|
||||
//@compile-flags: -Zmiri-retag-fields
|
||||
use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
|
||||
use std::mem::{self, MaybeUninit};
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
//@compile-flags: -Zmiri-retag-fields
|
||||
#![feature(allocator_api)]
|
||||
use std::ptr;
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
//@compile-flags: -Zmiri-retag-fields
|
||||
// Checks that the test does not run forever (which relies on a fast path).
|
||||
|
||||
#![allow(dropping_copy_types)]
|
||||
|
Loading…
Reference in New Issue
Block a user