]> git.lizzy.rs Git - rust.git/blobdiff - src/machine.rs
rustup
[rust.git] / src / machine.rs
index a75ac844902fc507b96769e95a57db8b0f4d47ce..7ab15b9f9ceb61c78a9dfbd1603419fb4485fd70 100644 (file)
@@ -3,28 +3,33 @@
 
 use std::borrow::Cow;
 use std::cell::RefCell;
+use std::collections::HashSet;
 use std::fmt;
 use std::num::NonZeroU64;
+use std::rc::Rc;
 use std::time::Instant;
 
 use rand::rngs::StdRng;
 use rand::SeedableRng;
 
+use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::FxHashMap;
+#[allow(unused)]
+use rustc_data_structures::static_assert_size;
 use rustc_middle::{
     mir,
     ty::{
         self,
         layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout},
-        Instance, TyCtxt,
+        Instance, TyCtxt, TypeAndMut,
     },
 };
-use rustc_span::def_id::DefId;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::def_id::{CrateNum, DefId};
+use rustc_span::Symbol;
 use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 
-use crate::*;
+use crate::{shims::posix::FileHandler, *};
 
 // Some global facts about the emulated machine.
 pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture
@@ -71,8 +76,9 @@ pub enum MiriMemoryKind {
     /// Memory for args, errno, and other parts of the machine-managed environment.
     /// This memory may leak.
     Machine,
-    /// Memory for env vars. Separate from `Machine` because we clean it up and leak-check it.
-    Env,
+    /// Memory allocated by the runtime (e.g. env vars). Separate from `Machine`
+    /// because we clean it up and leak-check it.
+    Runtime,
     /// Globals copied from `tcx`.
     /// This memory may leak.
     Global,
@@ -96,7 +102,7 @@ impl MayLeak for MiriMemoryKind {
     fn may_leak(self) -> bool {
         use self::MiriMemoryKind::*;
         match self {
-            Rust | C | WinHeap | Env => false,
+            Rust | C | WinHeap | Runtime => false,
             Machine | Global | ExternStatic | Tls => true,
         }
     }
@@ -110,7 +116,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             C => write!(f, "C heap"),
             WinHeap => write!(f, "Windows heap"),
             Machine => write!(f, "machine-managed memory"),
-            Env => write!(f, "environment variable"),
+            Runtime => write!(f, "language runtime memory"),
             Global => write!(f, "global (static or const)"),
             ExternStatic => write!(f, "extern static"),
             Tls => write!(f, "thread-local static"),
@@ -126,6 +132,13 @@ pub struct Tag {
     pub sb: SbTag,
 }
 
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(Pointer<Tag>, 24);
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(Pointer<Option<Tag>>, 24);
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(ScalarMaybeUninit<Tag>, 32);
+
 impl Provenance for Tag {
     /// We use absolute addresses in the `offset` of a `Pointer<Tag>`.
     const OFFSET_IS_ADDR: bool = true;
@@ -146,8 +159,8 @@ fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{:?}", tag.sb)
     }
 
-    fn get_alloc_id(self) -> AllocId {
-        self.alloc_id
+    fn get_alloc_id(self) -> Option<AllocId> {
+        Some(self.alloc_id)
     }
 }
 
@@ -161,103 +174,6 @@ pub struct AllocExtra {
     pub data_race: Option<data_race::AllocExtra>,
 }
 
-/// Extra global memory data
-#[derive(Debug)]
-pub struct MemoryExtra {
-    pub stacked_borrows: Option<stacked_borrows::MemoryExtra>,
-    pub data_race: Option<data_race::MemoryExtra>,
-    pub intptrcast: intptrcast::MemoryExtra,
-
-    /// Mapping extern static names to their base pointer.
-    extern_statics: FxHashMap<Symbol, Pointer<Tag>>,
-
-    /// The random number generator used for resolving non-determinism.
-    /// Needs to be queried by ptr_to_int, hence needs interior mutability.
-    pub(crate) rng: RefCell<StdRng>,
-
-    /// An allocation ID to report when it is being allocated
-    /// (helps for debugging memory leaks and use after free bugs).
-    tracked_alloc_id: Option<AllocId>,
-
-    /// Controls whether alignment of memory accesses is being checked.
-    pub(crate) check_alignment: AlignmentCheck,
-
-    /// Failure rate of compare_exchange_weak, between 0.0 and 1.0
-    pub(crate) cmpxchg_weak_failure_rate: f64,
-}
-
-impl MemoryExtra {
-    pub fn new(config: &MiriConfig) -> Self {
-        let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
-        let stacked_borrows = if config.stacked_borrows {
-            Some(RefCell::new(stacked_borrows::GlobalState::new(
-                config.tracked_pointer_tag,
-                config.tracked_call_id,
-                config.tag_raw,
-            )))
-        } else {
-            None
-        };
-        let data_race =
-            if config.data_race_detector { Some(data_race::GlobalState::new()) } else { None };
-        MemoryExtra {
-            stacked_borrows,
-            data_race,
-            intptrcast: Default::default(),
-            extern_statics: FxHashMap::default(),
-            rng: RefCell::new(rng),
-            tracked_alloc_id: config.tracked_alloc_id,
-            check_alignment: config.check_alignment,
-            cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate,
-        }
-    }
-
-    fn add_extern_static<'tcx, 'mir>(
-        this: &mut MiriEvalContext<'mir, 'tcx>,
-        name: &str,
-        ptr: Pointer<Option<Tag>>,
-    ) {
-        let ptr = ptr.into_pointer_or_addr().unwrap();
-        this.memory.extra.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
-    }
-
-    /// Sets up the "extern statics" for this machine.
-    pub fn init_extern_statics<'tcx, 'mir>(
-        this: &mut MiriEvalContext<'mir, 'tcx>,
-    ) -> InterpResult<'tcx> {
-        match this.tcx.sess.target.os.as_str() {
-            "linux" => {
-                // "environ"
-                Self::add_extern_static(
-                    this,
-                    "environ",
-                    this.machine.env_vars.environ.unwrap().ptr,
-                );
-                // A couple zero-initialized pointer-sized extern statics.
-                // Most of them are for weak symbols, which we all set to null (indicating that the
-                // symbol is not supported, and triggering fallback code which ends up calling a
-                // syscall that we do support).
-                for name in &["__cxa_thread_atexit_impl", "getrandom", "statx"] {
-                    let layout = this.machine.layouts.usize;
-                    let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
-                    this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?;
-                    Self::add_extern_static(this, name, place.ptr);
-                }
-            }
-            "windows" => {
-                // "_tls_used"
-                // This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
-                let layout = this.machine.layouts.u8;
-                let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
-                this.write_scalar(Scalar::from_u8(0), &place.into())?;
-                Self::add_extern_static(this, "_tls_used", place.ptr);
-            }
-            _ => {} // No "extern statics" supported on this target
-        }
-        Ok(())
-    }
-}
-
 /// Precomputed layouts of primitive types
 pub struct PrimitiveLayouts<'tcx> {
     pub unit: TyAndLayout<'tcx>,
@@ -267,24 +183,34 @@ pub struct PrimitiveLayouts<'tcx> {
     pub u8: TyAndLayout<'tcx>,
     pub u32: TyAndLayout<'tcx>,
     pub usize: TyAndLayout<'tcx>,
+    pub bool: TyAndLayout<'tcx>,
+    pub mut_raw_ptr: TyAndLayout<'tcx>,
 }
 
 impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
     fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, LayoutError<'tcx>> {
