miri/
helpers.rs

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