about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2025-06-30 08:22:51 +0200
committerRalf Jung <post@ralfj.de>2025-06-30 08:22:51 +0200
commitcd971c6e1e969996a92889e26714cde45556ec87 (patch)
treecab2320c5d2150d58b5e491fda92306d0dc94f52 /src/tools
parent555553f0b86eccb6e9e480bd731dd6d59cb67aa0 (diff)
downloadrust-cd971c6e1e969996a92889e26714cde45556ec87.tar.gz
rust-cd971c6e1e969996a92889e26714cde45556ec87.zip
linux futex: fix for val > i32::MAX
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/sync.rs7
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs5
2 files changed, 9 insertions, 3 deletions
diff --git a/src/tools/miri/src/shims/unix/linux_like/sync.rs b/src/tools/miri/src/shims/unix/linux_like/sync.rs
index 86e8b57824c..9fad74c0241 100644
--- a/src/tools/miri/src/shims/unix/linux_like/sync.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/sync.rs
@@ -15,12 +15,13 @@ pub fn futex<'tcx>(
 ) -> InterpResult<'tcx> {
     let [addr, op, val] = check_min_vararg_count("`syscall(SYS_futex, ...)`", varargs)?;
 
+    // See <https://man7.org/linux/man-pages/man2/futex.2.html> for docs.
     // The first three arguments (after the syscall number itself) are the same to all futex operations:
-    //     (int *addr, int op, int val).
+    //     (uint32_t *addr, int op, uint32_t val).
     // We checked above that these definitely exist.
     let addr = ecx.read_pointer(addr)?;
     let op = ecx.read_scalar(op)?.to_i32()?;
-    let val = ecx.read_scalar(val)?.to_i32()?;
+    let val = ecx.read_scalar(val)?.to_u32()?;
 
     // This is a vararg function so we have to bring our own type for this pointer.
     let addr = ecx.ptr_to_mplace(addr, ecx.machine.layouts.i32);
@@ -138,7 +139,7 @@ pub fn futex<'tcx>(
             // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
             // We do an acquire read -- it only seems reasonable that if we observe a value here, we
             // actually establish an ordering with that value.
-            let futex_val = ecx.read_scalar_atomic(&addr, AtomicReadOrd::Acquire)?.to_i32()?;
+            let futex_val = ecx.read_scalar_atomic(&addr, AtomicReadOrd::Acquire)?.to_u32()?;
             if val == futex_val {
                 // The value still matches, so we block the thread and make it wait for FUTEX_WAKE.
 
diff --git a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
index f8f1c554f0d..19d86f09595 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
@@ -33,6 +33,11 @@ fn wake_nobody() {
             0,
         );
     }
+
+    // Wake u32::MAX waiters.
+    unsafe {
+        assert_eq!(libc::syscall(libc::SYS_futex, addr_of!(futex), libc::FUTEX_WAKE, u32::MAX), 0);
+    }
 }
 
 fn wake_dangling() {