@@ -24,17 +24,14 @@ pub fn futex<'tcx>(
24
24
// The first three arguments (after the syscall number itself) are the same to all futex operations:
25
25
// (int *addr, int op, int val).
26
26
// 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 ] ) ?;
35
28
let op = this. read_scalar ( args[ 2 ] ) ?. to_i32 ( ) ?;
36
29
let val = this. read_scalar ( args[ 3 ] ) ?. to_i32 ( ) ?;
37
30
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
+
38
35
let thread = this. get_active_thread ( ) ;
39
36
40
37
let futex_private = this. eval_libc_i32 ( "FUTEX_PRIVATE_FLAG" ) ?;
@@ -73,14 +70,16 @@ pub fn futex<'tcx>(
73
70
} )
74
71
} ;
75
72
// 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 ( ) ?;
80
79
if val == futex_val {
81
80
// The value still matches, so we block the trait make it wait for FUTEX_WAKE.
82
81
this. block_thread ( thread) ;
83
- this. futex_wait ( addr , thread) ;
82
+ this. futex_wait ( futex_ptr , thread) ;
84
83
// Succesfully waking up from FUTEX_WAIT always returns zero.
85
84
this. write_scalar ( Scalar :: from_machine_isize ( 0 , this) , dest) ?;
86
85
// Register a timeout callback if a timeout was specified.
@@ -91,7 +90,7 @@ pub fn futex<'tcx>(
91
90
timeout_time,
92
91
Box :: new ( move |this| {
93
92
this. unblock_thread ( thread) ;
94
- this. futex_remove_waiter ( addr , thread) ;
93
+ this. futex_remove_waiter ( futex_ptr , thread) ;
95
94
let etimedout = this. eval_libc ( "ETIMEDOUT" ) ?;
96
95
this. set_last_error ( etimedout) ?;
97
96
this. write_scalar ( Scalar :: from_machine_isize ( -1 , this) , dest) ?;
@@ -114,7 +113,7 @@ pub fn futex<'tcx>(
114
113
op if op == futex_wake => {
115
114
let mut n = 0 ;
116
115
for _ in 0 ..val {
117
- if let Some ( thread) = this. futex_wake ( addr ) {
116
+ if let Some ( thread) = this. futex_wake ( futex_ptr ) {
118
117
this. unblock_thread ( thread) ;
119
118
this. unregister_timeout_callback_if_exists ( thread) ;
120
119
n += 1 ;
0 commit comments