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