Skip to content

Commit 9a0e671

Browse files
committed
lookup c_ulong instead of hard-coding the chunk size
1 parent c77a2c6 commit 9a0e671

File tree

5 files changed

+58
-57
lines changed

5 files changed

+58
-57
lines changed

src/tools/miri/src/concurrency/cpu_affinity.rs

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
use crate::bug;
1+
use rustc_middle::ty::layout::LayoutOf;
22
use rustc_target::abi::Endian;
33

4+
use crate::*;
5+
46
/// The maximum number of CPUs supported by miri.
57
///
68
/// 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]);
1921
impl CpuAffinityMask {
2022
pub(crate) const CPU_MASK_BYTES: usize = MAX_CPUS / 8;
2123

22-
pub fn new(target: &rustc_target::spec::Target, cpu_count: u32) -> Self {
24+
pub fn new<'tcx>(cx: &impl LayoutOf<'tcx>, cpu_count: u32) -> Self {
2325
let mut this = Self([0; Self::CPU_MASK_BYTES]);
2426

2527
// the default affinity mask includes only the available CPUs
2628
for i in 0..cpu_count as usize {
27-
this.set(target, i);
29+
this.set(cx, i);
2830
}
2931

3032
this
3133
}
3234

33-
pub fn chunk_size(target: &rustc_target::spec::Target) -> u64 {
34-
// The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either
35-
//
36-
// - [u32; 32] on 32-bit platforms
37-
// - [u64; 16] everywhere else
38-
39-
// FIXME: this should be `size_of::<core::ffi::c_ulong>()`
40-
u64::from(target.pointer_width / 8)
35+
pub fn chunk_size<'tcx>(cx: &impl LayoutOf<'tcx>) -> u64 {
36+
// The actual representation of the CpuAffinityMask is [c_ulong; _].
37+
let ulong = helpers::path_ty_layout(cx, &["core", "ffi", "c_ulong"]);
38+
ulong.size.bytes()
4139
}
4240

43-
fn set(&mut self, target: &rustc_target::spec::Target, cpu: usize) {
41+
fn set<'tcx>(&mut self, cx: &impl LayoutOf<'tcx>, cpu: usize) {
4442
// we silently ignore CPUs that are out of bounds. This matches the behavior of
4543
// `sched_setaffinity` with a mask that specifies more than `CPU_SETSIZE` CPUs.
4644
if cpu >= MAX_CPUS {
4745
return;
4846
}
4947

50-
// The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either
51-
//
52-
// - [u32; 32] on 32-bit platforms
53-
// - [u64; 16] everywhere else
54-
//
48+
// The actual representation of the CpuAffinityMask is [c_ulong; _].
5549
// Within the array elements, we need to use the endianness of the target.
56-
match Self::chunk_size(target) {
50+
let target = &cx.tcx().sess.target;
51+
match Self::chunk_size(cx) {
5752
4 => {
5853
let start = cpu / 32 * 4; // first byte of the correct u32
5954
let chunk = self.0[start..].first_chunk_mut::<4>().unwrap();
@@ -72,21 +67,21 @@ impl CpuAffinityMask {
7267
Endian::Big => (u64::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(),
7368
};
7469
}
75-
other => bug!("other chunk sizes are not supported: {other}"),
70+
other => bug!("chunk size not supported: {other}"),
7671
};
7772
}
7873

7974
pub fn as_slice(&self) -> &[u8] {
8075
self.0.as_slice()
8176
}
8277

83-
pub fn from_array(
84-
target: &rustc_target::spec::Target,
78+
pub fn from_array<'tcx>(
79+
cx: &impl LayoutOf<'tcx>,
8580
cpu_count: u32,
8681
bytes: [u8; Self::CPU_MASK_BYTES],
8782
) -> Option<Self> {
8883
// mask by what CPUs are actually available
89-
let default = Self::new(target, cpu_count);
84+
let default = Self::new(cx, cpu_count);
9085
let masked = std::array::from_fn(|i| bytes[i] & default.0[i]);
9186

9287
// at least one thread must be set for the input to be valid

src/tools/miri/src/eval.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,8 @@ pub fn create_ecx<'tcx>(
282282
})?;
283283

284284
// Make sure we have MIR. We check MIR for some stable monomorphic function in libcore.
285-
let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"], Namespace::ValueNS);
285+
let sentinel =
286+
helpers::try_resolve_path(tcx, &["core", "ascii", "escape_default"], Namespace::ValueNS);
286287
if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) {
287288
tcx.dcx().fatal(
288289
"the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \

src/tools/miri/src/helpers.rs

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1818
use rustc_middle::middle::dependency_format::Linkage;
1919
use rustc_middle::middle::exported_symbols::ExportedSymbol;
2020
use rustc_middle::mir;
21+
use rustc_middle::ty::layout::MaybeResult;
2122
use rustc_middle::ty::{
2223
self,
2324
layout::{LayoutOf, TyAndLayout},
@@ -159,6 +160,35 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>)
159160
None
160161
}
161162

163+
/// Gets an instance for a path; fails gracefully if the path does not exist.
164+
pub fn try_resolve_path<'tcx>(
165+
tcx: TyCtxt<'tcx>,
166+
path: &[&str],
167+
namespace: Namespace,
168+
) -> Option<ty::Instance<'tcx>> {
169+
let did = try_resolve_did(tcx, path, Some(namespace))?;
170+
Some(ty::Instance::mono(tcx, did))
171+
}
172+
173+
/// Gets an instance for a path.
174+
#[track_caller]
175+
pub fn resolve_path<'tcx>(
176+
tcx: TyCtxt<'tcx>,
177+
path: &[&str],
178+
namespace: Namespace,
179+
) -> ty::Instance<'tcx> {
180+
try_resolve_path(tcx, path, namespace)
181+
.unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
182+
}
183+
184+
/// Gets the layout of a type at a path.
185+
#[track_caller]
186+
pub fn path_ty_layout<'tcx>(cx: &impl LayoutOf<'tcx>, path: &[&str]) -> TyAndLayout<'tcx> {
187+
let ty =
188+
resolve_path(cx.tcx(), path, Namespace::TypeNS).ty(cx.tcx(), ty::ParamEnv::reveal_all());
189+
cx.layout_of(ty).to_result().ok().unwrap()
190+
}
191+
162192
/// Call `f` for each exported symbol.
163193
pub fn iter_exported_symbols<'tcx>(
164194
tcx: TyCtxt<'tcx>,
@@ -259,23 +289,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
259289
try_resolve_did(*self.eval_context_ref().tcx, path, None).is_some()
260290
}
261291

