From 46019523e8bc5096ae452a39073aed06a6c45e1f Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 6 Jul 2024 12:02:17 +0200 Subject: [PATCH] `sched_setaffinity`: test `cpusetsize == 0` --- .../miri/src/shims/unix/foreign_items.rs | 4 +++- .../miri/tests/pass-dep/libc/libc-affinity.rs | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index f1bae8646d31..3a18d6220333 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -645,7 +645,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.set_last_error(einval)?; this.write_scalar(Scalar::from_i32(-1), dest)?; } else { - // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES` + // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`. + // Any unspecified bytes are treated as zero here (none of the CPUs are configured). + // This is not exactly documented, so we assume that this is the behavior in practice. 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] = diff --git a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs index d360864b97c3..ac3001745db8 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs @@ -105,6 +105,24 @@ fn get_small_cpu_mask() { } } +fn set_small_cpu_mask() { + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + + // setting a mask of size 0 is invalid + let err = unsafe { sched_setaffinity(PID, 0, &cpuset) }; + assert_eq!(err, -1); + assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); + + // any other number of bytes (at least up to `size_of()` will work + for i in 1..24 { + let err = unsafe { sched_setaffinity(PID, i, &cpuset) }; + assert_eq!(err, 0, "fail for {i}"); + } +} + fn set_custom_cpu_mask() { let cpu_count = std::thread::available_parallelism().unwrap().get(); @@ -189,6 +207,7 @@ fn main() { configure_unavailable_cpu(); large_set(); get_small_cpu_mask(); + set_small_cpu_mask(); set_custom_cpu_mask(); parent_child(); }