1use std::num::NonZero;
2use std::sync::Mutex;
3use std::time::Duration;
4use std::{cmp, iter};
5
6use rand::RngCore;
7use rustc_abi::{Align, ExternAbi, FieldIdx, FieldsShape, Size, Variants};
8use rustc_apfloat::Float;
9use rustc_hash::FxHashSet;
10use rustc_hir::Safety;
11use rustc_hir::def::{DefKind, Namespace};
12use rustc_hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefId, LOCAL_CRATE};
13use rustc_index::IndexVec;
14use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
15use rustc_middle::middle::dependency_format::Linkage;
16use rustc_middle::middle::exported_symbols::ExportedSymbol;
17use rustc_middle::ty::layout::{LayoutOf, MaybeResult, TyAndLayout};
18use rustc_middle::ty::{self, IntTy, Ty, TyCtxt, UintTy};
19use rustc_session::config::CrateType;
20use rustc_span::{Span, Symbol};
21use rustc_symbol_mangling::mangle_internal_symbol;
22use rustc_target::spec::Os;
23
24use crate::*;
25
26fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>) -> Option<DefId> {
30 let _trace = enter_trace_span!("try_resolve_did", ?path);
31
32 fn find_children<'tcx: 'a, 'a>(
34 tcx: TyCtxt<'tcx>,
35 item: DefId,
36 name: &'a str,
37 ) -> impl Iterator<Item = DefId> + 'a {
38 let name = Symbol::intern(name);
39 tcx.module_children(item)
40 .iter()
41 .filter(move |item| item.ident.name == name)
42 .map(move |item| item.res.def_id())
43 }
44
45 let (&crate_name, path) = path.split_first().expect("paths must have at least one segment");
47 let (modules, item) = if let Some(namespace) = namespace {
48 let (&item_name, modules) =
49 path.split_last().expect("non-module paths must have at least 2 segments");
50 (modules, Some((item_name, namespace)))
51 } else {
52 (path, None)
53 };
54
55 'crates: for krate in
60 tcx.crates(()).iter().filter(|&&krate| tcx.crate_name(krate).as_str() == crate_name)
61 {
62 let mut cur_item = DefId { krate: *krate, index: CRATE_DEF_INDEX };
63 for &segment in modules {
65 let Some(next_item) = find_children(tcx, cur_item, segment)
66 .find(|item| tcx.def_kind(item) == DefKind::Mod)
67 else {
68 continue 'crates;
69 };
70 cur_item = next_item;
71 }
72 match item {
74 Some((item_name, namespace)) => {
75 let Some(item) = find_children(tcx, cur_item, item_name)
76 .find(|item| tcx.def_kind(item).ns() == Some(namespace))
77 else {
78 continue 'crates;
79 };
80 return Some(item);
81 }
82 None => {
83 return Some(cur_item);
85 }
86 }
87 }
88 None
90}
91
92pub fn try_resolve_path<'tcx>(
94 tcx: TyCtxt<'tcx>,
95 path: &[&str],
96 namespace: Namespace,
97) -> Option<ty::Instance<'tcx>> {
98 let did = try_resolve_did(tcx, path, Some(namespace))?;
99 Some(ty::Instance::mono(tcx, did))
100}
101
102#[track_caller]
104pub fn resolve_path<'tcx>(
105 tcx: TyCtxt<'tcx>,
106 path: &[&str],
107 namespace: Namespace,
108) -> ty::Instance<'tcx> {
109 try_resolve_path(tcx, path, namespace)
110 .unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
111}
112
113#[track_caller]
115pub fn path_ty_layout<'tcx>(cx: &impl LayoutOf<'tcx>, path: &[&str]) -> TyAndLayout<'tcx> {
116 let ty = resolve_path(cx.tcx(), path, Namespace::TypeNS).ty(cx.tcx(), cx.typing_env());
117 cx.layout_of(ty).to_result().ok().unwrap()
118}
119
120pub fn iter_exported_symbols<'tcx>(
122 tcx: TyCtxt<'tcx>,
123 mut f: impl FnMut(CrateNum, DefId) -> InterpResult<'tcx>,
124) -> InterpResult<'tcx> {
125 let crate_items = tcx.hir_crate_items(());
129 for def_id in crate_items.definitions() {
130 let exported = tcx.def_kind(def_id).has_codegen_attrs() && {
131 let codegen_attrs = tcx.codegen_fn_attrs(def_id);
132 codegen_attrs.contains_extern_indicator()
133 || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
134 || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
135 };
136 if exported {
137 f(LOCAL_CRATE, def_id.into())?;
138 }
139 }
140
141 let dependency_formats = tcx.dependency_formats(());
146 let dependency_format = dependency_formats
148 .get(&CrateType::Executable)
149 .expect("interpreting a non-executable crate");
150 for cnum in dependency_format
151 .iter_enumerated()
152 .filter_map(|(num, &linkage)| (linkage != Linkage::NotLinked).then_some(num))
153 {
154 if cnum == LOCAL_CRATE {
155 continue; }
157
158 for &(symbol, _export_info) in tcx.exported_non_generic_symbols(cnum) {
161 if let ExportedSymbol::NonGeneric(def_id) = symbol {
162 f(cnum, def_id)?;
163 }
164 }
165 }
166 interp_ok(())
167}
168
169pub trait ToHost {
171 type HostFloat;
172 fn to_host(self) -> Self::HostFloat;
173}
174
175pub trait ToSoft {
177 type SoftFloat;
178 fn to_soft(self) -> Self::SoftFloat;
179}
180
181impl ToHost for rustc_apfloat::ieee::Double {
182 type HostFloat = f64;
183
184 fn to_host(self) -> Self::HostFloat {
185 f64::from_bits(self.to_bits().try_into().unwrap())
186 }
187}
188
189impl ToSoft for f64 {
190 type SoftFloat = rustc_apfloat::ieee::Double;
191
192 fn to_soft(self) -> Self::SoftFloat {
193 Float::from_bits(self.to_bits().into())
194 }
195}
196
197impl ToHost for rustc_apfloat::ieee::Single {
198 type HostFloat = f32;
199
200 fn to_host(self) -> Self::HostFloat {
201 f32::from_bits(self.to_bits().try_into().unwrap())
202 }
203}
204
205impl ToSoft for f32 {
206 type SoftFloat = rustc_apfloat::ieee::Single;
207
208 fn to_soft(self) -> Self::SoftFloat {
209 Float::from_bits(self.to_bits().into())
210 }
211}
212
213impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
214pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
215 fn have_module(&self, path: &[&str]) -> bool {
217 try_resolve_did(*self.eval_context_ref().tcx, path, None).is_some()
218 }
219
220 fn eval_path(&self, path: &[&str]) -> MPlaceTy<'tcx> {
222 let this = self.eval_context_ref();
223 let instance = resolve_path(*this.tcx, path, Namespace::ValueNS);
224 this.eval_global(instance).unwrap_or_else(|err| {
226 panic!("failed to evaluate required Rust item: {path:?}\n{err:?}")
227 })
228 }
229 fn eval_path_scalar(&self, path: &[&str]) -> Scalar {
230 let this = self.eval_context_ref();
231 let val = this.eval_path(path);
232 this.read_scalar(&val)
233 .unwrap_or_else(|err| panic!("failed to read required Rust item: {path:?}\n{err:?}"))
234 }
235
236 fn eval_libc(&self, name: &str) -> Scalar {
238 if self.eval_context_ref().tcx.sess.target.os == Os::Windows {
239 panic!(
240 "`libc` crate is not reliably available on Windows targets; Miri should not use it there"
241 );
242 }
243 self.eval_path_scalar(&["libc", name])
244 }
245
246 fn eval_libc_i32(&self, name: &str) -> i32 {
248 self.eval_libc(name).to_i32().unwrap_or_else(|_err| {
250 panic!("required libc item has unexpected type (not `i32`): {name}")
251 })
252 }
253
254 fn eval_libc_u32(&self, name: &str) -> u32 {
256 self.eval_libc(name).to_u32().unwrap_or_else(|_err| {
258 panic!("required libc item has unexpected type (not `u32`): {name}")
259 })
260 }
261
262 fn eval_libc_u64(&self, name: &str) -> u64 {
264 self.eval_libc(name).to_u64().unwrap_or_else(|_err| {
266 panic!("required libc item has unexpected type (not `u64`): {name}")
267 })
268 }
269
270 fn eval_windows(&self, module: &str, name: &str) -> Scalar {
272 self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal", "windows", module, name])
273 }
274
275 fn eval_windows_u32(&self, module: &str, name: &str) -> u32 {
277 self.eval_windows(module, name).to_u32().unwrap_or_else(|_err| {
279 panic!("required Windows item has unexpected type (not `u32`): {module}::{name}")
280 })
281 }
282
283 fn eval_windows_u64(&self, module: &str, name: &str) -> u64 {
285 self.eval_windows(module, name).to_u64().unwrap_or_else(|_err| {
287 panic!("required Windows item has unexpected type (not `u64`): {module}::{name}")
288 })
289 }
290
291 fn libc_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
293 let this = self.eval_context_ref();
294 if this.tcx.sess.target.os == Os::Windows {
295 panic!(
296 "`libc` crate is not reliably available on Windows targets; Miri should not use it there"
297 );
298 }
299 path_ty_layout(this, &["libc", name])
300 }
301
302 fn windows_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
304 let this = self.eval_context_ref();
305 path_ty_layout(this, &["std", "sys", "pal", "windows", "c", name])
306 }
307
308 fn libc_array_ty_layout(&self, name: &str, size: u64) -> TyAndLayout<'tcx> {
310 let this = self.eval_context_ref();
311 let elem_ty_layout = this.libc_ty_layout(name);
312 let array_ty = Ty::new_array(*this.tcx, elem_ty_layout.ty, size);
313 this.layout_of(array_ty).unwrap()
314 }
315
316 fn try_project_field_named<P: Projectable<'tcx, Provenance>>(
318 &self,
319 base: &P,
320 name: &str,
321 ) -> InterpResult<'tcx, Option<P>> {
322 let this = self.eval_context_ref();
323 let adt = base.layout().ty.ty_adt_def().unwrap();
324 for (idx, field) in adt.non_enum_variant().fields.iter_enumerated() {
325 if field.name.as_str() == name {
326 return interp_ok(Some(this.project_field(base, idx)?));
327 }
328 }
329 interp_ok(None)
330 }
331
332 fn project_field_named<P: Projectable<'tcx, Provenance>>(
334 &self,
335 base: &P,
336 name: &str,
337 ) -> InterpResult<'tcx, P> {
338 interp_ok(
339 self.try_project_field_named(base, name)?
340 .unwrap_or_else(|| bug!("no field named {} in type {}", name, base.layout().ty)),
341 )
342 }
343
344 fn write_int(
348 &mut self,
349 i: impl Into<i128>,
350 dest: &impl Writeable<'tcx, Provenance>,
351 ) -> InterpResult<'tcx> {
352 assert!(
353 dest.layout().backend_repr.is_scalar(),
354 "write_int on non-scalar type {}",
355 dest.layout().ty
356 );
357 let val = if dest.layout().backend_repr.is_signed() {
358 Scalar::from_int(i, dest.layout().size)
359 } else {
360 Scalar::from_uint(u128::try_from(i.into()).unwrap(), dest.layout().size)
362 };
363 self.eval_context_mut().write_scalar(val, dest)
364 }
365
366 fn write_int_fields(
368 &mut self,
369 values: &[i128],
370 dest: &impl Writeable<'tcx, Provenance>,
371 ) -> InterpResult<'tcx> {
372 let this = self.eval_context_mut();
373 for (idx, &val) in values.iter().enumerate() {
374 let idx = FieldIdx::from_usize(idx);
375 let field = this.project_field(dest, idx)?;
376 this.write_int(val, &field)?;
377 }
378 interp_ok(())
379 }
380
381 fn write_int_fields_named(
383 &mut self,
384 values: &[(&str, i128)],
385 dest: &impl Writeable<'tcx, Provenance>,
386 ) -> InterpResult<'tcx> {
387 let this = self.eval_context_mut();
388 for &(name, val) in values.iter() {
389 let field = this.project_field_named(dest, name)?;
390 this.write_int(val, &field)?;
391 }
392 interp_ok(())
393 }
394
395 fn write_null(&mut self, dest: &impl Writeable<'tcx, Provenance>) -> InterpResult<'tcx> {
397 self.write_int(0, dest)
398 }
399
400 fn ptr_is_null(&self, ptr: Pointer) -> InterpResult<'tcx, bool> {
402 interp_ok(ptr.addr().bytes() == 0)
403 }
404
405 fn gen_random(&mut self, ptr: Pointer, len: u64) -> InterpResult<'tcx> {
407 if len == 0 {
413 return interp_ok(());
414 }
415 let this = self.eval_context_mut();
416
417 let mut data = vec![0; usize::try_from(len).unwrap()];
418
419 if this.machine.communicate() {
420 getrandom::fill(&mut data)
422 .map_err(|err| err_unsup_format!("host getrandom failed: {}", err))?;
423 } else {
424 let rng = this.machine.rng.get_mut();
425 rng.fill_bytes(&mut data);
426 }
427
428 this.write_bytes_ptr(ptr, data.iter().copied())
429 }
430
431 fn call_function(
437 &mut self,
438 f: ty::Instance<'tcx>,
439 caller_abi: ExternAbi,
440 args: &[ImmTy<'tcx>],
441 dest: Option<&MPlaceTy<'tcx>>,
442 cont: ReturnContinuation,
443 ) -> InterpResult<'tcx> {
444 let this = self.eval_context_mut();
445
446 let mir = this.load_mir(f.def, None)?;
448 let dest = match dest {
449 Some(dest) => dest.clone(),
450 None => MPlaceTy::fake_alloc_zst(this.machine.layouts.unit),
451 };
452
453 let sig = this.tcx.mk_fn_sig(
455 args.iter().map(|a| a.layout.ty),
456 dest.layout.ty,
457 false,
458 Safety::Safe,
459 caller_abi,
460 );
461 let caller_fn_abi = this.fn_abi_of_fn_ptr(ty::Binder::dummy(sig), ty::List::empty())?;
462
463 this.init_stack_frame(
465 f,
466 mir,
467 caller_fn_abi,
468 &args.iter().map(|a| FnArg::Copy(a.clone().into())).collect::<Vec<_>>(),
469 false,
470 &dest.into(),
471 cont,
472 )
473 }
474
475 fn call_thread_root_function(
477 &mut self,
478 f: ty::Instance<'tcx>,
479 caller_abi: ExternAbi,
480 args: &[ImmTy<'tcx>],
481 dest: Option<&MPlaceTy<'tcx>>,
482 span: Span,
483 ) -> InterpResult<'tcx> {
484 let this = self.eval_context_mut();
485 assert!(this.active_thread_stack().is_empty());
486 assert!(this.active_thread_ref().origin_span.is_dummy());
487 this.active_thread_mut().origin_span = span;
488 this.call_function(f, caller_abi, args, dest, ReturnContinuation::Stop { cleanup: true })
489 }
490
491 fn visit_freeze_sensitive(
495 &self,
496 place: &MPlaceTy<'tcx>,
497 size: Size,
498 mut action: impl FnMut(AllocRange, bool) -> InterpResult<'tcx>,
499 ) -> InterpResult<'tcx> {
500 let this = self.eval_context_ref();
501 trace!("visit_frozen(place={:?}, size={:?})", *place, size);
502 debug_assert_eq!(
503 size,
504 this.size_and_align_of_val(place)?
505 .map(|(size, _)| size)
506 .unwrap_or_else(|| place.layout.size)
507 );
508 let start_addr = place.ptr().addr();
512 let mut cur_addr = start_addr;
513 let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer, unsafe_cell_size: Size| {
516 let unsafe_cell_addr = unsafe_cell_ptr.addr();
519 assert!(unsafe_cell_addr >= cur_addr);
520 let frozen_size = unsafe_cell_addr - cur_addr;
521 if frozen_size != Size::ZERO {
523 action(alloc_range(cur_addr - start_addr, frozen_size), true)?;
524 }
525 cur_addr += frozen_size;
526 if unsafe_cell_size != Size::ZERO {
528 action(
529 alloc_range(cur_addr - start_addr, unsafe_cell_size),
530 false,
531 )?;
532 }
533 cur_addr += unsafe_cell_size;
534 interp_ok(())
536 };
537 {
539 let mut visitor = UnsafeCellVisitor {
540 ecx: this,
541 unsafe_cell_action: |place| {
542 trace!("unsafe_cell_action on {:?}", place.ptr());
543 let unsafe_cell_size = this
545 .size_and_align_of_val(place)?
546 .map(|(size, _)| size)
547 .unwrap_or_else(|| place.layout.size);
549 if unsafe_cell_size != Size::ZERO {
551 unsafe_cell_action(&place.ptr(), unsafe_cell_size)
552 } else {
553 interp_ok(())
554 }
555 },
556 };
557 visitor.visit_value(place)?;
558 }
559 unsafe_cell_action(&place.ptr().wrapping_offset(size, this), Size::ZERO)?;
562 return interp_ok(());
564
565 struct UnsafeCellVisitor<'ecx, 'tcx, F>
568 where
569 F: FnMut(&MPlaceTy<'tcx>) -> InterpResult<'tcx>,
570 {
571 ecx: &'ecx MiriInterpCx<'tcx>,
572 unsafe_cell_action: F,
573 }
574
575 impl<'ecx, 'tcx, F> ValueVisitor<'tcx, MiriMachine<'tcx>> for UnsafeCellVisitor<'ecx, 'tcx, F>
576 where
577 F: FnMut(&MPlaceTy<'tcx>) -> InterpResult<'tcx>,
578 {
579 type V = MPlaceTy<'tcx>;
580
581 #[inline(always)]
582 fn ecx(&self) -> &MiriInterpCx<'tcx> {
583 self.ecx
584 }
585
586 fn aggregate_field_iter(
587 memory_index: &IndexVec<FieldIdx, u32>,
588 ) -> impl Iterator<Item = FieldIdx> + 'static {
589 let inverse_memory_index = memory_index.invert_bijective_mapping();
590 inverse_memory_index.into_iter()
591 }
592
593 fn visit_value(&mut self, v: &MPlaceTy<'tcx>) -> InterpResult<'tcx> {
595 trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty);
596 let is_unsafe_cell = match v.layout.ty.kind() {
597 ty::Adt(adt, _) =>
598 Some(adt.did()) == self.ecx.tcx.lang_items().unsafe_cell_type(),
599 _ => false,
600 };
601 if is_unsafe_cell {
602 (self.unsafe_cell_action)(v)
604 } else if self.ecx.type_is_freeze(v.layout.ty) {
605 interp_ok(())
607 } else if matches!(v.layout.fields, FieldsShape::Union(..)) {
608 (self.unsafe_cell_action)(v)
610 } else {
611 match v.layout.variants {
618 Variants::Multiple { .. } => {
619 (self.unsafe_cell_action)(v)
627 }
628 Variants::Single { .. } | Variants::Empty => {
629 self.walk_value(v)
632 }
633 }
634 }
635 }
636
637 fn visit_union(
638 &mut self,
639 _v: &MPlaceTy<'tcx>,
640 _fields: NonZero<usize>,
641 ) -> InterpResult<'tcx> {
642 bug!("we should have already handled unions in `visit_value`")
643 }
644 }
645 }
646
647 fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> {
651 if !self.eval_context_ref().machine.communicate() {
652 self.reject_in_isolation(name, RejectOpWith::Abort)?;
653 }
654 interp_ok(())
655 }
656
657 fn reject_in_isolation(&self, op_name: &str, reject_with: RejectOpWith) -> InterpResult<'tcx> {
660 let this = self.eval_context_ref();
661 match reject_with {
662 RejectOpWith::Abort => isolation_abort_error(op_name),
663 RejectOpWith::WarningWithoutBacktrace => {
664 static DEDUP: Mutex<FxHashSet<String>> =
666 Mutex::new(FxHashSet::with_hasher(rustc_hash::FxBuildHasher));
667 let mut emitted_warnings = DEDUP.lock().unwrap();
668 if !emitted_warnings.contains(op_name) {
669 emitted_warnings.insert(op_name.to_owned());
671 this.tcx
672 .dcx()
673 .warn(format!("{op_name} was made to return an error due to isolation"));
674 }
675
676 interp_ok(())
677 }
678 RejectOpWith::Warning => {
679 this.emit_diagnostic(NonHaltingDiagnostic::RejectedIsolatedOp(op_name.to_string()));
680 interp_ok(())
681 }
682 RejectOpWith::NoWarning => interp_ok(()), }
684 }
685
686 fn assert_target_os(&self, target_os: Os, name: &str) {
690 assert_eq!(
691 self.eval_context_ref().tcx.sess.target.os,
692 target_os,
693 "`{name}` is only available on the `{target_os}` target OS",
694 )
695 }
696
697 fn check_target_os(&self, target_oses: &[Os], name: Symbol) -> InterpResult<'tcx> {
701 let target_os = &self.eval_context_ref().tcx.sess.target.os;
702 if !target_oses.contains(target_os) {
703 throw_unsup_format!("`{name}` is not supported on {target_os}");
704 }
705 interp_ok(())
706 }
707
708 fn assert_target_os_is_unix(&self, name: &str) {
712 assert!(self.target_os_is_unix(), "`{name}` is only available for unix targets",);
713 }
714
715 fn target_os_is_unix(&self) -> bool {
716 self.eval_context_ref().tcx.sess.target.families.iter().any(|f| f == "unix")
717 }
718
719 fn deref_pointer_as(
721 &self,
722 op: &impl Projectable<'tcx, Provenance>,
723 layout: TyAndLayout<'tcx>,
724 ) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
725 let this = self.eval_context_ref();
726 let ptr = this.read_pointer(op)?;
727 interp_ok(this.ptr_to_mplace(ptr, layout))
728 }
729
730 fn deref_pointer_and_offset(
732 &self,
733 op: &impl Projectable<'tcx, Provenance>,
734 offset: u64,
735 base_layout: TyAndLayout<'tcx>,
736 value_layout: TyAndLayout<'tcx>,
737 ) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
738 let this = self.eval_context_ref();
739 let op_place = this.deref_pointer_as(op, base_layout)?;
740 let offset = Size::from_bytes(offset);
741
742 assert!(base_layout.size >= offset + value_layout.size);
744 let value_place = op_place.offset(offset, value_layout, this)?;
745 interp_ok(value_place)
746 }
747
748 fn deref_pointer_and_read(
749 &self,
750 op: &impl Projectable<'tcx, Provenance>,
751 offset: u64,
752 base_layout: TyAndLayout<'tcx>,
753 value_layout: TyAndLayout<'tcx>,
754 ) -> InterpResult<'tcx, Scalar> {
755 let this = self.eval_context_ref();
756 let value_place = this.deref_pointer_and_offset(op, offset, base_layout, value_layout)?;
757 this.read_scalar(&value_place)
758 }
759
760 fn deref_pointer_and_write(
761 &mut self,
762 op: &impl Projectable<'tcx, Provenance>,
763 offset: u64,
764 value: impl Into<Scalar>,
765 base_layout: TyAndLayout<'tcx>,
766 value_layout: TyAndLayout<'tcx>,
767 ) -> InterpResult<'tcx, ()> {
768 let this = self.eval_context_mut();
769 let value_place = this.deref_pointer_and_offset(op, offset, base_layout, value_layout)?;
770 this.write_scalar(value, &value_place)
771 }
772
773 fn read_timespec(&mut self, tp: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option<Duration>> {
777 let this = self.eval_context_mut();
778 let seconds_place = this.project_field(tp, FieldIdx::ZERO)?;
779 let seconds_scalar = this.read_scalar(&seconds_place)?;
780 let seconds = seconds_scalar.to_target_isize(this)?;
781 let nanoseconds_place = this.project_field(tp, FieldIdx::ONE)?;
782 let nanoseconds_scalar = this.read_scalar(&nanoseconds_place)?;
783 let nanoseconds = nanoseconds_scalar.to_target_isize(this)?;
784
785 interp_ok(
786 try {
787 let seconds: u64 = seconds.try_into().ok()?;
789 let nanoseconds: u32 = nanoseconds.try_into().ok()?;
791 if nanoseconds >= 1_000_000_000 {
792 None?
794 }
795 Duration::new(seconds, nanoseconds)
796 },
797 )
798 }
799
800 fn read_byte_slice<'a>(&'a self, slice: &ImmTy<'tcx>) -> InterpResult<'tcx, &'a [u8]>
802 where
803 'tcx: 'a,
804 {
805 let this = self.eval_context_ref();
806 let (ptr, len) = slice.to_scalar_pair();
807 let ptr = ptr.to_pointer(this)?;
808 let len = len.to_target_usize(this)?;
809 let bytes = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
810 interp_ok(bytes)
811 }
812
813 fn read_c_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, &'a [u8]>
815 where
816 'tcx: 'a,
817 {
818 let this = self.eval_context_ref();
819 let size1 = Size::from_bytes(1);
820
821 let mut len = Size::ZERO;
823 loop {
824 let alloc = this.get_ptr_alloc(ptr.wrapping_offset(len, this), size1)?.unwrap(); let byte = alloc.read_integer(alloc_range(Size::ZERO, size1))?.to_u8()?;
828 if byte == 0 {
829 break;
830 } else {
831 len += size1;
832 }
833 }
834
835 this.read_bytes_ptr_strip_provenance(ptr, len)
837 }
838
839 fn write_c_str(
845 &mut self,
846 c_str: &[u8],
847 ptr: Pointer,
848 size: u64,
849 ) -> InterpResult<'tcx, (bool, u64)> {
850 let string_length = u64::try_from(c_str.len()).unwrap();
853 let string_length = string_length.strict_add(1);
854 if size < string_length {
855 return interp_ok((false, string_length));
856 }
857 self.eval_context_mut()
858 .write_bytes_ptr(ptr, c_str.iter().copied().chain(iter::once(0u8)))?;
859 interp_ok((true, string_length))
860 }
861
862 fn read_c_str_with_char_size<T>(
865 &self,
866 mut ptr: Pointer,
867 size: Size,
868 align: Align,
869 ) -> InterpResult<'tcx, Vec<T>>
870 where
871 T: TryFrom<u128>,
872 <T as TryFrom<u128>>::Error: std::fmt::Debug,
873 {
874 assert_ne!(size, Size::ZERO);
875
876 let this = self.eval_context_ref();
877
878 this.check_ptr_align(ptr, align)?;
879
880 let mut wchars = Vec::new();
881 loop {
882 let alloc = this.get_ptr_alloc(ptr, size)?.unwrap(); let wchar_int = alloc.read_integer(alloc_range(Size::ZERO, size))?.to_bits(size)?;
886 if wchar_int == 0 {
887 break;
888 } else {
889 wchars.push(wchar_int.try_into().unwrap());
890 ptr = ptr.wrapping_offset(size, this);
891 }
892 }
893
894 interp_ok(wchars)
895 }
896
897 fn read_wide_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec<u16>> {
899 self.read_c_str_with_char_size(ptr, Size::from_bytes(2), Align::from_bytes(2).unwrap())
900 }
901
902 fn write_wide_str(
909 &mut self,
910 wide_str: &[u16],
911 ptr: Pointer,
912 size: u64,
913 ) -> InterpResult<'tcx, (bool, u64)> {
914 let string_length = u64::try_from(wide_str.len()).unwrap();
917 let string_length = string_length.strict_add(1);
918 if size < string_length {
919 return interp_ok((false, string_length));
920 }
921
922 let size2 = Size::from_bytes(2);
924 let this = self.eval_context_mut();
925 this.check_ptr_align(ptr, Align::from_bytes(2).unwrap())?;
926 let mut alloc = this.get_ptr_alloc_mut(ptr, size2 * string_length)?.unwrap(); for (offset, wchar) in wide_str.iter().copied().chain(iter::once(0x0000)).enumerate() {
928 let offset = u64::try_from(offset).unwrap();
929 alloc.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar))?;
930 }
931 interp_ok((true, string_length))
932 }
933
934 fn read_wchar_t_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec<u32>> {
937 let this = self.eval_context_ref();
938 let wchar_t = if this.tcx.sess.target.os == Os::Windows {
939 this.machine.layouts.u16
941 } else {
942 this.libc_ty_layout("wchar_t")
943 };
944 self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi)
945 }
946
947 fn frame_in_std(&self) -> bool {
948 let this = self.eval_context_ref();
949 let frame = this.frame();
950 let instance: Option<_> = try {
952 let scope = frame.current_source_info()?.scope;
953 let inlined_parent = frame.body().source_scopes[scope].inlined_parent_scope?;
954 let source = &frame.body().source_scopes[inlined_parent];
955 source.inlined.expect("inlined_parent_scope points to scope without inline info").0
956 };
957 let instance = instance.unwrap_or(frame.instance());
959 let frame_crate = this.tcx.def_path(instance.def_id()).krate;
964 let crate_name = this.tcx.crate_name(frame_crate);
965 let crate_name = crate_name.as_str();
966 crate_name == "std" || crate_name == "std_miri_test"
968 }
969
970 fn mark_immutable(&mut self, mplace: &MPlaceTy<'tcx>) {
972 let this = self.eval_context_mut();
973 let provenance = mplace.ptr().into_pointer_or_addr().unwrap().provenance;
975 this.alloc_mark_immutable(provenance.get_alloc_id().unwrap()).unwrap();
976 }
977
978 fn get_twice_wide_int_ty(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
980 let this = self.eval_context_ref();
981 match ty.kind() {
982 ty::Uint(UintTy::U8) => this.tcx.types.u16,
984 ty::Uint(UintTy::U16) => this.tcx.types.u32,
985 ty::Uint(UintTy::U32) => this.tcx.types.u64,
986 ty::Uint(UintTy::U64) => this.tcx.types.u128,
987 ty::Int(IntTy::I8) => this.tcx.types.i16,
989 ty::Int(IntTy::I16) => this.tcx.types.i32,
990 ty::Int(IntTy::I32) => this.tcx.types.i64,
991 ty::Int(IntTy::I64) => this.tcx.types.i128,
992 _ => span_bug!(this.cur_span(), "unexpected type: {ty:?}"),
993 }
994 }
995
996 fn expect_target_feature_for_intrinsic(
1001 &self,
1002 intrinsic: Symbol,
1003 target_feature: &str,
1004 ) -> InterpResult<'tcx, ()> {
1005 let this = self.eval_context_ref();
1006 if !this.tcx.sess.unstable_target_features.contains(&Symbol::intern(target_feature)) {
1007 throw_ub_format!(
1008 "attempted to call intrinsic `{intrinsic}` that requires missing target feature {target_feature}"
1009 );
1010 }
1011 interp_ok(())
1012 }
1013
1014 fn lookup_link_section(
1017 &mut self,
1018 include_name: impl Fn(&str) -> bool,
1019 ) -> InterpResult<'tcx, Vec<(ImmTy<'tcx>, Span)>> {
1020 let this = self.eval_context_mut();
1021 let tcx = this.tcx.tcx;
1022
1023 let mut array = vec![];
1024
1025 iter_exported_symbols(tcx, |_cnum, def_id| {
1026 let attrs = tcx.codegen_fn_attrs(def_id);
1027 let Some(link_section) = attrs.link_section else {
1028 return interp_ok(());
1029 };
1030 if include_name(link_section.as_str()) {
1031 let instance = ty::Instance::mono(tcx, def_id);
1032 let span = tcx.def_span(def_id);
1033 let const_val = this.eval_global(instance).unwrap_or_else(|err| {
1034 panic!(
1035 "failed to evaluate static in required link_section: {def_id:?}\n{err:?}"
1036 )
1037 });
1038 match const_val.layout.ty.kind() {
1039 ty::FnPtr(..) => {
1040 array.push((this.read_immediate(&const_val)?, span));
1041 }
1042 ty::Array(elem_ty, _) if matches!(elem_ty.kind(), ty::FnPtr(..)) => {
1043 let mut elems = this.project_array_fields(&const_val)?;
1044 while let Some((_idx, elem)) = elems.next(this)? {
1045 array.push((this.read_immediate(&elem)?, span));
1046 }
1047 }
1048 _ =>
1049 throw_unsup_format!(
1050 "only function pointers and arrays of function pointers are supported in well-known linker sections"
1051 ),
1052 }
1053 }
1054 interp_ok(())
1055 })?;
1056
1057 interp_ok(array)
1058 }
1059
1060 fn mangle_internal_symbol<'a>(&'a mut self, name: &'static str) -> &'a str
1061 where
1062 'tcx: 'a,
1063 {
1064 let this = self.eval_context_mut();
1065 let tcx = *this.tcx;
1066 this.machine
1067 .mangle_internal_symbol_cache
1068 .entry(name)
1069 .or_insert_with(|| mangle_internal_symbol(tcx, name))
1070 }
1071}
1072
1073impl<'tcx> MiriMachine<'tcx> {
1074 pub fn current_user_relevant_span(&self) -> Span {
1079 self.threads.active_thread_ref().current_user_relevant_span()
1080 }
1081
1082 pub fn caller_span(&self) -> Span {
1088 let frame_idx = self.top_user_relevant_frame().unwrap();
1091 let frame_idx = cmp::min(frame_idx, self.stack().len().saturating_sub(2));
1092 self.stack()[frame_idx].current_span()
1093 }
1094
1095 fn stack(&self) -> &[Frame<'tcx, Provenance, machine::FrameExtra<'tcx>>] {
1096 self.threads.active_thread_stack()
1097 }
1098
1099 fn top_user_relevant_frame(&self) -> Option<usize> {
1100 self.threads.active_thread_ref().top_user_relevant_frame()
1101 }
1102
1103 pub fn user_relevance(&self, frame: &Frame<'tcx, Provenance>) -> u8 {
1105 if frame.instance().def.requires_caller_location(self.tcx) {
1106 return 0;
1107 }
1108 if self.is_local(frame.instance()) {
1109 u8::MAX
1110 } else {
1111 1
1114 }
1115 }
1116}
1117
1118pub fn isolation_abort_error<'tcx>(name: &str) -> InterpResult<'tcx> {
1119 throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
1120 "{name} not available when isolation is enabled",
1121 )))
1122}
1123
1124pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar {
1125 let val = if b { -1 } else { 0 };
1129 Scalar::from_int(val, size)
1130}
1131
1132pub(crate) fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 {
1136 if success {
1137 u32::try_from(len.strict_sub(1)).unwrap()
1140 } else {
1141 u32::try_from(len).unwrap()
1144 }
1145}
1146
1147pub trait ToUsize {
1149 fn to_usize(self) -> usize;
1150}
1151
1152impl ToUsize for u32 {
1153 fn to_usize(self) -> usize {
1154 self.try_into().unwrap()
1155 }
1156}
1157
1158pub trait ToU64 {
1161 fn to_u64(self) -> u64;
1162}
1163
1164impl ToU64 for usize {
1165 fn to_u64(self) -> u64 {
1166 self.try_into().unwrap()
1167 }
1168}
1169
1170#[macro_export]
1176macro_rules! enter_trace_span {
1177 ($($tt:tt)*) => {
1178 rustc_const_eval::enter_trace_span!($crate::MiriMachine<'static>, $($tt)*)
1179 };
1180}