@@ -11,7 +11,7 @@ use crate::*;
11
11
#[ inline]
12
12
fn mutexattr_kind_offset < ' tcx > ( ecx : & MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , u64 > {
13
13
Ok ( match & * ecx. tcx . sess . target . os {
14
- "linux" | "illumos" | "solaris" | "macos" => 0 ,
14
+ "linux" | "illumos" | "solaris" | "macos" | "freebsd" => 0 ,
15
15
os => throw_unsup_format ! ( "`pthread_mutexattr` is not supported on {os}" ) ,
16
16
} )
17
17
}
@@ -43,12 +43,11 @@ fn mutexattr_set_kind<'tcx>(
43
43
)
44
44
}
45
45
46
- /// A flag that allows to distinguish `PTHREAD_MUTEX_NORMAL` from
47
- /// `PTHREAD_MUTEX_DEFAULT`. Since in `glibc` they have the same numeric values,
48
- /// but different behaviour, we need a way to distinguish them. We do this by
49
- /// setting this bit flag to the `PTHREAD_MUTEX_NORMAL` mutexes. See the comment
50
- /// in `pthread_mutexattr_settype` function.
51
- const PTHREAD_MUTEX_NORMAL_FLAG : i32 = 0x8000000 ;
46
+ /// To differentiate "the mutex kind has not been changed" from
47
+ /// "the mutex kind has been set to PTHREAD_MUTEX_DEFAULT and that is
48
+ /// equal to some other mutex kind", we make the default value of this
49
+ /// field *not* PTHREAD_MUTEX_DEFAULT but this special flag.
50
+ const PTHREAD_MUTEX_KIND_UNCHANGED : i32 = 0x8000000 ;
52
51
53
52
/// The mutex kind.
54
53
#[ derive( Debug , Clone , Copy ) ]
@@ -74,8 +73,10 @@ pub struct AdditionalMutexData {
74
73
// - id: u32
75
74
76
75
fn mutex_id_offset < ' tcx > ( ecx : & MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , u64 > {
76
+ // When adding a new OS, make sure we also support all its static initializers in
77
+ // `mutex_kind_from_static_initializer`!
77
78
let offset = match & * ecx. tcx . sess . target . os {
78
- "linux" | "illumos" | "solaris" => 0 ,
79
+ "linux" | "illumos" | "solaris" | "freebsd" => 0 ,
79
80
// macOS stores a signature in the first bytes, so we have to move to offset 4.
80
81
"macos" => 4 ,
81
82
os => throw_unsup_format ! ( "`pthread_mutex` is not supported on {os}" ) ,
@@ -104,7 +105,7 @@ fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
104
105
check_static_initializer ( "PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP" ) ;
105
106
check_static_initializer ( "PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP" ) ;
106
107
}
107
- "illumos" | "solaris" | "macos" => {
108
+ "illumos" | "solaris" | "macos" | "freebsd" => {
108
109
// No non-standard initializers.
109
110
}
110
111
os => throw_unsup_format ! ( "`pthread_mutex` is not supported on {os}" ) ,
@@ -118,11 +119,10 @@ fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
118
119
fn mutex_create < ' tcx > (
119
120
ecx : & mut MiriInterpCx < ' tcx > ,
120
121
mutex_ptr : & OpTy < ' tcx > ,
121
- kind : i32 ,
122
+ kind : MutexKind ,
122
123
) -> InterpResult < ' tcx > {
123
124
let mutex = ecx. deref_pointer ( mutex_ptr) ?;
124
125
let address = mutex. ptr ( ) . addr ( ) . bytes ( ) ;
125
- let kind = mutex_translate_kind ( ecx, kind) ?;
126
126
let data = Box :: new ( AdditionalMutexData { address, kind } ) ;
127
127
ecx. mutex_create ( & mutex, mutex_id_offset ( ecx) ?, Some ( data) ) ?;
128
128
Ok ( ( ) )
@@ -163,33 +163,41 @@ fn mutex_kind_from_static_initializer<'tcx>(
163
163
ecx : & MiriInterpCx < ' tcx > ,
164
164
mutex : & MPlaceTy < ' tcx > ,
165
165
) -> InterpResult < ' tcx , MutexKind > {
166
- let kind = match & * ecx. tcx . sess . target . os {
166
+ Ok ( match & * ecx. tcx . sess . target . os {
167
167
// Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
168
168
"linux" => {
169
169
let offset = if ecx. pointer_size ( ) . bytes ( ) == 8 { 16 } else { 12 } ;
170
170
let kind_place =
171
171
mutex. offset ( Size :: from_bytes ( offset) , ecx. machine . layouts . i32 , ecx) ?;
172
- ecx. read_scalar ( & kind_place) ?. to_i32 ( ) ?
172
+ let kind = ecx. read_scalar ( & kind_place) ?. to_i32 ( ) ?;
173
+ // Here we give PTHREAD_MUTEX_DEFAULT priority so that
174
+ // PTHREAD_MUTEX_INITIALIZER behaves like `pthread_mutex_init` with a NULL argument.
175
+ if kind == ecx. eval_libc_i32 ( "PTHREAD_MUTEX_DEFAULT" ) {
176
+ MutexKind :: Default
177
+ } else {
178
+ mutex_translate_kind ( ecx, kind) ?
179
+ }
173
180
}
174
- "illumos" | "solaris" | "macos" => ecx. eval_libc_i32 ( "PTHREAD_MUTEX_DEFAULT" ) ,
175
- os => throw_unsup_format ! ( "`pthread_mutex` is not supported on {os}" ) ,
176
- } ;
177
-
178
- mutex_translate_kind ( ecx, kind)
181
+ _ => MutexKind :: Default ,
182
+ } )
179
183
}
180
184
181
185
fn mutex_translate_kind < ' tcx > (
182
186
ecx : & MiriInterpCx < ' tcx > ,
183
187
kind : i32 ,
184
188
) -> InterpResult < ' tcx , MutexKind > {
185
- Ok ( if kind == ecx. eval_libc_i32 ( "PTHREAD_MUTEX_DEFAULT" ) {
186
- MutexKind :: Default
187
- } else if kind == ( ecx. eval_libc_i32 ( "PTHREAD_MUTEX_NORMAL" ) | PTHREAD_MUTEX_NORMAL_FLAG ) {
189
+ Ok ( if kind == ( ecx. eval_libc_i32 ( "PTHREAD_MUTEX_NORMAL" ) ) {
188
190
MutexKind :: Normal
189
191
} else if kind == ecx. eval_libc_i32 ( "PTHREAD_MUTEX_ERRORCHECK" ) {
190
192
MutexKind :: ErrorCheck
191
193
} else if kind == ecx. eval_libc_i32 ( "PTHREAD_MUTEX_RECURSIVE" ) {
192
194
MutexKind :: Recursive
195
+ } else if kind == ecx. eval_libc_i32 ( "PTHREAD_MUTEX_DEFAULT" )
196
+ || kind == PTHREAD_MUTEX_KIND_UNCHANGED
197
+ {
198
+ // We check this *last* since PTHREAD_MUTEX_DEFAULT may be numerically equal to one of the
199
+ // others, and we want an explicit `mutexattr_settype` to work as expected.
200
+ MutexKind :: Default
193
201
} else {
194
202
throw_unsup_format ! ( "unsupported type of mutex: {kind}" ) ;
195
203
} )
@@ -208,7 +216,7 @@ pub struct AdditionalRwLockData {
208
216
209
217
fn rwlock_id_offset < ' tcx > ( ecx : & MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , u64 > {
210
218
let offset = match & * ecx. tcx . sess . target . os {
211
- "linux" | "illumos" | "solaris" => 0 ,
219
+ "linux" | "illumos" | "solaris" | "freebsd" => 0 ,
212
220
// macOS stores a signature in the first bytes, so we have to move to offset 4.
213
221
"macos" => 4 ,
214
222
os => throw_unsup_format ! ( "`pthread_rwlock` is not supported on {os}" ) ,
@@ -261,7 +269,7 @@ fn rwlock_get_id<'tcx>(
261
269
#[ inline]
262
270
fn condattr_clock_offset < ' tcx > ( ecx : & MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , u64 > {
263
271
Ok ( match & * ecx. tcx . sess . target . os {
264
- "linux" | "illumos" | "solaris" => 0 ,
272
+ "linux" | "illumos" | "solaris" | "freebsd" => 0 ,
265
273
// macOS does not have a clock attribute.
266
274
os => throw_unsup_format ! ( "`pthread_condattr` clock field is not supported on {os}" ) ,
267
275
} )
@@ -313,7 +321,7 @@ fn condattr_set_clock_id<'tcx>(
313
321
314
322
fn cond_id_offset < ' tcx > ( ecx : & MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , u64 > {
315
323
let offset = match & * ecx. tcx . sess . target . os {
316
- "linux" | "illumos" | "solaris" => 0 ,
324
+ "linux" | "illumos" | "solaris" | "freebsd" => 0 ,
317
325
// macOS stores a signature in the first bytes, so we have to move to offset 4.
318
326
"macos" => 4 ,
319
327
os => throw_unsup_format ! ( "`pthread_cond` is not supported on {os}" ) ,
@@ -380,8 +388,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
380
388
fn pthread_mutexattr_init ( & mut self , attr_op : & OpTy < ' tcx > ) -> InterpResult < ' tcx , ( ) > {
381
389
let this = self . eval_context_mut ( ) ;
382
390
383
- let default_kind = this. eval_libc_i32 ( "PTHREAD_MUTEX_DEFAULT" ) ;
384
- mutexattr_set_kind ( this, attr_op, default_kind) ?;
391
+ mutexattr_set_kind ( this, attr_op, PTHREAD_MUTEX_KIND_UNCHANGED ) ?;
385
392
386
393
Ok ( ( ) )
387
394
}
@@ -394,30 +401,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
394
401
let this = self . eval_context_mut ( ) ;
395
402
396
403
let kind = this. read_scalar ( kind_op) ?. to_i32 ( ) ?;
397
- if kind == this. eval_libc_i32 ( "PTHREAD_MUTEX_NORMAL" ) {
398
- // In `glibc` implementation, the numeric values of
399
- // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal.
400
- // However, a mutex created by explicitly passing
401
- // `PTHREAD_MUTEX_NORMAL` type has in some cases different behaviour
402
- // from the default mutex for which the type was not explicitly
403
- // specified. For a more detailed discussion, please see
404
- // https://github.com/rust-lang/miri/issues/1419.
405
- //
406
- // To distinguish these two cases in already constructed mutexes, we
407
- // use the same trick as glibc: for the case when
408
- // `pthread_mutexattr_settype` is called explicitly, we set the
409
- // `PTHREAD_MUTEX_NORMAL_FLAG` flag.
410
- let normal_kind = kind | PTHREAD_MUTEX_NORMAL_FLAG ;
411
- // Check that after setting the flag, the kind is distinguishable
412
- // from all other kinds.
413
- assert_ne ! ( normal_kind, this. eval_libc_i32( "PTHREAD_MUTEX_DEFAULT" ) ) ;
414
- assert_ne ! ( normal_kind, this. eval_libc_i32( "PTHREAD_MUTEX_ERRORCHECK" ) ) ;
415
- assert_ne ! ( normal_kind, this. eval_libc_i32( "PTHREAD_MUTEX_RECURSIVE" ) ) ;
416
- mutexattr_set_kind ( this, attr_op, normal_kind) ?;
417
- } else if kind == this. eval_libc_i32 ( "PTHREAD_MUTEX_DEFAULT" )
404
+ if kind == this. eval_libc_i32 ( "PTHREAD_MUTEX_NORMAL" )
405
+ || kind == this. eval_libc_i32 ( "PTHREAD_MUTEX_DEFAULT" )
418
406
|| kind == this. eval_libc_i32 ( "PTHREAD_MUTEX_ERRORCHECK" )
419
407
|| kind == this. eval_libc_i32 ( "PTHREAD_MUTEX_RECURSIVE" )
420
408
{
409
+ // Make sure we do not mix this up with the "unchanged" kind.
410
+ assert_ne ! ( kind, PTHREAD_MUTEX_KIND_UNCHANGED ) ;
421
411
mutexattr_set_kind ( this, attr_op, kind) ?;
422
412
} else {
423
413
let einval = this. eval_libc_i32 ( "EINVAL" ) ;
@@ -461,9 +451,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
461
451
462
452
let attr = this. read_pointer ( attr_op) ?;
463
453
let kind = if this. ptr_is_null ( attr) ? {
464
- this . eval_libc_i32 ( "PTHREAD_MUTEX_DEFAULT" )
454
+ MutexKind :: Default
465
455
} else {
466
- mutexattr_get_kind ( this, attr_op) ?
456
+ mutex_translate_kind ( this , mutexattr_get_kind ( this, attr_op) ? ) ?
467
457
} ;
468
458
469
459
mutex_create ( this, mutex_op, kind) ?;
0 commit comments