diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index f7295fd7d8a5..3d0fc5590eb8 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -9,7 +9,6 @@ use std::cmp::max; use rand::Rng; use rustc_abi::{Align, Size}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_span::Span; use self::reuse_pool::ReusePool; use crate::concurrency::VClock; @@ -319,17 +318,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match global_state.provenance_mode { 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(); + let mut int2ptr_warned = this.machine.int2ptr_warned.borrow_mut(); + let first = int2ptr_warned.is_empty(); + if int2ptr_warned.insert(this.cur_span()) { + // Newly inserted, so first time we see this span. + this.emit_diagnostic(NonHaltingDiagnostic::Int2Ptr { details: first }); } - PAST_WARNINGS.with_borrow_mut(|past_warnings| { - let first = past_warnings.is_empty(); - if past_warnings.insert(this.cur_span()) { - // Newly inserted, so first time we see this span. - this.emit_diagnostic(NonHaltingDiagnostic::Int2Ptr { details: first }); - } - }); } ProvenanceMode::Strict => { throw_machine_stop!(TerminationInfo::Int2PtrWithStrictProvenance); diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index ea75131078ee..bcc8668dbc12 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -5,7 +5,6 @@ pub mod diagnostics; mod item; mod stack; -use std::cell::RefCell; use std::fmt::Write; use std::{cmp, mem}; @@ -822,16 +821,9 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { let size = match size { Some(size) => size, None => { - // The first time this happens, show a warning. - thread_local! { static WARNING_SHOWN: RefCell = const { RefCell::new(false) }; } - WARNING_SHOWN.with_borrow_mut(|shown| { - if *shown { - return; - } - // Not yet shown. Show it! - *shown = true; + if !this.machine.sb_extern_type_warned.replace(true) { this.emit_diagnostic(NonHaltingDiagnostic::ExternTypeReborrow); - }); + } return interp_ok(place.clone()); } }; diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 690cb7a5b33f..adfec33beac6 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1,6 +1,4 @@ -use std::collections::BTreeSet; use std::num::NonZero; -use std::sync::Mutex; use std::time::Duration; use std::{cmp, iter}; @@ -641,11 +639,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match reject_with { RejectOpWith::Abort => isolation_abort_error(op_name), RejectOpWith::WarningWithoutBacktrace => { - // This exists to reduce verbosity; make sure we emit the warning at most once per - // operation. - static EMITTED_WARNINGS: Mutex> = Mutex::new(BTreeSet::new()); - - let mut emitted_warnings = EMITTED_WARNINGS.lock().unwrap(); + let mut emitted_warnings = this.machine.reject_in_isolation_warned.borrow_mut(); if !emitted_warnings.contains(op_name) { // First time we are seeing this. emitted_warnings.insert(op_name.to_owned()); @@ -653,6 +647,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .dcx() .warn(format!("{op_name} was made to return an error due to isolation")); } + interp_ok(()) } RejectOpWith::Warning => { diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 33cefd607646..5e8f616a37ea 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -3,7 +3,7 @@ use std::any::Any; use std::borrow::Cow; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; use std::path::Path; use std::{fmt, process}; @@ -595,6 +595,21 @@ pub struct MiriMachine<'tcx> { /// A cache of "data range" computations for unions (i.e., the offsets of non-padding bytes). union_data_ranges: FxHashMap, RangeSet>, + + /// Caches the sanity-checks for various pthread primitives. + pub(crate) pthread_mutex_sanity: Cell, + pub(crate) pthread_rwlock_sanity: Cell, + pub(crate) pthread_condvar_sanity: Cell, + + /// Remembers whether we already warned about an extern type with Stacked Borrows. + pub(crate) sb_extern_type_warned: Cell, + /// Remember whether we already warned about sharing memory with a native call. + #[cfg(unix)] + pub(crate) native_call_mem_warned: Cell, + /// Remembers which shims have already shown the warning about erroring in isolation. + pub(crate) reject_in_isolation_warned: RefCell>, + /// Remembers which int2ptr casts we have already warned about. + pub(crate) int2ptr_warned: RefCell>, } impl<'tcx> MiriMachine<'tcx> { @@ -732,6 +747,14 @@ impl<'tcx> MiriMachine<'tcx> { const_cache: RefCell::new(FxHashMap::default()), symbolic_alignment: RefCell::new(FxHashMap::default()), union_data_ranges: FxHashMap::default(), + pthread_mutex_sanity: Cell::new(false), + pthread_rwlock_sanity: Cell::new(false), + pthread_condvar_sanity: Cell::new(false), + sb_extern_type_warned: Cell::new(false), + #[cfg(unix)] + native_call_mem_warned: Cell::new(false), + reject_in_isolation_warned: Default::default(), + int2ptr_warned: Default::default(), } } @@ -844,6 +867,14 @@ impl VisitProvenance for MiriMachine<'_> { const_cache: _, symbolic_alignment: _, union_data_ranges: _, + pthread_mutex_sanity: _, + pthread_rwlock_sanity: _, + pthread_condvar_sanity: _, + sb_extern_type_warned: _, + #[cfg(unix)] + native_call_mem_warned: _, + reject_in_isolation_warned: _, + int2ptr_warned: _, } = self; threads.visit_provenance(visit); diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 92cca88bc962..87be5a521d13 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -1,5 +1,4 @@ //! Implements calling functions from a native library. -use std::cell::RefCell; use std::ops::Deref; use libffi::high::call as ffi; @@ -174,16 +173,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { continue; }; // The first time this happens, print a warning. - thread_local! { - static HAVE_WARNED: RefCell = const { RefCell::new(false) }; + if !this.machine.native_call_mem_warned.replace(true) { + // Newly set, so first time we get here. + this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem); } - HAVE_WARNED.with_borrow_mut(|have_warned| { - if !*have_warned { - // Newly inserted, so first time we see this span. - this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem); - *have_warned = true; - } - }); this.prepare_for_native_call(alloc_id, prov)?; } diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index 416cf020dcc9..5b0a9398b4b6 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -1,5 +1,3 @@ -use std::sync::atomic::{AtomicBool, Ordering}; - use rustc_abi::Size; use crate::concurrency::sync::LAZY_INIT_COOKIE; @@ -136,8 +134,7 @@ fn mutex_init_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, Size> // Sanity-check this against PTHREAD_MUTEX_INITIALIZER (but only once): // the `init` field must start out not equal to INIT_COOKIE. - static SANITY: AtomicBool = AtomicBool::new(false); - if !SANITY.swap(true, Ordering::Relaxed) { + if !ecx.machine.pthread_mutex_sanity.replace(true) { let check_static_initializer = |name| { let static_initializer = ecx.eval_path(&["libc", name]); let init_field = @@ -248,8 +245,7 @@ fn rwlock_init_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, Size // Sanity-check this against PTHREAD_RWLOCK_INITIALIZER (but only once): // the `init` field must start out not equal to LAZY_INIT_COOKIE. - static SANITY: AtomicBool = AtomicBool::new(false); - if !SANITY.swap(true, Ordering::Relaxed) { + if !ecx.machine.pthread_rwlock_sanity.replace(true) { let static_initializer = ecx.eval_path(&["libc", "PTHREAD_RWLOCK_INITIALIZER"]); let init_field = static_initializer.offset(offset, ecx.machine.layouts.u32, ecx).unwrap(); let init = ecx.read_scalar(&init_field).unwrap().to_u32().unwrap(); @@ -357,8 +353,7 @@ fn cond_init_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, Size> // Sanity-check this against PTHREAD_COND_INITIALIZER (but only once): // the `init` field must start out not equal to LAZY_INIT_COOKIE. - static SANITY: AtomicBool = AtomicBool::new(false); - if !SANITY.swap(true, Ordering::Relaxed) { + if !ecx.machine.pthread_condvar_sanity.replace(true) { let static_initializer = ecx.eval_path(&["libc", "PTHREAD_COND_INITIALIZER"]); let init_field = static_initializer.offset(offset, ecx.machine.layouts.u32, ecx).unwrap(); let init = ecx.read_scalar(&init_field).unwrap().to_u32().unwrap();