@@ -11,7 +11,7 @@ use crate::*;
1111#[ inline]
1212fn mutexattr_kind_offset < ' tcx > ( ecx : & MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , u64 > {
1313 Ok ( match & * ecx. tcx . sess . target . os {
14- "linux" | "illumos" | "solaris" | "macos" => 0 ,
14+ "linux" | "illumos" | "solaris" | "macos" | "freebsd" => 0 ,
1515 os => throw_unsup_format ! ( "`pthread_mutexattr` is not supported on {os}" ) ,
1616 } )
1717}
@@ -43,12 +43,11 @@ fn mutexattr_set_kind<'tcx>(
4343 )
4444}
4545
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 ;
5251
5352/// The mutex kind.
5453#[ derive( Debug , Clone , Copy ) ]
@@ -74,8 +73,10 @@ pub struct AdditionalMutexData {
7473// - id: u32
7574
7675fn 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`!
7778 let offset = match & * ecx. tcx . sess . target . os {
78- "linux" | "illumos" | "solaris" => 0 ,
79+ "linux" | "illumos" | "solaris" | "freebsd" => 0 ,
7980 // macOS stores a signature in the first bytes, so we have to move to offset 4.
8081 "macos" => 4 ,
8182 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> {
104105 check_static_initializer ( "PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP" ) ;
105106 check_static_initializer ( "PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP" ) ;
106107 }
107- "illumos" | "solaris" | "macos" => {
108+ "illumos" | "solaris" | "macos" | "freebsd" => {
108109 // No non-standard initializers.
109110 }
110111 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> {
118119fn mutex_create < ' tcx > (
119120 ecx : & mut MiriInterpCx < ' tcx > ,
120121 mutex_ptr : & OpTy < ' tcx > ,
121- kind : i32 ,
122+ kind : MutexKind ,
122123) -> InterpResult < ' tcx > {
123124 let mutex = ecx. deref_pointer ( mutex_ptr) ?;
124125 let address = mutex. ptr ( ) . addr ( ) . bytes ( ) ;
125- let kind = mutex_translate_kind ( ecx, kind) ?;
126126 let data = Box :: new ( AdditionalMutexData { address, kind } ) ;
127127 ecx. mutex_create ( & mutex, mutex_id_offset ( ecx) ?, Some ( data) ) ?;
128128 Ok ( ( ) )
@@ -163,33 +163,41 @@ fn mutex_kind_from_static_initializer<'tcx>(
163163 ecx : & MiriInterpCx < ' tcx > ,
164164 mutex : & MPlaceTy < ' tcx > ,
165165) -> InterpResult < ' tcx , MutexKind > {
166- let kind = match & * ecx. tcx . sess . target . os {
166+ Ok ( match & * ecx. tcx . sess . target . os {
167167 // Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
168168 "linux" => {
169169 let offset = if ecx. pointer_size ( ) . bytes ( ) == 8 { 16 } else { 12 } ;
170170 let kind_place =
171171 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+ }
173180 }
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+ } )
179183}
180184
181185fn mutex_translate_kind < ' tcx > (
182186 ecx : & MiriInterpCx < ' tcx > ,
183187 kind : i32 ,
184188) -> 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" ) ) {
188190 MutexKind :: Normal
189191 } else if kind == ecx. eval_libc_i32 ( "PTHREAD_MUTEX_ERRORCHECK" ) {
190192 MutexKind :: ErrorCheck
191193 } else if kind == ecx. eval_libc_i32 ( "PTHREAD_MUTEX_RECURSIVE" ) {
192194 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
193201 } else {
194202 throw_unsup_format ! ( "unsupported type of mutex: {kind}" ) ;
195203 } )
@@ -208,7 +216,7 @@ pub struct AdditionalRwLockData {
208216
209217fn rwlock_id_offset < ' tcx > ( ecx : & MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , u64 > {
210218 let offset = match & * ecx. tcx . sess . target . os {
211- "linux" | "illumos" | "solaris" => 0 ,
219+ "linux" | "illumos" | "solaris" | "freebsd" => 0 ,
212220 // macOS stores a signature in the first bytes, so we have to move to offset 4.
213221 "macos" => 4 ,
214222 os => throw_unsup_format ! ( "`pthread_rwlock` is not supported on {os}" ) ,
@@ -261,7 +269,7 @@ fn rwlock_get_id<'tcx>(
261269#[ inline]
262270fn condattr_clock_offset < ' tcx > ( ecx : & MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , u64 > {
263271 Ok ( match & * ecx. tcx . sess . target . os {
264- "linux" | "illumos" | "solaris" => 0 ,
272+ "linux" | "illumos" | "solaris" | "freebsd" => 0 ,
265273 // macOS does not have a clock attribute.
266274 os => throw_unsup_format ! ( "`pthread_condattr` clock field is not supported on {os}" ) ,
267275 } )
@@ -313,7 +321,7 @@ fn condattr_set_clock_id<'tcx>(
313321
314322fn cond_id_offset < ' tcx > ( ecx : & MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , u64 > {
315323 let offset = match & * ecx. tcx . sess . target . os {
316- "linux" | "illumos" | "solaris" => 0 ,
324+ "linux" | "illumos" | "solaris" | "freebsd" => 0 ,
317325 // macOS stores a signature in the first bytes, so we have to move to offset 4.
318326 "macos" => 4 ,
319327 os => throw_unsup_format ! ( "`pthread_cond` is not supported on {os}" ) ,
@@ -380,8 +388,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
380388 fn pthread_mutexattr_init ( & mut self , attr_op : & OpTy < ' tcx > ) -> InterpResult < ' tcx , ( ) > {
381389 let this = self . eval_context_mut ( ) ;
382390
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 ) ?;
385392
386393 Ok ( ( ) )
387394 }
@@ -394,30 +401,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
394401 let this = self . eval_context_mut ( ) ;
395402
396403 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" )
418406 || kind == this. eval_libc_i32 ( "PTHREAD_MUTEX_ERRORCHECK" )
419407 || kind == this. eval_libc_i32 ( "PTHREAD_MUTEX_RECURSIVE" )
420408 {
409+ // Make sure we do not mix this up with the "unchanged" kind.
410+ assert_ne ! ( kind, PTHREAD_MUTEX_KIND_UNCHANGED ) ;
421411 mutexattr_set_kind ( this, attr_op, kind) ?;
422412 } else {
423413 let einval = this. eval_libc_i32 ( "EINVAL" ) ;
@@ -461,9 +451,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
461451
462452 let attr = this. read_pointer ( attr_op) ?;
463453 let kind = if this. ptr_is_null ( attr) ? {
464- this . eval_libc_i32 ( "PTHREAD_MUTEX_DEFAULT" )
454+ MutexKind :: Default
465455 } else {
466- mutexattr_get_kind ( this, attr_op) ?
456+ mutex_translate_kind ( this , mutexattr_get_kind ( this, attr_op) ? ) ?
467457 } ;
468458
469459 mutex_create ( this, mutex_op, kind) ?;
0 commit comments