miri/
helpers.rs

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