diff --git a/README.md b/README.md index 50586c9ece..d7c50e9613 100644 --- a/README.md +++ b/README.md @@ -289,6 +289,11 @@ environment variable. We first document the most relevant and most commonly used `-Zmiri-disable-isolation` is set. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. +* `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and + [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html). + This will necessarily miss some bugs as those operations are not efficiently and accurately + implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is + subject to these operations. * `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables preemption. @@ -306,7 +311,17 @@ environment variable. We first document the most relevant and most commonly used * `-Zmiri-strict-provenance` enables [strict provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance - that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers`. + that cannot be used for any memory access. +* `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is + checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. + This can lead to cases where a program passes the alignment check by pure chance, because things + "happened to be" sufficiently aligned -- there is no UB in this execution but there would be UB in + others. To avoid such cases, the symbolic alignment check only takes into account the requested + alignment of the relevant allocation, and the offset into that allocation. This avoids missing + such bugs, but it also incurs some false positives when the code does manual integer arithmetic to + ensure alignment. (The standard library `align_to` method works fine in both modes; under + symbolic alignment it only fills the middle slice when the allocation guarantees sufficient + alignment.) The remaining flags are for advanced use only, and more likely to change or be removed. Some of these are **unsound**, which means they can lead @@ -321,7 +336,7 @@ to Miri failing to detect cases of undefined behavior in a program. integers via `mem::transmute` or union/pointer type punning. This has two effects: it disables the check against integers storing a pointer (i.e., data with provenance), thus allowing pointer-to-integer transmutation, and it treats integer-to-pointer transmutation as equivalent to - a cast. Using this flag is **unsound** and + a cast. Implies `-Zmiri-permissive-provenance`. Using this flag is **unsound** and [deprecated](https://github.com/rust-lang/miri/issues/2188). * `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag is **unsound**. @@ -354,27 +369,6 @@ 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-permissive-provenance` is **experimental**. This will make Miri do a - best-effort attempt to implement the semantics of - [`expose_addr`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.expose_addr) - and - [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html) - for pointer-to-int and int-to-pointer casts, respectively. This will - necessarily miss some bugs as those semantics are not efficiently - implementable in a sanitizer, but it will only miss bugs that concerns - memory/pointers which is subject to these operations. -* `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By - default, alignment is checked by casting the pointer to an integer, and making - sure that is a multiple of the alignment. This can lead to cases where a - program passes the alignment check by pure chance, because things "happened to - be" sufficiently aligned -- there is no UB in this execution but there would - be UB in others. To avoid such cases, the symbolic alignment check only takes - into account the requested alignment of the relevant allocation, and the - offset into that allocation. This avoids missing such bugs, but it also - incurs some false positives when the code does manual integer arithmetic to - ensure alignment. (The standard library `align_to` method works fine in both - modes; under symbolic alignment it only fills the middle slice when the - allocation guarantees sufficient alignment.) * `-Zmiri-track-alloc-id=,,...` shows a backtrace when the given allocations are being allocated or freed. This helps in debugging memory leaks and use after free bugs. Specifying this argument multiple times does not overwrite the previous @@ -389,13 +383,6 @@ to Miri failing to detect cases of undefined behavior in a program. happening and where in your code would be a good place to look for it. Specifying this argument multiple times does not overwrite the previous values, instead it appends its values to the list. Listing a tag multiple times has no effect. -* `-Zmiri-tag-raw-pointers` makes Stacked Borrows assign proper tags even for raw pointers. This can - make valid code using int-to-ptr casts fail to pass the checks, but also can help identify latent - aliasing issues in code that Miri accepts by default. You can recognize false positives by - `` occurring in the message -- this indicates a pointer that was cast from an integer, - so Miri was unable to track this pointer. Note that it is not currently guaranteed that code that - works with `-Zmiri-tag-raw-pointers` also works without `-Zmiri-tag-raw-pointers`, but for the - vast majority of code, this will be the case. [function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 91148400c9..1ccc54d6be 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -340,6 +340,7 @@ fn main() { Please let us know at if you rely on this flag." ); miri_config.allow_ptr_int_transmute = true; + miri_config.provenance_mode = ProvenanceMode::Permissive; } else if arg == "-Zmiri-disable-abi-check" { miri_config.check_abi = false; } else if arg == "-Zmiri-disable-isolation" { @@ -374,20 +375,18 @@ fn main() { } else if arg == "-Zmiri-panic-on-unsupported" { miri_config.panic_on_unsupported = true; } else if arg == "-Zmiri-tag-raw-pointers" { - miri_config.tag_raw = true; + eprintln!("WARNING: `-Zmiri-tag-raw-pointers` has no effect; it is enabled by default"); } else if arg == "-Zmiri-strict-provenance" { miri_config.provenance_mode = ProvenanceMode::Strict; - miri_config.tag_raw = true; + miri_config.allow_ptr_int_transmute = false; } else if arg == "-Zmiri-permissive-provenance" { miri_config.provenance_mode = ProvenanceMode::Permissive; - miri_config.tag_raw = true; } else if arg == "-Zmiri-mute-stdout-stderr" { miri_config.mute_stdout_stderr = true; } else if arg == "-Zmiri-track-raw-pointers" { eprintln!( - "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." + "WARNING: `-Zmiri-track-raw-pointers` has no effect; it is enabled by default" ); - miri_config.tag_raw = true; } else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") { if miri_config.seed.is_some() { panic!("Cannot specify -Zmiri-seed multiple times!"); @@ -410,7 +409,7 @@ fn main() { err ), }; - for id in ids.into_iter().map(miri::PtrId::new) { + for id in ids.into_iter().map(miri::SbTag::new) { if let Some(id) = id { miri_config.tracked_pointer_tags.insert(id); } else { diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 6986d9c572..83949a75de 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -69,6 +69,9 @@ pub enum NonHaltingDiagnostic { FreedAlloc(AllocId), RejectedIsolatedOp(String), ProgressReport, + Int2Ptr { + details: bool, + }, } /// Level of Miri specific diagnostics @@ -177,24 +180,6 @@ pub fn report_error<'tcx, 'mir>( helps.push((Some(*protection_span), "this protector is live for this call".to_string())); } } - Some(TagHistory::Untagged{ recently_created, recently_invalidated, matching_created, protected }) => { - if let Some((range, span)) = recently_created { - let msg = format!("tag was most recently created at offsets {}", HexRange(*range)); - helps.push((Some(*span), msg)); - } - if let Some((range, span)) = recently_invalidated { - let msg = format!("tag was later invalidated at offsets {}", HexRange(*range)); - helps.push((Some(*span), msg)); - } - if let Some((range, span)) = matching_created { - let msg = format!("this tag was also created here at offsets {}", HexRange(*range)); - helps.push((Some(*span), msg)); - } - if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { - helps.push((Some(*protecting_tag_span), format!("{:?} was protected due to a tag which was created here", protecting_tag))); - helps.push((Some(*protection_span), "this protector is live for this call".to_string())); - } - } None => {} } helps @@ -468,15 +453,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("{op} was made to return an error due to isolation"), ProgressReport => format!("progress report: current operation being executed is here"), + Int2Ptr { .. } => format!("integer-to-pointer cast"), }; let (title, diag_level) = match e { RejectedIsolatedOp(_) => ("operation rejected by isolation", DiagLevel::Warning), - _ => ("tracking was triggered", DiagLevel::Note), + Int2Ptr { .. } => ("integer-to-pointer cast", DiagLevel::Warning), + CreatedPointerTag(..) + | PoppedPointerTag(..) + | CreatedCallId(..) + | CreatedAlloc(..) + | FreedAlloc(..) + | ProgressReport => ("tracking was triggered", DiagLevel::Note), + }; + + let helps = match e { + Int2Ptr { details: true } => + vec![ + (None, format!("this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`,")), + (None, format!("which means that Miri might miss pointer bugs in this program")), + (None, format!("see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation")), + (None, format!("to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead")), + (None, format!("you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics")), + (None, format!("alternatively, the `-Zmiri-permissive-provenance` flag disables this warning")), + ], + _ => vec![], }; - report_msg(this, diag_level, title, vec![msg], vec![], &stacktrace); + report_msg(this, diag_level, title, vec![msg], helps, &stacktrace); } }); } diff --git a/src/eval.rs b/src/eval.rs index 7beb2ec9c4..12f1f52c78 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -96,13 +96,11 @@ pub struct MiriConfig { /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, /// The stacked borrows pointer ids to report about - pub tracked_pointer_tags: HashSet, + pub tracked_pointer_tags: HashSet, /// The stacked borrows call IDs to report about pub tracked_call_ids: HashSet, /// The allocation ids to report about. pub tracked_alloc_ids: HashSet, - /// Whether to track raw pointers in stacked borrows. - pub tag_raw: bool, /// Determine if data race detection should be enabled pub data_race_detector: bool, /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled @@ -146,14 +144,13 @@ impl Default for MiriConfig { tracked_pointer_tags: HashSet::default(), tracked_call_ids: HashSet::default(), tracked_alloc_ids: HashSet::default(), - tag_raw: false, data_race_detector: true, weak_memory_emulation: true, cmpxchg_weak_failure_rate: 0.8, // 80% measureme_out: None, panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, - provenance_mode: ProvenanceMode::Legacy, + provenance_mode: ProvenanceMode::Default, mute_stdout_stderr: false, preemption_rate: 0.01, // 1% report_progress: None, diff --git a/src/intptrcast.rs b/src/intptrcast.rs index cfaf61f9d5..a95b20868d 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -5,22 +5,20 @@ use log::trace; use rand::Rng; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_span::Span; use rustc_target::abi::{HasDataLayout, Size}; use crate::*; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ProvenanceMode { - /// Int2ptr casts return pointers with "wildcard" provenance - /// that basically matches that of all exposed pointers - /// (and SB tags, if enabled). + /// We support `expose_addr`/`from_exposed_addr` via "wildcard" provenance. + /// However, we want on `from_exposed_addr` to alert the user of the precision loss. + Default, + /// Like `Default`, but without the warning. Permissive, - /// Int2ptr casts return pointers with an invalid provenance, - /// i.e., not valid for any memory access. + /// We error on `from_exposed_addr`, ensuring no precision loss. Strict, - /// Int2ptr casts determine the allocation they point to at cast time. - /// All allocations are considered exposed. - Legacy, } pub type GlobalState = RefCell; @@ -66,6 +64,8 @@ impl<'mir, 'tcx> GlobalStateInner { let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); + // Determine the in-bounds provenance for this pointer. + // (This is only called on an actual access, so in-bounds is the only possible kind of provenance.) let alloc_id = match pos { Ok(pos) => Some(global_state.int_to_ptr_map[pos].1), Err(0) => None, @@ -91,21 +91,22 @@ impl<'mir, 'tcx> GlobalStateInner { } }?; - // In legacy mode, we consider all allocations exposed. - if global_state.provenance_mode == ProvenanceMode::Legacy - || global_state.exposed.contains(&alloc_id) - { - Some(alloc_id) - } else { - None + // We only use this provenance if it has been exposed, *and* is still live. + if global_state.exposed.contains(&alloc_id) { + // FIXME: this catches `InterpError`, which we should not usually do. + // We might need a proper fallible API from `memory.rs` to avoid this though. + if ecx.get_alloc_size_and_align(alloc_id, AllocCheck::Live).is_ok() { + return Some(alloc_id); + } } + + None } pub fn expose_ptr(ecx: &mut MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId, sb: SbTag) { let global_state = ecx.machine.intptrcast.get_mut(); - // In legacy and strict mode, we don't need this, so we can save some cycles - // by not tracking it. - if global_state.provenance_mode == ProvenanceMode::Permissive { + // In strict mode, we don't need this, so we can save some cycles by not tracking it. + if global_state.provenance_mode != ProvenanceMode::Strict { trace!("Exposing allocation id {alloc_id:?}"); global_state.exposed.insert(alloc_id); if ecx.machine.stacked_borrows.is_some() { @@ -120,42 +121,49 @@ impl<'mir, 'tcx> GlobalStateInner { ) -> Pointer> { trace!("Transmuting 0x{:x} to a pointer", addr); - if ecx.machine.allow_ptr_int_transmute { - // When we allow transmutes, treat them like casts. - Self::ptr_from_addr_cast(ecx, addr) + let provenance = if ecx.machine.allow_ptr_int_transmute { + // When we allow transmutes, treat them like casts: generating a wildcard pointer. + Some(Tag::Wildcard) } else { - // We consider transmuted pointers to be "invalid" (`None` provenance). - Pointer::new(None, Size::from_bytes(addr)) - } + // Usually, we consider transmuted pointers to be "invalid" (`None` provenance). + None + }; + Pointer::new(provenance, Size::from_bytes(addr)) } pub fn ptr_from_addr_cast( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> Pointer> { + ) -> InterpResult<'tcx, Pointer>> { trace!("Casting 0x{:x} to a pointer", addr); let global_state = ecx.machine.intptrcast.borrow(); match global_state.provenance_mode { - ProvenanceMode::Legacy => { - // Determine the allocation this points to at cast time. - let alloc_id = Self::alloc_id_from_addr(ecx, addr); - Pointer::new( - alloc_id.map(|alloc_id| Tag::Concrete { alloc_id, sb: SbTag::Untagged }), - Size::from_bytes(addr), - ) + ProvenanceMode::Default => { + // The first time this happens at a particular location, print a warning. + thread_local! { + // `Span` is non-`Send`, so we use a thread-local instead. + static PAST_WARNINGS: RefCell> = RefCell::default(); + } + PAST_WARNINGS.with_borrow_mut(|past_warnings| { + let first = past_warnings.is_empty(); + if past_warnings.insert(ecx.cur_span()) { + // Newly inserted, so first time we see this span. + register_diagnostic(NonHaltingDiagnostic::Int2Ptr { details: first }); + } + }); } ProvenanceMode::Strict => { - // We don't support int2ptr casts in this mode (i.e., we treat them like - // transmutes). - Pointer::new(None, Size::from_bytes(addr)) - } - ProvenanceMode::Permissive => { - // This is how wildcard pointers are born. - Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr)) + throw_unsup_format!( + "integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead" + ) } + ProvenanceMode::Permissive => {} } + + // This is how wildcard pointers are born. + Ok(Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr))) } fn alloc_base_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) -> u64 { @@ -214,6 +222,8 @@ impl<'mir, 'tcx> GlobalStateInner { dl.overflowing_offset(base_addr, offset.bytes()).0 } + /// When a pointer is used for a memory access, this computes where in which allocation the + /// access is going. pub fn abs_ptr_to_rel( ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, @@ -224,7 +234,6 @@ impl<'mir, 'tcx> GlobalStateInner { alloc_id } else { // A wildcard pointer. - assert_eq!(ecx.machine.intptrcast.borrow().provenance_mode, ProvenanceMode::Permissive); GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())? }; diff --git a/src/lib.rs b/src/lib.rs index 68489c9b47..e199fae31e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ #![feature(yeet_expr)] #![feature(is_some_with)] #![feature(nonzero_ops)] +#![feature(local_key_cell_methods)] #![warn(rust_2018_idioms)] #![allow( clippy::collapsible_else_if, @@ -89,8 +90,8 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, SbTag, SbTagExtra, - Stack, Stacks, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, Stack, + Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/machine.rs b/src/machine.rs index 3621744e80..5b18475458 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -140,8 +140,9 @@ pub enum Tag { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Pointer, 24); +// FIXME: this would with in 24bytes but layout optimizations are not smart enough // #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -// static_assert_size!(Pointer>, 24); +//static_assert_size!(Pointer>, 24); #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ScalarMaybeUninit, 32); @@ -353,7 +354,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { Some(RefCell::new(stacked_borrows::GlobalStateInner::new( config.tracked_pointer_tags.clone(), config.tracked_call_ids.clone(), - config.tag_raw, ))) } else { None @@ -681,9 +681,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr); let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { - stacked_borrows.borrow_mut().base_tag(ptr.provenance) + stacked_borrows.borrow_mut().base_ptr_tag(ptr.provenance) } else { - SbTag::Untagged + // Value does not matter, SB is disabled + SbTag::default() }; Pointer::new( Tag::Concrete { alloc_id: ptr.provenance, sb: sb_tag }, @@ -696,7 +697,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> InterpResult<'tcx, Pointer>> { - Ok(intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr)) + intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr) } #[inline(always)] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6fa70ddfc5..ea1132d3e1 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -23,42 +23,29 @@ use crate::*; pub mod diagnostics; use diagnostics::{AllocHistory, TagHistory}; -pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; + // Even reading memory can have effects on the stack, so we need a `RefCell` here. pub type AllocExtra = RefCell; /// Tracking pointer provenance -#[derive(Copy, Clone, Hash, Eq)] -pub enum SbTag { - Tagged(PtrId), - Untagged, -} +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +pub struct SbTag(NonZeroU64); impl SbTag { - fn as_u64(self) -> u64 { - match self { - SbTag::Tagged(id) => id.get(), - SbTag::Untagged => 0, - } + pub fn new(i: u64) -> Option { + NonZeroU64::new(i).map(SbTag) } -} -impl PartialEq for SbTag { - fn eq(&self, other: &Self) -> bool { - // The codegen for the derived Partialeq is bad here and includes a branch. - // Since this code is extremely hot, this is optimized here. - // https://github.com/rust-lang/rust/issues/49892 - self.as_u64() == other.as_u64() + // The default to be used when SB is disabled + pub fn default() -> Self { + Self::new(1).unwrap() } } impl fmt::Debug for SbTag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SbTag::Tagged(id) => write!(f, "<{}>", id), - SbTag::Untagged => write!(f, ""), - } + write!(f, "<{}>", self.0) } } @@ -73,7 +60,7 @@ pub enum SbTagExtra { impl fmt::Debug for SbTagExtra { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - SbTagExtra::Concrete(tag) => write!(f, "{tag:?}"), + SbTagExtra::Concrete(pid) => write!(f, "{pid:?}"), SbTagExtra::Wildcard => write!(f, ""), } } @@ -82,7 +69,7 @@ impl fmt::Debug for SbTagExtra { impl SbTagExtra { fn and_then(self, f: impl FnOnce(SbTag) -> Option) -> Option { match self { - SbTagExtra::Concrete(tag) => f(tag), + SbTagExtra::Concrete(pid) => f(pid), SbTagExtra::Wildcard => None, } } @@ -130,15 +117,15 @@ pub struct Stack { /// Used *mostly* as a stack; never empty. /// Invariants: /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. - /// * Except for `Untagged`, no tag occurs in the stack more than once. + /// * No tag occurs in the stack more than once. borrows: Vec, /// If this is `Some(id)`, then the actual current stack is unknown. This can happen when /// wildcard pointers are used to access this location. What we do know is that `borrows` are at - /// the top of the stack, and below it are arbitrarily many items whose `tag` is either - /// `Untagged` or strictly less than `id`. + /// the top of the stack, and below it are arbitrarily many items whose `tag` is strictly less + /// than `id`. /// When the bottom is unknown, `borrows` always has a `SharedReadOnly` or `Unique` at the bottom; /// we never have the unknown-to-known boundary in an SRW group. - unknown_bottom: Option, + unknown_bottom: Option, } /// Extra per-allocation state. @@ -156,21 +143,19 @@ pub struct Stacks { #[derive(Debug)] pub struct GlobalStateInner { /// Next unused pointer ID (tag). - next_ptr_id: PtrId, + next_ptr_tag: SbTag, /// Table storing the "base" tag for each allocation. /// The base tag is the one used for the initial pointer. /// We need this in a separate table to handle cyclic statics. - base_ptr_ids: FxHashMap, + base_ptr_tags: FxHashMap, /// Next unused call ID (for protectors). next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. active_calls: FxHashSet, /// The pointer ids to trace - tracked_pointer_tags: HashSet, + tracked_pointer_tags: HashSet, /// The call ids to trace tracked_call_ids: HashSet, - /// Whether to track raw pointers. - tag_raw: bool, } /// We need interior mutable access to the global state. @@ -219,28 +204,23 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalStateInner { - pub fn new( - tracked_pointer_tags: HashSet, - tracked_call_ids: HashSet, - tag_raw: bool, - ) -> Self { + pub fn new(tracked_pointer_tags: HashSet, tracked_call_ids: HashSet) -> Self { GlobalStateInner { - next_ptr_id: NonZeroU64::new(1).unwrap(), - base_ptr_ids: FxHashMap::default(), + next_ptr_tag: SbTag(NonZeroU64::new(1).unwrap()), + base_ptr_tags: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: FxHashSet::default(), tracked_pointer_tags, tracked_call_ids, - tag_raw, } } - fn new_ptr(&mut self) -> PtrId { - let id = self.next_ptr_id; + fn new_ptr(&mut self) -> SbTag { + let id = self.next_ptr_tag; if self.tracked_pointer_tags.contains(&id) { - register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id)); + register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id.0)); } - self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); + self.next_ptr_tag = SbTag(NonZeroU64::new(id.0.get() + 1).unwrap()); id } @@ -263,22 +243,14 @@ impl GlobalStateInner { self.active_calls.contains(&id) } - pub fn base_tag(&mut self, id: AllocId) -> SbTag { - self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { - let tag = SbTag::Tagged(self.new_ptr()); + pub fn base_ptr_tag(&mut self, id: AllocId) -> SbTag { + self.base_ptr_tags.get(&id).copied().unwrap_or_else(|| { + let tag = self.new_ptr(); trace!("New allocation {:?} has base tag {:?}", id, tag); - self.base_ptr_ids.try_insert(id, tag).unwrap(); + self.base_ptr_tags.try_insert(id, tag).unwrap(); tag }) } - - pub fn base_tag_untagged(&mut self, id: AllocId) -> SbTag { - trace!("New allocation {:?} has no base tag (untagged)", id); - let tag = SbTag::Untagged; - // This must only be done on new allocations. - self.base_ptr_ids.try_insert(id, tag).unwrap(); - tag - } } /// Error reporting @@ -368,10 +340,7 @@ impl<'tcx> Stack { // Couldn't find it in the stack; but if there is an unknown bottom it might be there. let found = self.unknown_bottom.is_some_and(|&unknown_limit| { - match tag { - SbTag::Tagged(tag_id) => tag_id < unknown_limit, // unknown_limit is an upper bound for what can be in the unknown bottom. - SbTag::Untagged => true, // yeah whatever - } + tag.0 < unknown_limit.0 // unknown_limit is an upper bound for what can be in the unknown bottom. }); if found { Ok(None) } else { Err(()) } } @@ -412,37 +381,29 @@ impl<'tcx> Stack { /// Within `provoking_access, the `AllocRange` refers the entire operation, and /// the `Size` refers to the specific location in the `AllocRange` that we are /// currently checking. - fn check_protector( + fn item_popped( item: &Item, provoking_access: Option<(SbTagExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { - if let SbTag::Tagged(id) = item.tag { - if global.tracked_pointer_tags.contains(&id) { - register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( - *item, - provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), - )); - } + if global.tracked_pointer_tags.contains(&item.tag) { + register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( + *item, + provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), + )); } + if let Some(call) = item.protector { if global.is_active(call) { - if let Some((tag, alloc_range, offset, _access)) = provoking_access { + if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { Err(err_sb_ub( format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item ), None, - tag.and_then(|tag| { - alloc_history.get_logs_relevant_to( - tag, - alloc_range, - offset, - Some(item.tag), - ) - }), + tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, Some(item.tag))), ))? } else { Err(err_sb_ub( @@ -495,7 +456,7 @@ impl<'tcx> Stack { }; for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector( + Stack::item_popped( &item, Some((tag, alloc_range, offset, access)), global, @@ -524,7 +485,7 @@ impl<'tcx> Stack { if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); - Stack::check_protector( + Stack::item_popped( item, Some((tag, alloc_range, offset, access)), global, @@ -544,21 +505,19 @@ impl<'tcx> Stack { for item in &self.borrows { // Skip disabled items, they cannot be matched anyway. if !matches!(item.perm, Permission::Disabled) { - if let SbTag::Tagged(tag) = item.tag { - // We are looking for a strict upper bound, so add 1 to this tag. - max = cmp::max(tag.checked_add(1).unwrap(), max); - } + // We are looking for a strict upper bound, so add 1 to this tag. + max = cmp::max(item.tag.0.checked_add(1).unwrap(), max); } } if let Some(unk) = self.unknown_bottom { - max = cmp::max(unk, max); + max = cmp::max(unk.0, max); } // Use `max` as new strict upper bound for everything. trace!( "access: forgetting stack to upper bound {max} due to wildcard or unknown access" ); self.borrows.clear(); - self.unknown_bottom = Some(max); + self.unknown_bottom = Some(SbTag(max)); } // Done. @@ -570,7 +529,7 @@ impl<'tcx> Stack { fn dealloc( &mut self, tag: SbTagExtra, - (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages + (alloc_id, _alloc_range, _offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, exposed_tags: &FxHashSet, @@ -582,13 +541,13 @@ impl<'tcx> Stack { tag, alloc_id, ), None, - tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, alloc_range, offset, None)), + tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, None)), ) })?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { - Stack::check_protector(&item, None, global, alloc_history)?; + Stack::item_popped(&item, None, global, alloc_history)?; } Ok(()) } @@ -636,7 +595,7 @@ impl<'tcx> Stack { // (for all we know, it might join an SRW group inside the unknown). trace!("reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown"); self.borrows.clear(); - self.unknown_bottom = Some(global.next_ptr_id); + self.unknown_bottom = Some(global.next_ptr_tag); return Ok(()); }; @@ -730,30 +689,9 @@ impl Stacks { // not through a pointer). That is, whenever we directly write to a local, this will pop // everything else off the stack, invalidating all previous pointers, // and in particular, *all* raw pointers. - MemoryKind::Stack => (extra.base_tag(id), Permission::Unique), - // `Global` memory can be referenced by global pointers from `tcx`. - // Thus we call `global_base_ptr` such that the global pointers get the same tag - // as what we use here. - // `ExternStatic` is used for extern statics, so the same reasoning applies. - // The others are various forms of machine-managed special global memory, and we can get - // away with precise tracking there. - // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::CallerLocation - | MemoryKind::Machine( - MiriMemoryKind::Global - | MiriMemoryKind::ExternStatic - | MiriMemoryKind::Tls - | MiriMemoryKind::Runtime - | MiriMemoryKind::Machine, - ) => (extra.base_tag(id), Permission::SharedReadWrite), - // Heap allocations we only track precisely when raw pointers are tagged, for now. - MemoryKind::Machine( - MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, - ) => { - let tag = - if extra.tag_raw { extra.base_tag(id) } else { extra.base_tag_untagged(id) }; - (tag, Permission::SharedReadWrite) - } + MemoryKind::Stack => (extra.base_ptr_tag(id), Permission::Unique), + // 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( @@ -1043,15 +981,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Compute new borrow. - let new_tag = { - let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); - match kind { - // Give up tracking for raw pointers. - RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, - // All other pointers are properly tracked. - _ => SbTag::Tagged(mem_extra.new_ptr()), - } - }; + 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)?; diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index a4a7f5e7a1..b1ff864bcd 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -32,7 +32,6 @@ struct Protection { #[derive(Clone, Debug)] struct Event { - time: usize, parent: Option, tag: SbTag, range: AllocRange, @@ -46,12 +45,6 @@ pub enum TagHistory { invalidated: Option<(AllocRange, SpanData)>, protected: Option<(SbTag, SpanData, SpanData)>, }, - Untagged { - recently_created: Option<(AllocRange, SpanData)>, - recently_invalidated: Option<(AllocRange, SpanData)>, - matching_created: Option<(AllocRange, SpanData)>, - protected: Option<(SbTag, SpanData, SpanData)>, - }, } impl AllocHistory { @@ -72,7 +65,7 @@ impl AllocHistory { current_span: &mut CurrentSpan<'_, '_, '_>, ) { let span = current_span.get(); - self.creations.push(Event { parent, tag, range, span, time: self.current_time }); + self.creations.push(Event { parent, tag, range, span }); self.current_time += 1; } @@ -83,7 +76,7 @@ impl AllocHistory { current_span: &mut CurrentSpan<'_, '_, '_>, ) { let span = current_span.get(); - self.invalidations.push(Event { parent: None, tag, range, span, time: self.current_time }); + self.invalidations.push(Event { parent: None, tag, range, span }); self.current_time += 1; } @@ -101,8 +94,6 @@ impl AllocHistory { pub fn get_logs_relevant_to( &self, tag: SbTag, - alloc_range: AllocRange, - offset: Size, protector_tag: Option, ) -> Option { let protected = protector_tag @@ -125,74 +116,17 @@ impl AllocHistory { }) }); - if let SbTag::Tagged(_) = tag { - 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, - }) - } else { - let mut created_time = 0; - // Find the most recently created tag that satsfies this offset - let recently_created = self.creations.iter().rev().find_map(|event| { - if event.tag == tag && offset >= event.range.start && offset < event.range.end() { - created_time = event.time; - Some((event.range, event.span.data())) - } else { - None - } - }); - - // Find a different recently created tag that satisfies this whole operation, predates - // the recently created tag, and has a different span. - // We're trying to make a guess at which span the user wanted to provide the tag that - // they're using. - let matching_created = recently_created.and_then(|(_created_range, created_span)| { - self.creations.iter().rev().find_map(|event| { - if event.tag == tag - && alloc_range.start >= event.range.start - && alloc_range.end() <= event.range.end() - && event.span.data() != created_span - && event.time != created_time - { - Some((event.range, event.span.data())) - } else { - None - } - }) - }); - - // Find the most recent invalidation of this tag which post-dates the creation - let recently_invalidated = recently_created.and_then(|_| { - self.invalidations - .iter() - .rev() - .take_while(|event| event.time > created_time) - .find_map(|event| { - if event.tag == tag - && offset >= event.range.start - && offset < event.range.end() - { - Some((event.range, event.span.data())) - } else { - None - } - }) - }); - - Some(TagHistory::Untagged { - recently_created, - matching_created, - recently_invalidated, - protected, + 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, + }) } /// Report a descriptive error when `new` could not be granted from `derived_from`. @@ -214,9 +148,7 @@ impl AllocHistory { 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, alloc_range, error_offset, None) - }), + derived_from.and_then(|derived_from| self.get_logs_relevant_to(derived_from, None)), ) } @@ -238,7 +170,7 @@ impl AllocHistory { 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, alloc_range, error_offset, None)), + tag.and_then(|tag| self.get_logs_relevant_to(tag, None)), ) } } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 1996563948..a16019a05e 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -114,20 +114,16 @@ def test_cargo_miri_test(): default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref" filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref" + # macOS needs permissive provenance inside getrandom. test("`cargo miri test`", cargo_miri("test"), default_ref, "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-seed=feed"}, + env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-seed=feed"}, ) test("`cargo miri test` (no isolation, no doctests)", cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml` "test.cross-target.stdout.ref", "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, - ) - test("`cargo miri test` (raw-ptr tracking)", - cargo_miri("test"), - default_ref, "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-tag-raw-pointers"}, + env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-disable-isolation"}, ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], @@ -136,6 +132,7 @@ def test_cargo_miri_test(): test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], "test.test-target.stdout.ref", "test.stderr-empty.ref", + env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, ) test("`cargo miri test` (bin target)", cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], @@ -153,11 +150,13 @@ def test_cargo_miri_test(): test("`cargo miri test` (custom target dir)", cargo_miri("test") + ["--target-dir=custom-test"], default_ref, "test.stderr-empty.ref", + env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, ) del os.environ["CARGO_TARGET_DIR"] # this overrides `build.target-dir` passed by `--config`, so unset it test("`cargo miri test` (config-cli)", cargo_miri("test") + ["--config=build.target-dir=\"config-cli\"", "-Zunstable-options"], default_ref, "test.stderr-empty.ref", + env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, ) os.chdir(os.path.dirname(os.path.realpath(__file__))) diff --git a/tests/fail/backtrace/bad-backtrace-flags.rs b/tests/fail/backtrace/bad-backtrace-flags.rs index 5f30513e93..9e24d32a33 100644 --- a/tests/fail/backtrace/bad-backtrace-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-flags.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_get_backtrace(2, 0 as *mut _); //~ ERROR unsupported operation: unknown `miri_get_backtrace` flags 2 + miri_get_backtrace(2, std::ptr::null_mut()); //~ ERROR unsupported operation: unknown `miri_get_backtrace` flags 2 } } diff --git a/tests/fail/backtrace/bad-backtrace-flags.stderr b/tests/fail/backtrace/bad-backtrace-flags.stderr index f6ffe3c93c..6d62ffc00e 100644 --- a/tests/fail/backtrace/bad-backtrace-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-flags.stderr @@ -1,8 +1,8 @@ error: unsupported operation: unknown `miri_get_backtrace` flags 2 --> $DIR/bad-backtrace-flags.rs:LL:CC | -LL | miri_get_backtrace(2, 0 as *mut _); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 +LL | miri_get_backtrace(2, std::ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support diff --git a/tests/fail/backtrace/bad-backtrace-ptr.rs b/tests/fail/backtrace/bad-backtrace-ptr.rs index c83bf1eb38..73d3561445 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(0 as *mut _, 0); //~ ERROR null pointer is not a valid pointer for this operation + miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR null pointer is not a valid pointer for this operation } } diff --git a/tests/fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/backtrace/bad-backtrace-ptr.stderr index ed726a5dcd..6911db9de0 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.stderr +++ b/tests/fail/backtrace/bad-backtrace-ptr.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: null pointer is not a valid pointer for this operation --> $DIR/bad-backtrace-ptr.rs:LL:CC | -LL | miri_resolve_frame(0 as *mut _, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation +LL | miri_resolve_frame(std::ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-flags.rs index 5a30253a89..2d4d619502 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-resolve-flags.rs @@ -15,7 +15,7 @@ extern "Rust" { fn main() { unsafe { - let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + let mut buf = vec![std::ptr::null_mut(); miri_backtrace_size(0)]; miri_get_backtrace(1, buf.as_mut_ptr()); diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs index 8e69a27575..6cea1fec1b 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs @@ -6,11 +6,11 @@ extern "Rust" { fn main() { unsafe { - let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + let mut buf = vec![std::ptr::null_mut(); miri_backtrace_size(0)]; miri_get_backtrace(1, buf.as_mut_ptr()); // miri_resolve_frame_names will error from an invalid backtrace before it will from invalid flags - miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); //~ ERROR unsupported operation: unknown `miri_resolve_frame_names` flags 2 + miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::null_mut()); //~ ERROR unsupported operation: unknown `miri_resolve_frame_names` flags 2 } } diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr index d575caa4ff..aa470cb9de 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -1,8 +1,8 @@ error: unsupported operation: unknown `miri_resolve_frame_names` flags 2 --> $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC | -LL | ... miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 +LL | ... miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index d5a4bf27f8..e6031b5e4c 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -7,9 +7,12 @@ #[thread_local] static mut TLS: u8 = 0; +struct SendRaw(*const u8); +unsafe impl Send for SendRaw {} + fn main() { unsafe { - let dangling_ptr = std::thread::spawn(|| &TLS as *const u8 as usize).join().unwrap(); - let _val = *(dangling_ptr as *const u8); //~ ERROR dereferenced after this allocation got freed + let dangling_ptr = std::thread::spawn(|| SendRaw(&TLS as *const u8)).join().unwrap(); + let _val = *dangling_ptr.0; //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index 2a3a8f0f55..d54c569de3 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/thread_local_static_dealloc.rs:LL:CC | -LL | let _val = *(dangling_ptr as *const u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed +LL | let _val = *dangling_ptr.0; + | ^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.rs b/tests/fail/dangling_pointers/deref-invalid-ptr.rs index 56830e97ca..cb2bbec8bc 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.rs @@ -1,5 +1,5 @@ // This should fail even without validation. -// compile-flags: -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation -Zmiri-permissive-provenance fn main() { let x = 16usize as *const u32; diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs index c87db4b022..370162142d 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -1,5 +1,5 @@ // This should fail even without validation, but some MIR opts mask the error -// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 +// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 -Zmiri-permissive-provenance static mut LEAK: usize = 0; @@ -10,7 +10,7 @@ fn fill(v: &mut i32) { } fn evil() { - unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dereferenced after this allocation got freed + unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR is not a valid pointer } fn main() { @@ -21,6 +21,6 @@ fn main() { _y = x; } // Now we use a pointer to `x` which is no longer in scope, and thus dead (even though the - // `main` stack frame still exists). + // `main` stack frame still exists). We even try going through a `usize` for extra sneakiness! evil(); } diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr index aed14105ad..d6030643bf 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed +error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer --> $DIR/storage_dead_dangling.rs:LL:CC | LL | unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | ^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.rs b/tests/fail/dangling_pointers/wild_pointer_deref.rs index eebaea48ba..7c9f5281fb 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/fail/dangling_pointers/wild_pointer_deref.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + fn main() { let p = 44 as *const i32; let x = unsafe { *p }; //~ ERROR is not a valid pointer diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs index 248d85d65e..ca38f39d25 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,4 +1,5 @@ // error-pattern: pointer arithmetic failed: null pointer is not a valid pointer +// compile-flags: -Zmiri-permissive-provenance fn main() { let x = 0 as *mut i32; diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs index e332a9dc62..809938d999 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,4 +1,5 @@ // error-pattern: is not a valid pointer +// compile-flags: -Zmiri-permissive-provenance fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs index 2d27e25a7a..903f89ff70 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,5 @@ // error-pattern: is not a valid pointer +// compile-flags: -Zmiri-permissive-provenance fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/fail/provenance/permissive_provenance_transmute.stderr b/tests/fail/provenance/permissive_provenance_transmute.stderr deleted file mode 100644 index 12f3562011..0000000000 --- a/tests/fail/provenance/permissive_provenance_transmute.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer - --> $DIR/permissive_provenance_transmute.rs:LL:CC - | -LL | let _val = *left_ptr; - | ^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `deref` at $DIR/permissive_provenance_transmute.rs:LL:CC -note: inside `main` at $DIR/permissive_provenance_transmute.rs:LL:CC - --> $DIR/permissive_provenance_transmute.rs:LL:CC - | -LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/provenance/permissive_provenance_transmute.rs b/tests/fail/provenance/provenance_transmute.rs similarity index 100% rename from tests/fail/provenance/permissive_provenance_transmute.rs rename to tests/fail/provenance/provenance_transmute.rs diff --git a/tests/fail/provenance/strict_provenance_transmute.stderr b/tests/fail/provenance/provenance_transmute.stderr similarity index 75% rename from tests/fail/provenance/strict_provenance_transmute.stderr rename to tests/fail/provenance/provenance_transmute.stderr index 8df94d50bb..9cbec077e4 100644 --- a/tests/fail/provenance/strict_provenance_transmute.stderr +++ b/tests/fail/provenance/provenance_transmute.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer - --> $DIR/strict_provenance_transmute.rs:LL:CC + --> $DIR/provenance_transmute.rs:LL:CC | LL | let _val = *left_ptr; | ^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer @@ -7,9 +7,9 @@ LL | let _val = *left_ptr; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `deref` at $DIR/strict_provenance_transmute.rs:LL:CC -note: inside `main` at $DIR/strict_provenance_transmute.rs:LL:CC - --> $DIR/strict_provenance_transmute.rs:LL:CC + = note: inside `deref` at $DIR/provenance_transmute.rs:LL:CC +note: inside `main` at $DIR/provenance_transmute.rs:LL:CC + --> $DIR/provenance_transmute.rs:LL:CC | LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/fail/provenance/ptr_legacy_provenance.rs b/tests/fail/provenance/ptr_legacy_provenance.rs deleted file mode 100644 index 538ec4484e..0000000000 --- a/tests/fail/provenance/ptr_legacy_provenance.rs +++ /dev/null @@ -1,22 +0,0 @@ -// compile-flags: -Zmiri-disable-stacked-borrows -// normalize-stderr-test: "offset -[0-9]+" -> "offset -XX" -#![feature(strict_provenance)] - -use std::ptr; - -// Make sure that with legacy provenance, the allocation id of -// a casted pointer is determined at cast-time -fn main() { - let x: i32 = 0; - let y: i32 = 1; - - let x_ptr = &x as *const i32; - let y_ptr = &y as *const i32; - - let x_usize = x_ptr.expose_addr(); - let y_usize = y_ptr.expose_addr(); - - let ptr = ptr::from_exposed_addr::(y_usize); - let ptr = ptr.with_addr(x_usize); - assert_eq!(unsafe { *ptr }, 0); //~ ERROR is out-of-bounds -} diff --git a/tests/fail/provenance/ptr_legacy_provenance.stderr b/tests/fail/provenance/ptr_legacy_provenance.stderr deleted file mode 100644 index 4552be0814..0000000000 --- a/tests/fail/provenance/ptr_legacy_provenance.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 4, so pointer to 4 bytes starting at offset -XX is out-of-bounds - --> $DIR/ptr_legacy_provenance.rs:LL:CC - | -LL | assert_eq!(unsafe { *ptr }, 0); - | ^^^^ dereferencing pointer failed: ALLOC has size 4, so pointer to 4 bytes starting at offset -XX is out-of-bounds - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/ptr_legacy_provenance.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/provenance/strict_provenance_cast.rs b/tests/fail/provenance/strict_provenance_cast.rs new file mode 100644 index 0000000000..8b2b053bdb --- /dev/null +++ b/tests/fail/provenance/strict_provenance_cast.rs @@ -0,0 +1,6 @@ +// compile-flags: -Zmiri-strict-provenance + +fn main() { + let addr = &0 as *const i32 as usize; + let _ptr = addr as *const i32; //~ ERROR integer-to-pointer casts and `from_exposed_addr` are not supported +} diff --git a/tests/fail/provenance/strict_provenance_cast.stderr b/tests/fail/provenance/strict_provenance_cast.stderr new file mode 100644 index 0000000000..32a39b81d9 --- /dev/null +++ b/tests/fail/provenance/strict_provenance_cast.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead + --> $DIR/strict_provenance_cast.rs:LL:CC + | +LL | let _ptr = addr as *const i32; + | ^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/strict_provenance_cast.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/provenance/strict_provenance_transmute.rs b/tests/fail/provenance/strict_provenance_transmute.rs deleted file mode 100644 index 12a141e9dd..0000000000 --- a/tests/fail/provenance/strict_provenance_transmute.rs +++ /dev/null @@ -1,27 +0,0 @@ -// compile-flags: -Zmiri-strict-provenance -#![feature(strict_provenance)] - -use std::mem; - -// This is the example from -// . - -unsafe fn deref(left: *const u8, right: *const u8) { - let left_int: usize = mem::transmute(left); - let right_int: usize = mem::transmute(right); - if left_int == right_int { - // The compiler is allowed to replace `left_int` by `right_int` here... - let left_ptr: *const u8 = mem::transmute(left_int); - // ...which however means here it could be dereferencing the wrong pointer. - let _val = *left_ptr; //~ERROR dereferencing pointer failed - } -} - -fn main() { - let ptr1 = &0u8 as *const u8; - let ptr2 = &1u8 as *const u8; - unsafe { - // Two pointers with the same address but different provenance. - deref(ptr1, ptr2.with_addr(ptr1.addr())); - } -} diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index a4187be0a2..66220cfbfc 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow 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 for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow 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] | = 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 most recently created at offsets [0x0..0x4] +help: was created by a 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: was later invalidated at offsets [0x0..0x4] --> $DIR/aliasing_mut3.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &i32) {} diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.rs b/tests/fail/stacked_borrows/box_exclusive_violation1.rs index 3ca480ae7a..66d092d627 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.rs @@ -8,7 +8,7 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { unknown_code_2(); // We know this will return 5 - *our //~ ERROR borrow stack + *our } // Now comes the evil context @@ -24,7 +24,7 @@ fn unknown_code_1(x: &i32) { fn unknown_code_2() { unsafe { - *LEAK = 7; + *LEAK = 7; //~ ERROR borrow stack } } diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 3c3e6bbf1b..06c2dc340b 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -1,31 +1,30 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | *our - | ^^^^ - | | - | attempting a read access using 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] +LL | *LEAK = 7; + | ^^^^^^^^^ + | | + | attempting a write access using 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: was created by a retag at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | / fn demo_mut_advanced_unique(mut our: Box) -> i32 { -LL | | unknown_code_1(&*our); -LL | | -LL | | // This "re-asserts" uniqueness of the reference: After writing, we know -... | -LL | | *our -LL | | } - | |_^ +LL | LEAK = x as *const _ as *mut _; + | ^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | *LEAK = 7; - | ^^^^^^^^^ - = note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC +LL | *our = 5; + | ^^^^^^^^ + = note: inside `unknown_code_2` at $DIR/box_exclusive_violation1.rs:LL:CC +note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC + --> $DIR/box_exclusive_violation1.rs:LL:CC + | +LL | unknown_code_2(); + | ^^^^^^^^^^^^^^^^ note: inside `main` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC | diff --git a/tests/fail/stacked_borrows/illegal_read3.rs b/tests/fail/stacked_borrows/illegal_read3.rs index 3de8f57d62..0173ca14b2 100644 --- a/tests/fail/stacked_borrows/illegal_read3.rs +++ b/tests/fail/stacked_borrows/illegal_read3.rs @@ -5,7 +5,7 @@ use std::mem; union HiddenRef { - // We avoid retagging at this type, so shared vs mutable does not matter. + // We avoid retagging at this type, and we only read, so shared vs mutable does not matter. r: &'static i32, } diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index 9782f1aa3a..2098dbdc6a 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read6.rs:LL:CC | LL | let _val = *raw; | ^^^^ | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a read access using 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 most recently created at offsets [0x0..0x4] +help: was created by a 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: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC | LL | let x = &mut *x; // kill `raw` diff --git a/tests/fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs index 1f566f18c1..58600402e4 100644 --- a/tests/fail/stacked_borrows/illegal_write1.rs +++ b/tests/fail/stacked_borrows/illegal_write1.rs @@ -3,7 +3,7 @@ fn main() { let xref = &*target; { let x: *mut u32 = xref as *const _ as *mut _; - unsafe { *x = 42 }; // invalidates shared ref, activates raw + unsafe { *x = 42 }; //~ ERROR only grants SharedReadOnly permission } - let _x = *xref; //~ ERROR borrow stack + let _x = *xref; } diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index 1731e3c1de..b2084da862 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -1,24 +1,19 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/illegal_write1.rs:LL:CC | -LL | let _x = *xref; - | ^^^^^ - | | - | attempting a read access using 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] +LL | unsafe { *x = 42 }; + | ^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission 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: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write1.rs:LL:CC | -LL | let xref = &*target; - | ^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] - --> $DIR/illegal_write1.rs:LL:CC - | -LL | unsafe { *x = 42 }; // invalidates shared ref, activates raw - | ^^^^^^^ +LL | let x: *mut u32 = xref as *const _ as *mut _; + | ^^^^ = note: inside `main` at $DIR/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index 7e896c530a..09784bd79a 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_write2.rs:LL:CC | LL | unsafe { *target2 = 13 }; | ^^^^^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a write access using 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 most recently created at offsets [0x0..0x4] +help: was created by a 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: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_write2.rs:LL:CC | LL | drop(&mut *target); // reborrow diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index 7e9c82769d..983894dad0 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -1,15 +1,15 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/illegal_write3.rs:LL:CC | LL | unsafe { *ptr = 42 }; | ^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission 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 most recently created at offsets [0x0..0x4] +help: was created by a 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 diff --git a/tests/fail/stacked_borrows/illegal_write4.rs b/tests/fail/stacked_borrows/illegal_write4.rs index be4f89ba28..654a23d382 100644 --- a/tests/fail/stacked_borrows/illegal_write4.rs +++ b/tests/fail/stacked_borrows/illegal_write4.rs @@ -6,8 +6,8 @@ fn main() { // Even just creating it unfreezes. let raw = &mut target as *mut _; // let this leak to raw let reference = unsafe { &*raw }; // freeze - let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag - let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag + let _ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag + let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. let _val = *reference; //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr index 404e13d113..ac4dd68bbc 100644 --- a/tests/fail/stacked_borrows/illegal_write4.stderr +++ b/tests/fail/stacked_borrows/illegal_write4.stderr @@ -17,7 +17,7 @@ LL | let reference = unsafe { &*raw }; // freeze help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_write4.rs:LL:CC | -LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag +LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag | ^^^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/illegal_write4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 11757cca9b..563397e062 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,17 +1,17 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] --> $DIR/illegal_write6.rs:LL:CC | LL | unsafe { *y = 2 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (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 most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write6.rs:LL:CC | LL | let p = x as *mut u32; | ^ -help: was protected due to a tag which was created here +help: was protected due to which was created here --> $DIR/illegal_write6.rs:LL:CC | LL | foo(x, p); diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 08d597ea18..826cdc9b5f 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -1,17 +1,17 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^ not granting access to tag because incompatible item is protected: [Unique for (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 most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | let xraw = &mut x as *mut _; | ^^^^^^ -help: was protected due to a tag which was created here +help: was protected due to which was created here --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | inner(xraw, xref); diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index 6aefa216ed..1cf90f91db 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -1,17 +1,17 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | unsafe { *x = 0 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (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 most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | let xraw = &mut x as *mut _; | ^^^^^^ -help: was protected due to a tag which was created here +help: was protected due to which was created here --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | inner(xraw, xref); diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index ea14536a39..8afb4fee18 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/mut_exclusive_violation1.rs:LL:CC | LL | *LEAK = 7; | ^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a write access using 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 most recently created at offsets [0x0..0x4] +help: was created by a 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: was later invalidated at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC | LL | *our = 5; diff --git a/tests/fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr index fe3bdd00f4..c218d500cf 100644 --- a/tests/fail/stacked_borrows/outdated_local.stderr +++ b/tests/fail/stacked_borrows/outdated_local.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/outdated_local.rs:LL:CC | LL | assert_eq!(unsafe { *y }, 1); | ^^ | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a read access using 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 most recently created at offsets [0x0..0x4] +help: was created by a 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: was later invalidated at offsets [0x0..0x4] --> $DIR/outdated_local.rs:LL:CC | LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local diff --git a/tests/fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr index 68ac631ec0..a3ab1b9fc5 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/pointer_smuggling.rs:LL:CC | LL | let _x = unsafe { *PTR }; | ^^^^ | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a read access using 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..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 most recently created at offsets [0x0..0x1] +help: was created by a retag at offsets [0x0..0x1] --> $DIR/pointer_smuggling.rs:LL:CC | LL | PTR = x; | ^ -help: tag was later invalidated at offsets [0x0..0x1] +help: was later invalidated at offsets [0x0..0x1] --> $DIR/pointer_smuggling.rs:LL:CC | LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. diff --git a/tests/fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs index 0b9c058f06..49fe983125 100644 --- a/tests/fail/stacked_borrows/raw_tracking.rs +++ b/tests/fail/stacked_borrows/raw_tracking.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers //! This demonstrates a provenance problem that requires tracking of raw pointers to be detected. fn main() { diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index 0808d8471b..5587230071 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -1,15 +1,15 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/shr_frozen_violation1.rs:LL:CC | LL | *(x as *const i32 as *mut i32) = 7; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission 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 most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/shr_frozen_violation1.rs:LL:CC | LL | *(x as *const i32 as *mut i32) = 7; diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index a9682f806b..91c3ff9f86 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -1,15 +1,19 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/transmute-is-no-escape.rs:LL:CC | LL | unsafe { *raw = 13 }; | ^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a write access using 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: was created by a 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); + | ^^^^^^^^^ = note: inside `main` at $DIR/transmute-is-no-escape.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index bfc937bb12..c994f6c381 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + // Make sure we cannot use raw ptrs to access a local that // we took the direct address of. fn main() { diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index 616c60b8aa..464296651c 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -1,24 +1,15 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location --> $DIR/unescaped_local.rs:LL:CC | LL | *raw = 13; | ^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission 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 most recently created at offsets [0x0..0x4] - --> $DIR/unescaped_local.rs:LL:CC - | -LL | let raw = &mut x as *mut i32 as usize as *mut i32; - | ^^^^^^ -help: tag was later invalidated at offsets [0x0..0x4] - --> $DIR/unescaped_local.rs:LL:CC - | -LL | let _ptr = &mut x; - | ^^^^^^ + = note: inside `main` at $DIR/unescaped_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr index a0ac19f042..621e9617fd 100644 --- a/tests/fail/stacked_borrows/unescaped_static.stderr +++ b/tests/fail/stacked_borrows/unescaped_static.stderr @@ -1,15 +1,19 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location --> $DIR/unescaped_static.rs:LL:CC | LL | let _val = unsafe { *ptr_to_first.add(1) }; | ^^^^^^^^^^^^^^^^^^^^ | | - | attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location + | attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x1..0x2] | = 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: was created by a retag at offsets [0x0..0x1] + --> $DIR/unescaped_static.rs:LL:CC + | +LL | let ptr_to_first = &ARRAY[0] as *const u8; + | ^^^^^^^^^ = note: inside `main` at $DIR/unescaped_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index 0a326a453e..dea9335ab7 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-symbolic-alignment-check +// compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance // With the symbolic alignment check, even with intptrcast and without // validation, we want to be *sure* to catch bugs that arise from pointers being // insufficiently aligned. The only way to achieve that is not not let programs diff --git a/tests/fail/uninit_byte_read.rs b/tests/fail/uninit_byte_read.rs index 6868e58955..683088e78b 100644 --- a/tests/fail/uninit_byte_read.rs +++ b/tests/fail/uninit_byte_read.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-disable-stacked-borrows fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; //~ ERROR uninitialized diff --git a/tests/fail/validity/cast_fn_ptr1.rs b/tests/fail/validity/cast_fn_ptr1.rs index 020e7be34f..eb5774fe79 100644 --- a/tests/fail/validity/cast_fn_ptr1.rs +++ b/tests/fail/validity/cast_fn_ptr1.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + fn main() { // Cast a function pointer such that on a call, the argument gets transmuted // from raw ptr to reference. This is ABI-compatible, so it's not the call that diff --git a/tests/fail/validity/cast_fn_ptr2.rs b/tests/fail/validity/cast_fn_ptr2.rs index 10fc39f56f..1cf4ca7d19 100644 --- a/tests/fail/validity/cast_fn_ptr2.rs +++ b/tests/fail/validity/cast_fn_ptr2.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + fn main() { // Cast a function pointer such that when returning, the return value gets transmuted // from raw ptr to reference. This is ABI-compatible, so it's not the call that diff --git a/tests/pass/adjacent-allocs.rs b/tests/pass/adjacent-allocs.rs index 509965fe4f..b3483a5b43 100644 --- a/tests/pass/adjacent-allocs.rs +++ b/tests/pass/adjacent-allocs.rs @@ -1,7 +1,9 @@ -fn main() { +// compile-flags: -Zmiri-permissive-provenance + +fn test1() { // The slack between allocations is random. // Loop a few times to hit the zero-slack case. - for _ in 0..1024 { + for _ in 0..512 { let n = 0u64; let ptr: *const u64 = &n; @@ -20,3 +22,26 @@ fn main() { unsafe { *zst } } } + +fn test2() { + fn foo() -> u64 { + 0 + } + + for _ in 0..512 { + let n = 0u64; + let ptr: *const u64 = &n; + foo(); + let iptr = ptr as usize; + unsafe { + let start = &*std::ptr::slice_from_raw_parts(iptr as *const (), 1); + let end = &*std::ptr::slice_from_raw_parts((iptr + 8) as *const (), 1); + assert_eq!(start.len(), end.len()); + } + } +} + +fn main() { + test1(); + test2(); +} diff --git a/tests/pass/align.rs b/tests/pass/align.rs index 5794b7f542..f412541bde 100644 --- a/tests/pass/align.rs +++ b/tests/pass/align.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + /// This manually makes sure that we have a pointer with the proper alignment. fn manual_alignment() { let x = &mut [0u8; 3]; diff --git a/tests/pass/box.rs b/tests/pass/box.rs index c2ecc37071..7bbe7be516 100644 --- a/tests/pass/box.rs +++ b/tests/pass/box.rs @@ -47,7 +47,7 @@ fn boxed_pair_to_vec() { struct Foo(u64); fn reinterstruct(box_pair: Box) -> Vec { let ref_pair = Box::leak(box_pair) as *mut PairFoo; - let ptr_foo = unsafe { &mut (*ref_pair).fst as *mut Foo }; + let ptr_foo = unsafe { std::ptr::addr_of_mut!((*ref_pair).fst) }; unsafe { Vec::from_raw_parts(ptr_foo, 2, 2) } } diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr new file mode 100644 index 0000000000..d821fcd9d1 --- /dev/null +++ b/tests/pass/box.stderr @@ -0,0 +1,33 @@ +warning: integer-to-pointer cast + --> $DIR/box.rs:LL:CC + | +LL | let r2 = ((r as usize) + 0) as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `into_raw` at $DIR/box.rs:LL:CC +note: inside `main` at $DIR/box.rs:LL:CC + --> $DIR/box.rs:LL:CC + | +LL | into_raw(); + | ^^^^^^^^^^ + +warning: integer-to-pointer cast + --> $DIR/box.rs:LL:CC + | +LL | let r = ((u.as_ptr() as usize) + 0) as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = note: inside `into_unique` at $DIR/box.rs:LL:CC +note: inside `main` at $DIR/box.rs:LL:CC + --> $DIR/box.rs:LL:CC + | +LL | into_unique(); + | ^^^^^^^^^^^^^ + diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index 4d69449821..29c57bf49a 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -4,6 +4,7 @@ extern crate libc; use std::mem; +use std::ptr; pub type Key = libc::pthread_key_t; @@ -11,7 +12,7 @@ static mut RECORD: usize = 0; static mut KEYS: [Key; 2] = [0; 2]; static mut GLOBALS: [u64; 2] = [1, 0]; -static mut CANNARY: *mut u64 = 0 as *mut _; // this serves as a cannary: if TLS dtors are not run properly, this will not get deallocated, making the test fail. +static mut CANNARY: *mut u64 = ptr::null_mut(); // this serves as a cannary: if TLS dtors are not run properly, this will not get deallocated, making the test fail. pub unsafe fn create(dtor: Option) -> Key { let mut key = 0; @@ -30,7 +31,7 @@ pub fn record(r: usize) { } unsafe extern "C" fn dtor(ptr: *mut u64) { - assert!(CANNARY != 0 as *mut _); // make sure we do not get run too often + assert!(CANNARY != ptr::null_mut()); // make sure we do not get run too often let val = *ptr; let which_key = @@ -48,7 +49,7 @@ unsafe extern "C" fn dtor(ptr: *mut u64) { // The correct sequence is: First key 0, then key 1, then key 0. if RECORD == 0_1_0 { drop(Box::from_raw(CANNARY)); - CANNARY = 0 as *mut _; + CANNARY = ptr::null_mut(); } } diff --git a/tests/pass/extern_types.stderr b/tests/pass/extern_types.stderr new file mode 100644 index 0000000000..f23526b52b --- /dev/null +++ b/tests/pass/extern_types.stderr @@ -0,0 +1,15 @@ +warning: integer-to-pointer cast + --> $DIR/extern_types.rs:LL:CC + | +LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; + | ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/extern_types.rs:LL:CC + diff --git a/tests/pass/intptrcast.rs b/tests/pass/intptrcast.rs index aafa90204f..2417a83493 100644 --- a/tests/pass/intptrcast.rs +++ b/tests/pass/intptrcast.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + // This strips provenance fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } @@ -88,6 +90,16 @@ fn ptr_eq_integer() { assert!(x != 64 as *const i32); } +fn zst_deref_of_dangling() { + let b = Box::new(0); + let addr = &*b as *const _ as usize; + drop(b); + // Now if we cast `addr` to a ptr it might pick up the dangling provenance. + // But if we only do a ZST deref there is no UB here! + let zst = addr as *const (); + let _val = unsafe { *zst }; +} + fn main() { cast(); cast_dangling(); @@ -99,4 +111,5 @@ fn main() { ptr_eq_out_of_bounds(); ptr_eq_out_of_bounds_null(); ptr_eq_integer(); + zst_deref_of_dangling(); } diff --git a/tests/pass/intrinsics.rs b/tests/pass/intrinsics.rs index 9e310082f3..0042872a3b 100644 --- a/tests/pass/intrinsics.rs +++ b/tests/pass/intrinsics.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-permissive-provenance #![feature(core_intrinsics, const_raw_ptr_comparison)] #![feature(layout_for_ptr)] diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index ad1a1f27c7..56a5369947 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -3,13 +3,15 @@ #![feature(rustc_private)] extern crate libc; +use std::ptr; + fn main() { let mut buf = [0u8; 5]; unsafe { assert_eq!( libc::syscall( libc::SYS_getrandom, - 0 as *mut libc::c_void, + ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint, ), @@ -26,7 +28,7 @@ fn main() { ); assert_eq!( - libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), + libc::getrandom(ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint), 0, ); assert_eq!( diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index 7d3f899f44..a3596e4c7a 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -2,13 +2,15 @@ #![feature(rustc_private)] extern crate libc; +use std::ptr; + fn main() { let mut buf = [0u8; 5]; unsafe { assert_eq!( libc::syscall( libc::SYS_getrandom, - 0 as *mut libc::c_void, + ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint, ), @@ -25,7 +27,7 @@ fn main() { ); assert_eq!( - libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), + libc::getrandom(ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint), 0, ); assert_eq!( diff --git a/tests/pass/panic/catch_panic.rs b/tests/pass/panic/catch_panic.rs index 2fb00391cd..3979fb3b07 100644 --- a/tests/pass/panic/catch_panic.rs +++ b/tests/pass/panic/catch_panic.rs @@ -1,5 +1,5 @@ // We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. -// compile-flags: -Zmiri-symbolic-alignment-check +// compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance #![feature(never_type)] #![allow(unconditional_panic, non_fmt_panics)] diff --git a/tests/pass/ptr_int_casts.rs b/tests/pass/ptr_int_casts.rs index 889b6bd04f..ffe6a114c6 100644 --- a/tests/pass/ptr_int_casts.rs +++ b/tests/pass/ptr_int_casts.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-permissive-provenance use std::mem; use std::ptr; diff --git a/tests/pass/ptr_offset.rs b/tests/pass/ptr_offset.rs index 1b25df7214..b16a06a726 100644 --- a/tests/pass/ptr_offset.rs +++ b/tests/pass/ptr_offset.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-permissive-provenance use std::{mem, ptr}; fn main() { diff --git a/tests/pass/stacked-borrows/2phase.rs b/tests/pass/stacked-borrows/2phase.rs index 345cb64ccf..eb543d691e 100644 --- a/tests/pass/stacked-borrows/2phase.rs +++ b/tests/pass/stacked-borrows/2phase.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers - trait S: Sized { fn tpb(&mut self, _s: Self) {} } diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 9ee8af45ae..79958ab553 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers use std::cell::{Cell, RefCell, UnsafeCell}; use std::mem::{self, MaybeUninit}; diff --git a/tests/pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs index 131783ef4f..eb0ff167eb 100644 --- a/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/tests/pass/stacked-borrows/stacked-borrows.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers use std::ptr; // Test various stacked-borrows-related things. diff --git a/tests/pass/zst.rs b/tests/pass/zst.rs index 3a853e7d8a..fade1e0dad 100644 --- a/tests/pass/zst.rs +++ b/tests/pass/zst.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-permissive-provenance #[derive(PartialEq, Debug)] struct A;