about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/miri/src/concurrency/cpu_affinity.rs39
-rw-r--r--src/tools/miri/src/eval.rs3
-rw-r--r--src/tools/miri/src/helpers.rs55
-rw-r--r--src/tools/miri/src/machine.rs6
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs12
5 files changed, 58 insertions, 57 deletions
diff --git a/src/tools/miri/src/concurrency/cpu_affinity.rs b/src/tools/miri/src/concurrency/cpu_affinity.rs
index 085900ac3aa..8df26d718bf 100644
--- a/src/tools/miri/src/concurrency/cpu_affinity.rs
+++ b/src/tools/miri/src/concurrency/cpu_affinity.rs
@@ -1,6 +1,8 @@
-use crate::bug;
+use rustc_middle::ty::layout::LayoutOf;
 use rustc_target::abi::Endian;
 
+use crate::*;
+
 /// The maximum number of CPUs supported by miri.
 ///
 /// This value is compatible with the libc `CPU_SETSIZE` constant and corresponds to the number
@@ -19,41 +21,34 @@ pub(crate) struct CpuAffinityMask([u8; Self::CPU_MASK_BYTES]);
 impl CpuAffinityMask {
     pub(crate) const CPU_MASK_BYTES: usize = MAX_CPUS / 8;
 
-    pub fn new(target: &rustc_target::spec::Target, cpu_count: u32) -> Self {
+    pub fn new<'tcx>(cx: &impl LayoutOf<'tcx>, cpu_count: u32) -> Self {
         let mut this = Self([0; Self::CPU_MASK_BYTES]);
 
         // the default affinity mask includes only the available CPUs
         for i in 0..cpu_count as usize {
-            this.set(target, i);
+            this.set(cx, i);
         }
 
         this
     }
 
-    pub fn chunk_size(target: &rustc_target::spec::Target) -> u64 {
-        // The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either
-        //
-        // - [u32; 32] on 32-bit platforms
-        // - [u64; 16] everywhere else
-
-        // FIXME: this should be `size_of::<core::ffi::c_ulong>()`
-        u64::from(target.pointer_width / 8)
+    pub fn chunk_size<'tcx>(cx: &impl LayoutOf<'tcx>) -> u64 {
+        // The actual representation of the CpuAffinityMask is [c_ulong; _].
+        let ulong = helpers::path_ty_layout(cx, &["core", "ffi", "c_ulong"]);
+        ulong.size.bytes()
     }
 
-    fn set(&mut self, target: &rustc_target::spec::Target, cpu: usize) {
+    fn set<'tcx>(&mut self, cx: &impl LayoutOf<'tcx>, cpu: usize) {
         // we silently ignore CPUs that are out of bounds. This matches the behavior of
         // `sched_setaffinity` with a mask that specifies more than `CPU_SETSIZE` CPUs.
         if cpu >= MAX_CPUS {
             return;
         }
 
-        // The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either
-        //
-        // - [u32; 32] on 32-bit platforms
-        // - [u64; 16] everywhere else
-        //
+        // The actual representation of the CpuAffinityMask is [c_ulong; _].
         // Within the array elements, we need to use the endianness of the target.
-        match Self::chunk_size(target) {
+        let target = &cx.tcx().sess.target;
+        match Self::chunk_size(cx) {
             4 => {
                 let start = cpu / 32 * 4; // first byte of the correct u32
                 let chunk = self.0[start..].first_chunk_mut::<4>().unwrap();
@@ -72,7 +67,7 @@ impl CpuAffinityMask {
                     Endian::Big => (u64::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(),
                 };
             }
-            other => bug!("other chunk sizes are not supported: {other}"),
+            other => bug!("chunk size not supported: {other}"),
         };
     }
 
@@ -80,13 +75,13 @@ impl CpuAffinityMask {
         self.0.as_slice()
     }
 
-    pub fn from_array(
-        target: &rustc_target::spec::Target,
+    pub fn from_array<'tcx>(
+        cx: &impl LayoutOf<'tcx>,
         cpu_count: u32,
         bytes: [u8; Self::CPU_MASK_BYTES],
     ) -> Option<Self> {
         // mask by what CPUs are actually available
-        let default = Self::new(target, cpu_count);
+        let default = Self::new(cx, cpu_count);
         let masked = std::array::from_fn(|i| bytes[i] & default.0[i]);
 
         // at least one thread must be set for the input to be valid
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 9142b8b5fdb..2184a4426c8 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -282,7 +282,8 @@ pub fn create_ecx<'tcx>(
     })?;
 
     // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore.
-    let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"], Namespace::ValueNS);
+    let sentinel =
+        helpers::try_resolve_path(tcx, &["core", "ascii", "escape_default"], Namespace::ValueNS);
     if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) {
         tcx.dcx().fatal(
             "the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 590e8984e99..ba094c988e5 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -18,6 +18,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
 use rustc_middle::mir;
+use rustc_middle::ty::layout::MaybeResult;
 use rustc_middle::ty::{
     self,
     layout::{LayoutOf, TyAndLayout},
@@ -159,6 +160,35 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>)
     None
 }
 
+/// Gets an instance for a path; fails gracefully if the path does not exist.
+pub fn try_resolve_path<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    path: &[&str],
+    namespace: Namespace,
+) -> Option<ty::Instance<'tcx>> {
+    let did = try_resolve_did(tcx, path, Some(namespace))?;
+    Some(ty::Instance::mono(tcx, did))
+}
+
+/// Gets an instance for a path.
+#[track_caller]
+pub fn resolve_path<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    path: &[&str],
+    namespace: Namespace,
+) -> ty::Instance<'tcx> {
+    try_resolve_path(tcx, path, namespace)
+        .unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
+}
+
+/// Gets the layout of a type at a path.
+#[track_caller]
+pub fn path_ty_layout<'tcx>(cx: &impl LayoutOf<'tcx>, path: &[&str]) -> TyAndLayout<'tcx> {
+    let ty =
+        resolve_path(cx.tcx(), path, Namespace::TypeNS).ty(cx.tcx(), ty::ParamEnv::reveal_all());
+    cx.layout_of(ty).to_result().ok().unwrap()
+}
+
 /// Call `f` for each exported symbol.
 pub fn iter_exported_symbols<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -259,23 +289,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         try_resolve_did(*self.eval_context_ref().tcx, path, None).is_some()
     }
 
