1
1
use rustc_middle:: mir;
2
+ use rustc_target:: abi:: { Align , Size } ;
2
3
3
4
use crate :: * ;
4
5
use crate :: helpers:: check_arg_count;
@@ -120,6 +121,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
120
121
. eval_libc ( "SYS_statx" ) ?
121
122
. to_machine_usize ( this) ?;
122
123
124
+ let sys_futex = this
125
+ . eval_libc ( "SYS_futex" ) ?
126
+ . to_machine_usize ( this) ?;
127
+
123
128
if args. is_empty ( ) {
124
129
throw_ub_format ! ( "incorrect number of arguments for syscall: got 0, expected at least 1" ) ;
125
130
}
@@ -139,6 +144,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
139
144
let result = this. linux_statx ( dirfd, pathname, flags, mask, statxbuf) ?;
140
145
this. write_scalar ( Scalar :: from_machine_isize ( result. into ( ) , this) , dest) ?;
141
146
}
147
+ // `futex` is used by some synchonization primitives.
148
+ id if id == sys_futex => {
149
+ futex ( this, args, dest) ?;
150
+ }
142
151
id => throw_unsup_format ! ( "miri does not support syscall ID {}" , id) ,
143
152
}
144
153
}
@@ -192,3 +201,61 @@ fn getrandom<'tcx>(
192
201
this. write_scalar ( Scalar :: from_machine_usize ( len, this) , dest) ?;
193
202
Ok ( ( ) )
194
203
}
204
+
205
+ fn futex < ' tcx > (
206
+ this : & mut MiriEvalContext < ' _ , ' tcx > ,
207
+ args : & [ OpTy < ' tcx , Tag > ] ,
208
+ dest : PlaceTy < ' tcx , Tag > ,
209
+ ) -> InterpResult < ' tcx > {
210
+ if args. len ( ) < 4 {
211
+ throw_ub_format ! ( "incorrect number of arguments for futex syscall: got {}, expected at least 4" , args. len( ) ) ;
212
+ }
213
+ let addr = this. read_scalar ( args[ 1 ] ) ?. check_init ( ) ?;
214
+ let op = this. read_scalar ( args[ 2 ] ) ?. to_i32 ( ) ?;
215
+ let val = this. read_scalar ( args[ 3 ] ) ?. to_i32 ( ) ?;
216
+
217
+ this. memory . check_ptr_access ( addr, Size :: from_bytes ( 4 ) , Align :: from_bytes ( 4 ) . unwrap ( ) ) ?;
218
+
219
+ let addr = addr. assert_ptr ( ) ;
220
+
221
+ let thread = this. get_active_thread ( ) ;
222
+
223
+ let futex_private = this. eval_libc_i32 ( "FUTEX_PRIVATE_FLAG" ) ?;
224
+ let futex_wait = this. eval_libc_i32 ( "FUTEX_WAIT" ) ?;
225
+ let futex_wake = this. eval_libc_i32 ( "FUTEX_WAKE" ) ?;
226
+
227
+ match op & !futex_private {
228
+ op if op == futex_wait => {
229
+ if args. len ( ) < 5 {
230
+ throw_ub_format ! ( "incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5" , args. len( ) ) ;
231
+ }
232
+ let timeout = this. read_scalar ( args[ 4 ] ) ?. check_init ( ) ?;
233
+ if !this. is_null ( timeout) ? {
234
+ throw_ub_format ! ( "miri does not support timeouts for futex operations" ) ;
235
+ }
236
+ let futex_val = this. read_scalar_at_offset ( args[ 1 ] , 0 , this. machine . layouts . i32 ) ?. to_i32 ( ) ?;
237
+ if val == futex_val {
238
+ this. block_thread ( thread) ;
239
+ this. futex_wait ( addr, thread) ;
240
+ } else {
241
+ let eagain = this. eval_libc ( "EAGAIN" ) ?;
242
+ this. set_last_error ( eagain) ?;
243
+ }
244
+ }
245
+ op if op == futex_wake => {
246
+ let mut n = 0 ;
247
+ for _ in 0 ..val {
248
+ if let Some ( thread) = this. futex_wake ( addr) {
249
+ this. unblock_thread ( thread) ;
250
+ n += 1 ;
251
+ } else {
252
+ break ;
253
+ }
254
+ }
255
+ this. write_scalar ( Scalar :: from_i32 ( n) , dest) ?;
256
+ }
257
+ op => throw_unsup_format ! ( "miri does not support SYS_futex operation {}" , op) ,
258
+ }
259
+
260
+ Ok ( ( ) )
261
+ }
0 commit comments