262-
/// Gets an instance for a path; fails gracefully if the path does not exist.
263-
fn try_resolve_path(&self, path: &[&str], namespace: Namespace) -> Option<ty::Instance<'tcx>> {
264-
let tcx = self.eval_context_ref().tcx.tcx;
265-
let did = try_resolve_did(tcx, path, Some(namespace))?;
266-
Some(ty::Instance::mono(tcx, did))
267-
}
268-
269-
/// Gets an instance for a path.
270-
fn resolve_path(&self, path: &[&str], namespace: Namespace) -> ty::Instance<'tcx> {
271-
self.try_resolve_path(path, namespace)
272-
.unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
273-
}
274-
275292
/// Evaluates the scalar at the specified path.
276293
fn eval_path(&self, path: &[&str]) -> OpTy<'tcx> {
277294
let this = self.eval_context_ref();
278-
let instance = this.resolve_path(path, Namespace::ValueNS);
295+
let instance = resolve_path(*this.tcx, path, Namespace::ValueNS);
279296
// We don't give a span -- this isn't actually used directly by the program anyway.
280297
let const_val = this.eval_global(instance).unwrap_or_else(|err| {
281298
panic!("failed to evaluate required Rust item: {path:?}\n{err:?}")
@@ -344,19 +361,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
344361
"`libc` crate is not reliably available on Windows targets; Miri should not use it there"
345362
);
346363
}
347-
let ty = this
348-
.resolve_path(&["libc", name], Namespace::TypeNS)
349-
.ty(*this.tcx, ty::ParamEnv::reveal_all());
350-
this.layout_of(ty).unwrap()
364+
path_ty_layout(this, &["libc", name])
351365
}
352366

353367
/// Helper function to get the `TyAndLayout` of a `windows` type
354368
fn windows_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
355369
let this = self.eval_context_ref();
356-
let ty = this
357-
.resolve_path(&["std", "sys", "pal", "windows", "c", name], Namespace::TypeNS)
358-
.ty(*this.tcx, ty::ParamEnv::reveal_all());
359-
this.layout_of(ty).unwrap()
370+
path_ty_layout(this, &["std", "sys", "pal", "windows", "c", name])
360371
}
361372

362373
/// Project to the given *named* field (which must be a struct or union type).

src/tools/miri/src/machine.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -643,10 +643,8 @@ impl<'tcx> MiriMachine<'tcx> {
643643
let threads = ThreadManager::default();
644644
let mut thread_cpu_affinity = FxHashMap::default();
645645
if matches!(&*tcx.sess.target.os, "linux" | "freebsd" | "android") {
646-
thread_cpu_affinity.insert(
647-
threads.active_thread(),
648-
CpuAffinityMask::new(&tcx.sess.target, config.num_cpus),
649-
);
646+
thread_cpu_affinity
647+
.insert(threads.active_thread(), CpuAffinityMask::new(&layout_cx, config.num_cpus));
650648
}
651649
MiriMachine {
652650
tcx,

src/tools/miri/src/shims/unix/foreign_items.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -594,11 +594,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
594594
_ => throw_unsup_format!("`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"),
595595
};
596596

597-
// The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either
598-
//
599-
// - [u32; 32] on 32-bit platforms
600-
// - [u64; 16] everywhere else
601-
let chunk_size = CpuAffinityMask::chunk_size(&this.tcx.sess.target);
597+
// The mask is stored in chunks, and the size must be a whole number of chunks.
598+
let chunk_size = CpuAffinityMask::chunk_size(this);
602599

603600
if this.ptr_is_null(mask)? {
604601
let einval = this.eval_libc("EFAULT");
@@ -643,7 +640,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
643640
_ => throw_unsup_format!("`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"),
644641
};
645642

646-
#[allow(clippy::map_entry)]
647643
if this.ptr_is_null(mask)? {
648644
let einval = this.eval_libc("EFAULT");
649645
this.set_last_error(einval)?;
@@ -652,9 +648,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
652648
// NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`
653649
let bits_slice = this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
654650
// This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES`
655-
let bits_array: [u8;CpuAffinityMask::CPU_MASK_BYTES] =
651+
let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
656652
std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
657-
match CpuAffinityMask::from_array(&this.tcx.sess.target, this.machine.num_cpus, bits_array) {
653+
match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
658654
Some(cpuset) => {
659655
this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
660656
this.write_scalar(Scalar::from_i32(0), dest)?;

0 commit comments

Comments
 (0)