-    /// Gets an instance for a path; fails gracefully if the path does not exist.
-    fn try_resolve_path(&self, path: &[&str], namespace: Namespace) -> Option<ty::Instance<'tcx>> {
-        let tcx = self.eval_context_ref().tcx.tcx;
-        let did = try_resolve_did(tcx, path, Some(namespace))?;
-        Some(ty::Instance::mono(tcx, did))
-    }
-
-    /// Gets an instance for a path.
-    fn resolve_path(&self, path: &[&str], namespace: Namespace) -> ty::Instance<'tcx> {
-        self.try_resolve_path(path, namespace)
-            .unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
-    }
-
     /// Evaluates the scalar at the specified path.
     fn eval_path(&self, path: &[&str]) -> OpTy<'tcx> {
         let this = self.eval_context_ref();
-        let instance = this.resolve_path(path, Namespace::ValueNS);
+        let instance = resolve_path(*this.tcx, path, Namespace::ValueNS);
         // We don't give a span -- this isn't actually used directly by the program anyway.
         let const_val = this.eval_global(instance).unwrap_or_else(|err| {
             panic!("failed to evaluate required Rust item: {path:?}\n{err:?}")
@@ -344,19 +361,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 "`libc` crate is not reliably available on Windows targets; Miri should not use it there"
             );
         }
-        let ty = this
-            .resolve_path(&["libc", name], Namespace::TypeNS)
-            .ty(*this.tcx, ty::ParamEnv::reveal_all());
-        this.layout_of(ty).unwrap()
+        path_ty_layout(this, &["libc", name])
     }
 
     /// Helper function to get the `TyAndLayout` of a `windows` type
     fn windows_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
         let this = self.eval_context_ref();
-        let ty = this
-            .resolve_path(&["std", "sys", "pal", "windows", "c", name], Namespace::TypeNS)
-            .ty(*this.tcx, ty::ParamEnv::reveal_all());
-        this.layout_of(ty).unwrap()
+        path_ty_layout(this, &["std", "sys", "pal", "windows", "c", name])
     }
 
     /// Project to the given *named* field (which must be a struct or union type).
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index fee6ab06817..02bfd6ec815 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -643,10 +643,8 @@ impl<'tcx> MiriMachine<'tcx> {
         let threads = ThreadManager::default();
         let mut thread_cpu_affinity = FxHashMap::default();
         if matches!(&*tcx.sess.target.os, "linux" | "freebsd" | "android") {
-            thread_cpu_affinity.insert(
-                threads.active_thread(),
-                CpuAffinityMask::new(&tcx.sess.target, config.num_cpus),
-            );
+            thread_cpu_affinity
+                .insert(threads.active_thread(), CpuAffinityMask::new(&layout_cx, config.num_cpus));
         }
         MiriMachine {
             tcx,
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index f5d3e0b536b..f1bae8646d3 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -594,11 +594,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     _ => throw_unsup_format!("`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"),
                 };
 
-                // The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either
-                //
-                // - [u32; 32] on 32-bit platforms
-                // - [u64; 16] everywhere else
-                let chunk_size = CpuAffinityMask::chunk_size(&this.tcx.sess.target);
+                // The mask is stored in chunks, and the size must be a whole number of chunks.
+                let chunk_size = CpuAffinityMask::chunk_size(this);
 
                 if this.ptr_is_null(mask)? {
                     let einval = this.eval_libc("EFAULT");
@@ -643,7 +640,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     _ => throw_unsup_format!("`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"),
                 };
 
-                #[allow(clippy::map_entry)]
                 if this.ptr_is_null(mask)? {
                     let einval = this.eval_libc("EFAULT");
                     this.set_last_error(einval)?;
@@ -652,9 +648,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`
                     let bits_slice = this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
                     // This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES`
-                    let bits_array: [u8;CpuAffinityMask::CPU_MASK_BYTES] =
+                    let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
                         std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
-                    match CpuAffinityMask::from_array(&this.tcx.sess.target, this.machine.num_cpus, bits_array) {
+                    match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
                         Some(cpuset) => {
                             this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
                             this.write_scalar(Scalar::from_i32(0), dest)?;