+        let tcx = layout_cx.tcx;
+        let mut_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut });
         Ok(Self {
-            unit: layout_cx.layout_of(layout_cx.tcx.mk_unit())?,
-            i8: layout_cx.layout_of(layout_cx.tcx.types.i8)?,
-            i32: layout_cx.layout_of(layout_cx.tcx.types.i32)?,
-            isize: layout_cx.layout_of(layout_cx.tcx.types.isize)?,
-            u8: layout_cx.layout_of(layout_cx.tcx.types.u8)?,
-            u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?,
-            usize: layout_cx.layout_of(layout_cx.tcx.types.usize)?,
+            unit: layout_cx.layout_of(tcx.mk_unit())?,
+            i8: layout_cx.layout_of(tcx.types.i8)?,
+            i32: layout_cx.layout_of(tcx.types.i32)?,
+            isize: layout_cx.layout_of(tcx.types.isize)?,
+            u8: layout_cx.layout_of(tcx.types.u8)?,
+            u32: layout_cx.layout_of(tcx.types.u32)?,
+            usize: layout_cx.layout_of(tcx.types.usize)?,
+            bool: layout_cx.layout_of(tcx.types.bool)?,
+            mut_raw_ptr: layout_cx.layout_of(mut_raw_ptr)?,
         })
     }
 }
 
 /// The machine itself.
 pub struct Evaluator<'mir, 'tcx> {
+    pub stacked_borrows: Option<stacked_borrows::GlobalState>,
+    pub data_race: Option<data_race::GlobalState>,
+    pub intptrcast: intptrcast::GlobalState,
+
     /// Environment variables set by `setenv`.
     /// Miri does not expose env vars from the host to the emulated program.
     pub(crate) env_vars: EnvVars<'tcx>,
@@ -346,18 +272,56 @@ pub struct Evaluator<'mir, 'tcx> {
 
     /// Equivalent setting as RUST_BACKTRACE on encountering an error.
     pub(crate) backtrace_style: BacktraceStyle,
+
+    /// Crates which are considered local for the purposes of error reporting.
+    pub(crate) local_crates: Rc<[CrateNum]>,
+
+    /// Mapping extern static names to their base pointer.
+    extern_statics: FxHashMap<Symbol, Pointer<Tag>>,
+
+    /// The random number generator used for resolving non-determinism.
+    /// Needs to be queried by ptr_to_int, hence needs interior mutability.
+    pub(crate) rng: RefCell<StdRng>,
+
+    /// The allocation IDs to report when they are being allocated
+    /// (helps for debugging memory leaks and use after free bugs).
+    tracked_alloc_ids: HashSet<AllocId>,
+
+    /// Controls whether alignment of memory accesses is being checked.
+    pub(crate) check_alignment: AlignmentCheck,
+
+    /// Failure rate of compare_exchange_weak, between 0.0 and 1.0
+    pub(crate) cmpxchg_weak_failure_rate: f64,
+
+    /// Corresponds to -Zmiri-mute-stdout-stderr and doesn't write the output but acts as if it succeeded.
+    pub(crate) mute_stdout_stderr: bool,
 }
 
 impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
     pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self {
+        let local_crates = helpers::get_local_crates(&layout_cx.tcx);
         let layouts =
             PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types");
         let profiler = config.measureme_out.as_ref().map(|out| {
             measureme::Profiler::new(out).expect("Couldn't create `measureme` profiler")
         });
+        let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
+        let stacked_borrows = if config.stacked_borrows {
+            Some(RefCell::new(stacked_borrows::GlobalStateInner::new(
+                config.tracked_pointer_tags.clone(),
+                config.tracked_call_ids.clone(),
+                config.tag_raw,
+            )))
+        } else {
+            None
+        };
+        let data_race =
+            if config.data_race_detector { Some(data_race::GlobalState::new()) } else { None };
         Evaluator {
-            // `env_vars` could be initialized properly here if `Memory` were available before
-            // calling this method.
+            stacked_borrows,
+            data_race,
+            intptrcast: RefCell::new(intptrcast::GlobalStateInner::new(config)),
+            // `env_vars` depends on a full interpreter so we cannot properly initialize it yet.
             env_vars: EnvVars::default(),
             argc: None,
             argv: None,
@@ -367,7 +331,7 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>)
             validate: config.validate,
             enforce_number_validity: config.check_number_validity,
             enforce_abi: config.check_abi,
-            file_handler: Default::default(),
+            file_handler: FileHandler::new(config.mute_stdout_stderr),
             dir_handler: Default::default(),
             time_anchor: Instant::now(),
             layouts,
@@ -378,12 +342,79 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>)
             exported_symbols_cache: FxHashMap::default(),
             panic_on_unsupported: config.panic_on_unsupported,
             backtrace_style: config.backtrace_style,
+            local_crates,
+            extern_statics: FxHashMap::default(),
+            rng: RefCell::new(rng),
+            tracked_alloc_ids: config.tracked_alloc_ids.clone(),
+            check_alignment: config.check_alignment,
+            cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate,
+            mute_stdout_stderr: config.mute_stdout_stderr,
         }
     }
 
