miri/
helpers.rs

1use std::num::NonZero;
2use std::sync::Mutex;
3use std::time::Duration;
4use std::{cmp, iter};
5
6use rand::RngCore;
7use rustc_abi::{Align, ExternAbi, FieldIdx, FieldsShape, Size, Variants};
8use rustc_apfloat::Float;
9use rustc_data_structures::fx::{FxBuildHasher, FxHashSet};
10use rustc_hir::Safety;
11use rustc_hir::def::{DefKind, Namespace};
12use rustc_hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefId, LOCAL_CRATE};
13use rustc_index::IndexVec;
14use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
15use rustc_middle::middle::dependency_format::Linkage;
16use rustc_middle::middle::exported_symbols::ExportedSymbol;
17use rustc_middle::ty::layout::{LayoutOf, MaybeResult, TyAndLayout};
18use rustc_middle::ty::{self, IntTy, Ty, TyCtxt, UintTy};
19use rustc_session::config::CrateType;
20use rustc_span::{Span, Symbol};
21use rustc_symbol_mangling::mangle_internal_symbol;
22use rustc_target::spec::Os;
23
24use crate::*;
25
26/// Gets an instance for a path.
27///
28/// A `None` namespace indicates we are looking for a module.
29fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>) -> Option<DefId> {
30    let _trace = enter_trace_span!("try_resolve_did", ?path);
31
32    /// Yield all children of the given item, that have the given name.
33    fn find_children<'tcx: 'a, 'a>(
34        tcx: TyCtxt<'tcx>,
35        item: DefId,
36        name: &'a str,
37    ) -> impl Iterator<Item = DefId> + 'a {
38        let name = Symbol::intern(name);
39        tcx.module_children(item)
40            .iter()
41            .filter(move |item| item.ident.name == name)
42            .map(move |item| item.res.def_id())
43    }
44
45    // Take apart the path: leading crate, a sequence of modules, and potentially a final item.
46    let (&crate_name, path) = path.split_first().expect("paths must have at least one segment");
47    let (modules, item) = if let Some(namespace) = namespace {
48        let (&item_name, modules) =
49            path.split_last().expect("non-module paths must have at least 2 segments");
50        (modules, Some((item_name, namespace)))
51    } else {
52        (path, None)
53    };
54
55    // There may be more than one crate with this name. We try them all.
56    // (This is particularly relevant when running `std` tests as then there are two `std` crates:
57    // the one in the sysroot and the one locally built by `cargo test`.)
58    // FIXME: can we prefer the one from the sysroot?
59    'crates: for krate in
60        tcx.crates(()).iter().filter(|&&krate| tcx.crate_name(krate).as_str() == crate_name)
61    {
62        let mut cur_item = DefId { krate: *krate, index: CRATE_DEF_INDEX };
63        // Go over the modules.
64        for &segment in modules {
65            let Some(next_item) = find_children(tcx, cur_item, segment)
66                .find(|item| tcx.def_kind(item) == DefKind::Mod)
67            else {
68                continue 'crates;
69            };
70            cur_item = next_item;
71        }
72        // Finally, look up the desired item in this module, if any.
73        match item {
74            Some((item_name, namespace)) => {
75                let Some(item) = find_children(tcx, cur_item, item_name)
76                    .find(|item| tcx.def_kind(item).ns() == Some(namespace))
77                else {
78                    continue 'crates;
79                };
80                return Some(item);
81            }
82            None => {
83                // Just return the module.
84                return Some(cur_item);
85            }
86        }
87    }
88    // Item not found in any of the crates with the right name.
89    None
90}
91
92/// Gets an instance for a path; fails gracefully if the path does not exist.
93pub fn try_resolve_path<'tcx>(
94    tcx: TyCtxt<'tcx>,
95    path: &[&str],
96    namespace: Namespace,
97) -> Option<ty::Instance<'tcx>> {
98    let did = try_resolve_did(tcx, path, Some(namespace))?;
99    Some(ty::Instance::mono(tcx, did))
100}
101
102/// Gets an instance for a path.
103#[track_caller]
104pub fn resolve_path<'tcx>(
105    tcx: TyCtxt<'tcx>,
106    path: &[&str],
107    namespace: Namespace,
108) -> ty::Instance<'tcx> {
109    try_resolve_path(tcx, path, namespace)
110        .unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
111}
112
113/// Gets the layout of a type at a path.
114#[track_caller]
115pub fn path_ty_layout<'tcx>(cx: &impl LayoutOf<'tcx>, path: &[&str]) -> TyAndLayout<'tcx> {
116    let ty = resolve_path(cx.tcx(), path, Namespace::TypeNS).ty(cx.tcx(), cx.typing_env());
117    cx.layout_of(ty).to_result().ok().unwrap()
118}
119
120/// Call `f` for each exported symbol.
121pub fn iter_exported_symbols<'tcx>(
122    tcx: TyCtxt<'tcx>,
123    mut f: impl FnMut(CrateNum, DefId) -> InterpResult<'tcx>,
124) -> InterpResult<'tcx> {
125    // First, the symbols in the local crate. We can't use `exported_symbols` here as that
126    // skips `#[used]` statics (since `reachable_set` skips them in binary crates).
127    // So we walk all HIR items ourselves instead.
128    let crate_items = tcx.hir_crate_items(());
129    for def_id in crate_items.definitions() {
130        let exported = tcx.def_kind(def_id).has_codegen_attrs() && {
131            let codegen_attrs = tcx.codegen_fn_attrs(def_id);
132            codegen_attrs.contains_extern_indicator()
133                || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
134                || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
135        };
136        if exported {
137            f(LOCAL_CRATE, def_id.into())?;
138        }
139    }
140
141    // Next, all our dependencies.
142    // `dependency_formats` includes all the transitive informations needed to link a crate,
143    // which is what we need here since we need to dig out `exported_symbols` from all transitive
144    // dependencies.
145    let dependency_formats = tcx.dependency_formats(());
146    // Find the dependencies of the executable we are running.
147    let dependency_format = dependency_formats
148        .get(&CrateType::Executable)
149        .expect("interpreting a non-executable crate");
150    for cnum in dependency_format
151        .iter_enumerated()
152        .filter_map(|(num, &linkage)| (linkage != Linkage::NotLinked).then_some(num))
153    {
154        if cnum == LOCAL_CRATE {
155            continue; // Already handled above
156        }
157
158        // We can ignore `_export_info` here: we are a Rust crate, and everything is exported
159        // from a Rust crate.
160        for &(symbol, _export_info) in tcx.exported_non_generic_symbols(cnum) {
161            if let ExportedSymbol::NonGeneric(def_id) = symbol {
162                f(cnum, def_id)?;
163            }
164        }
165    }
166    interp_ok(())
167}
168
169/// Convert a softfloat type to its corresponding hostfloat type.
170pub trait ToHost {
171    type HostFloat;
172    fn to_host(self) -> Self::HostFloat;
173}
174
175/// Convert a hostfloat type to its corresponding softfloat type.
176pub trait ToSoft {
177    type SoftFloat;
178    fn to_soft(self) -> Self::SoftFloat;
179}
180
181impl ToHost for rustc_apfloat::ieee::Double {
182    type HostFloat = f64;
183
184    fn to_host(self) -> Self::HostFloat {
185        f64::from_bits(self.to_bits().try_into().unwrap())
186    }
187}
188
189impl ToSoft for f64 {
190    type SoftFloat = rustc_apfloat::ieee::Double;
191
192    fn to_soft(self) -> Self::SoftFloat {
193        Float::from_bits(self.to_bits().into())
194    }
195}
196
197impl ToHost for rustc_apfloat::ieee::Single {
198    type HostFloat = f32;
199
200    fn to_host(self) -> Self::HostFloat {
201        f32::from_bits(self.to_bits().try_into().unwrap())
202    }
203}
204
205impl ToSoft for f32 {
206    type SoftFloat = rustc_apfloat::ieee::Single;
207
208    fn to_soft(self) -> Self::SoftFloat {
209        Float::from_bits(self.to_bits().into())
210    }
211}
212
213impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
214pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
215    /// Checks if the given crate/module exists.
216    fn have_module(&self, path: &[&str]) -> bool {
217        try_resolve_did(*self.eval_context_ref().tcx, path, None).is_some()
218    }
219
220    /// Evaluates the scalar at the specified path.
221    fn eval_path(&self, path: &[&str]) -> MPlaceTy<'tcx> {
222        let this = self.eval_context_ref();
223        let instance = resolve_path(*this.tcx, path, Namespace::ValueNS);
224        // We don't give a span -- this isn't actually used directly by the program anyway.
225        this.eval_global(instance).unwrap_or_else(|err| {
226            panic!("failed to evaluate required Rust item: {path:?}\n{err:?}")
227        })
228    }
229    fn eval_path_scalar(&self, path: &[&str]) -> Scalar {
230        let this = self.eval_context_ref();
231        let val = this.eval_path(path);
232        this.read_scalar(&val)
233            .unwrap_or_else(|err| panic!("failed to read required Rust item: {path:?}\n{err:?}"))
234    }
235
236    /// Helper function to get a `libc` constant as a `Scalar`.
237    fn eval_libc(&self, name: &str) -> Scalar {
238        if self.eval_context_ref().tcx.sess.target.os == Os::Windows {
239            panic!(
240                "`libc` crate is not reliably available on Windows targets; Miri should not use it there"
241            );
242        }
243        self.eval_path_scalar(&["libc", name])
244    }
245
246    /// Helper function to get a `libc` constant as an `i32`.
247    fn eval_libc_i32(&self, name: &str) -> i32 {
248        // TODO: Cache the result.
249        self.eval_libc(name).to_i32().unwrap_or_else(|_err| {
250            panic!("required libc item has unexpected type (not `i32`): {name}")
251        })
252    }
253
254    /// Helper function to get a `libc` constant as an `u32`.
255    fn eval_libc_u32(&self, name: &str) -> u32 {
256        // TODO: Cache the result.
257        self.eval_libc(name).to_u32().unwrap_or_else(|_err| {
258            panic!("required libc item has unexpected type (not `u32`): {name}")
259        })
260    }
261
262    /// Helper function to get a `libc` constant as an `u64`.
263    fn eval_libc_u64(&self, name: &str) -> u64 {
264        // TODO: Cache the result.
265        self.eval_libc(name).to_u64().unwrap_or_else(|_err| {
266            panic!("required libc item has unexpected type (not `u64`): {name}")
267        })
268    }
269
270    /// Helper function to get a `windows` constant as a `Scalar`.
271    fn eval_windows(&self, module: &str, name: &str) -> Scalar {
272        self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal", "windows", module, name])
273    }
274
275    /// Helper function to get a `windows` constant as a `u32`.
276    fn eval_windows_u32(&self, module: &str, name: &str) -> u32 {
277        // TODO: Cache the result.
278        self.eval_windows(module, name).to_u32().unwrap_or_else(|_err| {
279            panic!("required Windows item has unexpected type (not `u32`): {module}::{name}")
280        })
281    }
282
283    /// Helper function to get a `windows` constant as a `u64`.
284    fn eval_windows_u64(&self, module: &str, name: &str) -> u64 {
285        // TODO: Cache the result.
286        self.eval_windows(module, name).to_u64().unwrap_or_else(|_err| {
287            panic!("required Windows item has unexpected type (not `u64`): {module}::{name}")
288        })
289    }
290
291    /// Helper function to get the `TyAndLayout` of a `libc` type
292    fn libc_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
293        let this = self.eval_context_ref();
294        if this.tcx.sess.target.os == Os::Windows {
295            panic!(
296                "`libc` crate is not reliably available on Windows targets; Miri should not use it there"
297            );
298        }
299        path_ty_layout(this, &["libc", name])
300    }
301
302    /// Helper function to get the `TyAndLayout` of a `windows` type
303    fn windows_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
304        let this = self.eval_context_ref();
305        path_ty_layout(this, &["std", "sys", "pal", "windows", "c", name])
306    }
307
308    /// Helper function to get `TyAndLayout` of an array that consists of `libc` type.
309    fn libc_array_ty_layout(&self, name: &str, size: u64) -> TyAndLayout<'tcx> {
310        let this = self.eval_context_ref();
311        let elem_ty_layout = this.libc_ty_layout(name);
312        let array_ty = Ty::new_array(*this.tcx, elem_ty_layout.ty, size);
313        this.layout_of(array_ty).unwrap()
314    }
315
316    /// Project to the given *named* field (which must be a struct or union type).
317    fn try_project_field_named<P: Projectable<'tcx, Provenance>>(
318        &self,
319        base: &P,
320        name: &str,
321    ) -> InterpResult<'tcx, Option<P>> {
322        let this = self.eval_context_ref();
323        let adt = base.layout().ty.ty_adt_def().unwrap();
324        for (idx, field) in adt.non_enum_variant().fields.iter_enumerated() {
325            if field.name.as_str() == name {
326                return interp_ok(Some(this.project_field(base, idx)?));
327            }
328        }
329        interp_ok(None)
330    }
331
332    /// Project to the given *named* field (which must be a struct or union type).
333    fn project_field_named<P: Projectable<'tcx, Provenance>>(
334        &self,
335        base: &P,
336        name: &str,
337    ) -> InterpResult<'tcx, P> {
338        interp_ok(
339            self.try_project_field_named(base, name)?
340                .unwrap_or_else(|| bug!("no field named {} in type {}", name, base.layout().ty)),
341        )
342    }
343
344    /// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned,
345    /// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so
346    /// this method is fine for almost all integer types.
347    fn write_int(
348        &mut self,
349        i: impl Into<i128>,
350        dest: &impl Writeable<'tcx, Provenance>,
351    ) -> InterpResult<'tcx> {
352        assert!(
353            dest.layout().backend_repr.is_scalar(),
354            "write_int on non-scalar type {}",
355            dest.layout().ty
356        );
357        let val = if dest.layout().backend_repr.is_signed() {
358            Scalar::from_int(i, dest.layout().size)
359        } else {
360            // `unwrap` can only fail here if `i` is negative
361            Scalar::from_uint(u128::try_from(i.into()).unwrap(), dest.layout().size)
362        };
363        self.eval_context_mut().write_scalar(val, dest)
364    }
365
366    /// Write the first N fields of the given place.
367    fn write_int_fields(
368        &mut self,
369        values: &[i128],
370        dest: &impl Writeable<'tcx, Provenance>,
371    ) -> InterpResult<'tcx> {
372        let this = self.eval_context_mut();
373        for (idx, &val) in values.iter().enumerate() {
374            let idx = FieldIdx::from_usize(idx);
375            let field = this.project_field(dest, idx)?;
376            this.write_int(val, &field)?;
377        }
378        interp_ok(())
379    }
380
381    /// Write the given fields of the given place.
382    fn write_int_fields_named(
383        &mut self,
384        values: &[(&str, i128)],
385        dest: &impl Writeable<'tcx, Provenance>,
386    ) -> InterpResult<'tcx> {
387        let this = self.eval_context_mut();
388        for &(name, val) in values.iter() {
389            let field = this.project_field_named(dest, name)?;
390            this.write_int(val, &field)?;
391        }
392        interp_ok(())
393    }
394
395    /// Write a 0 of the appropriate size to `dest`.
396    fn write_null(&mut self, dest: &impl Writeable<'tcx, Provenance>) -> InterpResult<'tcx> {
397        self.write_int(0, dest)
398    }
399
400    /// Test if this pointer equals 0.
401    fn ptr_is_null(&self, ptr: Pointer) -> InterpResult<'tcx, bool> {
402        interp_ok(ptr.addr().bytes() == 0)
403    }
404
405    /// Generate some random bytes, and write them to `dest`.
406    fn gen_random(&mut self, ptr: Pointer, len: u64) -> InterpResult<'tcx> {
407        // Some programs pass in a null pointer and a length of 0
408        // to their platform's random-generation function (e.g. getrandom())
409        // on Linux. For compatibility with these programs, we don't perform
410        // any additional checks - it's okay if the pointer is invalid,
411        // since we wouldn't actually be writing to it.
412        if len == 0 {
413            return interp_ok(());
414        }
415        let this = self.eval_context_mut();
416
417        let mut data = vec![0; usize::try_from(len).unwrap()];
418
419        if this.machine.communicate() {
420            // Fill the buffer using the host's rng.
421            getrandom::fill(&mut data)
422                .map_err(|err| err_unsup_format!("host getrandom failed: {}", err))?;
423        } else {
424            let rng = this.machine.rng.get_mut();
425            rng.fill_bytes(&mut data);
426        }
427
428        this.write_bytes_ptr(ptr, data.iter().copied())
429    }
430
431    /// Call a function: Push the stack frame and pass the arguments.
432    /// For now, arguments must be scalars (so that the caller does not have to know the layout).
433    ///
434    /// If you do not provide a return place, a dangling zero-sized place will be created
435    /// for your convenience. This is only valid if the return type is `()`.
436    fn call_function(
437        &mut self,
438        f: ty::Instance<'tcx>,
439        caller_abi: ExternAbi,
440        args: &[ImmTy<'tcx>],
441        dest: Option<&MPlaceTy<'tcx>>,
442        cont: ReturnContinuation,
443    ) -> InterpResult<'tcx> {
444        let this = self.eval_context_mut();
445
446        // Get MIR.
447        let mir = this.load_mir(f.def, None)?;
448        let dest = match dest {
449            Some(dest) => dest.clone(),
450            None => MPlaceTy::fake_alloc_zst(this.machine.layouts.unit),
451        };
452
453        // Construct a function pointer type representing the caller perspective.
454        let sig = this.tcx.mk_fn_sig(
455            args.iter().map(|a| a.layout.ty),
456            dest.layout.ty,
457            /*c_variadic*/ false,
458            Safety::Safe,
459            caller_abi,
460        );
461        let caller_fn_abi = this.fn_abi_of_fn_ptr(ty::Binder::dummy(sig), ty::List::empty())?;
462
463        // This will also show proper errors if there is any ABI mismatch.
464        this.init_stack_frame(
465            f,
466            mir,
467            caller_fn_abi,
468            &args.iter().map(|a| FnArg::Copy(a.clone().into())).collect::<Vec<_>>(),
469            /*with_caller_location*/ false,
470            &dest.into(),
471            cont,
472        )
473    }
474
475    /// Call a function in an "empty" thread.
476    fn call_thread_root_function(
477        &mut self,
478        f: ty::Instance<'tcx>,
479        caller_abi: ExternAbi,
480        args: &[ImmTy<'tcx>],
481        dest: Option<&MPlaceTy<'tcx>>,
482        span: Span,
483    ) -> InterpResult<'tcx> {
484        let this = self.eval_context_mut();
485        assert!(this.active_thread_stack().is_empty());
486        assert!(this.active_thread_ref().origin_span.is_dummy());
487        this.active_thread_mut().origin_span = span;
488        this.call_function(f, caller_abi, args, dest, ReturnContinuation::Stop { cleanup: true })
489    }
490
491    /// Visits the memory covered by `place`, sensitive to freezing: the 2nd parameter
492    /// of `action` will be true if this is frozen, false if this is in an `UnsafeCell`.
493    /// The range is relative to `place`.
494    fn visit_freeze_sensitive(
495        &self,
496        place: &MPlaceTy<'tcx>,
497        size: Size,
498        mut action: impl FnMut(AllocRange, bool) -> InterpResult<'tcx>,
499    ) -> InterpResult<'tcx> {
500        let this = self.eval_context_ref();
501        trace!("visit_frozen(place={:?}, size={:?})", *place, size);
502        debug_assert_eq!(
503            size,
504            this.size_and_align_of_val(place)?
505                .map(|(size, _)| size)
506                .unwrap_or_else(|| place.layout.size)
507        );
508        // Store how far we proceeded into the place so far. Everything to the left of
509        // this offset has already been handled, in the sense that the frozen parts
510        // have had `action` called on them.
511        let start_addr = place.ptr().addr();
512        let mut cur_addr = start_addr;
513        // Called when we detected an `UnsafeCell` at the given offset and size.
514        // Calls `action` and advances `cur_ptr`.
515        let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer, unsafe_cell_size: Size| {
516            // We assume that we are given the fields in increasing offset order,
517            // and nothing else changes.
518            let unsafe_cell_addr = unsafe_cell_ptr.addr();
519            assert!(unsafe_cell_addr >= cur_addr);
520            let frozen_size = unsafe_cell_addr - cur_addr;
521            // Everything between the cur_ptr and this `UnsafeCell` is frozen.
522            if frozen_size != Size::ZERO {
523                action(alloc_range(cur_addr - start_addr, frozen_size), /*frozen*/ true)?;
524            }
525            cur_addr += frozen_size;
526            // This `UnsafeCell` is NOT frozen.
527            if unsafe_cell_size != Size::ZERO {
528                action(
529                    alloc_range(cur_addr - start_addr, unsafe_cell_size),
530                    /*frozen*/ false,
531                )?;
532            }
533            cur_addr += unsafe_cell_size;
534            // Done
535            interp_ok(())
536        };
537        // Run a visitor
538        {
539            let mut visitor = UnsafeCellVisitor {
540                ecx: this,
541                unsafe_cell_action: |place| {
542                    trace!("unsafe_cell_action on {:?}", place.ptr());
543                    // We need a size to go on.
544                    let unsafe_cell_size = this
545                        .size_and_align_of_val(place)?
546                        .map(|(size, _)| size)
547                        // for extern types, just cover what we can
548                        .unwrap_or_else(|| place.layout.size);
549                    // Now handle this `UnsafeCell`, unless it is empty.
550                    if unsafe_cell_size != Size::ZERO {
551                        unsafe_cell_action(&place.ptr(), unsafe_cell_size)
552                    } else {
553                        interp_ok(())
554                    }
555                },
556            };
557            visitor.visit_value(place)?;
558        }
559        // The part between the end_ptr and the end of the place is also frozen.
560        // So pretend there is a 0-sized `UnsafeCell` at the end.
561        unsafe_cell_action(&place.ptr().wrapping_offset(size, this), Size::ZERO)?;
562        // Done!
563        return interp_ok(());
564
565        /// Visiting the memory covered by a `MemPlace`, being aware of
566        /// whether we are inside an `UnsafeCell` or not.
567        struct UnsafeCellVisitor<'ecx, 'tcx, F>
568        where
569            F: FnMut(&MPlaceTy<'tcx>) -> InterpResult<'tcx>,
570        {
571            ecx: &'ecx MiriInterpCx<'tcx>,
572            unsafe_cell_action: F,
573        }
574
575        impl<'ecx, 'tcx, F> ValueVisitor<'tcx, MiriMachine<'tcx>> for UnsafeCellVisitor<'ecx, 'tcx, F>
576        where
577            F: FnMut(&MPlaceTy<'tcx>) -> InterpResult<'tcx>,
578        {
579            type V = MPlaceTy<'tcx>;
580
581            #[inline(always)]
582            fn ecx(&self) -> &MiriInterpCx<'tcx> {
583                self.ecx
584            }
585
586            fn aggregate_field_iter(
587                in_memory_order: &IndexVec<u32, FieldIdx>,
588            ) -> impl Iterator<Item = FieldIdx> {
589                in_memory_order.iter().copied()
590            }
591
592            // Hook to detect `UnsafeCell`.
593            fn visit_value(&mut self, v: &MPlaceTy<'tcx>) -> InterpResult<'tcx> {
594                trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty);
595                let is_unsafe_cell = match v.layout.ty.kind() {
596                    ty::Adt(adt, _) =>
597                        Some(adt.did()) == self.ecx.tcx.lang_items().unsafe_cell_type(),
598                    _ => false,
599                };
600                if is_unsafe_cell {
601                    // We do not have to recurse further, this is an `UnsafeCell`.
602                    (self.unsafe_cell_action)(v)
603                } else if self.ecx.type_is_freeze(v.layout.ty) {
604                    // This is `Freeze`, there cannot be an `UnsafeCell`
605                    interp_ok(())
606                } else if matches!(v.layout.fields, FieldsShape::Union(..)) {
607                    // A (non-frozen) union. We fall back to whatever the type says.
608                    (self.unsafe_cell_action)(v)
609                } else {
610                    // We want to not actually read from memory for this visit. So, before
611                    // walking this value, we have to make sure it is not a
612                    // `Variants::Multiple`.
613                    // FIXME: the current logic here is layout-dependent, so enums with
614                    // multiple variants where all but 1 are uninhabited will be recursed into.
615                    // Is that truly what we want?
616                    match v.layout.variants {
617                        Variants::Multiple { .. } => {
618                            // A multi-variant enum, or coroutine, or so.
619                            // Treat this like a union: without reading from memory,
620                            // we cannot determine the variant we are in. Reading from
621                            // memory would be subject to Stacked Borrows rules, leading
622                            // to all sorts of "funny" recursion.
623                            // We only end up here if the type is *not* freeze, so we just call the
624                            // `UnsafeCell` action.
625                            (self.unsafe_cell_action)(v)
626                        }
627                        Variants::Single { .. } | Variants::Empty => {
628                            // Proceed further, try to find where exactly that `UnsafeCell`
629                            // is hiding.
630                            self.walk_value(v)
631                        }
632                    }
633                }
634            }
635
636            fn visit_union(
637                &mut self,
638                _v: &MPlaceTy<'tcx>,
639                _fields: NonZero<usize>,
640            ) -> InterpResult<'tcx> {
641                bug!("we should have already handled unions in `visit_value`")
642            }
643        }
644    }
645
646    /// Helper function used inside the shims of foreign functions to check that isolation is
647    /// disabled. It returns an error using the `name` of the foreign function if this is not the
648    /// case.
649    fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> {
650        if !self.eval_context_ref().machine.communicate() {
651            self.reject_in_isolation(name, RejectOpWith::Abort)?;
652        }
653        interp_ok(())
654    }
655
656    /// Helper function used inside the shims of foreign functions which reject the op
657    /// when isolation is enabled. It is used to print a warning/backtrace about the rejection.
658    fn reject_in_isolation(&self, op_name: &str, reject_with: RejectOpWith) -> InterpResult<'tcx> {
659        let this = self.eval_context_ref();
660        match reject_with {
661            RejectOpWith::Abort => isolation_abort_error(op_name),
662            RejectOpWith::WarningWithoutBacktrace => {
663                // Deduplicate these warnings *by shim* (not by span)
664                static DEDUP: Mutex<FxHashSet<String>> =
665                    Mutex::new(FxHashSet::with_hasher(FxBuildHasher));
666                let mut emitted_warnings = DEDUP.lock().unwrap();
667                if !emitted_warnings.contains(op_name) {
668                    // First time we are seeing this.
669                    emitted_warnings.insert(op_name.to_owned());
670                    this.tcx
671                        .dcx()
672                        .warn(format!("{op_name} was made to return an error due to isolation"));
673                }
674
675                interp_ok(())
676            }
677            RejectOpWith::Warning => {
678                this.emit_diagnostic(NonHaltingDiagnostic::RejectedIsolatedOp(op_name.to_string()));
679                interp_ok(())
680            }
681            RejectOpWith::NoWarning => interp_ok(()), // no warning
682        }
683    }
684
685    /// Helper function used inside the shims of foreign functions to assert that the target OS
686    /// is `target_os`. It panics showing a message with the `name` of the foreign function
687    /// if this is not the case.
688    fn assert_target_os(&self, target_os: Os, name: &str) {
689        assert_eq!(
690            self.eval_context_ref().tcx.sess.target.os,
691            target_os,
692            "`{name}` is only available on the `{target_os}` target OS",
693        )
694    }
695
696    /// Helper function used inside shims of foreign functions to check that the target OS
697    /// is one of `target_oses`. It returns an error containing the `name` of the foreign function
698    /// in a message if this is not the case.
699    fn check_target_os(&self, target_oses: &[Os], name: Symbol) -> InterpResult<'tcx> {
700        let target_os = &self.eval_context_ref().tcx.sess.target.os;
701        if !target_oses.contains(target_os) {
702            throw_unsup_format!("`{name}` is not supported on {target_os}");
703        }
704        interp_ok(())
705    }
706
707    /// Helper function used inside the shims of foreign functions to assert that the target OS
708    /// is part of the UNIX family. It panics showing a message with the `name` of the foreign function
709    /// if this is not the case.
710    fn assert_target_os_is_unix(&self, name: &str) {
711        assert!(self.target_os_is_unix(), "`{name}` is only available for unix targets",);
712    }
713
714    fn target_os_is_unix(&self) -> bool {
715        self.eval_context_ref().tcx.sess.target.families.iter().any(|f| f == "unix")
716    }
717
718    /// Dereference a pointer operand to a place using `layout` instead of the pointer's declared type
719    fn deref_pointer_as(
720        &self,
721        op: &impl Projectable<'tcx, Provenance>,
722        layout: TyAndLayout<'tcx>,
723    ) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
724        let this = self.eval_context_ref();
725        let ptr = this.read_pointer(op)?;
726        interp_ok(this.ptr_to_mplace(ptr, layout))
727    }
728
729    /// Calculates the MPlaceTy given the offset and layout of an access on an operand
730    fn deref_pointer_and_offset(
731        &self,
732        op: &impl Projectable<'tcx, Provenance>,
733        offset: u64,
734        base_layout: TyAndLayout<'tcx>,
735        value_layout: TyAndLayout<'tcx>,
736    ) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
737        let this = self.eval_context_ref();
738        let op_place = this.deref_pointer_as(op, base_layout)?;
739        let offset = Size::from_bytes(offset);
740
741        // Ensure that the access is within bounds.
742        assert!(base_layout.size >= offset + value_layout.size);
743        let value_place = op_place.offset(offset, value_layout, this)?;
744        interp_ok(value_place)
745    }
746
747    fn deref_pointer_and_read(
748        &self,
749        op: &impl Projectable<'tcx, Provenance>,
750        offset: u64,
751        base_layout: TyAndLayout<'tcx>,
752        value_layout: TyAndLayout<'tcx>,
753    ) -> InterpResult<'tcx, Scalar> {
754        let this = self.eval_context_ref();
755        let value_place = this.deref_pointer_and_offset(op, offset, base_layout, value_layout)?;
756        this.read_scalar(&value_place)
757    }
758
759    fn deref_pointer_and_write(
760        &mut self,
761        op: &impl Projectable<'tcx, Provenance>,
762        offset: u64,
763        value: impl Into<Scalar>,
764        base_layout: TyAndLayout<'tcx>,
765        value_layout: TyAndLayout<'tcx>,
766    ) -> InterpResult<'tcx, ()> {
767        let this = self.eval_context_mut();
768        let value_place = this.deref_pointer_and_offset(op, offset, base_layout, value_layout)?;
769        this.write_scalar(value, &value_place)
770    }
771
772    /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None`
773    /// if the value in the `timespec` struct is invalid. Some libc functions will return
774    /// `EINVAL` in this case.
775    fn read_timespec(&mut self, tp: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option<Duration>> {
776        let this = self.eval_context_mut();
777        let seconds_place = this.project_field(tp, FieldIdx::ZERO)?;
778        let seconds_scalar = this.read_scalar(&seconds_place)?;
779        let seconds = seconds_scalar.to_target_isize(this)?;
780        let nanoseconds_place = this.project_field(tp, FieldIdx::ONE)?;
781        let nanoseconds_scalar = this.read_scalar(&nanoseconds_place)?;
782        let nanoseconds = nanoseconds_scalar.to_target_isize(this)?;
783
784        interp_ok(
785            try {
786                // tv_sec must be non-negative.
787                let seconds: u64 = seconds.try_into().ok()?;
788                // tv_nsec must be non-negative.
789                let nanoseconds: u32 = nanoseconds.try_into().ok()?;
790                if nanoseconds >= 1_000_000_000 {
791                    // tv_nsec must not be greater than 999,999,999.
792                    None?
793                }
794                Duration::new(seconds, nanoseconds)
795            },
796        )
797    }
798
799    /// Read bytes from a byte slice.
800    fn read_byte_slice<'a>(&'a self, slice: &ImmTy<'tcx>) -> InterpResult<'tcx, &'a [u8]>
801    where
802        'tcx: 'a,
803    {
804        let this = self.eval_context_ref();
805        let (ptr, len) = slice.to_scalar_pair();
806        let ptr = ptr.to_pointer(this)?;
807        let len = len.to_target_usize(this)?;
808        let bytes = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
809        interp_ok(bytes)
810    }
811
812    /// Read a sequence of bytes until the first null terminator.
813    fn read_c_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, &'a [u8]>
814    where
815        'tcx: 'a,
816    {
817        let this = self.eval_context_ref();
818        let size1 = Size::from_bytes(1);
819
820        // Step 1: determine the length.
821        let mut len = Size::ZERO;
822        loop {
823            // FIXME: We are re-getting the allocation each time around the loop.
824            // Would be nice if we could somehow "extend" an existing AllocRange.
825            let alloc = this.get_ptr_alloc(ptr.wrapping_offset(len, this), size1)?.unwrap(); // not a ZST, so we will get a result
826            let byte = alloc.read_integer(alloc_range(Size::ZERO, size1))?.to_u8()?;
827            if byte == 0 {
828                break;
829            } else {
830                len += size1;
831            }
832        }
833
834        // Step 2: get the bytes.
835        this.read_bytes_ptr_strip_provenance(ptr, len)
836    }
837
838    /// Helper function to write a sequence of bytes with an added null-terminator, which is what
839    /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying
840    /// to write if `size` is not large enough to fit the contents of `c_str` plus a null
841    /// terminator. It returns `Ok((true, length))` if the writing process was successful. The
842    /// string length returned does include the null terminator.
843    fn write_c_str(
844        &mut self,
845        c_str: &[u8],
846        ptr: Pointer,
847        size: u64,
848    ) -> InterpResult<'tcx, (bool, u64)> {
849        // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
850        // terminator to memory using the `ptr` pointer would cause an out-of-bounds access.
851        let string_length = u64::try_from(c_str.len()).unwrap();
852        let string_length = string_length.strict_add(1);
853        if size < string_length {
854            return interp_ok((false, string_length));
855        }
856        self.eval_context_mut()
857            .write_bytes_ptr(ptr, c_str.iter().copied().chain(iter::once(0u8)))?;
858        interp_ok((true, string_length))
859    }
860
861    /// Helper function to read a sequence of unsigned integers of the given size and alignment
862    /// until the first null terminator.
863    fn read_c_str_with_char_size<T>(
864        &self,
865        mut ptr: Pointer,
866        size: Size,
867        align: Align,
868    ) -> InterpResult<'tcx, Vec<T>>
869    where
870        T: TryFrom<u128>,
871        <T as TryFrom<u128>>::Error: std::fmt::Debug,
872    {
873        assert_ne!(size, Size::ZERO);
874
875        let this = self.eval_context_ref();
876
877        this.check_ptr_align(ptr, align)?;
878
879        let mut wchars = Vec::new();
880        loop {
881            // FIXME: We are re-getting the allocation each time around the loop.
882            // Would be nice if we could somehow "extend" an existing AllocRange.
883            let alloc = this.get_ptr_alloc(ptr, size)?.unwrap(); // not a ZST, so we will get a result
884            let wchar_int = alloc.read_integer(alloc_range(Size::ZERO, size))?.to_bits(size)?;
885            if wchar_int == 0 {
886                break;
887            } else {
888                wchars.push(wchar_int.try_into().unwrap());
889                ptr = ptr.wrapping_offset(size, this);
890            }
891        }
892
893        interp_ok(wchars)
894    }
895
896    /// Read a sequence of u16 until the first null terminator.
897    fn read_wide_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec<u16>> {
898        self.read_c_str_with_char_size(ptr, Size::from_bytes(2), Align::from_bytes(2).unwrap())
899    }
900
901    /// Helper function to write a sequence of u16 with an added 0x0000-terminator, which is what
902    /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying
903    /// to write if `size` is not large enough to fit the contents of `os_string` plus a null
904    /// terminator. It returns `Ok((true, length))` if the writing process was successful. The
905    /// string length returned does include the null terminator. Length is measured in units of
906    /// `u16.`
907    fn write_wide_str(
908        &mut self,
909        wide_str: &[u16],
910        ptr: Pointer,
911        size: u64,
912    ) -> InterpResult<'tcx, (bool, u64)> {
913        // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required
914        // 0x0000 terminator to memory would cause an out-of-bounds access.
915        let string_length = u64::try_from(wide_str.len()).unwrap();
916        let string_length = string_length.strict_add(1);
917        if size < string_length {
918            return interp_ok((false, string_length));
919        }
920
921        // Store the UTF-16 string.
922        let size2 = Size::from_bytes(2);
923        let this = self.eval_context_mut();
924        this.check_ptr_align(ptr, Align::from_bytes(2).unwrap())?;
925        let mut alloc = this.get_ptr_alloc_mut(ptr, size2 * string_length)?.unwrap(); // not a ZST, so we will get a result
926        for (offset, wchar) in wide_str.iter().copied().chain(iter::once(0x0000)).enumerate() {
927            let offset = u64::try_from(offset).unwrap();
928            alloc.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar))?;
929        }
930        interp_ok((true, string_length))
931    }
932
933    /// Read a sequence of wchar_t until the first null terminator.
934    /// Always returns a `Vec<u32>` no matter the size of `wchar_t`.
935    fn read_wchar_t_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec<u32>> {
936        let this = self.eval_context_ref();
937        let wchar_t = if this.tcx.sess.target.os == Os::Windows {
938            // We don't have libc on Windows so we have to hard-code the type ourselves.
939            this.machine.layouts.u16
940        } else {
941            this.libc_ty_layout("wchar_t")
942        };
943        self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi)
944    }
945
946    fn frame_in_std(&self) -> bool {
947        let this = self.eval_context_ref();
948        let frame = this.frame();
949        // Make an attempt to get at the instance of the function this is inlined from.
950        let instance: Option<_> = try {
951            let scope = frame.current_source_info()?.scope;
952            let inlined_parent = frame.body().source_scopes[scope].inlined_parent_scope?;
953            let source = &frame.body().source_scopes[inlined_parent];
954            source.inlined.expect("inlined_parent_scope points to scope without inline info").0
955        };
956        // Fall back to the instance of the function itself.
957        let instance = instance.unwrap_or(frame.instance());
958        // Now check the crate it is in. We could try to be clever here and e.g. check if this is
959        // the same crate as `start_fn`, but that would not work for running std tests in Miri, so
960        // we'd need some more hacks anyway. So we just check the name of the crate. If someone
961        // calls their crate `std` then we'll just let them keep the pieces.
962        let frame_crate = this.tcx.def_path(instance.def_id()).krate;
963        let crate_name = this.tcx.crate_name(frame_crate);
964        let crate_name = crate_name.as_str();
965        // On miri-test-libstd, the name of the crate is different.
966        crate_name == "std" || crate_name == "std_miri_test"
967    }
968
969    /// Mark a machine allocation that was just created as immutable.
970    fn mark_immutable(&mut self, mplace: &MPlaceTy<'tcx>) {
971        let this = self.eval_context_mut();
972        // This got just allocated, so there definitely is a pointer here.
973        let provenance = mplace.ptr().into_pointer_or_addr().unwrap().provenance;
974        this.alloc_mark_immutable(provenance.get_alloc_id().unwrap()).unwrap();
975    }
976
977    /// Returns an integer type that is twice wide as `ty`
978    fn get_twice_wide_int_ty(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
979        let this = self.eval_context_ref();
980        match ty.kind() {
981            // Unsigned
982            ty::Uint(UintTy::U8) => this.tcx.types.u16,
983            ty::Uint(UintTy::U16) => this.tcx.types.u32,
984            ty::Uint(UintTy::U32) => this.tcx.types.u64,
985            ty::Uint(UintTy::U64) => this.tcx.types.u128,
986            // Signed
987            ty::Int(IntTy::I8) => this.tcx.types.i16,
988            ty::Int(IntTy::I16) => this.tcx.types.i32,
989            ty::Int(IntTy::I32) => this.tcx.types.i64,
990            ty::Int(IntTy::I64) => this.tcx.types.i128,
991            _ => span_bug!(this.cur_span(), "unexpected type: {ty:?}"),
992        }
993    }
994
995    /// Checks that target feature `target_feature` is enabled.
996    ///
997    /// If not enabled, emits an UB error that states that the feature is
998    /// required by `intrinsic`.
999    fn expect_target_feature_for_intrinsic(
1000        &self,
1001        intrinsic: Symbol,
1002        target_feature: &str,
1003    ) -> InterpResult<'tcx, ()> {
1004        let this = self.eval_context_ref();
1005        if !this.tcx.sess.unstable_target_features.contains(&Symbol::intern(target_feature)) {
1006            throw_ub_format!(
1007                "attempted to call intrinsic `{intrinsic}` that requires missing target feature {target_feature}"
1008            );
1009        }
1010        interp_ok(())
1011    }
1012
1013    /// Lookup an array of immediates from any linker sections matching the provided predicate,
1014    /// with the spans of where they were found.
1015    fn lookup_link_section(
1016        &mut self,
1017        include_name: impl Fn(&str) -> bool,
1018    ) -> InterpResult<'tcx, Vec<(ImmTy<'tcx>, Span)>> {
1019        let this = self.eval_context_mut();
1020        let tcx = this.tcx.tcx;
1021
1022        let mut array = vec![];
1023
1024        iter_exported_symbols(tcx, |_cnum, def_id| {
1025            let attrs = tcx.codegen_fn_attrs(def_id);
1026            let Some(link_section) = attrs.link_section else {
1027                return interp_ok(());
1028            };
1029            if include_name(link_section.as_str()) {
1030                let instance = ty::Instance::mono(tcx, def_id);
1031                let span = tcx.def_span(def_id);
1032                let const_val = this.eval_global(instance).unwrap_or_else(|err| {
1033                    panic!(
1034                        "failed to evaluate static in required link_section: {def_id:?}\n{err:?}"
1035                    )
1036                });
1037                match const_val.layout.ty.kind() {
1038                    ty::FnPtr(..) => {
1039                        array.push((this.read_immediate(&const_val)?, span));
1040                    }
1041                    ty::Array(elem_ty, _) if matches!(elem_ty.kind(), ty::FnPtr(..)) => {
1042                        let mut elems = this.project_array_fields(&const_val)?;
1043                        while let Some((_idx, elem)) = elems.next(this)? {
1044                            array.push((this.read_immediate(&elem)?, span));
1045                        }
1046                    }
1047                    _ =>
1048                        throw_unsup_format!(
1049                            "only function pointers and arrays of function pointers are supported in well-known linker sections"
1050                        ),
1051                }
1052            }
1053            interp_ok(())
1054        })?;
1055
1056        interp_ok(array)
1057    }
1058
1059    fn mangle_internal_symbol<'a>(&'a mut self, name: &'static str) -> &'a str
1060    where
1061        'tcx: 'a,
1062    {
1063        let this = self.eval_context_mut();
1064        let tcx = *this.tcx;
1065        this.machine
1066            .mangle_internal_symbol_cache
1067            .entry(name)
1068            .or_insert_with(|| mangle_internal_symbol(tcx, name))
1069    }
1070}
1071
1072impl<'tcx> MiriMachine<'tcx> {
1073    /// Get the current span in the topmost function which is workspace-local and not
1074    /// `#[track_caller]`.
1075    /// This function is backed by a cache, and can be assumed to be very fast.
1076    /// It will work even when the stack is empty.
1077    pub fn current_user_relevant_span(&self) -> Span {
1078        self.threads.active_thread_ref().current_user_relevant_span()
1079    }
1080
1081    /// Returns the span of the *caller* of the current operation, again
1082    /// walking down the stack to find the closest frame in a local crate, if the caller of the
1083    /// current operation is not in a local crate.
1084    /// This is useful when we are processing something which occurs on function-entry and we want
1085    /// to point at the call to the function, not the function definition generally.
1086    pub fn caller_span(&self) -> Span {
1087        // We need to go down at least to the caller (len - 2), or however
1088        // far we have to go to find a frame in a local crate which is also not #[track_caller].
1089        let frame_idx = self.top_user_relevant_frame().unwrap();
1090        let frame_idx = cmp::min(frame_idx, self.stack().len().saturating_sub(2));
1091        self.stack()[frame_idx].current_span()
1092    }
1093
1094    fn stack(&self) -> &[Frame<'tcx, Provenance, machine::FrameExtra<'tcx>>] {
1095        self.threads.active_thread_stack()
1096    }
1097
1098    fn top_user_relevant_frame(&self) -> Option<usize> {
1099        self.threads.active_thread_ref().top_user_relevant_frame()
1100    }
1101
1102    /// This is the source of truth for the `user_relevance` flag in our `FrameExtra`.
1103    pub fn user_relevance(&self, frame: &Frame<'tcx, Provenance>) -> u8 {
1104        if frame.instance().def.requires_caller_location(self.tcx) {
1105            return 0;
1106        }
1107        if self.is_local(frame.instance()) {
1108            u8::MAX
1109        } else {
1110            // A non-relevant frame, but at least it doesn't require a caller location, so
1111            // better than nothing.
1112            1
1113        }
1114    }
1115}
1116
1117pub fn isolation_abort_error<'tcx>(name: &str) -> InterpResult<'tcx> {
1118    throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
1119        "{name} not available when isolation is enabled",
1120    )))
1121}
1122
1123pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar {
1124    // SIMD uses all-1 as pattern for "true". In two's complement,
1125    // -1 has all its bits set to one and `from_int` will truncate or
1126    // sign-extend it to `size` as required.
1127    let val = if b { -1 } else { 0 };
1128    Scalar::from_int(val, size)
1129}
1130
1131/// Check whether an operation that writes to a target buffer was successful.
1132/// Accordingly select return value.
1133/// Local helper function to be used in Windows shims.
1134pub(crate) fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 {
1135    if success {
1136        // If the function succeeds, the return value is the number of characters stored in the target buffer,
1137        // not including the terminating null character.
1138        u32::try_from(len.strict_sub(1)).unwrap()
1139    } else {
1140        // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters,
1141        // required to hold the string and its terminating null character.
1142        u32::try_from(len).unwrap()
1143    }
1144}
1145
1146/// We don't support 16-bit systems, so let's have ergonomic conversion from `u32` to `usize`.
1147pub trait ToUsize {
1148    fn to_usize(self) -> usize;
1149}
1150
1151impl ToUsize for u32 {
1152    fn to_usize(self) -> usize {
1153        self.try_into().unwrap()
1154    }
1155}
1156
1157/// Similarly, a maximum address size of `u64` is assumed widely here, so let's have ergonomic
1158/// converion from `usize` to `u64`.
1159pub trait ToU64 {
1160    fn to_u64(self) -> u64;
1161}
1162
1163impl ToU64 for usize {
1164    fn to_u64(self) -> u64 {
1165        self.try_into().unwrap()
1166    }
1167}
1168
1169/// Enters a [tracing::info_span] only if the "tracing" feature is enabled, otherwise does nothing.
1170/// This calls [rustc_const_eval::enter_trace_span] with [MiriMachine] as the first argument, which
1171/// will in turn call [MiriMachine::enter_trace_span], which takes care of determining at compile
1172/// time whether to trace or not (and supposedly the call is compiled out if tracing is disabled).
1173/// Look at [rustc_const_eval::enter_trace_span] for complete documentation, examples and tips.
1174#[macro_export]
1175macro_rules! enter_trace_span {
1176    ($($tt:tt)*) => {
1177        rustc_const_eval::enter_trace_span!($crate::MiriMachine<'static>, $($tt)*)
1178    };
1179}