Skip to main content

miri/
machine.rs

1//! Global machine state as well as implementation of the interpreter engine
2//! `Machine` trait.
3
4use std::borrow::Cow;
5use std::cell::{Cell, RefCell};
6use std::collections::BTreeMap;
7use std::path::Path;
8use std::rc::Rc;
9use std::{fmt, process};
10
11use rand::rngs::StdRng;
12use rand::{RngExt, SeedableRng};
13use rustc_abi::{Align, ExternAbi, Size};
14use rustc_apfloat::{Float, FloatConvert};
15use rustc_ast::Mutability;
16use rustc_ast::expand::allocator::{self, SpecialAllocatorMethod};
17use rustc_data_structures::either::Either;
18use rustc_data_structures::fx::{FxHashMap, FxHashSet};
19#[allow(unused)]
20use rustc_data_structures::static_assert_size;
21use rustc_hir::attrs::{InlineAttr, Linkage};
22use rustc_hir::def::DefKind;
23use rustc_log::tracing;
24use rustc_middle::middle::codegen_fn_attrs::TargetFeatureKind;
25use rustc_middle::mir;
26use rustc_middle::query::TyCtxtAt;
27use rustc_middle::ty::layout::{
28    HasTyCtxt, HasTypingEnv, LayoutCx, LayoutError, LayoutOf, TyAndLayout,
29};
30use rustc_middle::ty::{self, AtomicOrdering, Instance, Ty, TyCtxt};
31use rustc_session::config::InliningThreshold;
32use rustc_span::def_id::{CrateNum, DefId};
33use rustc_span::{Span, SpanData, Symbol};
34use rustc_symbol_mangling::mangle_internal_symbol;
35use rustc_target::callconv::FnAbi;
36use rustc_target::spec::{Arch, Os};
37
38use crate::alloc_addresses::EvalContextExt;
39use crate::concurrency::cpu_affinity::{self, CpuAffinityMask};
40use crate::concurrency::data_race::{self, NaReadType, NaWriteType};
41use crate::concurrency::sync::SyncObj;
42use crate::concurrency::{
43    AllocDataRaceHandler, GenmcCtx, GenmcEvalContextExt as _, GlobalDataRaceHandler, weak_memory,
44};
45use crate::helpers::is_no_core;
46use crate::shims::readiness::DelayedReadinessUpdates;
47use crate::*;
48
49/// First real-time signal.
50/// `signal(7)` says this must be between 32 and 64 and specifies 34 or 35
51/// as typical values.
52pub const SIGRTMIN: i32 = 34;
53
54/// Last real-time signal.
55/// `signal(7)` says it must be between 32 and 64 and specifies
56/// `SIGRTMAX` - `SIGRTMIN` >= 8 (which is the value of `_POSIX_RTSIG_MAX`)
57pub const SIGRTMAX: i32 = 42;
58
59/// Each anonymous global (constant, vtable, function pointer, ...) has multiple addresses, but only
60/// this many. Since const allocations are never deallocated, choosing a new [`AllocId`] and thus
61/// base address for each evaluation would produce unbounded memory usage.
62const ADDRS_PER_ANON_GLOBAL: usize = 32;
63
64#[derive(Copy, Clone, Debug, PartialEq)]
65pub enum AlignmentCheck {
66    /// Do not check alignment.
67    None,
68    /// Check alignment "symbolically", i.e., using only the requested alignment for an allocation and not its real base address.
69    Symbolic,
70    /// Check alignment on the actual physical integer address.
71    Int,
72}
73
74#[derive(Copy, Clone, Debug, PartialEq)]
75pub enum RejectOpWith {
76    /// Isolated op is rejected with an abort of the machine.
77    Abort,
78
79    /// If not Abort, miri returns an error for an isolated op.
80    /// Following options determine if user should be warned about such error.
81    /// Do not print warning about rejected isolated op.
82    NoWarning,
83
84    /// Print a warning about rejected isolated op, with backtrace.
85    Warning,
86
87    /// Print a warning about rejected isolated op, without backtrace.
88    WarningWithoutBacktrace,
89}
90
91#[derive(Copy, Clone, Debug, PartialEq)]
92pub enum IsolatedOp {
93    /// Reject an op requiring communication with the host. By
94    /// default, miri rejects the op with an abort. If not, it returns
95    /// an error code, and prints a warning about it. Warning levels
96    /// are controlled by `RejectOpWith` enum.
97    Reject(RejectOpWith),
98
99    /// Execute op requiring communication with the host, i.e. disable isolation.
100    Allow,
101}
102
103#[derive(Debug, Copy, Clone, PartialEq, Eq)]
104pub enum BacktraceStyle {
105    /// Prints a terser backtrace which ideally only contains relevant information.
106    Short,
107    /// Prints a backtrace with all possible information.
108    Full,
109    /// Prints only the frame that the error occurs in.
110    Off,
111}
112
113#[derive(Debug, Copy, Clone, PartialEq, Eq)]
114pub enum ValidationMode {
115    /// Do not perform any kind of validation.
116    No,
117    /// Validate the interior of the value, but not things behind references.
118    Shallow,
119    /// Fully recursively validate references.
120    Deep,
121}
122
123#[derive(Debug, Copy, Clone, PartialEq, Eq)]
124pub enum FloatRoundingErrorMode {
125    /// Apply a random error (the default).
126    Random,
127    /// Don't apply any error.
128    None,
129    /// Always apply the maximum error (with a random sign).
130    Max,
131}
132
133/// Extra data stored with each stack frame
134pub struct FrameExtra<'tcx> {
135    /// Extra data for the Borrow Tracker.
136    pub borrow_tracker: Option<borrow_tracker::FrameState>,
137
138    /// If this is Some(), then this is a special "catch unwind" frame (the frame of `try_fn`
139    /// called by `try`). When this frame is popped during unwinding a panic,
140    /// we stop unwinding, use the `CatchUnwindData` to handle catching.
141    pub catch_unwind: Option<CatchUnwindData<'tcx>>,
142
143    /// If `measureme` profiling is enabled, holds timing information
144    /// for the start of this frame. When we finish executing this frame,
145    /// we use this to register a completed event with `measureme`.
146    pub timing: Option<measureme::DetachedTiming>,
147
148    /// Indicates how user-relevant this frame is. `#[track_caller]` frames are never relevant.
149    /// Frames from user-relevant crates are maximally relevant; frames from other crates are less
150    /// relevant.
151    pub user_relevance: u8,
152
153    /// Data race detector per-frame data.
154    pub data_race: Option<data_race::FrameState>,
155}
156
157impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {
158    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159        // Omitting `timing`, it does not support `Debug`.
160        let FrameExtra { borrow_tracker, catch_unwind, timing: _, user_relevance, data_race } =
161            self;
162        f.debug_struct("FrameData")
163            .field("borrow_tracker", borrow_tracker)
164            .field("catch_unwind", catch_unwind)
165            .field("user_relevance", user_relevance)
166            .field("data_race", data_race)
167            .finish()
168    }
169}
170
171impl VisitProvenance for FrameExtra<'_> {
172    fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
173        let FrameExtra { catch_unwind, borrow_tracker, timing: _, user_relevance: _, data_race: _ } =
174            self;
175
176        catch_unwind.visit_provenance(visit);
177        borrow_tracker.visit_provenance(visit);
178    }
179}
180
181/// Extra memory kinds
182#[derive(Debug, Copy, Clone, PartialEq, Eq)]
183pub enum MiriMemoryKind {
184    /// `__rust_alloc` memory.
185    Rust,
186    /// `miri_alloc` memory.
187    Miri,
188    /// `malloc` memory.
189    C,
190    /// Windows `HeapAlloc` memory.
191    WinHeap,
192    /// Windows "local" memory (to be freed with `LocalFree`)
193    WinLocal,
194    /// Memory for args, errno, env vars, and other parts of the machine-managed environment.
195    /// This memory may leak.
196    Machine,
197    /// Memory allocated by the runtime, e.g. for readdir. Separate from `Machine` because we clean
198    /// it up (or expect the user to invoke operations that clean it up) and leak-check it.
199    Runtime,
200    /// Globals copied from `tcx`.
201    /// This memory may leak.
202    Global,
203    /// Memory for extern statics.
204    /// This memory may leak.
205    ExternStatic,
206    /// Memory for thread-local statics.
207    /// This memory may leak.
208    Tls,
209    /// Memory mapped directly by the program.
210    Mmap,
211    /// Memory allocated for `getaddrinfo` result.
212    SocketAddress,
213}
214
215impl From<MiriMemoryKind> for MemoryKind {
216    #[inline(always)]
217    fn from(kind: MiriMemoryKind) -> MemoryKind {
218        MemoryKind::Machine(kind)
219    }
220}
221
222impl MayLeak for MiriMemoryKind {
223    #[inline(always)]
224    fn may_leak(self) -> bool {
225        use self::MiriMemoryKind::*;
226        match self {
227            Rust | Miri | C | WinHeap | WinLocal | Runtime => false,
228            Machine | Global | ExternStatic | Tls | Mmap | SocketAddress => true,
229        }
230    }
231}
232
233impl MiriMemoryKind {
234    /// Whether we have a useful allocation span for an allocation of this kind.
235    fn should_save_allocation_span(self) -> bool {
236        use self::MiriMemoryKind::*;
237        match self {
238            // Heap allocations are fine since the `Allocation` is created immediately.
239            Rust | Miri | C | WinHeap | WinLocal | Mmap => true,
240            // Everything else is unclear, let's not show potentially confusing spans.
241            Machine | Global | ExternStatic | Tls | Runtime | SocketAddress => false,
242        }
243    }
244}
245
246impl fmt::Display for MiriMemoryKind {
247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248        use self::MiriMemoryKind::*;
249        match self {
250            Rust => write!(f, "Rust heap"),
251            Miri => write!(f, "Miri bare-metal heap"),
252            C => write!(f, "C heap"),
253            WinHeap => write!(f, "Windows heap"),
254            WinLocal => write!(f, "Windows local memory"),
255            Machine => write!(f, "machine-managed memory"),
256            Runtime => write!(f, "language runtime memory"),
257            Global => write!(f, "global (static or const)"),
258            ExternStatic => write!(f, "extern static"),
259            Tls => write!(f, "thread-local static"),
260            Mmap => write!(f, "mmap"),
261            SocketAddress => write!(f, "socket address"),
262        }
263    }
264}
265
266pub type MemoryKind = interpret::MemoryKind<MiriMemoryKind>;
267
268/// Pointer provenance.
269// This needs to be `Eq`+`Hash` because the `Machine` trait needs that because validity checking
270// *might* be recursive and then it has to track which places have already been visited.
271// These implementations are a bit questionable, and it means we may check the same place multiple
272// times with different provenance, but that is in general not wrong.
273#[derive(Clone, Copy, PartialEq, Eq, Hash)]
274pub enum Provenance {
275    /// For pointers with concrete provenance. we exactly know which allocation they are attached to
276    /// and what their borrow tag is.
277    Concrete {
278        alloc_id: AllocId,
279        /// Borrow Tracker tag.
280        tag: BorTag,
281    },
282    /// Pointers with wildcard provenance are created on int-to-ptr casts. According to the
283    /// specification, we should at that point angelically "guess" a provenance that will make all
284    /// future uses of this pointer work, if at all possible. Of course such a semantics cannot be
285    /// actually implemented in Miri. So instead, we approximate this, erroring on the side of
286    /// accepting too much code rather than rejecting correct code: a pointer with wildcard
287    /// provenance "acts like" any previously exposed pointer. Each time it is used, we check
288    /// whether *some* exposed pointer could have done what we want to do, and if the answer is yes
289    /// then we allow the access. This allows too much code in two ways:
290    /// - The same wildcard pointer can "take the role" of multiple different exposed pointers on
291    ///   subsequent memory accesses.
292    /// - In the aliasing model, we don't just have to know the borrow tag of the pointer used for
293    ///   the access, we also have to update the aliasing state -- and that update can be very
294    ///   different depending on which borrow tag we pick! Stacked Borrows has support for this by
295    ///   switching to a stack that is only approximately known, i.e. we over-approximate the effect
296    ///   of using *any* exposed pointer for this access, and only keep information about the borrow
297    ///   stack that would be true with all possible choices.
298    Wildcard,
299}
300
301/// The "extra" information a pointer has over a regular AllocId.
302#[derive(Copy, Clone, PartialEq)]
303pub enum ProvenanceExtra {
304    Concrete(BorTag),
305    Wildcard,
306}
307
308#[cfg(target_pointer_width = "64")]
309static_assert_size!(StrictPointer, 24);
310// Pointer does not fit as the layout algorithm isn't smart enough (but also, we tried using
311// pattern types to get a larger niche that makes this fit and it didn't improve performance).
312// #[cfg(target_pointer_width = "64")]
313//static_assert_size!(Pointer, 24);
314#[cfg(target_pointer_width = "64")]
315static_assert_size!(Scalar, 32);
316
317impl fmt::Debug for Provenance {
318    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
319        match self {
320            Provenance::Concrete { alloc_id, tag } => {
321                // Forward `alternate` flag to `alloc_id` printing.
322                if f.alternate() {
323                    write!(f, "[{alloc_id:#?}]")?;
324                } else {
325                    write!(f, "[{alloc_id:?}]")?;
326                }
327                // Print Borrow Tracker tag.
328                write!(f, "{tag:?}")?;
329            }
330            Provenance::Wildcard => {
331                write!(f, "[wildcard]")?;
332            }
333        }
334        Ok(())
335    }
336}
337
338impl interpret::Provenance for Provenance {
339    /// We use absolute addresses in the `offset` of a `StrictPointer`.
340    const OFFSET_IS_ADDR: bool = true;
341
342    /// Miri implements wildcard provenance.
343    const WILDCARD: Option<Self> = Some(Provenance::Wildcard);
344
345    fn get_alloc_id(self) -> Option<AllocId> {
346        match self {
347            Provenance::Concrete { alloc_id, .. } => Some(alloc_id),
348            Provenance::Wildcard => None,
349        }
350    }
351
352    fn fmt(ptr: &interpret::Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353        let (prov, addr) = ptr.into_raw_parts(); // offset is absolute address
354        write!(f, "{:#x}", addr.bytes())?;
355        if f.alternate() {
356            write!(f, "{prov:#?}")?;
357        } else {
358            write!(f, "{prov:?}")?;
359        }
360        Ok(())
361    }
362}
363
364impl fmt::Debug for ProvenanceExtra {
365    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366        match self {
367            ProvenanceExtra::Concrete(pid) => write!(f, "{pid:?}"),
368            ProvenanceExtra::Wildcard => write!(f, "<wildcard>"),
369        }
370    }
371}
372
373impl ProvenanceExtra {
374    pub fn and_then<T>(self, f: impl FnOnce(BorTag) -> Option<T>) -> Option<T> {
375        match self {
376            ProvenanceExtra::Concrete(pid) => f(pid),
377            ProvenanceExtra::Wildcard => None,
378        }
379    }
380}
381
382/// Extra per-allocation data
383#[derive(Debug)]
384pub struct AllocExtra<'tcx> {
385    /// Global state of the borrow tracker, if enabled.
386    pub borrow_tracker: Option<borrow_tracker::AllocState>,
387    /// Extra state for data race detection.
388    ///
389    /// Invariant: The enum variant must match the enum variant in the `data_race` field on `MiriMachine`
390    pub data_race: AllocDataRaceHandler,
391    /// A backtrace to where this allocation was allocated.
392    /// As this is recorded for leak reports, it only exists
393    /// if this allocation is leakable. The backtrace is not
394    /// pruned yet; that should be done before printing it.
395    pub backtrace: Option<Vec<FrameInfo<'tcx>>>,
396    /// Synchronization objects like to attach extra data to particular addresses. We store that
397    /// inside the relevant allocation, to ensure that everything is removed when the allocation is
398    /// freed.
399    /// This maps offsets to synchronization-primitive-specific data.
400    pub sync_objs: BTreeMap<Size, Box<dyn SyncObj>>,
401}
402
403// We need a `Clone` impl because the machine passes `Allocation` through `Cow`...
404// but that should never end up actually cloning our `AllocExtra`.
405impl<'tcx> Clone for AllocExtra<'tcx> {
406    fn clone(&self) -> Self {
407        panic!("our allocations should never be cloned");
408    }
409}
410
411impl VisitProvenance for AllocExtra<'_> {
412    fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
413        let AllocExtra { borrow_tracker, data_race, backtrace: _, sync_objs: _ } = self;
414
415        borrow_tracker.visit_provenance(visit);
416        data_race.visit_provenance(visit);
417    }
418}
419
420/// Precomputed layouts of primitive types
421pub struct PrimitiveLayouts<'tcx> {
422    pub unit: TyAndLayout<'tcx>,
423    pub i8: TyAndLayout<'tcx>,
424    pub i16: TyAndLayout<'tcx>,
425    pub i32: TyAndLayout<'tcx>,
426    pub i64: TyAndLayout<'tcx>,
427    pub i128: TyAndLayout<'tcx>,
428    pub isize: TyAndLayout<'tcx>,
429    pub u8: TyAndLayout<'tcx>,
430    pub u16: TyAndLayout<'tcx>,
431    pub u32: TyAndLayout<'tcx>,
432    pub u64: TyAndLayout<'tcx>,
433    pub u128: TyAndLayout<'tcx>,
434    pub usize: TyAndLayout<'tcx>,
435    pub bool: TyAndLayout<'tcx>,
436    pub mut_raw_ptr: TyAndLayout<'tcx>,   // *mut ()
437    pub const_raw_ptr: TyAndLayout<'tcx>, // *const ()
438}
439
440impl<'tcx> PrimitiveLayouts<'tcx> {
441    fn new(layout_cx: LayoutCx<'tcx>) -> Result<Self, &'tcx LayoutError<'tcx>> {
442        let tcx = layout_cx.tcx();
443        let mut_raw_ptr = Ty::new_mut_ptr(tcx, tcx.types.unit);
444        let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
445        Ok(Self {
446            unit: layout_cx.layout_of(tcx.types.unit)?,
447            i8: layout_cx.layout_of(tcx.types.i8)?,
448            i16: layout_cx.layout_of(tcx.types.i16)?,
449            i32: layout_cx.layout_of(tcx.types.i32)?,
450            i64: layout_cx.layout_of(tcx.types.i64)?,
451            i128: layout_cx.layout_of(tcx.types.i128)?,
452            isize: layout_cx.layout_of(tcx.types.isize)?,
453            u8: layout_cx.layout_of(tcx.types.u8)?,
454            u16: layout_cx.layout_of(tcx.types.u16)?,
455            u32: layout_cx.layout_of(tcx.types.u32)?,
456            u64: layout_cx.layout_of(tcx.types.u64)?,
457            u128: layout_cx.layout_of(tcx.types.u128)?,
458            usize: layout_cx.layout_of(tcx.types.usize)?,
459            bool: layout_cx.layout_of(tcx.types.bool)?,
460            mut_raw_ptr: layout_cx.layout_of(mut_raw_ptr)?,
461            const_raw_ptr: layout_cx.layout_of(const_raw_ptr)?,
462        })
463    }
464
465    pub fn uint(&self, size: Size) -> Option<TyAndLayout<'tcx>> {
466        match size.bits() {
467            8 => Some(self.u8),
468            16 => Some(self.u16),
469            32 => Some(self.u32),
470            64 => Some(self.u64),
471            128 => Some(self.u128),
472            _ => None,
473        }
474    }
475
476    pub fn int(&self, size: Size) -> Option<TyAndLayout<'tcx>> {
477        match size.bits() {
478            8 => Some(self.i8),
479            16 => Some(self.i16),
480            32 => Some(self.i32),
481            64 => Some(self.i64),
482            128 => Some(self.i128),
483            _ => None,
484        }
485    }
486}
487
488/// The machine itself.
489///
490/// If you add anything here that stores machine values, remember to update
491/// `visit_all_machine_values`!
492pub struct MiriMachine<'tcx> {
493    // We carry a copy of the global `TyCtxt` for convenience, so methods taking just `&Evaluator` have `tcx` access.
494    pub tcx: TyCtxt<'tcx>,
495
496    /// Global data for borrow tracking.
497    pub borrow_tracker: Option<borrow_tracker::GlobalState>,
498
499    /// Depending on settings, this will be `None`,
500    /// global data for a data race detector,
501    /// or the context required for running in GenMC mode.
502    ///
503    /// Invariant: The enum variant must match the enum variant of `AllocDataRaceHandler` in the `data_race` field of all `AllocExtra`.
504    pub data_race: GlobalDataRaceHandler,
505
506    /// Ptr-int-cast module global data.
507    pub alloc_addresses: alloc_addresses::GlobalState,
508
509    /// Environment variables.
510    pub(crate) env_vars: EnvVars<'tcx>,
511
512    /// Return place of the main function.
513    pub(crate) main_fn_ret_place: Option<MPlaceTy<'tcx>>,
514
515    /// Program arguments (`Option` because we can only initialize them after creating the ecx).
516    /// These are *pointers* to argc/argv because macOS.
517    /// We also need the full command line as one string because of Windows.
518    pub(crate) argc: Option<Pointer>,
519    pub(crate) argv: Option<Pointer>,
520    pub(crate) cmd_line: Option<Pointer>,
521
522    /// TLS state.
523    pub(crate) tls: TlsData<'tcx>,
524
525    /// What should Miri do when an op requires communicating with the host,
526    /// such as accessing host env vars, random number generation, and
527    /// file system access.
528    pub(crate) isolated_op: IsolatedOp,
529
530    /// Whether to enforce the validity invariant.
531    pub(crate) validation: ValidationMode,
532
533    /// The table of file descriptors.
534    pub(crate) fds: shims::FdTable,
535    /// The table of directory descriptors.
536    pub(crate) dirs: shims::DirTable,
537
538    /// Managing file descriptors whose readiness needs to be updated.
539    pub(crate) delayed_readiness_updates: Rc<DelayedReadinessUpdates>,
540
541    /// This machine's monotone clock.
542    pub(crate) monotonic_clock: MonotonicClock,
543
544    /// The set of threads.
545    pub(crate) threads: ThreadManager<'tcx>,
546
547    /// Handles blocking I/O and polling for completion.
548    pub(crate) blocking_io: BlockingIoManager,
549
550    /// Stores which thread is eligible to run on which CPUs.
551    /// This has no effect at all, it is just tracked to produce the correct result
552    /// in `sched_getaffinity`
553    /// This will be `None` when running `#![no_core]` crates.
554    pub(crate) thread_cpu_affinity: Option<FxHashMap<ThreadId, CpuAffinityMask>>,
555
556    /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri.
557    pub(crate) layouts: PrimitiveLayouts<'tcx>,
558
559    /// Allocations that are considered roots of static memory (that may leak).
560    pub(crate) static_roots: Vec<AllocId>,
561
562    /// The `measureme` profiler used to record timing information about
563    /// the emulated program.
564    profiler: Option<measureme::Profiler>,
565    /// Used with `profiler` to cache the `StringId`s for event names
566    /// used with `measureme`.
567    string_cache: FxHashMap<String, measureme::StringId>,
568
569    /// Cache of `Instance` exported under the given `Symbol` name.
570    /// `None` means no `Instance` exported under the given name is found.
571    pub(crate) exported_symbols_cache: RefCell<FxHashMap<Symbol, Option<Instance<'tcx>>>>,
572
573    /// Equivalent setting as RUST_BACKTRACE on encountering an error.
574    pub(crate) backtrace_style: BacktraceStyle,
575
576    /// Crates which are considered user-relevant for the purposes of error reporting.
577    pub(crate) user_relevant_crates: Vec<CrateNum>,
578
579    /// Mapping extern static names to their pointer.
580    pub(crate) extern_statics: FxHashMap<Symbol, StrictPointer>,
581    /// Statics with `import_linkage` have an extra indirection
582    /// (<https://github.com/rust-lang/rust/issues/156468>) so we keep them in a separate table.
583    pub(crate) extern_statics_imports: FxHashMap<Symbol, StrictPointer>,
584    /// A pointer to the allocation we provide for non-existent weak symbols.
585    pub(crate) extern_static_weak_import_default: Option<StrictPointer>,
586
587    /// The random number generator used for resolving non-determinism.
588    /// Needs to be queried by ptr_to_int, hence needs interior mutability.
589    pub(crate) rng: RefCell<StdRng>,
590
591    /// The allocator used for the machine's `AllocBytes` in native-libs mode.
592    pub(crate) allocator: Option<Rc<RefCell<crate::alloc::isolated_alloc::IsolatedAlloc>>>,
593
594    /// The allocation IDs to report when they are being allocated
595    /// (helps for debugging memory leaks and use after free bugs).
596    pub(crate) tracked_alloc_ids: FxHashSet<AllocId>,
597    /// For the tracked alloc ids, also report read/write accesses.
598    track_alloc_accesses: bool,
599
600    /// Controls whether alignment of memory accesses is being checked.
601    pub(crate) check_alignment: AlignmentCheck,
602
603    /// Failure rate of compare_exchange_weak, between 0.0 and 1.0
604    pub(crate) cmpxchg_weak_failure_rate: f64,
605
606    /// The probability of the active thread being preempted at the end of each basic block.
607    pub(crate) preemption_rate: f64,
608
609    /// If `Some`, we will report the current stack every N basic blocks.
610    pub(crate) report_progress: Option<u32>,
611    // The total number of blocks that have been executed.
612    pub(crate) basic_block_count: u64,
613
614    /// Handle of the optional shared object file for native functions.
615    #[cfg(all(feature = "native-lib", unix))]
616    pub native_lib: Vec<(libloading::Library, std::path::PathBuf)>,
617    #[cfg(not(all(feature = "native-lib", unix)))]
618    pub native_lib: Vec<!>,
619    /// A memory location for exchanging the current `ecx` pointer with native code.
620    #[cfg(all(feature = "native-lib", unix))]
621    pub native_lib_ecx_interchange: &'static Cell<usize>,
622
623    /// Run a garbage collector for BorTags every N basic blocks.
624    pub(crate) gc_interval: u32,
625    /// The number of blocks that passed since the last BorTag GC pass.
626    pub(crate) since_gc: u32,
627
628    /// The number of CPUs to be reported by miri.
629    pub(crate) num_cpus: u32,
630
631    /// Determines Miri's page size and associated values
632    pub(crate) page_size: u64,
633    pub(crate) stack_addr: u64,
634    pub(crate) stack_size: u64,
635
636    /// Whether to collect a backtrace when each allocation is created, just in case it leaks.
637    pub(crate) collect_leak_backtraces: bool,
638
639    /// The spans we will use to report where an allocation was created and deallocated in
640    /// diagnostics.
641    pub(crate) allocation_spans: RefCell<FxHashMap<AllocId, (Span, Option<Span>)>>,
642
643    /// For each allocation, an offset inside that allocation that was deemed aligned even for
644    /// symbolic alignment checks. This cannot be stored in `AllocExtra` since it needs to be
645    /// tracked for vtables and function allocations as well as regular allocations.
646    ///
647    /// Invariant: the promised alignment will never be less than the native alignment of the
648    /// allocation.
649    pub(crate) symbolic_alignment: RefCell<FxHashMap<AllocId, (Size, Align)>>,
650
651    /// A cache of "data range" computations for unions (i.e., the offsets of non-padding bytes).
652    union_data_ranges: FxHashMap<Ty<'tcx>, RangeSet>,
653
654    /// Caches the sanity-checks for various pthread primitives.
655    pub(crate) pthread_mutex_sanity: Cell<bool>,
656    pub(crate) pthread_rwlock_sanity: Cell<bool>,
657    pub(crate) pthread_condvar_sanity: Cell<bool>,
658
659    /// (Foreign) symbols that are synthesized as part of the allocator shim: the key indicates the
660    /// name of the symbol being synthesized; the value indicates whether this should invoke some
661    /// other symbol or whether this has special allocator semantics.
662    pub(crate) allocator_shim_symbols: FxHashMap<Symbol, Either<Symbol, SpecialAllocatorMethod>>,
663    /// Cache for `mangle_internal_symbol`.
664    pub(crate) mangle_internal_symbol_cache: FxHashMap<&'static str, String>,
665
666    /// Whether floating-point operations can behave non-deterministically.
667    pub float_nondet: bool,
668    /// Whether floating-point operations can have a non-deterministic rounding error.
669    pub float_rounding_error: FloatRoundingErrorMode,
670
671    /// Whether Miri artificially introduces short reads/writes on file descriptors.
672    pub short_fd_operations: bool,
673}
674
675impl<'tcx> MiriMachine<'tcx> {
676    /// Create a new MiriMachine.
677    ///
678    /// Invariant: `genmc_ctx.is_some() == config.genmc_config.is_some()`
679    pub(crate) fn new(
680        config: &MiriConfig,
681        layout_cx: LayoutCx<'tcx>,
682        genmc_ctx: Option<Rc<GenmcCtx>>,
683    ) -> Self {
684        let tcx = layout_cx.tcx();
685        let user_relevant_crates = Self::get_user_relevant_crates(tcx, config);
686        let layouts =
687            PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types");
688        let profiler = config.measureme_out.as_ref().map(|out| {
689            let crate_name =
690                tcx.sess.opts.crate_name.clone().unwrap_or_else(|| "unknown-crate".to_string());
691            let pid = process::id();
692            // We adopt the same naming scheme for the profiler output that rustc uses. In rustc,
693            // the PID is padded so that the nondeterministic value of the PID does not spread
694            // nondeterminism to the allocator. In Miri we are not aiming for such performance
695            // control, we just pad for consistency with rustc.
696            let filename = format!("{crate_name}-{pid:07}");
697            let path = Path::new(out).join(filename);
698            measureme::Profiler::new(path).expect("Couldn't create `measureme` profiler")
699        });
700        let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
701        let borrow_tracker = config.borrow_tracker.map(|bt| bt.instantiate_global_state(config));
702        let data_race = if config.genmc_config.is_some() {
703            // `genmc_ctx` persists across executions, so we don't create a new one here.
704            GlobalDataRaceHandler::Genmc(genmc_ctx.unwrap())
705        } else if config.data_race_detector {
706            GlobalDataRaceHandler::Vclocks(Box::new(data_race::GlobalState::new(config)))
707        } else {
708            GlobalDataRaceHandler::None
709        };
710        // Determine page size, stack address, and stack size.
711        // These values are mostly meaningless, but the stack address is also where we start
712        // allocating physical integer addresses for all allocations.
713        let page_size = if let Some(page_size) = config.page_size {
714            page_size
715        } else {
716            let target = &tcx.sess.target;
717            match target.arch {
718                Arch::Wasm32 | Arch::Wasm64 => 64 * 1024, // https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances
719                Arch::AArch64 if target.is_like_darwin => {
720                    // No "definitive" source, but see:
721                    // https://www.wwdcnotes.com/notes/wwdc20/10214/
722                    // https://github.com/ziglang/zig/issues/11308 etc.
723                    16 * 1024
724                }
725                _ => 4 * 1024,
726            }
727        };
728        // On 16bit targets, 32 pages is more than the entire address space!
729        let stack_addr = if tcx.pointer_size().bits() < 32 { page_size } else { page_size * 32 };
730        let stack_size =
731            if tcx.pointer_size().bits() < 32 { page_size * 4 } else { page_size * 16 };
732        assert!(
733            usize::try_from(config.num_cpus).unwrap() <= cpu_affinity::MAX_CPUS,
734            "miri only supports up to {} CPUs, but {} were configured",
735            cpu_affinity::MAX_CPUS,
736            config.num_cpus
737        );
738        let threads = ThreadManager::new(config);
739        let thread_cpu_affinity =
740            if matches!(&tcx.sess.target.os, Os::Linux | Os::FreeBsd | Os::Android)
741                && !is_no_core(tcx)
742            {
743                let mut affinity = FxHashMap::default();
744                affinity.insert(
745                    threads.active_thread(),
746                    CpuAffinityMask::new(&layout_cx, config.num_cpus),
747                );
748                Some(affinity)
749            } else {
750                None
751            };
752        let blocking_io = BlockingIoManager::new(config.isolated_op == IsolatedOp::Allow)
753            .expect("Couldn't create poll instance");
754        let alloc_addresses =
755            RefCell::new(alloc_addresses::GlobalStateInner::new(config, stack_addr, tcx));
756
757        MiriMachine {
758            tcx,
759            borrow_tracker,
760            data_race,
761            alloc_addresses,
762            // `env_vars` depends on a full interpreter so we cannot properly initialize it yet.
763            env_vars: EnvVars::default(),
764            main_fn_ret_place: None,
765            argc: None,
766            argv: None,
767            cmd_line: None,
768            tls: TlsData::default(),
769            isolated_op: config.isolated_op,
770            validation: config.validation,
771            fds: shims::FdTable::init(config.mute_stdout_stderr),
772            delayed_readiness_updates: Rc::new(DelayedReadinessUpdates::default()),
773            dirs: Default::default(),
774            layouts,
775            threads,
776            thread_cpu_affinity,
777            blocking_io,
778            static_roots: Vec::new(),
779            profiler,
780            string_cache: Default::default(),
781            exported_symbols_cache: RefCell::new(FxHashMap::default()),
782            backtrace_style: config.backtrace_style,
783            user_relevant_crates,
784            extern_statics: FxHashMap::default(),
785            extern_statics_imports: FxHashMap::default(),
786            extern_static_weak_import_default: None,
787            rng: RefCell::new(rng),
788            allocator: (!config.native_lib.is_empty())
789                .then(|| Rc::new(RefCell::new(crate::alloc::isolated_alloc::IsolatedAlloc::new()))),
790            tracked_alloc_ids: config.tracked_alloc_ids.clone(),
791            track_alloc_accesses: config.track_alloc_accesses,
792            check_alignment: config.check_alignment,
793            cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate,
794            preemption_rate: config.preemption_rate,
795            report_progress: config.report_progress,
796            basic_block_count: 0,
797            monotonic_clock: MonotonicClock::new(config.isolated_op == IsolatedOp::Allow),
798            #[cfg(all(feature = "native-lib", unix))]
799            native_lib: config.native_lib.iter().map(|lib_file_path| {
800                let host_triple = rustc_session::config::host_tuple();
801                let target_triple = tcx.sess.opts.target_triple.tuple();
802                // Check if host target == the session target.
803                if host_triple != target_triple {
804                    panic!(
805                        "calling native C functions in linked .so file requires host and target to be the same: \
806                        host={host_triple}, target={target_triple}",
807                    );
808                }
809                // Note: it is the user's responsibility to provide a correct SO file.
810                // WATCH OUT: If an invalid/incorrect SO file is specified, this can cause
811                // undefined behaviour in Miri itself!
812                (
813                    unsafe {
814                        libloading::Library::new(lib_file_path)
815                            .expect("failed to read specified extern shared object file")
816                    },
817                    lib_file_path.clone(),
818                )
819            }).collect(),
820            #[cfg(all(feature = "native-lib", unix))]
821            native_lib_ecx_interchange: Box::leak(Box::new(Cell::new(0))),
822            #[cfg(not(all(feature = "native-lib", unix)))]
823            native_lib: config.native_lib.iter().map(|_| {
824                panic!("calling functions from native libraries via FFI is not supported in this build of Miri")
825            }).collect(),
826            gc_interval: config.gc_interval,
827            since_gc: 0,
828            num_cpus: config.num_cpus,
829            page_size,
830            stack_addr,
831            stack_size,
832            collect_leak_backtraces: config.collect_leak_backtraces,
833            allocation_spans: RefCell::new(FxHashMap::default()),
834            symbolic_alignment: RefCell::new(FxHashMap::default()),
835            union_data_ranges: FxHashMap::default(),
836            pthread_mutex_sanity: Cell::new(false),
837            pthread_rwlock_sanity: Cell::new(false),
838            pthread_condvar_sanity: Cell::new(false),
839            allocator_shim_symbols: Self::allocator_shim_symbols(tcx),
840            mangle_internal_symbol_cache: Default::default(),
841            float_nondet: config.float_nondet,
842            float_rounding_error: config.float_rounding_error,
843            short_fd_operations: config.short_fd_operations,
844        }
845    }
846
847    fn allocator_shim_symbols(
848        tcx: TyCtxt<'tcx>,
849    ) -> FxHashMap<Symbol, Either<Symbol, SpecialAllocatorMethod>> {
850        use rustc_codegen_ssa::base::allocator_shim_contents;
851
852        // codegen uses `allocator_kind_for_codegen` here, but that's only needed to deal with
853        // dylibs which we do not support.
854        let Some(kind) = tcx.allocator_kind(()) else {
855            return Default::default();
856        };
857        let methods = allocator_shim_contents(tcx, kind);
858        let mut symbols = FxHashMap::default();
859        for method in methods {
860            let from_name = Symbol::intern(&mangle_internal_symbol(
861                tcx,
862                &allocator::global_fn_name(method.name),
863            ));
864            let to = match method.special {
865                Some(special) => Either::Right(special),
866                None =>
867                    Either::Left(Symbol::intern(&mangle_internal_symbol(
868                        tcx,
869                        &allocator::default_fn_name(method.name),
870                    ))),
871            };
872            symbols.try_insert(from_name, to).unwrap();
873        }
874        symbols
875    }
876
877    /// Retrieve the list of user-relevant crates based on MIRI_LOCAL_CRATES as set by cargo-miri,
878    /// and extra crates set in the config.
879    fn get_user_relevant_crates(tcx: TyCtxt<'_>, config: &MiriConfig) -> Vec<CrateNum> {
880        // Convert the local crate names from the passed-in config into CrateNums so that they can
881        // be looked up quickly during execution
882        let local_crate_names = std::env::var("MIRI_LOCAL_CRATES")
883            .map(|crates| crates.split(',').map(|krate| krate.to_string()).collect::<Vec<_>>())
884            .unwrap_or_default();
885        let mut local_crates = Vec::new();
886        for &crate_num in tcx.crates(()) {
887            let name = tcx.crate_name(crate_num);
888            let name = name.as_str();
889            if local_crate_names
890                .iter()
891                .chain(&config.user_relevant_crates)
892                .any(|local_name| local_name == name)
893            {
894                local_crates.push(crate_num);
895            }
896        }
897        local_crates
898    }
899
900    pub(crate) fn late_init(
901        ecx: &mut MiriInterpCx<'tcx>,
902        config: &MiriConfig,
903        on_main_stack_empty: StackEmptyCallback<'tcx>,
904    ) -> InterpResult<'tcx> {
905        EnvVars::init(ecx, config)?;
906        MiriMachine::init_extern_statics(ecx)?;
907        ThreadManager::init(ecx, on_main_stack_empty);
908        interp_ok(())
909    }
910
911    pub(crate) fn communicate(&self) -> bool {
912        self.isolated_op == IsolatedOp::Allow
913    }
914
915    /// Check whether the stack frame that this `FrameInfo` refers to is part of a local crate.
916    pub(crate) fn is_local(&self, instance: ty::Instance<'tcx>) -> bool {
917        let def_id = instance.def_id();
918        def_id.is_local() || self.user_relevant_crates.contains(&def_id.krate)
919    }
920
921    /// Called when the interpreter is going to shut down abnormally, such as due to a Ctrl-C.
922    pub(crate) fn handle_abnormal_termination(&mut self) {
923        // All strings in the profile data are stored in a single string table which is not
924        // written to disk until the profiler is dropped. If the interpreter exits without dropping
925        // the profiler, it is not possible to interpret the profile data and all measureme tools
926        // will panic when given the file.
927        drop(self.profiler.take());
928    }
929
930    pub(crate) fn page_align(&self) -> Align {
931        Align::from_bytes(self.page_size).unwrap()
932    }
933
934    pub(crate) fn allocated_span(&self, alloc_id: AllocId) -> Option<SpanData> {
935        self.allocation_spans
936            .borrow()
937            .get(&alloc_id)
938            .map(|(allocated, _deallocated)| allocated.data())
939    }
940
941    pub(crate) fn deallocated_span(&self, alloc_id: AllocId) -> Option<SpanData> {
942        self.allocation_spans
943            .borrow()
944            .get(&alloc_id)
945            .and_then(|(_allocated, deallocated)| *deallocated)
946            .map(Span::data)
947    }
948
949    fn init_allocation(
950        ecx: &MiriInterpCx<'tcx>,
951        id: AllocId,
952        kind: MemoryKind,
953        size: Size,
954        align: Align,
955    ) -> InterpResult<'tcx, AllocExtra<'tcx>> {
956        if ecx.machine.tracked_alloc_ids.contains(&id) {
957            ecx.emit_diagnostic(NonHaltingDiagnostic::TrackingAlloc(id, size, align));
958        }
959
960        let borrow_tracker = ecx
961            .machine
962            .borrow_tracker
963            .as_ref()
964            .map(|bt| bt.borrow_mut().new_allocation(id, size, kind, &ecx.machine));
965
966        let data_race = match &ecx.machine.data_race {
967            GlobalDataRaceHandler::None => AllocDataRaceHandler::None,
968            GlobalDataRaceHandler::Vclocks(data_race) =>
969                AllocDataRaceHandler::Vclocks(
970                    data_race::AllocState::new_allocation(
971                        data_race,
972                        &ecx.machine.threads,
973                        size,
974                        kind,
975                        ecx.machine.current_user_relevant_span(),
976                    ),
977                    data_race.weak_memory.then(weak_memory::AllocState::new_allocation),
978                ),
979            GlobalDataRaceHandler::Genmc(_genmc_ctx) => {
980                // GenMC learns about new allocations directly from the alloc_addresses module,
981                // since it has to be able to control the address at which they are placed.
982                AllocDataRaceHandler::Genmc
983            }
984        };
985
986        // If an allocation is leaked, we want to report a backtrace to indicate where it was
987        // allocated. We don't need to record a backtrace for allocations which are allowed to
988        // leak.
989        let backtrace = if kind.may_leak() || !ecx.machine.collect_leak_backtraces {
990            None
991        } else {
992            Some(ecx.generate_stacktrace())
993        };
994
995        if matches!(kind, MemoryKind::Machine(kind) if kind.should_save_allocation_span()) {
996            ecx.machine
997                .allocation_spans
998                .borrow_mut()
999                .insert(id, (ecx.machine.current_user_relevant_span(), None));
1000        }
1001
1002        interp_ok(AllocExtra {
1003            borrow_tracker,
1004            data_race,
1005            backtrace,
1006            sync_objs: BTreeMap::default(),
1007        })
1008    }
1009}
1010
1011impl VisitProvenance for MiriMachine<'_> {
1012    fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
1013        #[rustfmt::skip]
1014        let MiriMachine {
1015            threads,
1016            thread_cpu_affinity: _,
1017            tls,
1018            env_vars,
1019            main_fn_ret_place,
1020            argc,
1021            argv,
1022            cmd_line,
1023            extern_statics,
1024            extern_statics_imports,
1025            extern_static_weak_import_default,
1026            dirs,
1027            borrow_tracker,
1028            data_race,
1029            alloc_addresses,
1030            fds,
1031            blocking_io:_,
1032            delayed_readiness_updates: _,
1033            tcx: _,
1034            isolated_op: _,
1035            validation: _,
1036            monotonic_clock: _,
1037            layouts: _,
1038            static_roots: _,
1039            profiler: _,
1040            string_cache: _,
1041            exported_symbols_cache: _,
1042            backtrace_style: _,
1043            user_relevant_crates: _,
1044            rng: _,
1045            allocator: _,
1046            tracked_alloc_ids: _,
1047            track_alloc_accesses: _,
1048            check_alignment: _,
1049            cmpxchg_weak_failure_rate: _,
1050            preemption_rate: _,
1051            report_progress: _,
1052            basic_block_count: _,
1053            native_lib: _,
1054            #[cfg(all(feature = "native-lib", unix))]
1055            native_lib_ecx_interchange: _,
1056            gc_interval: _,
1057            since_gc: _,
1058            num_cpus: _,
1059            page_size: _,
1060            stack_addr: _,
1061            stack_size: _,
1062            collect_leak_backtraces: _,
1063            allocation_spans: _,
1064            symbolic_alignment: _,
1065            union_data_ranges: _,
1066            pthread_mutex_sanity: _,
1067            pthread_rwlock_sanity: _,
1068            pthread_condvar_sanity: _,
1069            allocator_shim_symbols: _,
1070            mangle_internal_symbol_cache: _,
1071            float_nondet: _,
1072            float_rounding_error: _,
1073            short_fd_operations: _,
1074        } = self;
1075
1076        threads.visit_provenance(visit);
1077        tls.visit_provenance(visit);
1078        env_vars.visit_provenance(visit);
1079        dirs.visit_provenance(visit);
1080        fds.visit_provenance(visit);
1081        data_race.visit_provenance(visit);
1082        borrow_tracker.visit_provenance(visit);
1083        alloc_addresses.visit_provenance(visit);
1084        main_fn_ret_place.visit_provenance(visit);
1085        argc.visit_provenance(visit);
1086        argv.visit_provenance(visit);
1087        cmd_line.visit_provenance(visit);
1088        extern_static_weak_import_default.visit_provenance(visit);
1089        extern_statics.visit_provenance(visit);
1090        extern_statics_imports.visit_provenance(visit);
1091    }
1092}
1093
1094/// A rustc InterpCx for Miri.
1095pub type MiriInterpCx<'tcx> = InterpCx<'tcx, MiriMachine<'tcx>>;
1096
1097/// A little trait that's useful to be inherited by extension traits.
1098pub trait MiriInterpCxExt<'tcx> {
1099    fn eval_context_ref<'a>(&'a self) -> &'a MiriInterpCx<'tcx>;
1100    fn eval_context_mut<'a>(&'a mut self) -> &'a mut MiriInterpCx<'tcx>;
1101}
1102impl<'tcx> MiriInterpCxExt<'tcx> for MiriInterpCx<'tcx> {
1103    #[inline(always)]
1104    fn eval_context_ref(&self) -> &MiriInterpCx<'tcx> {
1105        self
1106    }
1107    #[inline(always)]
1108    fn eval_context_mut(&mut self) -> &mut MiriInterpCx<'tcx> {
1109        self
1110    }
1111}
1112
1113/// Machine hook implementations.
1114impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
1115    type MemoryKind = MiriMemoryKind;
1116    type ExtraFnVal = DynSym;
1117
1118    type FrameExtra = FrameExtra<'tcx>;
1119    type AllocExtra = AllocExtra<'tcx>;
1120
1121    type Provenance = Provenance;
1122    type ProvenanceExtra = ProvenanceExtra;
1123    type Bytes = MiriAllocBytes;
1124
1125    type MemoryMap =
1126        MonoHashMap<AllocId, (MemoryKind, Allocation<Provenance, Self::AllocExtra, Self::Bytes>)>;
1127
1128    const GLOBAL_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::Global);
1129
1130    const PANIC_ON_ALLOC_FAIL: bool = false;
1131
1132    #[inline(always)]
1133    fn enforce_alignment(ecx: &MiriInterpCx<'tcx>) -> bool {
1134        ecx.machine.check_alignment != AlignmentCheck::None
1135    }
1136
1137    #[inline(always)]
1138    fn alignment_check(
1139        ecx: &MiriInterpCx<'tcx>,
1140        alloc_id: AllocId,
1141        alloc_align: Align,
1142        alloc_kind: AllocKind,
1143        offset: Size,
1144        align: Align,
1145    ) -> Option<Misalignment> {
1146        if ecx.machine.check_alignment != AlignmentCheck::Symbolic {
1147            // Just use the built-in check.
1148            return None;
1149        }
1150        if alloc_kind != AllocKind::LiveData {
1151            // Can't have any extra info here.
1152            return None;
1153        }
1154        // Let's see which alignment we have been promised for this allocation.
1155        let (promised_offset, promised_align) = ecx
1156            .machine
1157            .symbolic_alignment
1158            .borrow()
1159            .get(&alloc_id)
1160            .copied()
1161            .unwrap_or((Size::ZERO, alloc_align));
1162        if promised_align < align {
1163            // Definitely not enough.
1164            Some(Misalignment { has: promised_align, required: align })
1165        } else {
1166            // What's the offset between us and the promised alignment?
1167            let distance = offset.bytes().wrapping_sub(promised_offset.bytes());
1168            // That must also be aligned.
1169            if distance.is_multiple_of(align.bytes()) {
1170                // All looking good!
1171                None
1172            } else {
1173                // The biggest power of two through which `distance` is divisible.
1174                let distance_pow2 = 1 << distance.trailing_zeros();
1175                Some(Misalignment {
1176                    has: Align::from_bytes(distance_pow2).unwrap(),
1177                    required: align,
1178                })
1179            }
1180        }
1181    }
1182
1183    #[inline(always)]
1184    fn enforce_validity(ecx: &MiriInterpCx<'tcx>, _layout: TyAndLayout<'tcx>) -> bool {
1185        ecx.machine.validation != ValidationMode::No
1186    }
1187    #[inline(always)]
1188    fn enforce_validity_recursively(
1189        ecx: &InterpCx<'tcx, Self>,
1190        _layout: TyAndLayout<'tcx>,
1191    ) -> bool {
1192        ecx.machine.validation == ValidationMode::Deep
1193    }
1194
1195    #[inline(always)]
1196    fn ignore_optional_overflow_checks(ecx: &MiriInterpCx<'tcx>) -> bool {
1197        !ecx.tcx.sess.overflow_checks()
1198    }
1199
1200    fn check_fn_target_features(
1201        ecx: &MiriInterpCx<'tcx>,
1202        instance: ty::Instance<'tcx>,
1203    ) -> InterpResult<'tcx> {
1204        let attrs = ecx.tcx.codegen_instance_attrs(instance.def);
1205        if attrs
1206            .target_features
1207            .iter()
1208            .any(|feature| !ecx.tcx.sess.internal_target_features.contains(&feature.name))
1209        {
1210            let unavailable = attrs
1211                .target_features
1212                .iter()
1213                .filter(|&feature| {
1214                    feature.kind != TargetFeatureKind::Implied
1215                        && !ecx.tcx.sess.internal_target_features.contains(&feature.name)
1216                })
1217                .fold(String::new(), |mut s, feature| {
1218                    if !s.is_empty() {
1219                        s.push_str(", ");
1220                    }
1221                    s.push_str(feature.name.as_str());
1222                    s
1223                });
1224            let msg = format!(
1225                "calling a function that requires unavailable target features: {unavailable}"
1226            );
1227            // On WASM, this is not UB, but instead gets rejected during validation of the module
1228            // (see #84988).
1229            if ecx.tcx.sess.target.is_like_wasm {
1230                throw_machine_stop!(TerminationInfo::Abort(msg));
1231            } else {
1232                throw_ub_format!("{msg}");
1233            }
1234        }
1235        interp_ok(())
1236    }
1237
1238    #[inline(always)]
1239    fn find_mir_or_eval_fn(
1240        ecx: &mut MiriInterpCx<'tcx>,
1241        instance: ty::Instance<'tcx>,
1242        abi: &FnAbi<'tcx, Ty<'tcx>>,
1243        args: &[FnArg<'tcx>],
1244        dest: &PlaceTy<'tcx>,
1245        ret: Option<mir::BasicBlock>,
1246        unwind: mir::UnwindAction,
1247    ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> {
1248        // For foreign items, try to see if we can emulate them.
1249        if ecx.tcx.is_foreign_item(instance.def_id()) {
1250            let _trace = enter_trace_span!("emulate_foreign_item");
1251            // An external function call that does not have a MIR body. We either find MIR elsewhere
1252            // or emulate its effect.
1253            // This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need
1254            // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the
1255            // foreign function
1256            // Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
1257            let args = MiriInterpCx::copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit?
1258            let link_name = Symbol::intern(ecx.tcx.symbol_name(instance).name);
1259            return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
1260        }
1261
1262        if ecx.machine.data_race.as_genmc_ref().is_some()
1263            && ecx.genmc_intercept_function(instance, args, dest)?
1264        {
1265            ecx.return_to_block(ret)?;
1266            return interp_ok(None);
1267        }
1268
1269        // Otherwise, load the MIR.
1270        let _trace = enter_trace_span!("load_mir");
1271        interp_ok(Some((ecx.load_mir(instance.def, None)?, instance)))
1272    }
1273
1274    #[inline(always)]
1275    fn call_extra_fn(
1276        ecx: &mut MiriInterpCx<'tcx>,
1277        fn_val: DynSym,
1278        abi: &FnAbi<'tcx, Ty<'tcx>>,
1279        args: &[FnArg<'tcx>],
1280        dest: &PlaceTy<'tcx>,
1281        ret: Option<mir::BasicBlock>,
1282        unwind: mir::UnwindAction,
1283    ) -> InterpResult<'tcx> {
1284        let args = MiriInterpCx::copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit?
1285        ecx.emulate_dyn_sym(fn_val, abi, &args, dest, ret, unwind)
1286    }
1287
1288    #[inline(always)]
1289    fn call_intrinsic(
1290        ecx: &mut MiriInterpCx<'tcx>,
1291        instance: ty::Instance<'tcx>,
1292        args: &[OpTy<'tcx>],
1293        dest: &PlaceTy<'tcx>,
1294        ret: Option<mir::BasicBlock>,
1295        unwind: mir::UnwindAction,
1296    ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
1297        ecx.call_intrinsic(instance, args, dest, ret, unwind)
1298    }
1299
1300    #[inline(always)]
1301    fn call_llvm_intrinsic(
1302        ecx: &mut MiriInterpCx<'tcx>,
1303        instance: ty::Instance<'tcx>,
1304        args: &[OpTy<'tcx>],
1305        dest: &PlaceTy<'tcx>,
1306        ret: Option<mir::BasicBlock>,
1307    ) -> InterpResult<'tcx, ()> {
1308        ecx.call_llvm_intrinsic(instance, args, dest, ret)
1309    }
1310
1311    #[inline(always)]
1312    fn assert_panic(
1313        ecx: &mut MiriInterpCx<'tcx>,
1314        msg: &mir::AssertMessage<'tcx>,
1315        unwind: mir::UnwindAction,
1316    ) -> InterpResult<'tcx> {
1317        ecx.assert_panic(msg, unwind)
1318    }
1319
1320    fn panic_nounwind(ecx: &mut InterpCx<'tcx, Self>, msg: &str) -> InterpResult<'tcx> {
1321        ecx.start_panic_nounwind(msg)
1322    }
1323
1324    fn unwind_terminate(
1325        ecx: &mut InterpCx<'tcx, Self>,
1326        reason: mir::UnwindTerminateReason,
1327    ) -> InterpResult<'tcx> {
1328        // Call the lang item.
1329        let panic = ecx.tcx.lang_items().get(reason.lang_item()).unwrap();
1330        let panic = ty::Instance::mono(ecx.tcx.tcx, panic);
1331        ecx.call_function(
1332            panic,
1333            ExternAbi::Rust,
1334            &[],
1335            None,
1336            ReturnContinuation::Goto { ret: None, unwind: mir::UnwindAction::Unreachable },
1337        )?;
1338        interp_ok(())
1339    }
1340
1341    #[inline(always)]
1342    fn binary_ptr_op(
1343        ecx: &MiriInterpCx<'tcx>,
1344        bin_op: mir::BinOp,
1345        left: &ImmTy<'tcx>,
1346        right: &ImmTy<'tcx>,
1347    ) -> InterpResult<'tcx, ImmTy<'tcx>> {
1348        ecx.binary_ptr_op(bin_op, left, right)
1349    }
1350
1351    fn atomic_load(
1352        ecx: &MiriInterpCx<'tcx>,
1353        place: &MPlaceTy<'tcx>,
1354        ordering: AtomicOrdering,
1355    ) -> InterpResult<'tcx, Scalar> {
1356        ecx.read_scalar_atomic(place, AtomicReadOrd::from(ordering))
1357    }
1358
1359    fn atomic_store(
1360        ecx: &mut MiriInterpCx<'tcx>,
1361        place: &MPlaceTy<'tcx>,
1362        val: &ImmTy<'tcx>,
1363        ordering: AtomicOrdering,
1364    ) -> InterpResult<'tcx> {
1365        ecx.write_scalar_atomic(val.to_scalar(), place, AtomicWriteOrd::from(ordering))
1366    }
1367
1368    fn atomic_rmw(
1369        ecx: &mut MiriInterpCx<'tcx>,
1370        place: &MPlaceTy<'tcx>,
1371        op: AtomicRmwOp,
1372        operand: &ImmTy<'tcx>,
1373        ordering: AtomicOrdering,
1374    ) -> InterpResult<'tcx, Scalar> {
1375        ecx.atomic_rmw(place, operand, op, AtomicRwOrd::from(ordering))
1376    }
1377
1378    fn atomic_compare_exchange(
1379        ecx: &mut MiriInterpCx<'tcx>,
1380        place: &MPlaceTy<'tcx>,
1381        expected_old: &ImmTy<'tcx>,
1382        new: &ImmTy<'tcx>,
1383        can_fail_spuriously: bool,
1384        success_ordering: AtomicOrdering,
1385        failure_ordering: AtomicOrdering,
1386    ) -> InterpResult<'tcx, (Scalar, bool)> {
1387        ecx.atomic_compare_exchange(
1388            place,
1389            expected_old,
1390            new.to_scalar(),
1391            AtomicRwOrd::from(success_ordering),
1392            AtomicReadOrd::from(failure_ordering),
1393            can_fail_spuriously,
1394        )
1395    }
1396
1397    fn atomic_fence(
1398        ecx: &MiriInterpCx<'tcx>,
1399        ordering: AtomicOrdering,
1400        singlethread: bool,
1401    ) -> InterpResult<'tcx> {
1402        if singlethread {
1403            // We don't support signal handlers or interrupts so this is a NOP.
1404            return interp_ok(());
1405        }
1406        ecx.atomic_fence(AtomicFenceOrd::from(ordering))
1407    }
1408
1409    #[inline(always)]
1410    fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(
1411        ecx: &InterpCx<'tcx, Self>,
1412        inputs: &[F1],
1413    ) -> F2 {
1414        ecx.generate_nan(inputs)
1415    }
1416
1417    #[inline(always)]
1418    fn apply_float_nondet(
1419        ecx: &mut InterpCx<'tcx, Self>,
1420        val: ImmTy<'tcx>,
1421    ) -> InterpResult<'tcx, ImmTy<'tcx>> {
1422        crate::math::apply_random_float_error_to_imm(ecx, val, 4)
1423    }
1424
1425    #[inline(always)]
1426    fn equal_float_min_max<F: Float>(ecx: &MiriInterpCx<'tcx>, a: F, b: F) -> F {
1427        ecx.equal_float_min_max(a, b)
1428    }
1429
1430    #[inline(always)]
1431    fn float_fuse_mul_add(ecx: &InterpCx<'tcx, Self>) -> bool {
1432        ecx.machine.float_nondet && ecx.machine.rng.borrow_mut().random()
1433    }
1434
1435    #[inline(always)]
1436    fn runtime_checks(
1437        ecx: &InterpCx<'tcx, Self>,
1438        r: mir::RuntimeChecks,
1439    ) -> InterpResult<'tcx, bool> {
1440        interp_ok(r.value(ecx.tcx.sess))
1441    }
1442
1443    #[inline(always)]
1444    fn thread_local_static_pointer(
1445        ecx: &mut MiriInterpCx<'tcx>,
1446        def_id: DefId,
1447    ) -> InterpResult<'tcx, StrictPointer> {
1448        ecx.get_or_create_thread_local_alloc(def_id)
1449    }
1450
1451    fn extern_static_pointer(
1452        ecx: &MiriInterpCx<'tcx>,
1453        def_id: DefId,
1454    ) -> InterpResult<'tcx, StrictPointer> {
1455        let link_name = Symbol::intern(ecx.tcx.symbol_name(Instance::mono(*ecx.tcx, def_id)).name);
1456        let def_ty = ecx.tcx.type_of(def_id).instantiate_identity().skip_norm_wip();
1457        let extern_decl_layout =
1458            ecx.tcx.layout_of(ecx.typing_env().as_query_input(def_ty)).unwrap();
1459
1460        // Look up the `ptr` in the right map, depending on whether this is an "import"
1461        // static or a real one.
1462        let ptr = match ecx.tcx.codegen_fn_attrs(def_id).import_linkage {
1463            None => ecx.machine.extern_statics.get(&link_name),
1464            Some(_) => ecx.machine.extern_statics_imports.get(&link_name),
1465        };
1466        if let Some(&ptr) = ptr {
1467            ecx.check_shim_symbol_clash(link_name)?;
1468            // Various parts of the engine rely on `get_alloc_info` for size and alignment
1469            // information. That uses the type information of this static.
1470            // Make sure it matches the Miri allocation for this.
1471            let Provenance::Concrete { alloc_id, .. } = ptr.provenance else {
1472                panic!("extern_statics cannot contain wildcards")
1473            };
1474            let info = ecx.get_alloc_info(alloc_id);
1475            if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align {
1476                throw_unsup_format!(
1477                    "extern static `{link_name}` has been declared as `{krate}::{name}` \
1478                    with a size of {decl_size} bytes and alignment of {decl_align} bytes, \
1479                    but Miri emulates it via an extern static shim \
1480                    with a size of {shim_size} bytes and alignment of {shim_align} bytes",
1481                    name = ecx.tcx.def_path_str(def_id),
1482                    krate = ecx.tcx.crate_name(def_id.krate),
1483                    decl_size = extern_decl_layout.size.bytes(),
1484                    decl_align = extern_decl_layout.align.bytes(),
1485                    shim_size = info.size.bytes(),
1486                    shim_align = info.align.bytes(),
1487                )
1488            }
1489            interp_ok(ptr)
1490        } else if ecx.tcx.codegen_fn_attrs(def_id).import_linkage == Some(Linkage::ExternalWeak) {
1491            // Symbols with weak linkage default to null if they are not defined. However we can't
1492            // create new allocations here. On the plus side we know rustc rejects non-ptr-sized
1493            // weak statics so we can just use a single global "null" allocation for all of them.
1494            // The memory we are assigning this address to is anyway somewhat "fake", it's an
1495            // indirection introduced by how Rust represents external symbols with linkage (see
1496            // <https://github.com/rust-lang/rust/issues/156468>). So we can just specify that such
1497            // memory does not have unique addresses, despite being technically a `static`.
1498            assert_eq!(
1499                extern_decl_layout.size,
1500                ecx.tcx.data_layout.pointer_size(),
1501                "non-pointer-sized weak static"
1502            );
1503            interp_ok(
1504                ecx.machine
1505                    .extern_static_weak_import_default
1506                    .expect("`missing_weak_symbol` should have been initialized"),
1507            )
1508        } else {
1509            // Look for a Rust static with this symbol name in the crate graph.
1510            let Some(instance) = ecx.lookup_exported_static(link_name)? else {
1511                throw_unsup_format!("extern static `{link_name}` is not supported by Miri");
1512            };
1513            // Evaluate the static to get its allocation.
1514            let place = ecx.eval_global(instance)?;
1515            let static_ptr = place.ptr().into_pointer_or_addr().unwrap();
1516            // Validate the allocation matches the declared size and alignment.
1517            let alloc_id = static_ptr.provenance.get_alloc_id().unwrap();
1518            let info = ecx.get_alloc_info(alloc_id);
1519            if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align {
1520                throw_ub_format!(
1521                    "extern static `{link_name}` has been declared as `{krate}::{name}` \
1522                    with a size of {decl_size} bytes and alignment of {decl_align} bytes, \
1523                    but the exported static with that name has a size of {shim_size} bytes and \
1524                    alignment of {shim_align} bytes",
1525                    name = ecx.tcx.def_path_str(def_id),
1526                    krate = ecx.tcx.crate_name(def_id.krate),
1527                    decl_size = extern_decl_layout.size.bytes(),
1528                    decl_align = extern_decl_layout.align.bytes(),
1529                    shim_size = info.size.bytes(),
1530                    shim_align = info.align.bytes(),
1531                )
1532            }
1533            // Check that the mutability of the declared static matches that of the backing.
1534            // If the backing static can be modified (because it is a `static mut`, or because
1535            // it is a `static` whose type has interior mutability) while the declaration here
1536            // is a non-mut `static` with a `Freeze` type, then the compiler's assumption that
1537            // the value never changes may be violated, so this may cause UB.
1538            // This is somehow defensive, as the allocation might be mutable but no mutation
1539            // ever happens, but this is probably the most precise thing we can do.
1540            // Specially, the second case is very defensive and we may be able to lift it.
1541            let DefKind::Static { mutability, .. } = ecx.tcx.def_kind(def_id) else {
1542                unreachable!("`{def_id:?}` is not a static");
1543            };
1544            let decl_is_mut =
1545                !(mutability == Mutability::Not && ecx.type_is_freeze(extern_decl_layout.ty));
1546            let backing_is_mut = ecx.get_alloc_mutability(alloc_id)? == Mutability::Mut;
1547            if !decl_is_mut && backing_is_mut {
1548                throw_ub_format!(
1549                    "extern static `{krate}::{name}` is declared as an immutable `static`, \
1550                    but the backing static is mutable",
1551                    name = ecx.tcx.def_path_str(def_id),
1552                    krate = ecx.tcx.crate_name(def_id.krate),
1553                )
1554            }
1555            if decl_is_mut && !backing_is_mut {
1556                throw_ub_format!(
1557                    "extern static `{krate}::{name}` is declared as an mutable `static`, \
1558                    but the backing static is immutable",
1559                    name = ecx.tcx.def_path_str(def_id),
1560                    krate = ecx.tcx.crate_name(def_id.krate),
1561                )
1562            }
1563            interp_ok(static_ptr)
1564        }
1565    }
1566
1567    fn init_local_allocation(
1568        ecx: &MiriInterpCx<'tcx>,
1569        id: AllocId,
1570        kind: MemoryKind,
1571        size: Size,
1572        align: Align,
1573    ) -> InterpResult<'tcx, Self::AllocExtra> {
1574        assert!(kind != MiriMemoryKind::Global.into());
1575        MiriMachine::init_allocation(ecx, id, kind, size, align)
1576    }
1577
1578    fn adjust_alloc_root_pointer(
1579        ecx: &MiriInterpCx<'tcx>,
1580        ptr: interpret::Pointer<CtfeProvenance>,
1581        kind: Option<MemoryKind>,
1582    ) -> InterpResult<'tcx, interpret::Pointer<Provenance>> {
1583        let kind = kind.expect("we set our GLOBAL_KIND so this cannot be None");
1584        let alloc_id = ptr.provenance.alloc_id();
1585        if cfg!(debug_assertions) {
1586            // The machine promises to never call us on thread-local or extern statics.
1587            match ecx.tcx.try_get_global_alloc(alloc_id) {
1588                Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => {
1589                    panic!("adjust_alloc_root_pointer called on thread-local static")
1590                }
1591                Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_foreign_item(def_id) => {
1592                    panic!("adjust_alloc_root_pointer called on extern static")
1593                }
1594                _ => {}
1595            }
1596        }
1597        // FIXME: can we somehow preserve the immutability of `ptr`?
1598        let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
1599            borrow_tracker.borrow_mut().root_ptr_tag(alloc_id, &ecx.machine)
1600        } else {
1601            // Value does not matter, SB is disabled
1602            BorTag::default()
1603        };
1604        ecx.adjust_alloc_root_pointer(ptr, tag, kind)
1605    }
1606
1607    /// Called on `usize as ptr` casts.
1608    #[inline(always)]
1609    fn ptr_from_addr_cast(ecx: &MiriInterpCx<'tcx>, addr: u64) -> InterpResult<'tcx, Pointer> {
1610        ecx.ptr_from_addr_cast(addr)
1611    }
1612
1613    /// Called on `ptr as usize` casts.
1614    /// (Actually computing the resulting `usize` doesn't need machine help,
1615    /// that's just `Scalar::try_to_int`.)
1616    #[inline(always)]
1617    fn expose_provenance(
1618        ecx: &InterpCx<'tcx, Self>,
1619        provenance: Self::Provenance,
1620    ) -> InterpResult<'tcx> {
1621        ecx.expose_provenance(provenance)
1622    }
1623
1624    /// Convert a pointer with provenance into an allocation-offset pair and extra provenance info.
1625    /// `size` says how many bytes of memory are expected at that pointer. The *sign* of `size` can
1626    /// be used to disambiguate situations where a wildcard pointer sits right in between two
1627    /// allocations.
1628    ///
1629    /// If `ptr.provenance.get_alloc_id()` is `Some(p)`, the returned `AllocId` must be `p`.
1630    /// The resulting `AllocId` will just be used for that one step and the forgotten again
1631    /// (i.e., we'll never turn the data returned here back into a `Pointer` that might be
1632    /// stored in machine state).
1633    ///
1634    /// When this fails, that means the pointer does not point to a live allocation.
1635    fn ptr_get_alloc(
1636        ecx: &MiriInterpCx<'tcx>,
1637        ptr: StrictPointer,
1638        size: i64,
1639    ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> {
1640        let rel = ecx.ptr_get_alloc(ptr, size);
1641
1642        rel.map(|(alloc_id, size)| {
1643            let tag = match ptr.provenance {
1644                Provenance::Concrete { tag, .. } => ProvenanceExtra::Concrete(tag),
1645                Provenance::Wildcard => ProvenanceExtra::Wildcard,
1646            };
1647            (alloc_id, size, tag)
1648        })
1649    }
1650
1651    /// Called to adjust global allocations to the Provenance and AllocExtra of this machine.
1652    ///
1653    /// If `alloc` contains pointers, then they are all pointing to globals.
1654    ///
1655    /// This should avoid copying if no work has to be done! If this returns an owned
1656    /// allocation (because a copy had to be done to adjust things), machine memory will
1657    /// cache the result. (This relies on `AllocMap::get_or` being able to add the
1658    /// owned allocation to the map even when the map is shared.)
1659    fn adjust_global_allocation<'b>(
1660        ecx: &InterpCx<'tcx, Self>,
1661        id: AllocId,
1662        alloc: &'b Allocation,
1663    ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>
1664    {
1665        let alloc = alloc.adjust_from_tcx(
1666            &ecx.tcx,
1667            |bytes, align| ecx.get_global_alloc_bytes(id, bytes, align),
1668            |ptr| ecx.global_root_pointer(ptr),
1669        )?;
1670        let kind = MiriMemoryKind::Global.into();
1671        let extra = MiriMachine::init_allocation(ecx, id, kind, alloc.size(), alloc.align)?;
1672        interp_ok(Cow::Owned(alloc.with_extra(extra)))
1673    }
1674
1675    #[inline(always)]
1676    fn before_memory_read(
1677        _tcx: TyCtxtAt<'tcx>,
1678        machine: &Self,
1679        alloc_extra: &AllocExtra<'tcx>,
1680        ptr: Pointer,
1681        (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
1682        range: AllocRange,
1683    ) -> InterpResult<'tcx> {
1684        if machine.track_alloc_accesses && machine.tracked_alloc_ids.contains(&alloc_id) {
1685            machine.emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(
1686                alloc_id,
1687                range,
1688                borrow_tracker::AccessKind::Read,
1689            ));
1690        }
1691        // The order of checks is deliberate, to prefer reporting a data race over a borrow tracker error.
1692        match &machine.data_race {
1693            GlobalDataRaceHandler::None => {}
1694            GlobalDataRaceHandler::Genmc(genmc_ctx) =>
1695                genmc_ctx.memory_load(machine, ptr.addr(), range.size)?,
1696            GlobalDataRaceHandler::Vclocks(_data_race) => {
1697                let _trace = enter_trace_span!(data_race::before_memory_read);
1698                let AllocDataRaceHandler::Vclocks(data_race, _weak_memory) = &alloc_extra.data_race
1699                else {
1700                    unreachable!();
1701                };
1702                data_race.read_non_atomic(alloc_id, range, NaReadType::Read, None, machine)?;
1703            }
1704        }
1705        if let Some(borrow_tracker) = &alloc_extra.borrow_tracker {
1706            borrow_tracker.before_memory_read(alloc_id, prov_extra, range, machine)?;
1707        }
1708        // Check if there are any sync objects that would like to prevent reading this memory.
1709        for (_offset, obj) in alloc_extra.sync_objs.range(range.start..range.end()) {
1710            obj.on_access(concurrency::sync::AccessKind::Read)?;
1711        }
1712
1713        interp_ok(())
1714    }
1715
1716    #[inline(always)]
1717    fn before_memory_write(
1718        _tcx: TyCtxtAt<'tcx>,
1719        machine: &mut Self,
1720        alloc_extra: &mut AllocExtra<'tcx>,
1721        ptr: Pointer,
1722        (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
1723        range: AllocRange,
1724    ) -> InterpResult<'tcx> {
1725        if machine.track_alloc_accesses && machine.tracked_alloc_ids.contains(&alloc_id) {
1726            machine.emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(
1727                alloc_id,
1728                range,
1729                borrow_tracker::AccessKind::Write,
1730            ));
1731        }
1732        match &machine.data_race {
1733            GlobalDataRaceHandler::None => {}
1734            GlobalDataRaceHandler::Genmc(genmc_ctx) =>
1735                genmc_ctx.memory_store(machine, ptr.addr(), range.size)?,
1736            GlobalDataRaceHandler::Vclocks(_global_state) => {
1737                let _trace = enter_trace_span!(data_race::before_memory_write);
1738                let AllocDataRaceHandler::Vclocks(data_race, weak_memory) =
1739                    &mut alloc_extra.data_race
1740                else {
1741                    unreachable!()
1742                };
1743                data_race.write_non_atomic(alloc_id, range, NaWriteType::Write, None, machine)?;
1744                if let Some(weak_memory) = weak_memory {
1745                    weak_memory
1746                        .non_atomic_write(range, machine.data_race.as_vclocks_ref().unwrap());
1747                }
1748            }
1749        }
1750        if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker {
1751            borrow_tracker.before_memory_write(alloc_id, prov_extra, range, machine)?;
1752        }
1753        // Delete sync objects that don't like writes.
1754        // Most of the time, we can just skip this.
1755        if !alloc_extra.sync_objs.is_empty() {
1756            let mut to_delete = vec![];
1757            for (offset, obj) in alloc_extra.sync_objs.range(range.start..range.end()) {
1758                obj.on_access(concurrency::sync::AccessKind::Write)?;
1759                if obj.delete_on_write() {
1760                    to_delete.push(*offset);
1761                }
1762            }
1763            for offset in to_delete {
1764                alloc_extra.sync_objs.remove(&offset);
1765            }
1766        }
1767        interp_ok(())
1768    }
1769
1770    #[inline(always)]
1771    fn before_memory_deallocation(
1772        _tcx: TyCtxtAt<'tcx>,
1773        machine: &mut Self,
1774        alloc_extra: &mut AllocExtra<'tcx>,
1775        ptr: Pointer,
1776        (alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra),
1777        size: Size,
1778        align: Align,
1779        kind: MemoryKind,
1780    ) -> InterpResult<'tcx> {
1781        if machine.tracked_alloc_ids.contains(&alloc_id) {
1782            machine.emit_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id));
1783        }
1784        match &machine.data_race {
1785            GlobalDataRaceHandler::None => {}
1786            GlobalDataRaceHandler::Genmc(genmc_ctx) =>
1787                genmc_ctx.handle_dealloc(machine, alloc_id, ptr.addr(), kind)?,
1788            GlobalDataRaceHandler::Vclocks(_global_state) => {
1789                let _trace = enter_trace_span!(data_race::before_memory_deallocation);
1790                let data_race = alloc_extra.data_race.as_vclocks_mut().unwrap();
1791                data_race.write_non_atomic(
1792                    alloc_id,
1793                    alloc_range(Size::ZERO, size),
1794                    NaWriteType::Deallocate,
1795                    None,
1796                    machine,
1797                )?;
1798            }
1799        }
1800        if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker {
1801            borrow_tracker.before_memory_deallocation(alloc_id, prove_extra, size, machine)?;
1802        }
1803        // Check if there are any sync objects that would like to prevent freeing this memory.
1804        for obj in alloc_extra.sync_objs.values() {
1805            obj.on_access(concurrency::sync::AccessKind::Dealloc)?;
1806        }
1807
1808        if let Some((_, deallocated_at)) = machine.allocation_spans.borrow_mut().get_mut(&alloc_id)
1809        {
1810            *deallocated_at = Some(machine.current_user_relevant_span());
1811        }
1812        machine.free_alloc_id(alloc_id, size, align, kind);
1813        interp_ok(())
1814    }
1815
1816    #[inline(always)]
1817    fn retag_ptr_value(
1818        ecx: &mut InterpCx<'tcx, Self>,
1819        val: &ImmTy<'tcx>,
1820        ty: Ty<'tcx>,
1821    ) -> InterpResult<'tcx, Option<ImmTy<'tcx>>> {
1822        if ecx.machine.borrow_tracker.is_some() {
1823            ecx.retag_ptr_value(val, ty)
1824        } else {
1825            interp_ok(None)
1826        }
1827    }
1828
1829    #[inline(always)]
1830    fn with_retag_mode<T>(
1831        ecx: &mut InterpCx<'tcx, Self>,
1832        mode: RetagMode,
1833        f: impl FnOnce(&mut InterpCx<'tcx, Self>) -> InterpResult<'tcx, T>,
1834    ) -> InterpResult<'tcx, T> {
1835        if ecx.machine.borrow_tracker.is_some() { ecx.with_retag_mode(mode, f) } else { f(ecx) }
1836    }
1837
1838    fn protect_in_place_function_argument(
1839        ecx: &mut InterpCx<'tcx, Self>,
1840        place: &MPlaceTy<'tcx>,
1841    ) -> InterpResult<'tcx> {
1842        // If we have a borrow tracker, we also have it set up protection so that all reads *and
1843        // writes* during this call are insta-UB.
1844        let protected_place = if ecx.machine.borrow_tracker.is_some() {
1845            ecx.protect_place(place)?
1846        } else {
1847            // No borrow tracker.
1848            place.clone()
1849        };
1850        // We do need to write `uninit` so that even after the call ends, the former contents of
1851        // this place cannot be observed any more. We do the write after retagging so that for
1852        // Tree Borrows, this is considered to activate the new tag.
1853        // Conveniently this also ensures that the place actually points to suitable memory.
1854        ecx.write_uninit(&protected_place)?;
1855        // Now we throw away the protected place, ensuring its tag is never used again.
1856        interp_ok(())
1857    }
1858
1859    #[inline(always)]
1860    fn init_frame(
1861        ecx: &mut InterpCx<'tcx, Self>,
1862        frame: Frame<'tcx, Provenance>,
1863    ) -> InterpResult<'tcx, Frame<'tcx, Provenance, FrameExtra<'tcx>>> {
1864        // Start recording our event before doing anything else
1865        let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() {
1866            let fn_name = frame.instance().to_string();
1867            let entry = ecx.machine.string_cache.entry(fn_name.clone());
1868            let name = entry.or_insert_with(|| profiler.alloc_string(&*fn_name));
1869
1870            Some(profiler.start_recording_interval_event_detached(
1871                *name,
1872                measureme::EventId::from_label(*name),
1873                ecx.active_thread().to_u32(),
1874            ))
1875        } else {
1876            None
1877        };
1878
1879        let borrow_tracker = ecx.machine.borrow_tracker.as_ref();
1880
1881        let extra = FrameExtra {
1882            borrow_tracker: borrow_tracker.map(|bt| bt.borrow_mut().new_frame()),
1883            catch_unwind: None,
1884            timing,
1885            user_relevance: ecx.machine.user_relevance(&frame),
1886            data_race: ecx
1887                .machine
1888                .data_race
1889                .as_vclocks_ref()
1890                .map(|_| data_race::FrameState::default()),
1891        };
1892
1893        interp_ok(frame.with_extra(extra))
1894    }
1895
1896    fn stack<'a>(
1897        ecx: &'a InterpCx<'tcx, Self>,
1898    ) -> &'a [Frame<'tcx, Self::Provenance, Self::FrameExtra>] {
1899        ecx.active_thread_stack()
1900    }
1901
1902    fn stack_mut<'a>(
1903        ecx: &'a mut InterpCx<'tcx, Self>,
1904    ) -> &'a mut Vec<Frame<'tcx, Self::Provenance, Self::FrameExtra>> {
1905        ecx.active_thread_stack_mut()
1906    }
1907
1908    fn before_terminator(ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
1909        ecx.machine.basic_block_count += 1u64; // a u64 that is only incremented by 1 will "never" overflow
1910        ecx.machine.since_gc += 1;
1911        // Possibly report our progress. This will point at the terminator we are about to execute.
1912        if let Some(report_progress) = ecx.machine.report_progress {
1913            if ecx.machine.basic_block_count.is_multiple_of(u64::from(report_progress)) {
1914                ecx.emit_diagnostic(NonHaltingDiagnostic::ProgressReport {
1915                    block_count: ecx.machine.basic_block_count,
1916                });
1917            }
1918        }
1919
1920        // Search for BorTags to find all live pointers, then remove all other tags from borrow
1921        // stacks. Also clean up dropped readiness watchers from the global readiness interest
1922        // table and closed source file descriptions in the blocking I/O manager.
1923        // When debug assertions are enabled, run the GC as often as possible so that any cases
1924        // where it mistakenly removes an important tag become visible.
1925        if ecx.machine.gc_interval > 0 && ecx.machine.since_gc >= ecx.machine.gc_interval {
1926            ecx.machine.since_gc = 0;
1927            ecx.run_provenance_gc();
1928            ecx.machine.blocking_io.run_gc();
1929        }
1930
1931        // These are our preemption points.
1932        // (This will only take effect after the terminator has been executed.)
1933        ecx.maybe_preempt_active_thread();
1934
1935        // Make sure some time passes.
1936        ecx.machine.monotonic_clock.tick();
1937
1938        interp_ok(())
1939    }
1940
1941    #[inline(always)]
1942    fn after_stack_push(ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
1943        if ecx.frame().extra.user_relevance >= ecx.active_thread_ref().current_user_relevance() {
1944            // We just pushed a frame that's at least as relevant as the so-far most relevant frame.
1945            // That means we are now the most relevant frame.
1946            let stack_len = ecx.active_thread_stack().len();
1947            ecx.active_thread_mut().set_top_user_relevant_frame(stack_len - 1);
1948        }
1949        interp_ok(())
1950    }
1951
1952    fn before_stack_pop(ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
1953        let frame = ecx.frame();
1954        // We want this *before* the return value copy, because the return place itself is protected
1955        // until we do `on_stack_pop` here, and we need to un-protect it to copy the return value.
1956        if ecx.machine.borrow_tracker.is_some() {
1957            ecx.on_stack_pop(frame)?;
1958        }
1959        if ecx
1960            .active_thread_ref()
1961            .top_user_relevant_frame()
1962            .expect("there should always be a most relevant frame for a non-empty stack")
1963            == ecx.frame_idx()
1964        {
1965            // We are popping the most relevant frame. We have no clue what the next relevant frame
1966            // below that is, so we recompute that.
1967            // (If this ever becomes a bottleneck, we could have `push` store the previous
1968            // user-relevant frame and restore that here.)
1969            // We have to skip the frame that is just being popped.
1970            ecx.active_thread_mut().recompute_top_user_relevant_frame(/* skip */ 1);
1971        }
1972        // tracing-tree can automatically annotate scope changes, but it gets very confused by our
1973        // concurrency and what it prints is just plain wrong. So we print our own information
1974        // instead. (Cc https://github.com/rust-lang/miri/issues/2266)
1975        info!("Leaving {}", ecx.frame().instance());
1976        interp_ok(())
1977    }
1978
1979    #[inline(always)]
1980    fn after_stack_pop(
1981        ecx: &mut InterpCx<'tcx, Self>,
1982        frame: Frame<'tcx, Provenance, FrameExtra<'tcx>>,
1983        unwinding: bool,
1984    ) -> InterpResult<'tcx, ReturnAction> {
1985        let res = {
1986            // Move `frame` into a sub-scope so we control when it will be dropped.
1987            let mut frame = frame;
1988            let timing = frame.extra.timing.take();
1989            let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding);
1990            if let Some(profiler) = ecx.machine.profiler.as_ref() {
1991                profiler.finish_recording_interval_event(timing.unwrap());
1992            }
1993            res
1994        };
1995        // Needs to be done after dropping frame to show up on the right nesting level.
1996        // (Cc https://github.com/rust-lang/miri/issues/2266)
1997        if !ecx.active_thread_stack().is_empty() {
1998            info!("Continuing in {}", ecx.frame().instance());
1999        }
2000        res
2001    }
2002
2003    fn after_local_read(
2004        ecx: &InterpCx<'tcx, Self>,
2005        frame: &Frame<'tcx, Provenance, FrameExtra<'tcx>>,
2006        local: mir::Local,
2007    ) -> InterpResult<'tcx> {
2008        if let Some(data_race) = &frame.extra.data_race {
2009            let _trace = enter_trace_span!(data_race::after_local_read);
2010            data_race.local_read(local, &ecx.machine);
2011        }
2012        interp_ok(())
2013    }
2014
2015    fn after_local_write(
2016        ecx: &mut InterpCx<'tcx, Self>,
2017        local: mir::Local,
2018        storage_live: bool,
2019    ) -> InterpResult<'tcx> {
2020        if let Some(data_race) = &ecx.frame().extra.data_race {
2021            let _trace = enter_trace_span!(data_race::after_local_write);
2022            data_race.local_write(local, storage_live, &ecx.machine);
2023        }
2024        interp_ok(())
2025    }
2026
2027    fn after_local_moved_to_memory(
2028        ecx: &mut InterpCx<'tcx, Self>,
2029        local: mir::Local,
2030        mplace: &MPlaceTy<'tcx>,
2031    ) -> InterpResult<'tcx> {
2032        let Some(Provenance::Concrete { alloc_id, .. }) = mplace.ptr().provenance else {
2033            panic!("after_local_allocated should only be called on fresh allocations");
2034        };
2035        // Record the span where this was allocated: the declaration of the local.
2036        let local_decl = &ecx.frame().body().local_decls[local];
2037        let span = local_decl.source_info.span;
2038        ecx.machine.allocation_spans.borrow_mut().insert(alloc_id, (span, None));
2039        // The data race system has to fix the clocks used for this write.
2040        let (alloc_info, machine) = ecx.get_alloc_extra_mut(alloc_id)?;
2041        if let Some(data_race) =
2042            &machine.threads.active_thread_stack().last().unwrap().extra.data_race
2043        {
2044            let _trace = enter_trace_span!(data_race::after_local_moved_to_memory);
2045            data_race.local_moved_to_memory(
2046                local,
2047                alloc_info.data_race.as_vclocks_mut().unwrap(),
2048                machine,
2049            );
2050        }
2051        interp_ok(())
2052    }
2053
2054    fn get_global_alloc_salt(
2055        ecx: &InterpCx<'tcx, Self>,
2056        instance: Option<ty::Instance<'tcx>>,
2057    ) -> usize {
2058        let unique = if let Some(instance) = instance {
2059            // Functions cannot be identified by pointers, as asm-equal functions can get
2060            // deduplicated by the linker (we set the "unnamed_addr" attribute for LLVM) and
2061            // functions can be duplicated across crates. We thus generate a new `AllocId` for every
2062            // mention of a function. This means that `main as fn() == main as fn()` is false, while
2063            // `let x = main as fn(); x == x` is true. However, as a quality-of-life feature it can
2064            // be useful to identify certain functions uniquely, e.g. for backtraces. So we identify
2065            // whether codegen will actually emit duplicate functions. It does that when they have
2066            // non-lifetime generics, or when they can be inlined. All other functions are given a
2067            // unique address. This is not a stable guarantee! The `inline` attribute is a hint and
2068            // cannot be relied upon for anything. But if we don't do this, the
2069            // `__rust_begin_short_backtrace`/`__rust_end_short_backtrace` logic breaks and panic
2070            // backtraces look terrible.
2071            let is_generic = instance
2072                .args
2073                .into_iter()
2074                .any(|arg| !matches!(arg.kind(), ty::GenericArgKind::Lifetime(_)));
2075            let can_be_inlined = matches!(
2076                ecx.tcx.sess.opts.unstable_opts.cross_crate_inline_threshold,
2077                InliningThreshold::Always
2078            ) || !matches!(
2079                ecx.tcx.codegen_instance_attrs(instance.def).inline,
2080                InlineAttr::Never
2081            );
2082            !is_generic && !can_be_inlined
2083        } else {
2084            // Non-functions are never unique.
2085            false
2086        };
2087        // Always use the same salt if the allocation is unique.
2088        if unique {
2089            CTFE_ALLOC_SALT
2090        } else {
2091            ecx.machine.rng.borrow_mut().random_range(0..ADDRS_PER_ANON_GLOBAL)
2092        }
2093    }
2094
2095    fn cached_union_data_range<'e>(
2096        ecx: &'e mut InterpCx<'tcx, Self>,
2097        ty: Ty<'tcx>,
2098        compute_range: impl FnOnce() -> RangeSet,
2099    ) -> Cow<'e, RangeSet> {
2100        Cow::Borrowed(ecx.machine.union_data_ranges.entry(ty).or_insert_with(compute_range))
2101    }
2102
2103    fn get_default_alloc_params(&self) -> <Self::Bytes as AllocBytes>::AllocParams {
2104        use crate::alloc::MiriAllocParams;
2105
2106        match &self.allocator {
2107            Some(alloc) => MiriAllocParams::Isolated(alloc.clone()),
2108            None => MiriAllocParams::Global,
2109        }
2110    }
2111
2112    fn enter_trace_span(span: impl FnOnce() -> tracing::Span) -> impl EnteredTraceSpan {
2113        #[cfg(feature = "tracing")]
2114        {
2115            span().entered()
2116        }
2117        #[cfg(not(feature = "tracing"))]
2118        #[expect(clippy::unused_unit)]
2119        {
2120            let _ = span; // so we avoid the "unused variable" warning
2121            ()
2122        }
2123    }
2124}
2125
2126/// Trait for callbacks handling asynchronous machine operations.
2127pub trait MachineCallback<'tcx, T>: VisitProvenance {
2128    /// The function to be invoked when the callback is fired.
2129    fn call(
2130        self: Box<Self>,
2131        ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
2132        arg: T,
2133    ) -> InterpResult<'tcx>;
2134}
2135
2136/// Type alias for boxed machine callbacks with generic argument type.
2137pub type DynMachineCallback<'tcx, T> = Box<dyn MachineCallback<'tcx, T> + 'tcx>;
2138
2139/// Creates a `DynMachineCallback`:
2140///
2141/// ```rust
2142/// callback!(
2143///     @capture<'tcx> {
2144///         var1: Ty1,
2145///         var2: Ty2<'tcx>,
2146///     }
2147///     |this, arg: ArgTy| {
2148///         // Implement the callback here.
2149///         todo!()
2150///     }
2151/// )
2152/// ```
2153///
2154/// All the argument types must implement `VisitProvenance`.
2155#[macro_export]
2156macro_rules! callback {
2157    (@capture<$tcx:lifetime $(,)? $($lft:lifetime),*>
2158        { $($name:ident: $type:ty),* $(,)? }
2159     |$this:ident, $arg:ident: $arg_ty:ty| $body:expr $(,)?) => {{
2160        struct Callback<$tcx, $($lft),*> {
2161            $($name: $type,)*
2162            _phantom: std::marker::PhantomData<&$tcx ()>,
2163        }
2164
2165        impl<$tcx, $($lft),*> VisitProvenance for Callback<$tcx, $($lft),*> {
2166            fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
2167                $(
2168                    VisitProvenance::visit_provenance(&self.$name, _visit);
2169                )*
2170            }
2171        }
2172
2173        impl<$tcx, $($lft),*> MachineCallback<$tcx, $arg_ty> for Callback<$tcx, $($lft),*> {
2174            fn call(
2175                self: Box<Self>,
2176                $this: &mut MiriInterpCx<$tcx>,
2177                $arg: $arg_ty
2178            ) -> InterpResult<$tcx> {
2179                #[allow(unused_variables)]
2180                let Callback { $($name,)* _phantom } = *self;
2181                $body
2182            }
2183        }
2184
2185        Box::new(Callback {
2186            $($name,)*
2187            _phantom: std::marker::PhantomData
2188        })
2189    }};
2190}