diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 0cbfe0e96a3fc..f6c675839e01f 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -220,7 +220,6 @@ degree documented below): - `solaris` / `illumos`: maintained by @devnexen. Supports the entire test suite. - `freebsd`: maintained by @YohDeadfall and @LorrensP-2158466. Supports the entire test suite. - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works. - - `wasi`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works. - For targets on other operating systems, Miri might fail before even reaching the `main` function. However, even for targets that we do support, the degree of support for accessing platform APIs diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index bcc110f648b9b..2d27f02749991 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -153,7 +153,6 @@ case $HOST_TARGET in BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd - TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC hello wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std ;; diff --git a/src/tools/miri/genmc-sys/build.rs b/src/tools/miri/genmc-sys/build.rs index f10e151a3d0bc..1b4e064d1ba21 100644 --- a/src/tools/miri/genmc-sys/build.rs +++ b/src/tools/miri/genmc-sys/build.rs @@ -26,9 +26,9 @@ mod downloading { use super::GENMC_DOWNLOAD_PATH; /// The GenMC repository the we get our commit from. - pub(crate) const GENMC_GITHUB_URL: &str = "https://gitlab.inf.ethz.ch/public-plf/genmc.git"; + pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/MPI-SWS/genmc.git"; /// The GenMC commit we depend on. It must be available on the specified GenMC repository. - pub(crate) const GENMC_COMMIT: &str = "ce775ccd7866db820fa12ffca66463087a11dd96"; + pub(crate) const GENMC_COMMIT: &str = "d9527280bb99f1cef64326b1803ffd952e3880df"; /// Ensure that a local GenMC repo is present and set to the correct commit. /// Return the path of the GenMC repo and whether the checked out commit was changed. diff --git a/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp b/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp index b0bd397ab34b1..3a04edc013681 100644 --- a/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp +++ b/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp @@ -261,7 +261,7 @@ namespace GenmcScalarExt { inline GenmcScalar uninit() { return GenmcScalar { .value = 0, - .extra = 0, + .provenance = 0, .is_init = false, }; } @@ -269,19 +269,19 @@ inline GenmcScalar uninit() { inline GenmcScalar from_sval(SVal sval) { return GenmcScalar { .value = sval.get(), - .extra = sval.getExtra(), + .provenance = sval.getProvenance(), .is_init = true, }; } inline SVal to_sval(GenmcScalar scalar) { ERROR_ON(!scalar.is_init, "Cannot convert an uninitialized `GenmcScalar` into an `SVal`\n"); - return SVal(scalar.value, scalar.extra); + return SVal(scalar.value, scalar.provenance); } inline std::optional try_to_sval(GenmcScalar scalar) { if (scalar.is_init) - return { SVal(scalar.value, scalar.extra) }; + return { SVal(scalar.value, scalar.provenance) }; return std::nullopt; } } // namespace GenmcScalarExt diff --git a/src/tools/miri/genmc-sys/src/lib.rs b/src/tools/miri/genmc-sys/src/lib.rs index a34c7f2b3a667..69aeca3ebc723 100644 --- a/src/tools/miri/genmc-sys/src/lib.rs +++ b/src/tools/miri/genmc-sys/src/lib.rs @@ -45,14 +45,14 @@ pub fn create_genmc_driver_handle( } impl GenmcScalar { - pub const UNINIT: Self = Self { value: 0, extra: 0, is_init: false }; + pub const UNINIT: Self = Self { value: 0, provenance: 0, is_init: false }; pub const fn from_u64(value: u64) -> Self { - Self { value, extra: 0, is_init: true } + Self { value, provenance: 0, is_init: true } } pub const fn has_provenance(&self) -> bool { - self.extra != 0 + self.provenance != 0 } } @@ -172,8 +172,9 @@ mod ffi { value: u64, /// This is zero for integer values. For pointers, this encodes the provenance by /// storing the base address of the allocation that this pointer belongs to. - /// Operations on `SVal` in GenMC (e.g., `fetch_add`) preserve the `extra` of the left argument (`left.fetch_add(right, ...)`). - extra: u64, + /// Operations on `SVal` in GenMC (e.g., `fetch_add`) preserve the `provenance` of the left + /// argument (`left.fetch_add(right, ...)`). + provenance: u64, /// Indicates whether this value is initialized. If this is `false`, the other fields do not matter. /// (Ideally we'd use `std::optional` but CXX does not support that.) is_init: bool, diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index bf33c10dd0352..036282b12f5de 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -292be5c7c05138d753bbd4b30db7a3f1a5c914f7 +5f9dd05862d2e4bceb3be1031b6c936e35671501 diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs index e21775c9f239f..968e4961a6355 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -640,7 +640,7 @@ mod propagation_optimization_checks { impl Exhaustive for AccessRelatedness { fn exhaustive() -> Box> { use AccessRelatedness::*; - Box::new(vec![This, StrictChildAccess, AncestorAccess, CousinAccess].into_iter()) + Box::new(vec![ForeignAccess, LocalAccess].into_iter()) } } @@ -716,13 +716,11 @@ mod propagation_optimization_checks { // We now assert it is idempotent, and never causes UB. // First, if the SIFA includes foreign reads, assert it is idempotent under foreign reads. if access >= IdempotentForeignAccess::Read { - // We use `CousinAccess` here. We could also use `AncestorAccess`, since `transition::perform_access` treats these the same. - // The only place they are treated differently is in protector end accesses, but these are not handled here. - assert_eq!(perm, transition::perform_access(AccessKind::Read, AccessRelatedness::CousinAccess, perm, prot).unwrap()); + assert_eq!(perm, transition::perform_access(AccessKind::Read, AccessRelatedness::ForeignAccess, perm, prot).unwrap()); } // Then, if the SIFA includes foreign writes, assert it is idempotent under foreign writes. if access >= IdempotentForeignAccess::Write { - assert_eq!(perm, transition::perform_access(AccessKind::Write, AccessRelatedness::CousinAccess, perm, prot).unwrap()); + assert_eq!(perm, transition::perform_access(AccessKind::Write, AccessRelatedness::ForeignAccess, perm, prot).unwrap()); } } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index c4345c63289f1..740483844e795 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -24,7 +24,7 @@ use crate::borrow_tracker::tree_borrows::diagnostics::{ }; use crate::borrow_tracker::tree_borrows::foreign_access_skipping::IdempotentForeignAccess; use crate::borrow_tracker::tree_borrows::perms::PermTransition; -use crate::borrow_tracker::tree_borrows::unimap::{UniEntry, UniIndex, UniKeyMap, UniValMap}; +use crate::borrow_tracker::tree_borrows::unimap::{UniIndex, UniKeyMap, UniValMap}; use crate::borrow_tracker::{GlobalState, ProtectorKind}; use crate::*; @@ -265,13 +265,15 @@ pub(super) struct Node { } /// Data given to the transition function -struct NodeAppArgs<'node> { - /// Node on which the transition is currently being applied - node: &'node mut Node, - /// Mutable access to its permissions - perm: UniEntry<'node, LocationState>, - /// Relative position of the access +struct NodeAppArgs<'visit> { + /// The index of the current node. + idx: UniIndex, + /// Relative position of the access. rel_pos: AccessRelatedness, + /// The node map of this tree. + nodes: &'visit mut UniValMap, + /// The permissions map of this tree. + perms: &'visit mut UniValMap, } /// Data given to the error handler struct ErrHandlerArgs<'node, InErr> { @@ -348,8 +350,7 @@ where idx: UniIndex, rel_pos: AccessRelatedness, ) -> ContinueTraversal { - let node = this.nodes.get_mut(idx).unwrap(); - let args = NodeAppArgs { node, perm: this.perms.entry(idx), rel_pos }; + let args = NodeAppArgs { idx, rel_pos, nodes: this.nodes, perms: this.perms }; (self.f_continue)(&args) } @@ -359,16 +360,14 @@ where idx: UniIndex, rel_pos: AccessRelatedness, ) -> Result<(), OutErr> { - let node = this.nodes.get_mut(idx).unwrap(); - (self.f_propagate)(NodeAppArgs { node, perm: this.perms.entry(idx), rel_pos }).map_err( - |error_kind| { + (self.f_propagate)(NodeAppArgs { idx, rel_pos, nodes: this.nodes, perms: this.perms }) + .map_err(|error_kind| { (self.err_builder)(ErrHandlerArgs { error_kind, conflicting_info: &this.nodes.get(idx).unwrap().debug_info, accessed_info: &this.nodes.get(self.initial).unwrap().debug_info, }) - }, - ) + }) } fn go_upwards_from_accessed( @@ -386,14 +385,14 @@ where // be handled differently here compared to the further parents // of `accesssed_node`. { - self.propagate_at(this, accessed_node, AccessRelatedness::This)?; + self.propagate_at(this, accessed_node, AccessRelatedness::LocalAccess)?; if matches!(visit_children, ChildrenVisitMode::VisitChildrenOfAccessed) { let accessed_node = this.nodes.get(accessed_node).unwrap(); // We `rev()` here because we reverse the entire stack later. for &child in accessed_node.children.iter().rev() { self.stack.push(( child, - AccessRelatedness::AncestorAccess, + AccessRelatedness::ForeignAccess, RecursionState::BeforeChildren, )); } @@ -404,7 +403,7 @@ where // not the subtree that contains the accessed node. let mut last_node = accessed_node; while let Some(current) = this.nodes.get(last_node).unwrap().parent { - self.propagate_at(this, current, AccessRelatedness::StrictChildAccess)?; + self.propagate_at(this, current, AccessRelatedness::LocalAccess)?; let node = this.nodes.get(current).unwrap(); // We `rev()` here because we reverse the entire stack later. for &child in node.children.iter().rev() { @@ -413,7 +412,7 @@ where } self.stack.push(( child, - AccessRelatedness::CousinAccess, + AccessRelatedness::ForeignAccess, RecursionState::BeforeChildren, )); } @@ -741,7 +740,9 @@ impl<'tcx> Tree { // visit all children, skipping none |_| ContinueTraversal::Recurse, |args: NodeAppArgs<'_>| -> Result<(), TransitionError> { - let NodeAppArgs { node, perm, .. } = args; + let node = args.nodes.get(args.idx).unwrap(); + let perm = args.perms.entry(args.idx); + let perm = perm.get().copied().unwrap_or_else(|| node.default_location_state()); if global.borrow().protected_tags.get(&node.tag) @@ -812,32 +813,34 @@ impl<'tcx> Tree { // `perms_range` is only for diagnostics (it is the range of // the `RangeMap` on which we are currently working). let node_skipper = |access_kind: AccessKind, args: &NodeAppArgs<'_>| -> ContinueTraversal { - let NodeAppArgs { node, perm, rel_pos } = args; + let node = args.nodes.get(args.idx).unwrap(); + let perm = args.perms.get(args.idx); - let old_state = perm.get().copied().unwrap_or_else(|| node.default_location_state()); - old_state.skip_if_known_noop(access_kind, *rel_pos) + let old_state = perm.copied().unwrap_or_else(|| node.default_location_state()); + old_state.skip_if_known_noop(access_kind, args.rel_pos) }; let node_app = |perms_range: Range, access_kind: AccessKind, access_cause: diagnostics::AccessCause, args: NodeAppArgs<'_>| -> Result<(), TransitionError> { - let NodeAppArgs { node, mut perm, rel_pos } = args; + let node = args.nodes.get_mut(args.idx).unwrap(); + let mut perm = args.perms.entry(args.idx); let old_state = perm.or_insert(node.default_location_state()); // Call this function now, which ensures it is only called when // `skip_if_known_noop` returns `Recurse`, due to the contract of // `traverse_this_parents_children_other`. - old_state.record_new_access(access_kind, rel_pos); + old_state.record_new_access(access_kind, args.rel_pos); let protected = global.borrow().protected_tags.contains_key(&node.tag); - let transition = old_state.perform_access(access_kind, rel_pos, protected)?; + let transition = old_state.perform_access(access_kind, args.rel_pos, protected)?; // Record the event as part of the history if !transition.is_noop() { node.debug_info.history.push(diagnostics::Event { transition, - is_foreign: rel_pos.is_foreign(), + is_foreign: args.rel_pos.is_foreign(), access_cause, access_range: access_range_and_kind.map(|x| x.0), transition_range: perms_range, @@ -1075,24 +1078,18 @@ impl VisitProvenance for Tree { /// Relative position of the access #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum AccessRelatedness { - /// The accessed pointer is the current one - This, - /// The accessed pointer is a (transitive) child of the current one. - // Current pointer is excluded (unlike in some other places of this module - // where "child" is inclusive). - StrictChildAccess, - /// The accessed pointer is a (transitive) parent of the current one. - // Current pointer is excluded. - AncestorAccess, - /// The accessed pointer is neither of the above. - // It's a cousin/uncle/etc., something in a side branch. - CousinAccess, + /// The access happened either through the node itself or one of + /// its transitive children. + LocalAccess, + /// The access happened through this nodes ancestor or through + /// a sibling/cousin/uncle/etc. + ForeignAccess, } impl AccessRelatedness { /// Check that access is either Ancestor or Distant, i.e. not /// a transitive child (initial pointer included). pub fn is_foreign(self) -> bool { - matches!(self, AccessRelatedness::AncestorAccess | AccessRelatedness::CousinAccess) + matches!(self, AccessRelatedness::ForeignAccess) } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs index 189e48eca724a..0b83de2cedc09 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs @@ -263,15 +263,15 @@ mod spurious_read { match xy_rel { RelPosXY::MutuallyForeign => match self { - PtrSelector::X => (This, CousinAccess), - PtrSelector::Y => (CousinAccess, This), - PtrSelector::Other => (CousinAccess, CousinAccess), + PtrSelector::X => (LocalAccess, ForeignAccess), + PtrSelector::Y => (ForeignAccess, LocalAccess), + PtrSelector::Other => (ForeignAccess, ForeignAccess), }, RelPosXY::XChildY => match self { - PtrSelector::X => (This, StrictChildAccess), - PtrSelector::Y => (AncestorAccess, This), - PtrSelector::Other => (CousinAccess, CousinAccess), + PtrSelector::X => (LocalAccess, LocalAccess), + PtrSelector::Y => (ForeignAccess, LocalAccess), + PtrSelector::Other => (ForeignAccess, ForeignAccess), }, } } diff --git a/src/tools/miri/src/concurrency/genmc/helper.rs b/src/tools/miri/src/concurrency/genmc/helper.rs index b2e4b5aea5346..ae16898106d86 100644 --- a/src/tools/miri/src/concurrency/genmc/helper.rs +++ b/src/tools/miri/src/concurrency/genmc/helper.rs @@ -55,7 +55,7 @@ pub fn scalar_to_genmc_scalar<'tcx>( rustc_const_eval::interpret::Scalar::Int(scalar_int) => { // FIXME(genmc): Add u128 support once GenMC supports it. let value: u64 = scalar_int.to_uint(scalar_int.size()).try_into().unwrap(); - GenmcScalar { value, extra: 0, is_init: true } + GenmcScalar { value, provenance: 0, is_init: true } } rustc_const_eval::interpret::Scalar::Ptr(pointer, size) => { // FIXME(genmc,borrow tracking): Borrow tracking information is lost. @@ -69,7 +69,7 @@ pub fn scalar_to_genmc_scalar<'tcx>( let base_addr = ecx.addr_from_alloc_id(alloc_id, None)?; // Add the base_addr alloc_id pair to the map. genmc_ctx.exec_state.genmc_shared_allocs_map.borrow_mut().insert(base_addr, alloc_id); - GenmcScalar { value: addr.bytes(), extra: base_addr, is_init: true } + GenmcScalar { value: addr.bytes(), provenance: base_addr, is_init: true } } }) } @@ -84,16 +84,17 @@ pub fn genmc_scalar_to_scalar<'tcx>( scalar: GenmcScalar, size: Size, ) -> InterpResult<'tcx, Scalar> { - // If `extra` is zero, we have a regular integer. - if scalar.extra == 0 { + // If `provenance` is zero, we have a regular integer. + if scalar.provenance == 0 { // NOTE: GenMC always returns 64 bit values, and the upper bits are not yet truncated. // FIXME(genmc): GenMC should be doing the truncation, not Miri. let (value_scalar_int, _got_truncated) = ScalarInt::truncate_from_uint(scalar.value, size); return interp_ok(Scalar::from(value_scalar_int)); } - // `extra` is non-zero, we have a pointer. - // When we get a pointer from GenMC, then we must have sent it to GenMC before in the same execution (since the reads-from relation is always respected). - let alloc_id = genmc_ctx.exec_state.genmc_shared_allocs_map.borrow()[&scalar.extra]; + // `provenance` is non-zero, we have a pointer. + // When we get a pointer from GenMC, then we must have sent it to GenMC before in the same + // execution (since the reads-from relation is always respected). + let alloc_id = genmc_ctx.exec_state.genmc_shared_allocs_map.borrow()[&scalar.provenance]; // FIXME(genmc,borrow tracking): Borrow tracking not yet supported. let provenance = machine::Provenance::Concrete { alloc_id, tag: BorTag::default() }; let ptr = interpret::Pointer::new(provenance, Size::from_bytes(scalar.value)); diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index dd2b0edcb896a..6178f87d78495 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -181,7 +181,6 @@ pub struct Thread<'tcx> { /// The index of the topmost user-relevant frame in `stack`. This field must contain /// the value produced by `get_top_user_relevant_frame`. - /// The `None` state here represents /// This field is a cache to reduce how often we call that method. The cache is manually /// maintained inside `MiriMachine::after_stack_push` and `MiriMachine::after_stack_pop`. top_user_relevant_frame: Option, @@ -232,12 +231,21 @@ impl<'tcx> Thread<'tcx> { /// justifying the optimization that only pushes of user-relevant frames require updating the /// `top_user_relevant_frame` field. fn compute_top_user_relevant_frame(&self, skip: usize) -> Option { - self.stack - .iter() - .enumerate() - .rev() - .skip(skip) - .find_map(|(idx, frame)| if frame.extra.is_user_relevant { Some(idx) } else { None }) + // We are search for the frame with maximum relevance. + let mut best = None; + for (idx, frame) in self.stack.iter().enumerate().rev().skip(skip) { + let relevance = frame.extra.user_relevance; + if relevance == u8::MAX { + // We can short-circuit this search. + return Some(idx); + } + if best.is_none_or(|(_best_idx, best_relevance)| best_relevance < relevance) { + // The previous best frame has strictly worse relevance, so despite us being lower + // in the stack, we win. + best = Some((idx, relevance)); + } + } + best.map(|(idx, _relevance)| idx) } /// Re-compute the top user-relevant frame from scratch. `skip` indicates how many top frames @@ -256,14 +264,20 @@ impl<'tcx> Thread<'tcx> { /// Returns the topmost frame that is considered user-relevant, or the /// top of the stack if there is no such frame, or `None` if the stack is empty. pub fn top_user_relevant_frame(&self) -> Option { - debug_assert_eq!(self.top_user_relevant_frame, self.compute_top_user_relevant_frame(0)); // This can be called upon creation of an allocation. We create allocations while setting up // parts of the Rust runtime when we do not have any stack frames yet, so we need to handle // empty stacks. self.top_user_relevant_frame.or_else(|| self.stack.len().checked_sub(1)) } + pub fn current_user_relevance(&self) -> u8 { + self.top_user_relevant_frame() + .map(|frame_idx| self.stack[frame_idx].extra.user_relevance) + .unwrap_or(0) + } + pub fn current_user_relevant_span(&self) -> Span { + debug_assert_eq!(self.top_user_relevant_frame, self.compute_top_user_relevant_frame(0)); self.top_user_relevant_frame() .map(|frame_idx| self.stack[frame_idx].current_span()) .unwrap_or(rustc_span::DUMMY_SP) diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 0acdfdd3ffe54..d0cfb9c805e15 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -187,16 +187,14 @@ pub fn prune_stacktrace<'tcx>( } BacktraceStyle::Short => { let original_len = stacktrace.len(); - // Only prune frames if there is at least one local frame. This check ensures that if - // we get a backtrace that never makes it to the user code because it has detected a - // bug in the Rust runtime, we don't prune away every frame. - let has_local_frame = stacktrace.iter().any(|frame| machine.is_local(frame)); + // Remove all frames marked with `caller_location` -- that attribute indicates we + // usually want to point at the caller, not them. + stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(machine.tcx)); + // Only prune further frames if there is at least one local frame. This check ensures + // that if we get a backtrace that never makes it to the user code because it has + // detected a bug in the Rust runtime, we don't prune away every frame. + let has_local_frame = stacktrace.iter().any(|frame| machine.is_local(frame.instance)); if has_local_frame { - // Remove all frames marked with `caller_location` -- that attribute indicates we - // usually want to point at the caller, not them. - stacktrace - .retain(|frame| !frame.instance.def.requires_caller_location(machine.tcx)); - // This is part of the logic that `std` uses to select the relevant part of a // backtrace. But here, we only look for __rust_begin_short_backtrace, not // __rust_end_short_backtrace because the end symbol comes from a call to the default @@ -216,7 +214,7 @@ pub fn prune_stacktrace<'tcx>( // This len check ensures that we don't somehow remove every frame, as doing so breaks // the primary error message. while stacktrace.len() > 1 - && stacktrace.last().is_some_and(|frame| !machine.is_local(frame)) + && stacktrace.last().is_some_and(|frame| !machine.is_local(frame.instance)) { stacktrace.pop(); } @@ -619,7 +617,7 @@ pub fn report_msg<'tcx>( write!(backtrace_title, ":").unwrap(); err.note(backtrace_title); for (idx, frame_info) in stacktrace.iter().enumerate() { - let is_local = machine.is_local(frame_info); + let is_local = machine.is_local(frame_info.instance); // No span for non-local frames and the first frame (which is the error site). if is_local && idx > 0 { err.subdiagnostic(frame_info.as_note(machine.tcx)); diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 769e501c45333..7e1fdfa8cdf26 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1088,11 +1088,18 @@ impl<'tcx> MiriMachine<'tcx> { self.threads.active_thread_ref().top_user_relevant_frame() } - /// This is the source of truth for the `is_user_relevant` flag in our `FrameExtra`. - pub fn is_user_relevant(&self, frame: &Frame<'tcx, Provenance>) -> bool { - let def_id = frame.instance().def_id(); - (def_id.is_local() || self.user_relevant_crates.contains(&def_id.krate)) - && !frame.instance().def.requires_caller_location(self.tcx) + /// This is the source of truth for the `user_relevance` flag in our `FrameExtra`. + pub fn user_relevance(&self, frame: &Frame<'tcx, Provenance>) -> u8 { + if frame.instance().def.requires_caller_location(self.tcx) { + return 0; + } + if self.is_local(frame.instance()) { + u8::MAX + } else { + // A non-relevant frame, but at least it doesn't require a caller location, so + // better than nothing. + 1 + } } } diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 3b18545fee6c9..1767a8a7456ed 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -139,11 +139,10 @@ pub struct FrameExtra<'tcx> { /// we use this to register a completed event with `measureme`. pub timing: Option, - /// Indicates whether a `Frame` is part of a workspace-local crate and is also not - /// `#[track_caller]`. We compute this once on creation and store the result, as an - /// optimization. - /// This is used by `MiriMachine::current_span` and `MiriMachine::caller_span` - pub is_user_relevant: bool, + /// Indicates how user-relevant this frame is. `#[track_caller]` frames are never relevant. + /// Frames from user-relevant crates are maximally relevant; frames from other crates are less + /// relevant. + pub user_relevance: u8, /// Data race detector per-frame data. pub data_race: Option, @@ -152,12 +151,12 @@ pub struct FrameExtra<'tcx> { impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. - let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant, data_race } = + let FrameExtra { borrow_tracker, catch_unwind, timing: _, user_relevance, data_race } = self; f.debug_struct("FrameData") .field("borrow_tracker", borrow_tracker) .field("catch_unwind", catch_unwind) - .field("is_user_relevant", is_user_relevant) + .field("user_relevance", user_relevance) .field("data_race", data_race) .finish() } @@ -165,13 +164,8 @@ impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> { impl VisitProvenance for FrameExtra<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let FrameExtra { - catch_unwind, - borrow_tracker, - timing: _, - is_user_relevant: _, - data_race: _, - } = self; + let FrameExtra { catch_unwind, borrow_tracker, timing: _, user_relevance: _, data_race: _ } = + self; catch_unwind.visit_provenance(visit); borrow_tracker.visit_provenance(visit); @@ -910,8 +904,8 @@ impl<'tcx> MiriMachine<'tcx> { } /// Check whether the stack frame that this `FrameInfo` refers to is part of a local crate. - pub(crate) fn is_local(&self, frame: &FrameInfo<'_>) -> bool { - let def_id = frame.instance.def_id(); + pub(crate) fn is_local(&self, instance: ty::Instance<'tcx>) -> bool { + let def_id = instance.def_id(); def_id.is_local() || self.user_relevant_crates.contains(&def_id.krate) } @@ -1702,7 +1696,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { borrow_tracker: borrow_tracker.map(|bt| bt.borrow_mut().new_frame()), catch_unwind: None, timing, - is_user_relevant: ecx.machine.is_user_relevant(&frame), + user_relevance: ecx.machine.user_relevance(&frame), data_race: ecx .machine .data_race @@ -1758,9 +1752,9 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { - if ecx.frame().extra.is_user_relevant { - // We just pushed a local frame, so we know that the topmost local frame is the topmost - // frame. If we push a non-local frame, there's no need to do anything. + if ecx.frame().extra.user_relevance >= ecx.active_thread_ref().current_user_relevance() { + // We just pushed a frame that's at least as relevant as the so-far most relevant frame. + // That means we are now the most relevant frame. let stack_len = ecx.active_thread_stack().len(); ecx.active_thread_mut().set_top_user_relevant_frame(stack_len - 1); } @@ -1774,9 +1768,14 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if ecx.machine.borrow_tracker.is_some() { ecx.on_stack_pop(frame)?; } - if frame.extra.is_user_relevant { - // All that we store is whether or not the frame we just removed is local, so now we - // have no idea where the next topmost local frame is. So we recompute it. + if ecx + .active_thread_ref() + .top_user_relevant_frame() + .expect("there should always be a most relevant frame for a non-empty stack") + == ecx.frame_idx() + { + // We are popping the most relevant frame. We have no clue what the next relevant frame + // below that is, so we recompute that. // (If this ever becomes a bottleneck, we could have `push` store the previous // user-relevant frame and restore that here.) // We have to skip the frame that is just being popped. diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 689cd3a7269cc..b9fb9192df4a8 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -51,7 +51,7 @@ impl<'tcx> EnvVars<'tcx> { } else if ecx.tcx.sess.target.os == "windows" { EnvVars::Windows(WindowsEnvVars::new(ecx, env_vars)?) } else { - // Used e.g. for wasi + // For "none" targets (i.e., without an OS). EnvVars::Uninit }; ecx.machine.env_vars = env_vars; diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 74a1ac729e88f..54fe27382efd5 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -102,7 +102,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_ref(); match this.tcx.sess.target.os.as_ref() { os if this.target_os_is_unix() => shims::unix::foreign_items::is_dyn_sym(name, os), - "wasi" => shims::wasi::foreign_items::is_dyn_sym(name), "windows" => shims::windows::foreign_items::is_dyn_sym(name), _ => false, } @@ -846,10 +845,6 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_inner( this, link_name, abi, args, dest, ), - "wasi" => - shims::wasi::foreign_items::EvalContextExt::emulate_foreign_item_inner( - this, link_name, abi, args, dest, - ), "windows" => shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_inner( this, link_name, abi, args, dest, diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 7f7bc3b1cf720..e51ace2fd9072 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -8,7 +8,6 @@ mod math; #[cfg(all(unix, feature = "native-lib"))] mod native_lib; mod unix; -mod wasi; mod windows; mod x86; diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index 1200029692dc3..9dc829d7a1eef 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -253,7 +253,6 @@ impl<'tcx> TlsDtorsState<'tcx> { } _ => { // No TLS dtor support. - // FIXME: should we do something on wasi? break 'new_state Done; } } diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs deleted file mode 100644 index ffc02dc986f9a..0000000000000 --- a/src/tools/miri/src/shims/wasi/foreign_items.rs +++ /dev/null @@ -1,110 +0,0 @@ -use rustc_abi::CanonAbi; -use rustc_middle::ty::Ty; -use rustc_span::Symbol; -use rustc_target::callconv::FnAbi; - -use crate::shims::alloc::EvalContextExt as _; -use crate::*; - -pub fn is_dyn_sym(_name: &str) -> bool { - false -} - -impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn emulate_foreign_item_inner( - &mut self, - link_name: Symbol, - abi: &FnAbi<'tcx, Ty<'tcx>>, - args: &[OpTy<'tcx>], - dest: &MPlaceTy<'tcx>, - ) -> InterpResult<'tcx, EmulateItemResult> { - let this = self.eval_context_mut(); - match link_name.as_str() { - // Allocation - "posix_memalign" => { - let [memptr, align, size] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.posix_memalign(memptr, align, size)?; - this.write_scalar(result, dest)?; - } - "aligned_alloc" => { - let [align, size] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let res = this.aligned_alloc(align, size)?; - this.write_pointer(res, dest)?; - } - - // Standard input/output - // FIXME: These shims are hacks that just get basic stdout/stderr working. We can't - // constrain them to "std" since std itself uses the wasi crate for this. - "get-stdout" => { - let [] = - this.check_shim_sig(shim_sig!(extern "C" fn() -> i32), link_name, abi, args)?; - this.write_scalar(Scalar::from_i32(1), dest)?; // POSIX FD number for stdout - } - "get-stderr" => { - let [] = - this.check_shim_sig(shim_sig!(extern "C" fn() -> i32), link_name, abi, args)?; - this.write_scalar(Scalar::from_i32(2), dest)?; // POSIX FD number for stderr - } - "[resource-drop]output-stream" => { - let [handle] = - this.check_shim_sig(shim_sig!(extern "C" fn(i32) -> ()), link_name, abi, args)?; - let handle = this.read_scalar(handle)?.to_i32()?; - - if !(handle == 1 || handle == 2) { - throw_unsup_format!("wasm output-stream: unsupported handle"); - } - // We don't actually close these FDs, so this is a NOP. - } - "[method]output-stream.blocking-write-and-flush" => { - let [handle, buf, len, ret_area] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *mut _, usize, *mut _) -> ()), - link_name, - abi, - args, - )?; - let handle = this.read_scalar(handle)?.to_i32()?; - let buf = this.read_pointer(buf)?; - let len = this.read_target_usize(len)?; - let ret_area = this.read_pointer(ret_area)?; - - if len > 4096 { - throw_unsup_format!( - "wasm output-stream.blocking-write-and-flush: buffer too big" - ); - } - let len = usize::try_from(len).unwrap(); - let Some(fd) = this.machine.fds.get(handle) else { - throw_unsup_format!( - "wasm output-stream.blocking-write-and-flush: unsupported handle" - ); - }; - fd.write( - this.machine.communicate(), - buf, - len, - this, - callback!( - @capture<'tcx> { - len: usize, - ret_area: Pointer, - } - |this, result: Result| { - if !matches!(result, Ok(l) if l == len) { - throw_unsup_format!("wasm output-stream.blocking-write-and-flush: returning errors is not supported"); - } - // 0 in the first byte of the ret_area indicates success. - let ret = this.ptr_to_mplace(ret_area, this.machine.layouts.u8); - this.write_null(&ret)?; - interp_ok(()) - }), - )?; - } - - _ => return interp_ok(EmulateItemResult::NotSupported), - } - interp_ok(EmulateItemResult::NeedsReturn) - } -} diff --git a/src/tools/miri/src/shims/wasi/mod.rs b/src/tools/miri/src/shims/wasi/mod.rs deleted file mode 100644 index 09c6507b24f84..0000000000000 --- a/src/tools/miri/src/shims/wasi/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod foreign_items; diff --git a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr index 4fdaa97e1d0a2..39263a8d61cc9 100644 --- a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr +++ b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr @@ -4,5 +4,6 @@ ow fatal runtime error: thread local panicked on drop, aborting error: abnormal termination: the program aborted execution + error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/pass/std/arc.check_count.stderr b/src/tools/miri/tests/genmc/pass/std/arc.check_count.stderr index 878077edb818e..695aa3f5aeaf8 100644 --- a/src/tools/miri/tests/genmc/pass/std/arc.check_count.stderr +++ b/src/tools/miri/tests/genmc/pass/std/arc.check_count.stderr @@ -1,9 +1,9 @@ Running GenMC Verification... warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/thread/mod.rs:LL:CC | -LL | intrinsics::atomic_cxchgweak::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/thread/current.rs:LL:CC @@ -91,19 +91,34 @@ LL | handle.join().unwrap(); | ^^^^^^^^^^^^^ warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/rt.rs:LL:CC | -LL | intrinsics::atomic_cxchgweak::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | / CLEANUP.call_once(|| unsafe { +LL | | // Flush stdout and disable buffering. +LL | | crate::io::cleanup(); +... | +LL | | }); + | |______^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC +warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. + --> RUSTLIB/std/src/sync/once.rs:LL:CC + | +LL | self.inner.call(true, &mut |p| f.take().unwrap()(p)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code + | + = note: BACKTRACE: + = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/sync/once.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC + warning: GenMC currently does not model the failure ordering for `compare_exchange`. Due to success ordering 'Acquire', the failure ordering 'Relaxed' is treated like 'Acquire'. Miri with GenMC might miss bugs related to this memory access. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/sys/exit_guard.rs:LL:CC | -LL | intrinsics::atomic_cxchg::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/src/tools/miri/tests/genmc/pass/std/arc.try_upgrade.stderr b/src/tools/miri/tests/genmc/pass/std/arc.try_upgrade.stderr index fc43c63135902..8609c2c5c8645 100644 --- a/src/tools/miri/tests/genmc/pass/std/arc.try_upgrade.stderr +++ b/src/tools/miri/tests/genmc/pass/std/arc.try_upgrade.stderr @@ -1,9 +1,9 @@ Running GenMC Verification... warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/thread/mod.rs:LL:CC | -LL | intrinsics::atomic_cxchgweak::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/thread/current.rs:LL:CC @@ -91,19 +91,34 @@ LL | handle.join().unwrap(); | ^^^^^^^^^^^^^ warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/rt.rs:LL:CC | -LL | intrinsics::atomic_cxchgweak::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | / CLEANUP.call_once(|| unsafe { +LL | | // Flush stdout and disable buffering. +LL | | crate::io::cleanup(); +... | +LL | | }); + | |______^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC +warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. + --> RUSTLIB/std/src/sync/once.rs:LL:CC + | +LL | self.inner.call(true, &mut |p| f.take().unwrap()(p)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code + | + = note: BACKTRACE: + = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/sync/once.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC + warning: GenMC currently does not model the failure ordering for `compare_exchange`. Due to success ordering 'Acquire', the failure ordering 'Relaxed' is treated like 'Acquire'. Miri with GenMC might miss bugs related to this memory access. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/sys/exit_guard.rs:LL:CC | -LL | intrinsics::atomic_cxchg::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/src/tools/miri/tests/genmc/pass/std/empty_main.stderr b/src/tools/miri/tests/genmc/pass/std/empty_main.stderr index 1b8712167d8a9..b1413ee6d574b 100644 --- a/src/tools/miri/tests/genmc/pass/std/empty_main.stderr +++ b/src/tools/miri/tests/genmc/pass/std/empty_main.stderr @@ -1,28 +1,43 @@ Running GenMC Verification... warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/thread/mod.rs:LL:CC | -LL | intrinsics::atomic_cxchgweak::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/thread/current.rs:LL:CC = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/rt.rs:LL:CC | -LL | intrinsics::atomic_cxchgweak::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | / CLEANUP.call_once(|| unsafe { +LL | | // Flush stdout and disable buffering. +LL | | crate::io::cleanup(); +... | +LL | | }); + | |______^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC +warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. + --> RUSTLIB/std/src/sync/once.rs:LL:CC + | +LL | self.inner.call(true, &mut |p| f.take().unwrap()(p)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code + | + = note: BACKTRACE: + = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/sync/once.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC + warning: GenMC currently does not model the failure ordering for `compare_exchange`. Due to success ordering 'Acquire', the failure ordering 'Relaxed' is treated like 'Acquire'. Miri with GenMC might miss bugs related to this memory access. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/sys/exit_guard.rs:LL:CC | -LL | intrinsics::atomic_cxchg::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/src/tools/miri/tests/genmc/pass/std/spawn_std_threads.stderr b/src/tools/miri/tests/genmc/pass/std/spawn_std_threads.stderr index b148c11e39b1f..87d3c60ef02e7 100644 --- a/src/tools/miri/tests/genmc/pass/std/spawn_std_threads.stderr +++ b/src/tools/miri/tests/genmc/pass/std/spawn_std_threads.stderr @@ -1,9 +1,9 @@ Running GenMC Verification... warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/thread/mod.rs:LL:CC | -LL | intrinsics::atomic_cxchgweak::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/thread/current.rs:LL:CC @@ -95,19 +95,34 @@ LL | handles.into_iter().for_each(|handle| handle.join().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/rt.rs:LL:CC | -LL | intrinsics::atomic_cxchgweak::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | / CLEANUP.call_once(|| unsafe { +LL | | // Flush stdout and disable buffering. +LL | | crate::io::cleanup(); +... | +LL | | }); + | |______^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC +warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. + --> RUSTLIB/std/src/sync/once.rs:LL:CC + | +LL | self.inner.call(true, &mut |p| f.take().unwrap()(p)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code + | + = note: BACKTRACE: + = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/sync/once.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC + warning: GenMC currently does not model the failure ordering for `compare_exchange`. Due to success ordering 'Acquire', the failure ordering 'Relaxed' is treated like 'Acquire'. Miri with GenMC might miss bugs related to this memory access. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/sys/exit_guard.rs:LL:CC | -LL | intrinsics::atomic_cxchg::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/src/tools/miri/tests/genmc/pass/std/thread_locals.stderr b/src/tools/miri/tests/genmc/pass/std/thread_locals.stderr index 208de4e37ffba..91d2f5daa146f 100644 --- a/src/tools/miri/tests/genmc/pass/std/thread_locals.stderr +++ b/src/tools/miri/tests/genmc/pass/std/thread_locals.stderr @@ -1,9 +1,9 @@ Running GenMC Verification... warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/thread/mod.rs:LL:CC | -LL | intrinsics::atomic_cxchgweak::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/thread/current.rs:LL:CC @@ -78,19 +78,34 @@ LL | handles.into_iter().for_each(|handle| handle.join().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/rt.rs:LL:CC | -LL | intrinsics::atomic_cxchgweak::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | / CLEANUP.call_once(|| unsafe { +LL | | // Flush stdout and disable buffering. +LL | | crate::io::cleanup(); +... | +LL | | }); + | |______^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC +warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. + --> RUSTLIB/std/src/sync/once.rs:LL:CC + | +LL | self.inner.call(true, &mut |p| f.take().unwrap()(p)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code + | + = note: BACKTRACE: + = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/sync/once.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC + warning: GenMC currently does not model the failure ordering for `compare_exchange`. Due to success ordering 'Acquire', the failure ordering 'Relaxed' is treated like 'Acquire'. Miri with GenMC might miss bugs related to this memory access. - --> RUSTLIB/core/src/sync/atomic.rs:LL:CC + --> RUSTLIB/std/src/sys/exit_guard.rs:LL:CC | -LL | intrinsics::atomic_cxchg::(dst, old, new) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code +LL | match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/src/tools/miri/tests/pass/shims/x86/rounding-error.rs b/src/tools/miri/tests/pass/shims/x86/rounding-error.rs index bf56111b2e496..aa9fd96861812 100644 --- a/src/tools/miri/tests/pass/shims/x86/rounding-error.rs +++ b/src/tools/miri/tests/pass/shims/x86/rounding-error.rs @@ -11,25 +11,27 @@ use std::arch::x86_64::*; use std::collections::HashSet; fn main() { + let a = unsafe { _mm_setr_ps(4.0, 4.0, 4.0, 4.0) }; + let exact = 0.5; + // max error: 2^-12. + let rel_error_bound = 1.0 / (1 << 12) as f32; + let mut vals = HashSet::new(); for _ in 0..50 { - unsafe { - // Compute the inverse square root of 4.0, four times. - let a = _mm_setr_ps(4.0, 4.0, 4.0, 4.0); - let exact = 0.5; - let r = _mm_rsqrt_ps(a); - let r: [f32; 4] = std::mem::transmute(r); - // Check the results. - for r in r { - vals.insert(r.to_bits()); - // Ensure the relative error is less than 2^-12. - let rel_error = (r - exact) / exact; - let log_error = rel_error.abs().log2(); - assert!( - rel_error == 0.0 || log_error < -12.0, - "got an error of {rel_error} = 2^{log_error}" - ); - } + // Compute the inverse square root of 4.0, four times. + let r = unsafe { _mm_rsqrt_ps(a) }; + let r: [f32; 4] = unsafe { std::mem::transmute(r) }; + // Check the results. + for r in r { + vals.insert(r.to_bits()); + // Ensure the relative error is no more than 2^-12. + let rel_error = (r - exact) / exact; + assert!( + rel_error.abs() <= rel_error_bound, + "correct result: {exact}, got: {r}\n\ + that's a relative error of {rel_error} (= 2^{log_error})", + log_error = rel_error.abs().log2() + ); } } // Ensure we saw a bunch of different results.