+    pub(crate) fn late_init(
+        this: &mut MiriEvalContext<'mir, 'tcx>,
+        config: &MiriConfig,
+    ) -> InterpResult<'tcx> {
+        EnvVars::init(this, config)?;
+        Evaluator::init_extern_statics(this)?;
+        Ok(())
+    }
+
+    fn add_extern_static(
+        this: &mut MiriEvalContext<'mir, 'tcx>,
+        name: &str,
+        ptr: Pointer<Option<Tag>>,
+    ) {
+        // This got just allocated, so there definitely is a pointer here.
+        let ptr = ptr.into_pointer_or_addr().unwrap();
+        this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
+    }
+
+    /// Sets up the "extern statics" for this machine.
+    fn init_extern_statics(this: &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx> {
+        match this.tcx.sess.target.os.as_ref() {
+            "linux" => {
+                // "environ"
+                Self::add_extern_static(
+                    this,
+                    "environ",
+                    this.machine.env_vars.environ.unwrap().ptr,
+                );
+                // A couple zero-initialized pointer-sized extern statics.
+                // Most of them are for weak symbols, which we all set to null (indicating that the
+                // symbol is not supported, and triggering fallback code which ends up calling a
+                // syscall that we do support).
+                for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"]
+                {
+                    let layout = this.machine.layouts.usize;
+                    let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
+                    this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?;
+                    Self::add_extern_static(this, name, place.ptr);
+                }
+            }
+            "windows" => {
+                // "_tls_used"
+                // This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
+                let layout = this.machine.layouts.u8;
+                let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
+                this.write_scalar(Scalar::from_u8(0), &place.into())?;
+                Self::add_extern_static(this, "_tls_used", place.ptr);
+            }
+            _ => {} // No "extern statics" supported on this target
+        }
+        Ok(())
+    }
+
     pub(crate) fn communicate(&self) -> bool {
         self.isolated_op == IsolatedOp::Allow
     }
+
+    /// Check whether the stack frame that this `FrameInfo` refers to is part of a local crate.
+    pub(crate) fn is_local(&self, frame: &FrameInfo<'_>) -> bool {
+        let def_id = frame.instance.def_id();
+        def_id.is_local() || self.local_crates.contains(&def_id.krate)
+    }
 }
 
 /// A rustc InterpCx for Miri.
