From 6df54c47a7ac0a0788d68c12198f1369b559b93e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 12:11:24 +0200 Subject: [PATCH] Use read_scalar_at_offset in futex_wait instead of memory.get_raw. --- src/shims/posix/linux/sync.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 38667850833..cc09b33ba68 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -24,17 +24,14 @@ pub fn futex<'tcx>( // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). // We checked above that these definitely exist. - // - // `addr` is used to identify the mutex, but note that not all futex - // operations actually read from this addres or even require this address - // to exist. Also, the type of `addr` is not consistent. The API requires - // it to be a 4-byte aligned pointer, and will use the 4 bytes at the given - // address as an (atomic) i32. It's not uncommon for `addr` to be passed as - // another type than `*mut i32`, such as `*const AtomicI32`. - let addr = this.force_ptr(this.read_scalar(args[1])?.check_init()?)?; + let addr = this.read_immediate(args[1])?; let op = this.read_scalar(args[2])?.to_i32()?; let val = this.read_scalar(args[3])?.to_i32()?; + // The raw pointer value is used to identify the mutex. + // Not all mutex operations actually read from this address or even require this address to exist. + let futex_ptr = this.force_ptr(addr.to_scalar()?)?; + let thread = this.get_active_thread(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; @@ -73,14 +70,16 @@ pub fn futex<'tcx>( }) }; // Check the pointer for alignment and validity. - // Atomic operations are only available for fully aligned values. - this.memory.check_ptr_access(addr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?; - // Read an `i32` through the pointer, regardless of any wrapper types (e.g. `AtomicI32`). - let futex_val = this.memory.get_raw(addr.alloc_id)?.read_scalar(this, addr, Size::from_bytes(4))?.to_i32()?; + // The API requires `addr` to be a 4-byte aligned pointer, and will + // use the 4 bytes at the given address as an (atomic) i32. + this.memory.check_ptr_access(addr.to_scalar()?, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + // Read an `i32` through the pointer, regardless of any wrapper types. + // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. + let futex_val = this.read_scalar_at_offset(addr.into(), 0, this.machine.layouts.i32)?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); - this.futex_wait(addr, thread); + this.futex_wait(futex_ptr, thread); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. @@ -91,7 +90,7 @@ pub fn futex<'tcx>( timeout_time, Box::new(move |this| { this.unblock_thread(thread); - this.futex_remove_waiter(addr, thread); + this.futex_remove_waiter(futex_ptr, thread); let etimedout = this.eval_libc("ETIMEDOUT")?; this.set_last_error(etimedout)?; this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; @@ -114,7 +113,7 @@ pub fn futex<'tcx>( op if op == futex_wake => { let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(addr) { + if let Some(thread) = this.futex_wake(futex_ptr) { this.unblock_thread(thread); this.unregister_timeout_callback_if_exists(thread); n += 1; -- 2.44.0