1use std::borrow::Cow;
5use std::cell::{Cell, RefCell};
6use std::collections::BTreeMap;
7use std::path::Path;
8use std::rc::Rc;
9use std::{fmt, process};
10
11use rand::rngs::StdRng;
12use rand::{RngExt, SeedableRng};
13use rustc_abi::{Align, ExternAbi, Size};
14use rustc_apfloat::{Float, FloatConvert};
15use rustc_ast::Mutability;
16use rustc_ast::expand::allocator::{self, SpecialAllocatorMethod};
17use rustc_data_structures::either::Either;
18use rustc_data_structures::fx::{FxHashMap, FxHashSet};
19#[allow(unused)]
20use rustc_data_structures::static_assert_size;
21use rustc_hir::attrs::{InlineAttr, Linkage};
22use rustc_hir::def::DefKind;
23use rustc_log::tracing;
24use rustc_middle::middle::codegen_fn_attrs::TargetFeatureKind;
25use rustc_middle::mir;
26use rustc_middle::query::TyCtxtAt;
27use rustc_middle::ty::layout::{
28 HasTyCtxt, HasTypingEnv, LayoutCx, LayoutError, LayoutOf, TyAndLayout,
29};
30use rustc_middle::ty::{self, AtomicOrdering, Instance, Ty, TyCtxt};
31use rustc_session::config::InliningThreshold;
32use rustc_span::def_id::{CrateNum, DefId};
33use rustc_span::{Span, SpanData, Symbol};
34use rustc_symbol_mangling::mangle_internal_symbol;
35use rustc_target::callconv::FnAbi;
36use rustc_target::spec::{Arch, Os};
37
38use crate::alloc_addresses::EvalContextExt;
39use crate::concurrency::data_race::{self, NaReadType, NaWriteType};
40use crate::concurrency::sync::SyncObj;
41use crate::concurrency::{
42 AllocDataRaceHandler, GenmcCtx, GenmcEvalContextExt as _, GlobalDataRaceHandler, weak_memory,
43};
44use crate::helpers::is_no_core;
45use crate::*;
46
47pub const SIGRTMIN: i32 = 34;
51
52pub const SIGRTMAX: i32 = 42;
56
57const ADDRS_PER_ANON_GLOBAL: usize = 32;
61
62#[derive(Copy, Clone, Debug, PartialEq)]
63pub enum AlignmentCheck {
64 None,
66 Symbolic,
68 Int,
70}
71
72#[derive(Copy, Clone, Debug, PartialEq)]
73pub enum RejectOpWith {
74 Abort,
76
77 NoWarning,
81
82 Warning,
84
85 WarningWithoutBacktrace,
87}
88
89#[derive(Copy, Clone, Debug, PartialEq)]
90pub enum IsolatedOp {
91 Reject(RejectOpWith),
96
97 Allow,
99}
100
101#[derive(Debug, Copy, Clone, PartialEq, Eq)]
102pub enum BacktraceStyle {
103 Short,
105 Full,
107 Off,
109}
110
111#[derive(Debug, Copy, Clone, PartialEq, Eq)]
112pub enum ValidationMode {
113 No,
115 Shallow,
117 Deep,
119}
120
121#[derive(Debug, Copy, Clone, PartialEq, Eq)]
122pub enum FloatRoundingErrorMode {
123 Random,
125 None,
127 Max,
129}
130
131pub struct FrameExtra<'tcx> {
133 pub borrow_tracker: Option<borrow_tracker::FrameState>,
135
136 pub catch_unwind: Option<CatchUnwindData<'tcx>>,
140
141 pub timing: Option<measureme::DetachedTiming>,
145
146 pub user_relevance: u8,
150
151 pub data_race: Option<data_race::FrameState>,
153}
154
155impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {
156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157 let FrameExtra { borrow_tracker, catch_unwind, timing: _, user_relevance, data_race } =
159 self;
160 f.debug_struct("FrameData")
161 .field("borrow_tracker", borrow_tracker)
162 .field("catch_unwind", catch_unwind)
163 .field("user_relevance", user_relevance)
164 .field("data_race", data_race)
165 .finish()
166 }
167}
168
169impl VisitProvenance for FrameExtra<'_> {
170 fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
171 let FrameExtra { catch_unwind, borrow_tracker, timing: _, user_relevance: _, data_race: _ } =
172 self;
173
174 catch_unwind.visit_provenance(visit);
175 borrow_tracker.visit_provenance(visit);
176 }
177}
178
179#[derive(Debug, Copy, Clone, PartialEq, Eq)]
181pub enum MiriMemoryKind {
182 Rust,
184 Miri,
186 C,
188 WinHeap,
190 WinLocal,
192 Machine,
195 Runtime,
198 Global,
201 ExternStatic,
204 Tls,
207 Mmap,
209 SocketAddress,
211}
212
213impl From<MiriMemoryKind> for MemoryKind {
214 #[inline(always)]
215 fn from(kind: MiriMemoryKind) -> MemoryKind {
216 MemoryKind::Machine(kind)
217 }
218}
219
220impl MayLeak for MiriMemoryKind {
221 #[inline(always)]
222 fn may_leak(self) -> bool {
223 use self::MiriMemoryKind::*;
224 match self {
225 Rust | Miri | C | WinHeap | WinLocal | Runtime => false,
226 Machine | Global | ExternStatic | Tls | Mmap | SocketAddress => true,
227 }
228 }
229}
230
231impl MiriMemoryKind {
232 fn should_save_allocation_span(self) -> bool {
234 use self::MiriMemoryKind::*;
235 match self {
236 Rust | Miri | C | WinHeap | WinLocal | Mmap => true,
238 Machine | Global | ExternStatic | Tls | Runtime | SocketAddress => false,
240 }
241 }
242}
243
244impl fmt::Display for MiriMemoryKind {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 use self::MiriMemoryKind::*;
247 match self {
248 Rust => write!(f, "Rust heap"),
249 Miri => write!(f, "Miri bare-metal heap"),
250 C => write!(f, "C heap"),
251 WinHeap => write!(f, "Windows heap"),
252 WinLocal => write!(f, "Windows local memory"),
253 Machine => write!(f, "machine-managed memory"),
254 Runtime => write!(f, "language runtime memory"),
255 Global => write!(f, "global (static or const)"),
256 ExternStatic => write!(f, "extern static"),
257 Tls => write!(f, "thread-local static"),
258 Mmap => write!(f, "mmap"),
259 SocketAddress => write!(f, "socket address"),
260 }
261 }
262}
263
264pub type MemoryKind = interpret::MemoryKind<MiriMemoryKind>;
265
266#[derive(Clone, Copy, PartialEq, Eq, Hash)]
272pub enum Provenance {
273 Concrete {
276 alloc_id: AllocId,
277 tag: BorTag,
279 },
280 Wildcard,
297}
298
299#[derive(Copy, Clone, PartialEq)]
301pub enum ProvenanceExtra {
302 Concrete(BorTag),
303 Wildcard,
304}
305
306#[cfg(target_pointer_width = "64")]
307static_assert_size!(StrictPointer, 24);
308#[cfg(target_pointer_width = "64")]
313static_assert_size!(Scalar, 32);
314
315impl fmt::Debug for Provenance {
316 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317 match self {
318 Provenance::Concrete { alloc_id, tag } => {
319 if f.alternate() {
321 write!(f, "[{alloc_id:#?}]")?;
322 } else {
323 write!(f, "[{alloc_id:?}]")?;
324 }
325 write!(f, "{tag:?}")?;
327 }
328 Provenance::Wildcard => {
329 write!(f, "[wildcard]")?;
330 }
331 }
332 Ok(())
333 }
334}
335
336impl interpret::Provenance for Provenance {
337 const OFFSET_IS_ADDR: bool = true;
339
340 const WILDCARD: Option<Self> = Some(Provenance::Wildcard);
342
343 fn get_alloc_id(self) -> Option<AllocId> {
344 match self {
345 Provenance::Concrete { alloc_id, .. } => Some(alloc_id),
346 Provenance::Wildcard => None,
347 }
348 }
349
350 fn fmt(ptr: &interpret::Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351 let (prov, addr) = ptr.into_raw_parts(); write!(f, "{:#x}", addr.bytes())?;
353 if f.alternate() {
354 write!(f, "{prov:#?}")?;
355 } else {
356 write!(f, "{prov:?}")?;
357 }
358 Ok(())
359 }
360}
361
362impl fmt::Debug for ProvenanceExtra {
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 match self {
365 ProvenanceExtra::Concrete(pid) => write!(f, "{pid:?}"),
366 ProvenanceExtra::Wildcard => write!(f, "<wildcard>"),
367 }
368 }
369}
370
371impl ProvenanceExtra {
372 pub fn and_then<T>(self, f: impl FnOnce(BorTag) -> Option<T>) -> Option<T> {
373 match self {
374 ProvenanceExtra::Concrete(pid) => f(pid),
375 ProvenanceExtra::Wildcard => None,
376 }
377 }
378}
379
380#[derive(Debug)]
382pub struct AllocExtra<'tcx> {
383 pub borrow_tracker: Option<borrow_tracker::AllocState>,
385 pub data_race: AllocDataRaceHandler,
389 pub backtrace: Option<Vec<FrameInfo<'tcx>>>,
394 pub sync_objs: BTreeMap<Size, Box<dyn SyncObj>>,
399}
400
401impl<'tcx> Clone for AllocExtra<'tcx> {
404 fn clone(&self) -> Self {
405 panic!("our allocations should never be cloned");
406 }
407}
408
409impl VisitProvenance for AllocExtra<'_> {
410 fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
411 let AllocExtra { borrow_tracker, data_race, backtrace: _, sync_objs: _ } = self;
412
413 borrow_tracker.visit_provenance(visit);
414 data_race.visit_provenance(visit);
415 }
416}
417
418pub struct PrimitiveLayouts<'tcx> {
420 pub unit: TyAndLayout<'tcx>,
421 pub i8: TyAndLayout<'tcx>,
422 pub i16: TyAndLayout<'tcx>,
423 pub i32: TyAndLayout<'tcx>,
424 pub i64: TyAndLayout<'tcx>,
425 pub i128: TyAndLayout<'tcx>,
426 pub isize: TyAndLayout<'tcx>,
427 pub u8: TyAndLayout<'tcx>,
428 pub u16: TyAndLayout<'tcx>,
429 pub u32: TyAndLayout<'tcx>,
430 pub u64: TyAndLayout<'tcx>,
431 pub u128: TyAndLayout<'tcx>,
432 pub usize: TyAndLayout<'tcx>,
433 pub bool: TyAndLayout<'tcx>,
434 pub unit_ptr_mut: TyAndLayout<'tcx>, pub unit_ptr_const: TyAndLayout<'tcx>, pub void_ptr_mut: TyAndLayout<'tcx>, pub void_ptr_const: TyAndLayout<'tcx>, pub fn_ptr: TyAndLayout<'tcx>, }
440
441impl<'tcx> PrimitiveLayouts<'tcx> {
442 fn new(layout_cx: LayoutCx<'tcx>) -> Result<Self, &'tcx LayoutError<'tcx>> {
443 let tcx = layout_cx.tcx();
444
445 let unit_ptr_mut = Ty::new_mut_ptr(tcx, tcx.types.unit);
446 let unit_ptr_const = Ty::new_imm_ptr(tcx, tcx.types.unit);
447 let c_void = match tcx.lang_items().c_void() {
449 Some(c_void) => ty::Instance::mono(tcx, c_void).ty(tcx, layout_cx.typing_env),
450 None => tcx.types.unit,
451 };
452 let void_ptr_mut = Ty::new_mut_ptr(tcx, c_void);
453 let void_ptr_const = Ty::new_imm_ptr(tcx, c_void);
454
455 let sig_kind = ty::FnSigKind::default()
456 .set_abi(ExternAbi::C { unwind: false })
457 .set_safety(rustc_hir::Safety::Safe);
458 let fn_ptr =
459 Ty::new_fn_ptr(tcx, ty::Binder::dummy(tcx.mk_fn_sig([], tcx.types.unit, sig_kind)));
460
461 Ok(Self {
462 unit: layout_cx.layout_of(tcx.types.unit)?,
463 i8: layout_cx.layout_of(tcx.types.i8)?,
464 i16: layout_cx.layout_of(tcx.types.i16)?,
465 i32: layout_cx.layout_of(tcx.types.i32)?,
466 i64: layout_cx.layout_of(tcx.types.i64)?,
467 i128: layout_cx.layout_of(tcx.types.i128)?,
468 isize: layout_cx.layout_of(tcx.types.isize)?,
469 u8: layout_cx.layout_of(tcx.types.u8)?,
470 u16: layout_cx.layout_of(tcx.types.u16)?,
471 u32: layout_cx.layout_of(tcx.types.u32)?,
472 u64: layout_cx.layout_of(tcx.types.u64)?,
473 u128: layout_cx.layout_of(tcx.types.u128)?,
474 usize: layout_cx.layout_of(tcx.types.usize)?,
475 bool: layout_cx.layout_of(tcx.types.bool)?,
476 unit_ptr_mut: layout_cx.layout_of(unit_ptr_mut)?,
477 unit_ptr_const: layout_cx.layout_of(unit_ptr_const)?,
478 void_ptr_mut: layout_cx.layout_of(void_ptr_mut)?,
479 void_ptr_const: layout_cx.layout_of(void_ptr_const)?,
480 fn_ptr: layout_cx.layout_of(fn_ptr)?,
481 })
482 }
483
484 pub fn uint(&self, size: Size) -> Option<TyAndLayout<'tcx>> {
485 match size.bits() {
486 8 => Some(self.u8),
487 16 => Some(self.u16),
488 32 => Some(self.u32),
489 64 => Some(self.u64),
490 128 => Some(self.u128),
491 _ => None,
492 }
493 }
494
495 pub fn int(&self, size: Size) -> Option<TyAndLayout<'tcx>> {
496 match size.bits() {
497 8 => Some(self.i8),
498 16 => Some(self.i16),
499 32 => Some(self.i32),
500 64 => Some(self.i64),
501 128 => Some(self.i128),
502 _ => None,
503 }
504 }
505}
506
507pub struct MiriMachine<'tcx> {
512 pub tcx: TyCtxt<'tcx>,
514
515 pub borrow_tracker: Option<borrow_tracker::GlobalState>,
517
518 pub data_race: GlobalDataRaceHandler,
524
525 pub alloc_addresses: alloc_addresses::GlobalState,
527
528 pub(crate) env_vars: EnvVars<'tcx>,
530
531 pub(crate) main_fn_ret_place: Option<MPlaceTy<'tcx>>,
533
534 pub(crate) argc: Option<Pointer>,
538 pub(crate) argv: Option<Pointer>,
539 pub(crate) cmd_line: Option<Pointer>,
540
541 pub(crate) tls: TlsData<'tcx>,
543
544 pub(crate) isolated_op: IsolatedOp,
548
549 pub(crate) validation: ValidationMode,
551
552 pub(crate) fds: shims::FdTable,
554 pub(crate) dirs: shims::DirTable,
556
557 pub(crate) delayed_readiness_updates: Rc<shims::DelayedReadinessUpdates>,
559
560 pub(crate) monotonic_clock: MonotonicClock,
562
563 pub(crate) threads: ThreadManager<'tcx>,
565
566 pub(crate) blocking_io: BlockingIoManager,
568
569 pub(crate) thread_cpu_affinity: Option<FxHashMap<ThreadId, shims::CpuAffinityMask>>,
574
575 pub(crate) layouts: PrimitiveLayouts<'tcx>,
577
578 pub(crate) static_roots: Vec<AllocId>,
580
581 profiler: Option<measureme::Profiler>,
584 string_cache: FxHashMap<String, measureme::StringId>,
587
588 pub(crate) exported_symbols_cache: RefCell<FxHashMap<Symbol, Option<Instance<'tcx>>>>,
591
592 pub(crate) backtrace_style: BacktraceStyle,
594
595 pub(crate) user_relevant_crates: Vec<CrateNum>,
597
598 pub(crate) extern_statics: FxHashMap<Symbol, StrictPointer>,
600 pub(crate) extern_statics_imports: FxHashMap<Symbol, StrictPointer>,
603 pub(crate) extern_static_weak_import_default: Option<StrictPointer>,
605
606 pub(crate) rng: RefCell<StdRng>,
609
610 pub(crate) allocator: Option<Rc<RefCell<crate::alloc::isolated_alloc::IsolatedAlloc>>>,
612
613 pub(crate) tracked_alloc_ids: FxHashSet<AllocId>,
616 track_alloc_accesses: bool,
618
619 pub(crate) check_alignment: AlignmentCheck,
621
622 pub(crate) cmpxchg_weak_failure_rate: f64,
624
625 pub(crate) preemption_rate: f64,
627
628 pub(crate) report_progress: Option<u32>,
630 pub(crate) basic_block_count: u64,
632
633 #[cfg(all(feature = "native-lib", unix))]
635 pub native_lib: Vec<(libloading::Library, std::path::PathBuf)>,
636 #[cfg(not(all(feature = "native-lib", unix)))]
637 pub native_lib: Vec<!>,
638 #[cfg(all(feature = "native-lib", unix))]
640 pub native_lib_ecx_interchange: &'static Cell<usize>,
641
642 pub(crate) gc_interval: u32,
644 pub(crate) since_gc: u32,
646
647 pub(crate) num_cpus: u32,
649
650 pub(crate) page_size: u64,
652 pub(crate) stack_addr: u64,
653 pub(crate) stack_size: u64,
654
655 pub(crate) collect_leak_backtraces: bool,
657
658 pub(crate) allocation_spans: RefCell<FxHashMap<AllocId, (Span, Option<Span>)>>,
661
662 pub(crate) symbolic_alignment: RefCell<FxHashMap<AllocId, (Size, Align)>>,
669
670 union_data_ranges: FxHashMap<Ty<'tcx>, RangeSet>,
672
673 pub(crate) pthread_mutex_sanity: Cell<bool>,
675 pub(crate) pthread_rwlock_sanity: Cell<bool>,
676 pub(crate) pthread_condvar_sanity: Cell<bool>,
677
678 pub(crate) allocator_shim_symbols: FxHashMap<Symbol, Either<Symbol, SpecialAllocatorMethod>>,
682 pub(crate) mangle_internal_symbol_cache: FxHashMap<&'static str, String>,
684
685 pub float_nondet: bool,
687 pub float_rounding_error: FloatRoundingErrorMode,
689
690 pub short_fd_operations: bool,
692}
693
694impl<'tcx> MiriMachine<'tcx> {
695 pub(crate) fn new(
699 config: &MiriConfig,
700 layout_cx: LayoutCx<'tcx>,
701 genmc_ctx: Option<Rc<GenmcCtx>>,
702 ) -> Self {
703 let tcx = layout_cx.tcx();
704 let user_relevant_crates = Self::get_user_relevant_crates(tcx, config);
705 let layouts =
706 PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types");
707 let profiler = config.measureme_out.as_ref().map(|out| {
708 let crate_name =
709 tcx.sess.opts.crate_name.clone().unwrap_or_else(|| "unknown-crate".to_string());
710 let pid = process::id();
711 let filename = format!("{crate_name}-{pid:07}");
716 let path = Path::new(out).join(filename);
717 measureme::Profiler::new(path).expect("Couldn't create `measureme` profiler")
718 });
719 let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
720 let borrow_tracker = config.borrow_tracker.map(|bt| bt.instantiate_global_state(config));
721 let data_race = if config.genmc_config.is_some() {
722 GlobalDataRaceHandler::Genmc(genmc_ctx.unwrap())
724 } else if config.data_race_detector {
725 GlobalDataRaceHandler::Vclocks(Box::new(data_race::GlobalState::new(config)))
726 } else {
727 GlobalDataRaceHandler::None
728 };
729 let page_size = if let Some(page_size) = config.page_size {
733 page_size
734 } else {
735 let target = &tcx.sess.target;
736 match target.arch {
737 Arch::Wasm32 | Arch::Wasm64 => 64 * 1024, Arch::AArch64 if target.is_like_darwin => {
739 16 * 1024
743 }
744 _ => 4 * 1024,
745 }
746 };
747 let stack_addr = if tcx.pointer_size().bits() < 32 { page_size } else { page_size * 32 };
749 let stack_size =
750 if tcx.pointer_size().bits() < 32 { page_size * 4 } else { page_size * 16 };
751 assert!(
752 usize::try_from(config.num_cpus).unwrap() <= shims::cpu_affinity::MAX_CPUS,
753 "miri only supports up to {} CPUs, but {} were configured",
754 shims::cpu_affinity::MAX_CPUS,
755 config.num_cpus
756 );
757 let threads = ThreadManager::new(config);
758 let thread_cpu_affinity =
759 if matches!(&tcx.sess.target.os, Os::Linux | Os::FreeBsd | Os::Android)
760 && !is_no_core(tcx)
761 {
762 let mut affinity = FxHashMap::default();
763 affinity.insert(
764 threads.active_thread(),
765 shims::CpuAffinityMask::new(&layout_cx, config.num_cpus),
766 );
767 Some(affinity)
768 } else {
769 None
770 };
771 let blocking_io = BlockingIoManager::new(config.isolated_op == IsolatedOp::Allow)
772 .expect("Couldn't create poll instance");
773 let alloc_addresses =
774 RefCell::new(alloc_addresses::GlobalStateInner::new(config, stack_addr, tcx));
775
776 MiriMachine {
777 tcx,
778 borrow_tracker,
779 data_race,
780 alloc_addresses,
781 env_vars: EnvVars::default(),
783 main_fn_ret_place: None,
784 argc: None,
785 argv: None,
786 cmd_line: None,
787 tls: TlsData::default(),
788 isolated_op: config.isolated_op,
789 validation: config.validation,
790 fds: shims::FdTable::init(config.mute_stdout_stderr),
791 delayed_readiness_updates: Rc::new(shims::DelayedReadinessUpdates::default()),
792 dirs: Default::default(),
793 layouts,
794 threads,
795 thread_cpu_affinity,
796 blocking_io,
797 static_roots: Vec::new(),
798 profiler,
799 string_cache: Default::default(),
800 exported_symbols_cache: RefCell::new(FxHashMap::default()),
801 backtrace_style: config.backtrace_style,
802 user_relevant_crates,
803 extern_statics: FxHashMap::default(),
804 extern_statics_imports: FxHashMap::default(),
805 extern_static_weak_import_default: None,
806 rng: RefCell::new(rng),
807 allocator: (!config.native_lib.is_empty())
808 .then(|| Rc::new(RefCell::new(crate::alloc::isolated_alloc::IsolatedAlloc::new()))),
809 tracked_alloc_ids: config.tracked_alloc_ids.clone(),
810 track_alloc_accesses: config.track_alloc_accesses,
811 check_alignment: config.check_alignment,
812 cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate,
813 preemption_rate: config.preemption_rate,
814 report_progress: config.report_progress,
815 basic_block_count: 0,
816 monotonic_clock: MonotonicClock::new(config.isolated_op == IsolatedOp::Allow),
817 #[cfg(all(feature = "native-lib", unix))]
818 native_lib: config.native_lib.iter().map(|lib_file_path| {
819 let host_triple = rustc_session::config::host_tuple();
820 let target_triple = tcx.sess.opts.target_triple.tuple();
821 if host_triple != target_triple {
823 panic!(
824 "calling native C functions in linked .so file requires host and target to be the same: \
825 host={host_triple}, target={target_triple}",
826 );
827 }
828 (
832 unsafe {
833 libloading::Library::new(lib_file_path)
834 .expect("failed to read specified extern shared object file")
835 },
836 lib_file_path.clone(),
837 )
838 }).collect(),
839 #[cfg(all(feature = "native-lib", unix))]
840 native_lib_ecx_interchange: Box::leak(Box::new(Cell::new(0))),
841 #[cfg(not(all(feature = "native-lib", unix)))]
842 native_lib: config.native_lib.iter().map(|_| {
843 panic!("calling functions from native libraries via FFI is not supported in this build of Miri")
844 }).collect(),
845 gc_interval: config.gc_interval,
846 since_gc: 0,
847 num_cpus: config.num_cpus,
848 page_size,
849 stack_addr,
850 stack_size,
851 collect_leak_backtraces: config.collect_leak_backtraces,
852 allocation_spans: RefCell::new(FxHashMap::default()),
853 symbolic_alignment: RefCell::new(FxHashMap::default()),
854 union_data_ranges: FxHashMap::default(),
855 pthread_mutex_sanity: Cell::new(false),
856 pthread_rwlock_sanity: Cell::new(false),
857 pthread_condvar_sanity: Cell::new(false),
858 allocator_shim_symbols: Self::allocator_shim_symbols(tcx),
859 mangle_internal_symbol_cache: Default::default(),
860 float_nondet: config.float_nondet,
861 float_rounding_error: config.float_rounding_error,
862 short_fd_operations: config.short_fd_operations,
863 }
864 }
865
866 fn allocator_shim_symbols(
867 tcx: TyCtxt<'tcx>,
868 ) -> FxHashMap<Symbol, Either<Symbol, SpecialAllocatorMethod>> {
869 use rustc_codegen_ssa::base::allocator_shim_contents;
870
871 let Some(kind) = tcx.allocator_kind(()) else {
874 return Default::default();
875 };
876 let methods = allocator_shim_contents(tcx, kind);
877 let mut symbols = FxHashMap::default();
878 for method in methods {
879 let from_name = Symbol::intern(&mangle_internal_symbol(
880 tcx,
881 &allocator::global_fn_name(method.name),
882 ));
883 let to = match method.special {
884 Some(special) => Either::Right(special),
885 None =>
886 Either::Left(Symbol::intern(&mangle_internal_symbol(
887 tcx,
888 &allocator::default_fn_name(method.name),
889 ))),
890 };
891 symbols.try_insert(from_name, to).unwrap();
892 }
893 symbols
894 }
895
896 fn get_user_relevant_crates(tcx: TyCtxt<'_>, config: &MiriConfig) -> Vec<CrateNum> {
899 let local_crate_names = std::env::var("MIRI_LOCAL_CRATES")
902 .map(|crates| crates.split(',').map(|krate| krate.to_string()).collect::<Vec<_>>())
903 .unwrap_or_default();
904 let mut local_crates = Vec::new();
905 for &crate_num in tcx.crates(()) {
906 let name = tcx.crate_name(crate_num);
907 let name = name.as_str();
908 if local_crate_names
909 .iter()
910 .chain(&config.user_relevant_crates)
911 .any(|local_name| local_name == name)
912 {
913 local_crates.push(crate_num);
914 }
915 }
916 local_crates
917 }
918
919 pub(crate) fn late_init(
920 ecx: &mut MiriInterpCx<'tcx>,
921 config: &MiriConfig,
922 on_main_stack_empty: StackEmptyCallback<'tcx>,
923 ) -> InterpResult<'tcx> {
924 EnvVars::init(ecx, config)?;
925 MiriMachine::init_extern_statics(ecx)?;
926 ThreadManager::init(ecx, on_main_stack_empty);
927 interp_ok(())
928 }
929
930 pub(crate) fn communicate(&self) -> bool {
931 self.isolated_op == IsolatedOp::Allow
932 }
933
934 pub(crate) fn is_local(&self, instance: ty::Instance<'tcx>) -> bool {
936 let def_id = instance.def_id();
937 def_id.is_local() || self.user_relevant_crates.contains(&def_id.krate)
938 }
939
940 pub(crate) fn handle_abnormal_termination(&mut self) {
942 drop(self.profiler.take());
947 }
948
949 pub(crate) fn page_align(&self) -> Align {
950 Align::from_bytes(self.page_size).unwrap()
951 }
952
953 pub(crate) fn allocated_span(&self, alloc_id: AllocId) -> Option<SpanData> {
954 self.allocation_spans
955 .borrow()
956 .get(&alloc_id)
957 .map(|(allocated, _deallocated)| allocated.data())
958 }
959
960 pub(crate) fn deallocated_span(&self, alloc_id: AllocId) -> Option<SpanData> {
961 self.allocation_spans
962 .borrow()
963 .get(&alloc_id)
964 .and_then(|(_allocated, deallocated)| *deallocated)
965 .map(Span::data)
966 }
967
968 fn init_allocation(
969 ecx: &MiriInterpCx<'tcx>,
970 id: AllocId,
971 kind: MemoryKind,
972 size: Size,
973 align: Align,
974 ) -> InterpResult<'tcx, AllocExtra<'tcx>> {
975 if ecx.machine.tracked_alloc_ids.contains(&id) {
976 ecx.emit_diagnostic(NonHaltingDiagnostic::TrackingAlloc(id, size, align));
977 }
978
979 let borrow_tracker = ecx
980 .machine
981 .borrow_tracker
982 .as_ref()
983 .map(|bt| bt.borrow_mut().new_allocation(id, size, kind, &ecx.machine));
984
985 let data_race = match &ecx.machine.data_race {
986 GlobalDataRaceHandler::None => AllocDataRaceHandler::None,
987 GlobalDataRaceHandler::Vclocks(data_race) =>
988 AllocDataRaceHandler::Vclocks(
989 data_race::AllocState::new_allocation(
990 data_race,
991 &ecx.machine.threads,
992 size,
993 kind,
994 ecx.machine.current_user_relevant_span(),
995 ),
996 data_race.weak_memory.then(weak_memory::AllocState::new_allocation),
997 ),
998 GlobalDataRaceHandler::Genmc(_genmc_ctx) => {
999 AllocDataRaceHandler::Genmc
1002 }
1003 };
1004
1005 let backtrace = if kind.may_leak() || !ecx.machine.collect_leak_backtraces {
1009 None
1010 } else {
1011 Some(ecx.generate_stacktrace())
1012 };
1013
1014 if matches!(kind, MemoryKind::Machine(kind) if kind.should_save_allocation_span()) {
1015 ecx.machine
1016 .allocation_spans
1017 .borrow_mut()
1018 .insert(id, (ecx.machine.current_user_relevant_span(), None));
1019 }
1020
1021 interp_ok(AllocExtra {
1022 borrow_tracker,
1023 data_race,
1024 backtrace,
1025 sync_objs: BTreeMap::default(),
1026 })
1027 }
1028}
1029
1030impl VisitProvenance for MiriMachine<'_> {
1031 fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
1032 #[rustfmt::skip]
1033 let MiriMachine {
1034 threads,
1035 thread_cpu_affinity: _,
1036 tls,
1037 env_vars,
1038 main_fn_ret_place,
1039 argc,
1040 argv,
1041 cmd_line,
1042 extern_statics,
1043 extern_statics_imports,
1044 extern_static_weak_import_default,
1045 dirs,
1046 borrow_tracker,
1047 data_race,
1048 alloc_addresses,
1049 fds,
1050 blocking_io:_,
1051 delayed_readiness_updates: _,
1052 tcx: _,
1053 isolated_op: _,
1054 validation: _,
1055 monotonic_clock: _,
1056 layouts: _,
1057 static_roots: _,
1058 profiler: _,
1059 string_cache: _,
1060 exported_symbols_cache: _,
1061 backtrace_style: _,
1062 user_relevant_crates: _,
1063 rng: _,
1064 allocator: _,
1065 tracked_alloc_ids: _,
1066 track_alloc_accesses: _,
1067 check_alignment: _,
1068 cmpxchg_weak_failure_rate: _,
1069 preemption_rate: _,
1070 report_progress: _,
1071 basic_block_count: _,
1072 native_lib: _,
1073 #[cfg(all(feature = "native-lib", unix))]
1074 native_lib_ecx_interchange: _,
1075 gc_interval: _,
1076 since_gc: _,
1077 num_cpus: _,
1078 page_size: _,
1079 stack_addr: _,
1080 stack_size: _,
1081 collect_leak_backtraces: _,
1082 allocation_spans: _,
1083 symbolic_alignment: _,
1084 union_data_ranges: _,
1085 pthread_mutex_sanity: _,
1086 pthread_rwlock_sanity: _,
1087 pthread_condvar_sanity: _,
1088 allocator_shim_symbols: _,
1089 mangle_internal_symbol_cache: _,
1090 float_nondet: _,
1091 float_rounding_error: _,
1092 short_fd_operations: _,
1093 } = self;
1094
1095 threads.visit_provenance(visit);
1096 tls.visit_provenance(visit);
1097 env_vars.visit_provenance(visit);
1098 dirs.visit_provenance(visit);
1099 fds.visit_provenance(visit);
1100 data_race.visit_provenance(visit);
1101 borrow_tracker.visit_provenance(visit);
1102 alloc_addresses.visit_provenance(visit);
1103 main_fn_ret_place.visit_provenance(visit);
1104 argc.visit_provenance(visit);
1105 argv.visit_provenance(visit);
1106 cmd_line.visit_provenance(visit);
1107 extern_static_weak_import_default.visit_provenance(visit);
1108 extern_statics.visit_provenance(visit);
1109 extern_statics_imports.visit_provenance(visit);
1110 }
1111}
1112
1113pub type MiriInterpCx<'tcx> = InterpCx<'tcx, MiriMachine<'tcx>>;
1115
1116pub trait MiriInterpCxExt<'tcx> {
1118 fn eval_context_ref<'a>(&'a self) -> &'a MiriInterpCx<'tcx>;
1119 fn eval_context_mut<'a>(&'a mut self) -> &'a mut MiriInterpCx<'tcx>;
1120}
1121impl<'tcx> MiriInterpCxExt<'tcx> for MiriInterpCx<'tcx> {
1122 #[inline(always)]
1123 fn eval_context_ref(&self) -> &MiriInterpCx<'tcx> {
1124 self
1125 }
1126 #[inline(always)]
1127 fn eval_context_mut(&mut self) -> &mut MiriInterpCx<'tcx> {
1128 self
1129 }
1130}
1131
1132impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
1134 type MemoryKind = MiriMemoryKind;
1135 type ExtraFnVal = DynSym;
1136
1137 type FrameExtra = FrameExtra<'tcx>;
1138 type AllocExtra = AllocExtra<'tcx>;
1139
1140 type Provenance = Provenance;
1141 type ProvenanceExtra = ProvenanceExtra;
1142 type Bytes = MiriAllocBytes;
1143
1144 type MemoryMap =
1145 MonoHashMap<AllocId, (MemoryKind, Allocation<Provenance, Self::AllocExtra, Self::Bytes>)>;
1146
1147 const GLOBAL_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::Global);
1148
1149 const PANIC_ON_ALLOC_FAIL: bool = false;
1150
1151 #[inline(always)]
1152 fn enforce_alignment(ecx: &MiriInterpCx<'tcx>) -> bool {
1153 ecx.machine.check_alignment != AlignmentCheck::None
1154 }
1155
1156 #[inline(always)]
1157 fn alignment_check(
1158 ecx: &MiriInterpCx<'tcx>,
1159 alloc_id: AllocId,
1160 alloc_align: Align,
1161 alloc_kind: AllocKind,
1162 offset: Size,
1163 align: Align,
1164 ) -> Option<Misalignment> {
1165 if ecx.machine.check_alignment != AlignmentCheck::Symbolic {
1166 return None;
1168 }
1169 if alloc_kind != AllocKind::LiveData {
1170 return None;
1172 }
1173 let (promised_offset, promised_align) = ecx
1175 .machine
1176 .symbolic_alignment
1177 .borrow()
1178 .get(&alloc_id)
1179 .copied()
1180 .unwrap_or((Size::ZERO, alloc_align));
1181 if promised_align < align {
1182 Some(Misalignment { has: promised_align, required: align })
1184 } else {
1185 let distance = offset.bytes().wrapping_sub(promised_offset.bytes());
1187 if distance.is_multiple_of(align.bytes()) {
1189 None
1191 } else {
1192 let distance_pow2 = 1 << distance.trailing_zeros();
1194 Some(Misalignment {
1195 has: Align::from_bytes(distance_pow2).unwrap(),
1196 required: align,
1197 })
1198 }
1199 }
1200 }
1201
1202 #[inline(always)]
1203 fn enforce_validity(ecx: &MiriInterpCx<'tcx>, _layout: TyAndLayout<'tcx>) -> bool {
1204 ecx.machine.validation != ValidationMode::No
1205 }
1206 #[inline(always)]
1207 fn enforce_validity_recursively(
1208 ecx: &InterpCx<'tcx, Self>,
1209 _layout: TyAndLayout<'tcx>,
1210 ) -> bool {
1211 ecx.machine.validation == ValidationMode::Deep
1212 }
1213
1214 #[inline(always)]
1215 fn ignore_optional_overflow_checks(ecx: &MiriInterpCx<'tcx>) -> bool {
1216 !ecx.tcx.sess.overflow_checks()
1217 }
1218
1219 fn check_fn_target_features(
1220 ecx: &MiriInterpCx<'tcx>,
1221 instance: ty::Instance<'tcx>,
1222 ) -> InterpResult<'tcx> {
1223 let attrs = ecx.tcx.codegen_instance_attrs(instance.def);
1224 if attrs
1225 .target_features
1226 .iter()
1227 .any(|feature| !ecx.tcx.sess.internal_target_features.contains(&feature.name))
1228 {
1229 let unavailable = attrs
1230 .target_features
1231 .iter()
1232 .filter(|&feature| {
1233 feature.kind != TargetFeatureKind::Implied
1234 && !ecx.tcx.sess.internal_target_features.contains(&feature.name)
1235 })
1236 .fold(String::new(), |mut s, feature| {
1237 if !s.is_empty() {
1238 s.push_str(", ");
1239 }
1240 s.push_str(feature.name.as_str());
1241 s
1242 });
1243 let msg = format!(
1244 "calling a function that requires unavailable target features: {unavailable}"
1245 );
1246 if ecx.tcx.sess.target.is_like_wasm {
1249 throw_machine_stop!(TerminationInfo::Abort(msg));
1250 } else {
1251 throw_ub_format!("{msg}");
1252 }
1253 }
1254 interp_ok(())
1255 }
1256
1257 #[inline(always)]
1258 fn find_mir_or_eval_fn(
1259 ecx: &mut MiriInterpCx<'tcx>,
1260 instance: ty::Instance<'tcx>,
1261 abi: &FnAbi<'tcx, Ty<'tcx>>,
1262 args: &[FnArg<'tcx>],
1263 dest: &PlaceTy<'tcx>,
1264 ret: Option<mir::BasicBlock>,
1265 unwind: mir::UnwindAction,
1266 ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> {
1267 if ecx.tcx.is_foreign_item(instance.def_id()) {
1269 let _trace = enter_trace_span!("emulate_foreign_item");
1270 let args = MiriInterpCx::copy_fn_args(args); let link_name = Symbol::intern(ecx.tcx.symbol_name(instance).name);
1278 return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
1279 }
1280
1281 if ecx.machine.data_race.as_genmc_ref().is_some()
1282 && ecx.genmc_intercept_function(instance, args, dest)?
1283 {
1284 ecx.return_to_block(ret)?;
1285 return interp_ok(None);
1286 }
1287
1288 let _trace = enter_trace_span!("load_mir");
1290 interp_ok(Some((ecx.load_mir(instance.def, None)?, instance)))
1291 }
1292
1293 #[inline(always)]
1294 fn call_extra_fn(
1295 ecx: &mut MiriInterpCx<'tcx>,
1296 fn_val: DynSym,
1297 abi: &FnAbi<'tcx, Ty<'tcx>>,
1298 args: &[FnArg<'tcx>],
1299 dest: &PlaceTy<'tcx>,
1300 ret: Option<mir::BasicBlock>,
1301 unwind: mir::UnwindAction,
1302 ) -> InterpResult<'tcx> {
1303 let args = MiriInterpCx::copy_fn_args(args); ecx.emulate_dyn_sym(fn_val, abi, &args, dest, ret, unwind)
1305 }
1306
1307 #[inline(always)]
1308 fn call_intrinsic(
1309 ecx: &mut MiriInterpCx<'tcx>,
1310 instance: ty::Instance<'tcx>,
1311 args: &[OpTy<'tcx>],
1312 dest: &PlaceTy<'tcx>,
1313 ret: Option<mir::BasicBlock>,
1314 unwind: mir::UnwindAction,
1315 ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
1316 ecx.call_intrinsic(instance, args, dest, ret, unwind)
1317 }
1318
1319 #[inline(always)]
1320 fn call_llvm_intrinsic(
1321 ecx: &mut MiriInterpCx<'tcx>,
1322 instance: ty::Instance<'tcx>,
1323 args: &[OpTy<'tcx>],
1324 dest: &PlaceTy<'tcx>,
1325 ret: Option<mir::BasicBlock>,
1326 ) -> InterpResult<'tcx, ()> {
1327 ecx.call_llvm_intrinsic(instance, args, dest, ret)
1328 }
1329
1330 #[inline(always)]
1331 fn assert_panic(
1332 ecx: &mut MiriInterpCx<'tcx>,
1333 msg: &mir::AssertMessage<'tcx>,
1334 unwind: mir::UnwindAction,
1335 ) -> InterpResult<'tcx> {
1336 ecx.assert_panic(msg, unwind)
1337 }
1338
1339 fn panic_nounwind(ecx: &mut InterpCx<'tcx, Self>, msg: &str) -> InterpResult<'tcx> {
1340 ecx.start_panic_nounwind(msg)
1341 }
1342
1343 fn unwind_terminate(
1344 ecx: &mut InterpCx<'tcx, Self>,
1345 reason: mir::UnwindTerminateReason,
1346 ) -> InterpResult<'tcx> {
1347 let panic = ecx.tcx.lang_items().get(reason.lang_item()).unwrap();
1349 let panic = ty::Instance::mono(ecx.tcx.tcx, panic);
1350 ecx.call_function(
1351 panic,
1352 ExternAbi::Rust,
1353 &[],
1354 None,
1355 ReturnContinuation::Goto { ret: None, unwind: mir::UnwindAction::Unreachable },
1356 )?;
1357 interp_ok(())
1358 }
1359
1360 #[inline(always)]
1361 fn binary_ptr_op(
1362 ecx: &MiriInterpCx<'tcx>,
1363 bin_op: mir::BinOp,
1364 left: &ImmTy<'tcx>,
1365 right: &ImmTy<'tcx>,
1366 ) -> InterpResult<'tcx, ImmTy<'tcx>> {
1367 ecx.binary_ptr_op(bin_op, left, right)
1368 }
1369
1370 fn atomic_load(
1371 ecx: &MiriInterpCx<'tcx>,
1372 place: &MPlaceTy<'tcx>,
1373 ordering: AtomicOrdering,
1374 ) -> InterpResult<'tcx, Scalar> {
1375 ecx.read_scalar_atomic(place, AtomicReadOrd::from(ordering))
1376 }
1377
1378 fn atomic_store(
1379 ecx: &mut MiriInterpCx<'tcx>,
1380 place: &MPlaceTy<'tcx>,
1381 val: &ImmTy<'tcx>,
1382 ordering: AtomicOrdering,
1383 ) -> InterpResult<'tcx> {
1384 ecx.write_scalar_atomic(val.to_scalar(), place, AtomicWriteOrd::from(ordering))
1385 }
1386
1387 fn atomic_rmw(
1388 ecx: &mut MiriInterpCx<'tcx>,
1389 place: &MPlaceTy<'tcx>,
1390 op: AtomicRmwOp,
1391 operand: &ImmTy<'tcx>,
1392 ordering: AtomicOrdering,
1393 ) -> InterpResult<'tcx, Scalar> {
1394 ecx.atomic_rmw(place, operand, op, AtomicRwOrd::from(ordering))
1395 }
1396
1397 fn atomic_compare_exchange(
1398 ecx: &mut MiriInterpCx<'tcx>,
1399 place: &MPlaceTy<'tcx>,
1400 expected_old: &ImmTy<'tcx>,
1401 new: &ImmTy<'tcx>,
1402 can_fail_spuriously: bool,
1403 success_ordering: AtomicOrdering,
1404 failure_ordering: AtomicOrdering,
1405 ) -> InterpResult<'tcx, (Scalar, bool)> {
1406 ecx.atomic_compare_exchange(
1407 place,
1408 expected_old,
1409 new.to_scalar(),
1410 AtomicRwOrd::from(success_ordering),
1411 AtomicReadOrd::from(failure_ordering),
1412 can_fail_spuriously,
1413 )
1414 }
1415
1416 fn atomic_fence(
1417 ecx: &MiriInterpCx<'tcx>,
1418 ordering: AtomicOrdering,
1419 singlethread: bool,
1420 ) -> InterpResult<'tcx> {
1421 if singlethread {
1422 return interp_ok(());
1424 }
1425 ecx.atomic_fence(AtomicFenceOrd::from(ordering))
1426 }
1427
1428 #[inline(always)]
1429 fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(
1430 ecx: &InterpCx<'tcx, Self>,
1431 inputs: &[F1],
1432 ) -> F2 {
1433 ecx.generate_nan(inputs)
1434 }
1435
1436 #[inline(always)]
1437 fn apply_float_nondet(
1438 ecx: &mut InterpCx<'tcx, Self>,
1439 val: ImmTy<'tcx>,
1440 ) -> InterpResult<'tcx, ImmTy<'tcx>> {
1441 crate::math::apply_random_float_error_to_imm(ecx, val, 4)
1442 }
1443
1444 #[inline(always)]
1445 fn equal_float_min_max<F: Float>(ecx: &MiriInterpCx<'tcx>, a: F, b: F) -> F {
1446 ecx.equal_float_min_max(a, b)
1447 }
1448
1449 #[inline(always)]
1450 fn float_fuse_mul_add(ecx: &InterpCx<'tcx, Self>) -> bool {
1451 ecx.machine.float_nondet && ecx.machine.rng.borrow_mut().random()
1452 }
1453
1454 #[inline(always)]
1455 fn runtime_checks(
1456 ecx: &InterpCx<'tcx, Self>,
1457 r: mir::RuntimeChecks,
1458 ) -> InterpResult<'tcx, bool> {
1459 interp_ok(r.value(ecx.tcx.sess))
1460 }
1461
1462 #[inline(always)]
1463 fn thread_local_static_pointer(
1464 ecx: &mut MiriInterpCx<'tcx>,
1465 def_id: DefId,
1466 ) -> InterpResult<'tcx, StrictPointer> {
1467 ecx.get_or_create_thread_local_alloc(def_id)
1468 }
1469
1470 fn extern_static_pointer(
1471 ecx: &MiriInterpCx<'tcx>,
1472 def_id: DefId,
1473 ) -> InterpResult<'tcx, StrictPointer> {
1474 let link_name = Symbol::intern(ecx.tcx.symbol_name(Instance::mono(*ecx.tcx, def_id)).name);
1475 let def_ty = ecx.tcx.type_of(def_id).instantiate_identity().skip_norm_wip();
1476 let extern_decl_layout =
1477 ecx.tcx.layout_of(ecx.typing_env().as_query_input(def_ty)).unwrap();
1478
1479 let ptr = match ecx.tcx.codegen_fn_attrs(def_id).import_linkage {
1482 None => ecx.machine.extern_statics.get(&link_name),
1483 Some(_) => ecx.machine.extern_statics_imports.get(&link_name),
1484 };
1485 if let Some(&ptr) = ptr {
1486 ecx.check_shim_symbol_clash(link_name)?;
1487 let Provenance::Concrete { alloc_id, .. } = ptr.provenance else {
1491 panic!("extern_statics cannot contain wildcards")
1492 };
1493 let info = ecx.get_alloc_info(alloc_id);
1494 if extern_decl_layout.size > info.size || extern_decl_layout.align.abi > info.align {
1495 throw_ub_format!(
1496 "extern static `{link_name}` has been declared as `{krate}::{name}` \
1497 with a size of {decl_size} bytes and alignment of {decl_align} bytes, \
1498 but Miri emulates it via an extern static shim \
1499 with a size of {shim_size} bytes and alignment of {shim_align} bytes",
1500 name = ecx.tcx.def_path_str(def_id),
1501 krate = ecx.tcx.crate_name(def_id.krate),
1502 decl_size = extern_decl_layout.size.bytes(),
1503 decl_align = extern_decl_layout.align.bytes(),
1504 shim_size = info.size.bytes(),
1505 shim_align = info.align.bytes(),
1506 )
1507 }
1508 interp_ok(ptr)
1509 } else if ecx.tcx.codegen_fn_attrs(def_id).import_linkage == Some(Linkage::ExternalWeak) {
1510 assert_eq!(
1518 extern_decl_layout.size,
1519 ecx.tcx.data_layout.pointer_size(),
1520 "non-pointer-sized weak static"
1521 );
1522 interp_ok(
1523 ecx.machine
1524 .extern_static_weak_import_default
1525 .expect("`missing_weak_symbol` should have been initialized"),
1526 )
1527 } else {
1528 let Some(instance) = ecx.lookup_exported_static(link_name)? else {
1530 throw_unsup_format!("extern static `{link_name}` is not supported by Miri");
1531 };
1532 let place = ecx.eval_global(instance)?;
1534 let static_ptr = place.ptr().into_pointer_or_addr().unwrap();
1535 let alloc_id = static_ptr.provenance.get_alloc_id().unwrap();
1537 let info = ecx.get_alloc_info(alloc_id);
1538 if extern_decl_layout.size > info.size || extern_decl_layout.align.abi > info.align {
1539 throw_ub_format!(
1540 "extern static `{link_name}` has been declared as `{krate}::{name}` \
1541 with a size of {decl_size} bytes and alignment of {decl_align} bytes, \
1542 but the exported static with that name has a size of {shim_size} bytes and \
1543 alignment of {shim_align} bytes",
1544 name = ecx.tcx.def_path_str(def_id),
1545 krate = ecx.tcx.crate_name(def_id.krate),
1546 decl_size = extern_decl_layout.size.bytes(),
1547 decl_align = extern_decl_layout.align.bytes(),
1548 shim_size = info.size.bytes(),
1549 shim_align = info.align.bytes(),
1550 )
1551 }
1552 let DefKind::Static { mutability, .. } = ecx.tcx.def_kind(def_id) else {
1561 unreachable!("`{def_id:?}` is not a static");
1562 };
1563 let decl_is_mut =
1564 !(mutability == Mutability::Not && ecx.type_is_freeze(extern_decl_layout.ty));
1565 let backing_is_mut = ecx.get_alloc_mutability(alloc_id)? == Mutability::Mut;
1566 if !decl_is_mut && backing_is_mut {
1567 throw_ub_format!(
1568 "extern static `{krate}::{name}` is declared as an immutable `static`, \
1569 but the backing static is mutable",
1570 name = ecx.tcx.def_path_str(def_id),
1571 krate = ecx.tcx.crate_name(def_id.krate),
1572 )
1573 }
1574 if decl_is_mut && !backing_is_mut {
1575 throw_ub_format!(
1576 "extern static `{krate}::{name}` is declared as an mutable `static`, \
1577 but the backing static is immutable",
1578 name = ecx.tcx.def_path_str(def_id),
1579 krate = ecx.tcx.crate_name(def_id.krate),
1580 )
1581 }
1582 interp_ok(static_ptr)
1583 }
1584 }
1585
1586 fn init_local_allocation(
1587 ecx: &MiriInterpCx<'tcx>,
1588 id: AllocId,
1589 kind: MemoryKind,
1590 size: Size,
1591 align: Align,
1592 ) -> InterpResult<'tcx, Self::AllocExtra> {
1593 assert!(kind != MiriMemoryKind::Global.into());
1594 MiriMachine::init_allocation(ecx, id, kind, size, align)
1595 }
1596
1597 fn adjust_alloc_root_pointer(
1598 ecx: &MiriInterpCx<'tcx>,
1599 ptr: interpret::Pointer<CtfeProvenance>,
1600 kind: Option<MemoryKind>,
1601 ) -> InterpResult<'tcx, interpret::Pointer<Provenance>> {
1602 let kind = kind.expect("we set our GLOBAL_KIND so this cannot be None");
1603 let alloc_id = ptr.provenance.alloc_id();
1604 if cfg!(debug_assertions) {
1605 match ecx.tcx.try_get_global_alloc(alloc_id) {
1607 Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => {
1608 panic!("adjust_alloc_root_pointer called on thread-local static")
1609 }
1610 Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_foreign_item(def_id) => {
1611 panic!("adjust_alloc_root_pointer called on extern static")
1612 }
1613 _ => {}
1614 }
1615 }
1616 let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
1618 borrow_tracker.borrow_mut().root_ptr_tag(alloc_id, &ecx.machine)
1619 } else {
1620 BorTag::default()
1622 };
1623 ecx.adjust_alloc_root_pointer(ptr, tag, kind)
1624 }
1625
1626 #[inline(always)]
1628 fn ptr_from_addr_cast(ecx: &MiriInterpCx<'tcx>, addr: u64) -> InterpResult<'tcx, Pointer> {
1629 ecx.ptr_from_addr_cast(addr)
1630 }
1631
1632 #[inline(always)]
1636 fn expose_provenance(
1637 ecx: &InterpCx<'tcx, Self>,
1638 provenance: Self::Provenance,
1639 ) -> InterpResult<'tcx> {
1640 ecx.expose_provenance(provenance)
1641 }
1642
1643 fn ptr_get_alloc(
1655 ecx: &MiriInterpCx<'tcx>,
1656 ptr: StrictPointer,
1657 size: i64,
1658 ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> {
1659 let rel = ecx.ptr_get_alloc(ptr, size);
1660
1661 rel.map(|(alloc_id, size)| {
1662 let tag = match ptr.provenance {
1663 Provenance::Concrete { tag, .. } => ProvenanceExtra::Concrete(tag),
1664 Provenance::Wildcard => ProvenanceExtra::Wildcard,
1665 };
1666 (alloc_id, size, tag)
1667 })
1668 }
1669
1670 fn adjust_global_allocation<'b>(
1679 ecx: &InterpCx<'tcx, Self>,
1680 id: AllocId,
1681 alloc: &'b Allocation,
1682 ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>
1683 {
1684 let alloc = alloc.adjust_from_tcx(
1685 &ecx.tcx,
1686 |bytes, align| ecx.get_global_alloc_bytes(id, bytes, align),
1687 |ptr| ecx.global_root_pointer(ptr),
1688 )?;
1689 let kind = MiriMemoryKind::Global.into();
1690 let extra = MiriMachine::init_allocation(ecx, id, kind, alloc.size(), alloc.align)?;
1691 interp_ok(Cow::Owned(alloc.with_extra(extra)))
1692 }
1693
1694 #[inline(always)]
1695 fn before_memory_read(
1696 _tcx: TyCtxtAt<'tcx>,
1697 machine: &Self,
1698 alloc_extra: &AllocExtra<'tcx>,
1699 ptr: Pointer,
1700 (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
1701 range: AllocRange,
1702 ) -> InterpResult<'tcx> {
1703 if machine.track_alloc_accesses && machine.tracked_alloc_ids.contains(&alloc_id) {
1704 machine.emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(
1705 alloc_id,
1706 range,
1707 borrow_tracker::AccessKind::Read,
1708 ));
1709 }
1710 match &machine.data_race {
1712 GlobalDataRaceHandler::None => {}
1713 GlobalDataRaceHandler::Genmc(genmc_ctx) =>
1714 genmc_ctx.memory_load(machine, ptr.addr(), range.size)?,
1715 GlobalDataRaceHandler::Vclocks(_data_race) => {
1716 let _trace = enter_trace_span!(data_race::before_memory_read);
1717 let AllocDataRaceHandler::Vclocks(data_race, _weak_memory) = &alloc_extra.data_race
1718 else {
1719 unreachable!();
1720 };
1721 data_race.read_non_atomic(alloc_id, range, NaReadType::Read, None, machine)?;
1722 }
1723 }
1724 if let Some(borrow_tracker) = &alloc_extra.borrow_tracker {
1725 borrow_tracker.before_memory_read(alloc_id, prov_extra, range, machine)?;
1726 }
1727 for (_offset, obj) in alloc_extra.sync_objs.range(range.start..range.end()) {
1729 obj.on_access(concurrency::sync::AccessKind::Read)?;
1730 }
1731
1732 interp_ok(())
1733 }
1734
1735 #[inline(always)]
1736 fn before_memory_write(
1737 _tcx: TyCtxtAt<'tcx>,
1738 machine: &mut Self,
1739 alloc_extra: &mut AllocExtra<'tcx>,
1740 ptr: Pointer,
1741 (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
1742 range: AllocRange,
1743 ) -> InterpResult<'tcx> {
1744 if machine.track_alloc_accesses && machine.tracked_alloc_ids.contains(&alloc_id) {
1745 machine.emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(
1746 alloc_id,
1747 range,
1748 borrow_tracker::AccessKind::Write,
1749 ));
1750 }
1751 match &machine.data_race {
1752 GlobalDataRaceHandler::None => {}
1753 GlobalDataRaceHandler::Genmc(genmc_ctx) =>
1754 genmc_ctx.memory_store(machine, ptr.addr(), range.size)?,
1755 GlobalDataRaceHandler::Vclocks(_global_state) => {
1756 let _trace = enter_trace_span!(data_race::before_memory_write);
1757 let AllocDataRaceHandler::Vclocks(data_race, weak_memory) =
1758 &mut alloc_extra.data_race
1759 else {
1760 unreachable!()
1761 };
1762 data_race.write_non_atomic(alloc_id, range, NaWriteType::Write, None, machine)?;
1763 if let Some(weak_memory) = weak_memory {
1764 weak_memory
1765 .non_atomic_write(range, machine.data_race.as_vclocks_ref().unwrap());
1766 }
1767 }
1768 }
1769 if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker {
1770 borrow_tracker.before_memory_write(alloc_id, prov_extra, range, machine)?;
1771 }
1772 if !alloc_extra.sync_objs.is_empty() {
1775 let mut to_delete = vec![];
1776 for (offset, obj) in alloc_extra.sync_objs.range(range.start..range.end()) {
1777 obj.on_access(concurrency::sync::AccessKind::Write)?;
1778 if obj.delete_on_write() {
1779 to_delete.push(*offset);
1780 }
1781 }
1782 for offset in to_delete {
1783 alloc_extra.sync_objs.remove(&offset);
1784 }
1785 }
1786 interp_ok(())
1787 }
1788
1789 #[inline(always)]
1790 fn before_memory_deallocation(
1791 _tcx: TyCtxtAt<'tcx>,
1792 machine: &mut Self,
1793 alloc_extra: &mut AllocExtra<'tcx>,
1794 ptr: Pointer,
1795 (alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra),
1796 size: Size,
1797 align: Align,
1798 kind: MemoryKind,
1799 ) -> InterpResult<'tcx> {
1800 if machine.tracked_alloc_ids.contains(&alloc_id) {
1801 machine.emit_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id));
1802 }
1803 match &machine.data_race {
1804 GlobalDataRaceHandler::None => {}
1805 GlobalDataRaceHandler::Genmc(genmc_ctx) =>
1806 genmc_ctx.handle_dealloc(machine, alloc_id, ptr.addr(), kind)?,
1807 GlobalDataRaceHandler::Vclocks(_global_state) => {
1808 let _trace = enter_trace_span!(data_race::before_memory_deallocation);
1809 let data_race = alloc_extra.data_race.as_vclocks_mut().unwrap();
1810 data_race.write_non_atomic(
1811 alloc_id,
1812 alloc_range(Size::ZERO, size),
1813 NaWriteType::Deallocate,
1814 None,
1815 machine,
1816 )?;
1817 }
1818 }
1819 if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker {
1820 borrow_tracker.before_memory_deallocation(alloc_id, prove_extra, size, machine)?;
1821 }
1822 for obj in alloc_extra.sync_objs.values() {
1824 obj.on_access(concurrency::sync::AccessKind::Dealloc)?;
1825 }
1826
1827 if let Some((_, deallocated_at)) = machine.allocation_spans.borrow_mut().get_mut(&alloc_id)
1828 {
1829 *deallocated_at = Some(machine.current_user_relevant_span());
1830 }
1831 machine.free_alloc_id(alloc_id, size, align, kind);
1832 interp_ok(())
1833 }
1834
1835 #[inline(always)]
1836 fn retag_ptr_value(
1837 ecx: &mut InterpCx<'tcx, Self>,
1838 val: &ImmTy<'tcx>,
1839 ty: Ty<'tcx>,
1840 ) -> InterpResult<'tcx, Option<ImmTy<'tcx>>> {
1841 if ecx.machine.borrow_tracker.is_some() {
1842 ecx.retag_ptr_value(val, ty)
1843 } else {
1844 interp_ok(None)
1845 }
1846 }
1847
1848 #[inline(always)]
1849 fn with_retag_mode<T>(
1850 ecx: &mut InterpCx<'tcx, Self>,
1851 mode: RetagMode,
1852 f: impl FnOnce(&mut InterpCx<'tcx, Self>) -> InterpResult<'tcx, T>,
1853 ) -> InterpResult<'tcx, T> {
1854 if ecx.machine.borrow_tracker.is_some() { ecx.with_retag_mode(mode, f) } else { f(ecx) }
1855 }
1856
1857 fn protect_in_place_function_argument(
1858 ecx: &mut InterpCx<'tcx, Self>,
1859 place: &MPlaceTy<'tcx>,
1860 ) -> InterpResult<'tcx> {
1861 let protected_place = if ecx.machine.borrow_tracker.is_some() {
1864 ecx.protect_place(place)?
1865 } else {
1866 place.clone()
1868 };
1869 ecx.write_uninit(&protected_place)?;
1874 interp_ok(())
1876 }
1877
1878 #[inline(always)]
1879 fn init_frame(
1880 ecx: &mut InterpCx<'tcx, Self>,
1881 frame: Frame<'tcx, Provenance>,
1882 ) -> InterpResult<'tcx, Frame<'tcx, Provenance, FrameExtra<'tcx>>> {
1883 let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() {
1885 let fn_name = frame.instance().to_string();
1886 let entry = ecx.machine.string_cache.entry(fn_name.clone());
1887 let name = entry.or_insert_with(|| profiler.alloc_string(&*fn_name));
1888
1889 Some(profiler.start_recording_interval_event_detached(
1890 *name,
1891 measureme::EventId::from_label(*name),
1892 ecx.active_thread().to_u32(),
1893 ))
1894 } else {
1895 None
1896 };
1897
1898 let borrow_tracker = ecx.machine.borrow_tracker.as_ref();
1899
1900 let extra = FrameExtra {
1901 borrow_tracker: borrow_tracker.map(|bt| bt.borrow_mut().new_frame()),
1902 catch_unwind: None,
1903 timing,
1904 user_relevance: ecx.machine.user_relevance(&frame),
1905 data_race: ecx
1906 .machine
1907 .data_race
1908 .as_vclocks_ref()
1909 .map(|_| data_race::FrameState::default()),
1910 };
1911
1912 interp_ok(frame.with_extra(extra))
1913 }
1914
1915 fn stack<'a>(
1916 ecx: &'a InterpCx<'tcx, Self>,
1917 ) -> &'a [Frame<'tcx, Self::Provenance, Self::FrameExtra>] {
1918 ecx.active_thread_stack()
1919 }
1920
1921 fn stack_mut<'a>(
1922 ecx: &'a mut InterpCx<'tcx, Self>,
1923 ) -> &'a mut Vec<Frame<'tcx, Self::Provenance, Self::FrameExtra>> {
1924 ecx.active_thread_stack_mut()
1925 }
1926
1927 fn before_terminator(ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
1928 ecx.machine.basic_block_count += 1u64; ecx.machine.since_gc += 1;
1930 if let Some(report_progress) = ecx.machine.report_progress {
1932 if ecx.machine.basic_block_count.is_multiple_of(u64::from(report_progress)) {
1933 ecx.emit_diagnostic(NonHaltingDiagnostic::ProgressReport {
1934 block_count: ecx.machine.basic_block_count,
1935 });
1936 }
1937 }
1938
1939 if ecx.machine.gc_interval > 0 && ecx.machine.since_gc >= ecx.machine.gc_interval {
1945 ecx.machine.since_gc = 0;
1946 ecx.run_provenance_gc();
1947 ecx.machine.blocking_io.run_gc();
1948 }
1949
1950 ecx.maybe_preempt_active_thread();
1953
1954 ecx.machine.monotonic_clock.tick();
1956
1957 interp_ok(())
1958 }
1959
1960 #[inline(always)]
1961 fn after_stack_push(ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
1962 if ecx.frame().extra.user_relevance >= ecx.active_thread_ref().current_user_relevance() {
1963 let stack_len = ecx.active_thread_stack().len();
1966 ecx.active_thread_mut().set_top_user_relevant_frame(stack_len - 1);
1967 }
1968 interp_ok(())
1969 }
1970
1971 fn before_stack_pop(ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
1972 let frame = ecx.frame();
1973 if ecx.machine.borrow_tracker.is_some() {
1976 ecx.on_stack_pop(frame)?;
1977 }
1978 if ecx
1979 .active_thread_ref()
1980 .top_user_relevant_frame()
1981 .expect("there should always be a most relevant frame for a non-empty stack")
1982 == ecx.frame_idx()
1983 {
1984 ecx.active_thread_mut().recompute_top_user_relevant_frame(1);
1990 }
1991 info!("Leaving {}", ecx.frame().instance());
1995 interp_ok(())
1996 }
1997
1998 #[inline(always)]
1999 fn after_stack_pop(
2000 ecx: &mut InterpCx<'tcx, Self>,
2001 frame: Frame<'tcx, Provenance, FrameExtra<'tcx>>,
2002 unwinding: bool,
2003 ) -> InterpResult<'tcx, ReturnAction> {
2004 let res = {
2005 let mut frame = frame;
2007 let timing = frame.extra.timing.take();
2008 let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding);
2009 if let Some(profiler) = ecx.machine.profiler.as_ref() {
2010 profiler.finish_recording_interval_event(timing.unwrap());
2011 }
2012 res
2013 };
2014 if !ecx.active_thread_stack().is_empty() {
2017 info!("Continuing in {}", ecx.frame().instance());
2018 }
2019 res
2020 }
2021
2022 fn after_local_read(ecx: &InterpCx<'tcx, Self>, local: mir::Local) -> InterpResult<'tcx> {
2023 if let Some(data_race) = &ecx.frame().extra.data_race {
2024 let _trace = enter_trace_span!(data_race::after_local_read);
2025 data_race.local_read(local, &ecx.machine);
2026 }
2027 interp_ok(())
2028 }
2029
2030 fn after_local_write(
2031 ecx: &mut InterpCx<'tcx, Self>,
2032 local: mir::Local,
2033 storage_live: bool,
2034 ) -> InterpResult<'tcx> {
2035 if let Some(data_race) = &ecx.frame().extra.data_race {
2036 let _trace = enter_trace_span!(data_race::after_local_write);
2037 data_race.local_write(local, storage_live, &ecx.machine);
2038 }
2039 interp_ok(())
2040 }
2041
2042 fn after_local_moved_to_memory(
2043 ecx: &mut InterpCx<'tcx, Self>,
2044 local: mir::Local,
2045 mplace: &MPlaceTy<'tcx>,
2046 ) -> InterpResult<'tcx> {
2047 let Some(Provenance::Concrete { alloc_id, .. }) = mplace.ptr().provenance else {
2048 panic!("after_local_allocated should only be called on fresh allocations");
2049 };
2050 let local_decl = &ecx.frame().body().local_decls[local];
2052 let span = local_decl.source_info.span;
2053 ecx.machine.allocation_spans.borrow_mut().insert(alloc_id, (span, None));
2054 let (alloc_info, machine) = ecx.get_alloc_extra_mut(alloc_id)?;
2056 if let Some(data_race) =
2057 &machine.threads.active_thread_stack().last().unwrap().extra.data_race
2058 {
2059 let _trace = enter_trace_span!(data_race::after_local_moved_to_memory);
2060 data_race.local_moved_to_memory(
2061 local,
2062 alloc_info.data_race.as_vclocks_mut().unwrap(),
2063 machine,
2064 );
2065 }
2066 interp_ok(())
2067 }
2068
2069 fn get_global_alloc_salt(
2070 ecx: &InterpCx<'tcx, Self>,
2071 instance: Option<ty::Instance<'tcx>>,
2072 ) -> usize {
2073 let unique = if let Some(instance) = instance {
2074 let is_generic = instance
2087 .args
2088 .into_iter()
2089 .any(|arg| !matches!(arg.kind(), ty::GenericArgKind::Lifetime(_)));
2090 let can_be_inlined = matches!(
2091 ecx.tcx.sess.opts.unstable_opts.cross_crate_inline_threshold,
2092 InliningThreshold::Always
2093 ) || !matches!(
2094 ecx.tcx.codegen_instance_attrs(instance.def).inline,
2095 InlineAttr::Never
2096 );
2097 !is_generic && !can_be_inlined
2098 } else {
2099 false
2101 };
2102 if unique {
2104 CTFE_ALLOC_SALT
2105 } else {
2106 ecx.machine.rng.borrow_mut().random_range(0..ADDRS_PER_ANON_GLOBAL)
2107 }
2108 }
2109
2110 fn cached_union_data_range<'e>(
2111 ecx: &'e mut InterpCx<'tcx, Self>,
2112 ty: Ty<'tcx>,
2113 compute_range: impl FnOnce() -> RangeSet,
2114 ) -> Cow<'e, RangeSet> {
2115 Cow::Borrowed(ecx.machine.union_data_ranges.entry(ty).or_insert_with(compute_range))
2116 }
2117
2118 fn get_default_alloc_params(&self) -> <Self::Bytes as AllocBytes>::AllocParams {
2119 use crate::alloc::MiriAllocParams;
2120
2121 match &self.allocator {
2122 Some(alloc) => MiriAllocParams::Isolated(alloc.clone()),
2123 None => MiriAllocParams::Global,
2124 }
2125 }
2126
2127 fn enter_trace_span(span: impl FnOnce() -> tracing::Span) -> impl EnteredTraceSpan {
2128 #[cfg(feature = "tracing")]
2129 {
2130 span().entered()
2131 }
2132 #[cfg(not(feature = "tracing"))]
2133 #[expect(clippy::unused_unit)]
2134 {
2135 let _ = span; ()
2137 }
2138 }
2139}
2140
2141pub trait MachineCallback<'tcx, T>: VisitProvenance {
2143 fn call(
2145 self: Box<Self>,
2146 ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
2147 arg: T,
2148 ) -> InterpResult<'tcx>;
2149}
2150
2151pub type DynMachineCallback<'tcx, T> = Box<dyn MachineCallback<'tcx, T> + 'tcx>;
2153
2154#[macro_export]
2171macro_rules! callback {
2172 (@capture<$tcx:lifetime $(,)? $($lft:lifetime),*>
2173 { $($name:ident: $type:ty),* $(,)? }
2174 |$this:ident, $arg:ident: $arg_ty:ty| $body:expr $(,)?) => {{
2175 struct Callback<$tcx, $($lft),*> {
2176 $($name: $type,)*
2177 _phantom: std::marker::PhantomData<&$tcx ()>,
2178 }
2179
2180 impl<$tcx, $($lft),*> VisitProvenance for Callback<$tcx, $($lft),*> {
2181 fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
2182 $(
2183 VisitProvenance::visit_provenance(&self.$name, _visit);
2184 )*
2185 }
2186 }
2187
2188 impl<$tcx, $($lft),*> MachineCallback<$tcx, $arg_ty> for Callback<$tcx, $($lft),*> {
2189 fn call(
2190 self: Box<Self>,
2191 $this: &mut MiriInterpCx<$tcx>,
2192 $arg: $arg_ty
2193 ) -> InterpResult<$tcx> {
2194 #[allow(unused_variables)]
2195 let Callback { $($name,)* _phantom } = *self;
2196 $body
2197 }
2198 }
2199
2200 Box::new(Callback {
2201 $($name,)*
2202 _phantom: std::marker::PhantomData
2203 })
2204 }};
2205}