Skip to content

Commit 6df54c4

Browse files
committed
Use read_scalar_at_offset in futex_wait instead of memory.get_raw.
1 parent 5880e7d commit 6df54c4

File tree

1 file changed

+14
-15
lines changed

1 file changed

+14
-15
lines changed

src/shims/posix/linux/sync.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,14 @@ pub fn futex<'tcx>(
2424
// The first three arguments (after the syscall number itself) are the same to all futex operations:
2525
// (int *addr, int op, int val).
2626
// We checked above that these definitely exist.
27-
//
28-
// `addr` is used to identify the mutex, but note that not all futex
29-
// operations actually read from this addres or even require this address
30-
// to exist. Also, the type of `addr` is not consistent. The API requires
31-
// it to be a 4-byte aligned pointer, and will use the 4 bytes at the given
32-
// address as an (atomic) i32. It's not uncommon for `addr` to be passed as
33-
// another type than `*mut i32`, such as `*const AtomicI32`.
34-
let addr = this.force_ptr(this.read_scalar(args[1])?.check_init()?)?;
27+
let addr = this.read_immediate(args[1])?;
3528
let op = this.read_scalar(args[2])?.to_i32()?;
3629
let val = this.read_scalar(args[3])?.to_i32()?;
3730

31+
// The raw pointer value is used to identify the mutex.
32+
// Not all mutex operations actually read from this address or even require this address to exist.
33+
let futex_ptr = this.force_ptr(addr.to_scalar()?)?;
34+
3835
let thread = this.get_active_thread();
3936

4037
let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?;
@@ -73,14 +70,16 @@ pub fn futex<'tcx>(
7370
})
7471
};
7572
// Check the pointer for alignment and validity.
76-
// Atomic operations are only available for fully aligned values.
77-
this.memory.check_ptr_access(addr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?;
78-
// Read an `i32` through the pointer, regardless of any wrapper types (e.g. `AtomicI32`).
79-
let futex_val = this.memory.get_raw(addr.alloc_id)?.read_scalar(this, addr, Size::from_bytes(4))?.to_i32()?;
73+
// The API requires `addr` to be a 4-byte aligned pointer, and will
74+
// use the 4 bytes at the given address as an (atomic) i32.
75+
this.memory.check_ptr_access(addr.to_scalar()?, Size::from_bytes(4), Align::from_bytes(4).unwrap())?;
76+
// Read an `i32` through the pointer, regardless of any wrapper types.
77+
// It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
78+
let futex_val = this.read_scalar_at_offset(addr.into(), 0, this.machine.layouts.i32)?.to_i32()?;
8079
if val == futex_val {
8180
// The value still matches, so we block the trait make it wait for FUTEX_WAKE.
8281
this.block_thread(thread);
83-
this.futex_wait(addr, thread);
82+
this.futex_wait(futex_ptr, thread);
8483
// Succesfully waking up from FUTEX_WAIT always returns zero.
8584
this.write_scalar(Scalar::from_machine_isize(0, this), dest)?;
8685
// Register a timeout callback if a timeout was specified.
@@ -91,7 +90,7 @@ pub fn futex<'tcx>(
9190
timeout_time,
9291
Box::new(move |this| {
9392
this.unblock_thread(thread);
94-
this.futex_remove_waiter(addr, thread);
93+
this.futex_remove_waiter(futex_ptr, thread);
9594
let etimedout = this.eval_libc("ETIMEDOUT")?;
9695
this.set_last_error(etimedout)?;
9796
this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
@@ -114,7 +113,7 @@ pub fn futex<'tcx>(
114113
op if op == futex_wake => {
115114
let mut n = 0;
116115
for _ in 0..val {
117-
if let Some(thread) = this.futex_wake(addr) {
116+
if let Some(thread) = this.futex_wake(futex_ptr) {
118117
this.unblock_thread(thread);
119118
this.unregister_timeout_callback_if_exists(thread);
120119
n += 1;

0 commit comments

Comments
 (0)