Skip to main content

miri/
helpers.rs

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