@@ -408,12 +439,13 @@ fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> {
 /// Machine hook implementations.
 impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
     type MemoryKind = MiriMemoryKind;
+    type ExtraFnVal = Dlsym;
 
     type FrameExtra = FrameData<'tcx>;
-    type MemoryExtra = MemoryExtra;
     type AllocExtra = AllocExtra;
+
     type PointerTag = Tag;
-    type ExtraFnVal = Dlsym;
+    type TagExtra = SbTag;
 
     type MemoryMap =
         MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<Tag, Self::AllocExtra>)>;
@@ -423,33 +455,38 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
     const PANIC_ON_ALLOC_FAIL: bool = false;
 
     #[inline(always)]
-    fn enforce_alignment(memory_extra: &MemoryExtra) -> bool {
-        memory_extra.check_alignment != AlignmentCheck::None
+    fn enforce_alignment(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool {
+        ecx.machine.check_alignment != AlignmentCheck::None
     }
 
     #[inline(always)]
-    fn force_int_for_alignment_check(memory_extra: &Self::MemoryExtra) -> bool {
-        memory_extra.check_alignment == AlignmentCheck::Int
+    fn force_int_for_alignment_check(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool {
+        ecx.machine.check_alignment == AlignmentCheck::Int
     }
 
     #[inline(always)]
-    fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+    fn enforce_validity(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool {
         ecx.machine.validate
     }
 
     #[inline(always)]
-    fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+    fn enforce_number_init(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool {
+        ecx.machine.enforce_number_validity
+    }
+
+    #[inline(always)]
+    fn enforce_number_no_provenance(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool {
         ecx.machine.enforce_number_validity
     }
 
     #[inline(always)]
-    fn enforce_abi(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+    fn enforce_abi(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool {
         ecx.machine.enforce_abi
     }
 
     #[inline(always)]
     fn find_mir_or_eval_fn(
-        ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        ecx: &mut MiriEvalContext<'mir, 'tcx>,
         instance: ty::Instance<'tcx>,
         abi: Abi,
         args: &[OpTy<'tcx, Tag>],
@@ -461,7 +498,7 @@ fn find_mir_or_eval_fn(
 
     #[inline(always)]
     fn call_extra_fn(
-        ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        ecx: &mut MiriEvalContext<'mir, 'tcx>,
         fn_val: Dlsym,
         abi: Abi,
         args: &[OpTy<'tcx, Tag>],
@@ -473,7 +510,7 @@ fn call_extra_fn(
 
     #[inline(always)]
     fn call_intrinsic(
-        ecx: &mut rustc_const_eval::interpret::InterpCx<'mir, 'tcx, Self>,
+        ecx: &mut MiriEvalContext<'mir, 'tcx>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Tag>],
         ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
@@ -484,7 +521,7 @@ fn call_intrinsic(
 
     #[inline(always)]
     fn assert_panic(
-        ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        ecx: &mut MiriEvalContext<'mir, 'tcx>,
         msg: &mir::AssertMessage<'tcx>,
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx> {
@@ -492,13 +529,13 @@ fn assert_panic(
     }
 
     #[inline(always)]
-    fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> {
+    fn abort(_ecx: &mut MiriEvalContext<'mir, 'tcx>, msg: String) -> InterpResult<'tcx, !> {
         throw_machine_stop!(TerminationInfo::Abort(msg))
     }
 
     #[inline(always)]
     fn binary_ptr_op(
-        ecx: &rustc_const_eval::interpret::InterpCx<'mir, 'tcx, Self>,
+        ecx: &MiriEvalContext<'mir, 'tcx>,
         bin_op: mir::BinOp,
         left: &ImmTy<'tcx, Tag>,
         right: &ImmTy<'tcx, Tag>,
@@ -507,22 +544,18 @@ fn binary_ptr_op(
     }
 
     fn thread_local_static_base_pointer(
-        ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        ecx: &mut MiriEvalContext<'mir, 'tcx>,
         def_id: DefId,
     ) -> InterpResult<'tcx, Pointer<Tag>> {
         ecx.get_or_create_thread_local_alloc(def_id)
     }
 
     fn extern_static_base_pointer(
-        memory: &Memory<'mir, 'tcx, Self>,
+        ecx: &MiriEvalContext<'mir, 'tcx>,
         def_id: DefId,
     ) -> InterpResult<'tcx, Pointer<Tag>> {
-        let attrs = memory.tcx.get_attrs(def_id);
-        let link_name = match memory.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) {
-            Some(name) => name,
-            None => memory.tcx.item_name(def_id),
-        };
-        if let Some(&ptr) = memory.extra.extern_statics.get(&link_name) {
+        let link_name = ecx.item_link_name(def_id);
+        if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) {
             Ok(ptr)
         } else {
             throw_unsup_format!("`extern` static {:?} is not supported by Miri", def_id)
@@ -530,41 +563,48 @@ fn extern_static_base_pointer(
     }
 
     fn init_allocation_extra<'b>(
-        mem: &Memory<'mir, 'tcx, Self>,
+        ecx: &MiriEvalContext<'mir, 'tcx>,
         id: AllocId,
         alloc: Cow<'b, Allocation>,
         kind: Option<MemoryKind<Self::MemoryKind>>,
     ) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>> {
-        if Some(id) == mem.extra.tracked_alloc_id {
+        if ecx.machine.tracked_alloc_ids.contains(&id) {
             register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id));
         }
 
         let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
         let alloc = alloc.into_owned();
-        let stacks = if let Some(stacked_borrows) = &mem.extra.stacked_borrows {
-            Some(Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind))
+        let stacks = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows {
+            Some(Stacks::new_allocation(
+                id,
+                alloc.size(),
+                stacked_borrows,
+                kind,
+                &ecx.machine.threads,
+                ecx.machine.local_crates.clone(),
+            ))
         } else {
             None
         };
-        let race_alloc = if let Some(data_race) = &mem.extra.data_race {
-            Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size(), kind))
+        let race_alloc = if let Some(data_race) = &ecx.machine.data_race {
+            Some(data_race::AllocExtra::new_allocation(data_race, alloc.size(), kind))
         } else {
             None
         };
         let alloc: Allocation<Tag, Self::AllocExtra> = alloc.convert_tag_add_extra(
-            &mem.tcx,
+            &ecx.tcx,
             AllocExtra { stacked_borrows: stacks, data_race: race_alloc },
-            |ptr| Evaluator::tag_alloc_base_pointer(mem, ptr),
+            |ptr| Evaluator::tag_alloc_base_pointer(ecx, ptr),
         );
         Cow::Owned(alloc)
     }
 
     fn tag_alloc_base_pointer(
-        mem: &Memory<'mir, 'tcx, Self>,
+        ecx: &MiriEvalContext<'mir, 'tcx>,
         ptr: Pointer<AllocId>,
     ) -> Pointer<Tag> {
-        let absolute_addr = intptrcast::GlobalState::rel_ptr_to_addr(&mem, ptr);
-        let sb_tag = if let Some(stacked_borrows) = &mem.extra.stacked_borrows {
+        let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr);
+        let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows {
             stacked_borrows.borrow_mut().base_tag(ptr.provenance)
         } else {
             SbTag::Untagged
@@ -573,39 +613,57 @@ fn tag_alloc_base_pointer(
     }
 
     #[inline(always)]
-    fn ptr_from_addr(
-        mem: &Memory<'mir, 'tcx, Self>,
+    fn ptr_from_addr_cast(
+        ecx: &MiriEvalContext<'mir, 'tcx>,
+        addr: u64,
+    ) -> Pointer<Option<Self::PointerTag>> {
+        intptrcast::GlobalStateInner::ptr_from_addr(addr, ecx)
+    }
+
+    #[inline(always)]
+    fn ptr_from_addr_transmute(
+        ecx: &MiriEvalContext<'mir, 'tcx>,
         addr: u64,
     ) -> Pointer<Option<Self::PointerTag>> {
-        intptrcast::GlobalState::ptr_from_addr(addr, mem)
+        Self::ptr_from_addr_cast(ecx, addr)
+    }
+
+    #[inline(always)]
+    fn expose_ptr(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _ptr: Pointer<Self::PointerTag>,
+    ) -> InterpResult<'tcx> {
+        Ok(())
     }
 
     /// Convert a pointer with provenance into an allocation-offset pair,
     /// or a `None` with an absolute address if that conversion is not possible.
     fn ptr_get_alloc(
-        mem: &Memory<'mir, 'tcx, Self>,
+        ecx: &MiriEvalContext<'mir, 'tcx>,
         ptr: Pointer<Self::PointerTag>,
-    ) -> (AllocId, Size) {
-        let rel = intptrcast::GlobalState::abs_ptr_to_rel(mem, ptr);
-        (ptr.provenance.alloc_id, rel)
+    ) -> Option<(AllocId, Size, Self::TagExtra)> {
+        let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr);
+        Some((ptr.provenance.alloc_id, rel, ptr.provenance.sb))
     }
 
     #[inline(always)]
     fn memory_read(
-        memory_extra: &Self::MemoryExtra,
+        _tcx: TyCtxt<'tcx>,
+        machine: &Self,
         alloc_extra: &AllocExtra,
-        tag: Tag,
+        (alloc_id, tag): (AllocId, Self::TagExtra),
         range: AllocRange,
     ) -> InterpResult<'tcx> {
         if let Some(data_race) = &alloc_extra.data_race {
-            data_race.read(tag.alloc_id, range, memory_extra.data_race.as_ref().unwrap())?;
+            data_race.read(alloc_id, range, machine.data_race.as_ref().unwrap())?;
         }
         if let Some(stacked_borrows) = &alloc_extra.stacked_borrows {
             stacked_borrows.memory_read(
-                tag.alloc_id,
-                tag.sb,
+                alloc_id,
+                tag,
                 range,
-                memory_extra.stacked_borrows.as_ref().unwrap(),
+                machine.stacked_borrows.as_ref().unwrap(),
+                &machine.threads,
             )
         } else {
             Ok(())
@@ -614,20 +672,22 @@ fn memory_read(
 
     #[inline(always)]
     fn memory_written(
-        memory_extra: &mut Self::MemoryExtra,
+        _tcx: TyCtxt<'tcx>,
+        machine: &mut Self,
         alloc_extra: &mut AllocExtra,
-        tag: Tag,
+        (alloc_id, tag): (AllocId, Self::TagExtra),
         range: AllocRange,
     ) -> InterpResult<'tcx> {
         if let Some(data_race) = &mut alloc_extra.data_race {
-            data_race.write(tag.alloc_id, range, memory_extra.data_race.as_mut().unwrap())?;
+            data_race.write(alloc_id, range, machine.data_race.as_mut().unwrap())?;
         }
         if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
             stacked_borrows.memory_written(
-                tag.alloc_id,
-                tag.sb,
+                alloc_id,
+                tag,
                 range,
-                memory_extra.stacked_borrows.as_mut().unwrap(),
+                machine.stacked_borrows.as_ref().unwrap(),
+                &machine.threads,
             )
         } else {
             Ok(())
@@ -636,23 +696,24 @@ fn memory_written(
 
     #[inline(always)]
     fn memory_deallocated(
-        memory_extra: &mut Self::MemoryExtra,
+        _tcx: TyCtxt<'tcx>,
+        machine: &mut Self,
         alloc_extra: &mut AllocExtra,
-        tag: Tag,
+        (alloc_id, tag): (AllocId, Self::TagExtra),
         range: AllocRange,
     ) -> InterpResult<'tcx> {
-        if Some(tag.alloc_id) == memory_extra.tracked_alloc_id {
-            register_diagnostic(NonHaltingDiagnostic::FreedAlloc(tag.alloc_id));
+        if machine.tracked_alloc_ids.contains(&alloc_id) {
+            register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id));
         }
         if let Some(data_race) = &mut alloc_extra.data_race {
-            data_race.deallocate(tag.alloc_id, range, memory_extra.data_race.as_mut().unwrap())?;
+            data_race.deallocate(alloc_id, range, machine.data_race.as_mut().unwrap())?;
         }
         if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
             stacked_borrows.memory_deallocated(
-                tag.alloc_id,
-                tag.sb,
+                alloc_id,
+                tag,
                 range,
-                memory_extra.stacked_borrows.as_mut().unwrap(),
+                machine.stacked_borrows.as_ref().unwrap(),
             )
         } else {
             Ok(())
@@ -665,7 +726,7 @@ fn retag(
         kind: mir::RetagKind,
         place: &PlaceTy<'tcx, Tag>,
     ) -> InterpResult<'tcx> {
-        if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) }
+        if ecx.machine.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) }
     }
 
     #[inline(always)]
@@ -688,7 +749,7 @@ fn init_frame_extra(
             None
         };
 
-        let stacked_borrows = ecx.memory.extra.stacked_borrows.as_ref();
+        let stacked_borrows = ecx.machine.stacked_borrows.as_ref();
         let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| {
             stacked_borrows.borrow_mut().new_call()
         });
@@ -711,7 +772,7 @@ fn stack_mut<'a>(
 
     #[inline(always)]
     fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
-        if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) }
+        if ecx.machine.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) }
     }
 
     #[inline(always)]