@@ -50,15 +50,6 @@ fn mutexattr_set_kind<'tcx>(
5050/// in `pthread_mutexattr_settype` function.
5151const PTHREAD_MUTEX_NORMAL_FLAG : i32 = 0x8000000 ;
5252
53- fn is_mutex_kind_default < ' tcx > ( ecx : & MiriInterpCx < ' tcx > , kind : i32 ) -> InterpResult < ' tcx , bool > {
54- Ok ( kind == ecx. eval_libc_i32 ( "PTHREAD_MUTEX_DEFAULT" ) )
55- }
56-
57- fn is_mutex_kind_normal < ' tcx > ( ecx : & MiriInterpCx < ' tcx > , kind : i32 ) -> InterpResult < ' tcx , bool > {
58- let mutex_normal_kind = ecx. eval_libc_i32 ( "PTHREAD_MUTEX_NORMAL" ) ;
59- Ok ( kind == ( mutex_normal_kind | PTHREAD_MUTEX_NORMAL_FLAG ) )
60- }
61-
6253/// The mutex kind.
6354#[ derive( Debug , Clone , Copy ) ]
6455pub enum MutexKind {
@@ -78,7 +69,7 @@ pub struct AdditionalMutexData {
7869 pub address : u64 ,
7970}
8071
81- // pthread_mutex_t is between 24 and 48 bytes, depending on the platform.
72+ // pthread_mutex_t is between 4 and 48 bytes, depending on the platform.
8273// We ignore the platform layout and store our own fields:
8374// - id: u32
8475
@@ -131,7 +122,7 @@ fn mutex_create<'tcx>(
131122) -> InterpResult < ' tcx > {
132123 let mutex = ecx. deref_pointer ( mutex_ptr) ?;
133124 let address = mutex. ptr ( ) . addr ( ) . bytes ( ) ;
134- let kind = translate_kind ( ecx, kind) ?;
125+ let kind = mutex_translate_kind ( ecx, kind) ?;
135126 let data = Box :: new ( AdditionalMutexData { address, kind } ) ;
136127 ecx. mutex_create ( & mutex, mutex_id_offset ( ecx) ?, Some ( data) ) ?;
137128 Ok ( ( ) )
@@ -151,7 +142,7 @@ fn mutex_get_id<'tcx>(
151142 let id = ecx. mutex_get_or_create_id ( & mutex, mutex_id_offset ( ecx) ?, |ecx| {
152143 // This is called if a static initializer was used and the lock has not been assigned
153144 // an ID yet. We have to determine the mutex kind from the static initializer.
154- let kind = kind_from_static_initializer ( ecx, & mutex) ?;
145+ let kind = mutex_kind_from_static_initializer ( ecx, & mutex) ?;
155146
156147 Ok ( Some ( Box :: new ( AdditionalMutexData { kind, address } ) ) )
157148 } ) ?;
@@ -168,12 +159,12 @@ fn mutex_get_id<'tcx>(
168159}
169160
170161/// Returns the kind of a static initializer.
171- fn kind_from_static_initializer < ' tcx > (
162+ fn mutex_kind_from_static_initializer < ' tcx > (
172163 ecx : & MiriInterpCx < ' tcx > ,
173164 mutex : & MPlaceTy < ' tcx > ,
174165) -> InterpResult < ' tcx , MutexKind > {
175- // Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
176166 let kind = match & * ecx. tcx . sess . target . os {
167+ // Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
177168 "linux" => {
178169 let offset = if ecx. pointer_size ( ) . bytes ( ) == 8 { 16 } else { 12 } ;
179170 let kind_place =
@@ -184,13 +175,16 @@ fn kind_from_static_initializer<'tcx>(
184175 os => throw_unsup_format ! ( "`pthread_mutex` is not supported on {os}" ) ,
185176 } ;
186177
187- translate_kind ( ecx, kind)
178+ mutex_translate_kind ( ecx, kind)
188179}
189180
190- fn translate_kind < ' tcx > ( ecx : & MiriInterpCx < ' tcx > , kind : i32 ) -> InterpResult < ' tcx , MutexKind > {
191- Ok ( if is_mutex_kind_default ( ecx, kind) ? {
181+ fn mutex_translate_kind < ' tcx > (
182+ ecx : & MiriInterpCx < ' tcx > ,
183+ kind : i32 ,
184+ ) -> InterpResult < ' tcx , MutexKind > {
185+ Ok ( if kind == ecx. eval_libc_i32 ( "PTHREAD_MUTEX_DEFAULT" ) {
192186 MutexKind :: Default
193- } else if is_mutex_kind_normal ( ecx, kind ) ? {
187+ } else if kind == ( ecx. eval_libc_i32 ( "PTHREAD_MUTEX_NORMAL" ) | PTHREAD_MUTEX_NORMAL_FLAG ) {
194188 MutexKind :: Normal
195189 } else if kind == ecx. eval_libc_i32 ( "PTHREAD_MUTEX_ERRORCHECK" ) {
196190 MutexKind :: ErrorCheck
@@ -201,7 +195,7 @@ fn translate_kind<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tc
201195 } )
202196}
203197
204- // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform.
198+ // pthread_rwlock_t is between 4 and 56 bytes, depending on the platform.
205199// We ignore the platform layout and store our own fields:
206200// - id: u32
207201
@@ -286,11 +280,11 @@ fn condattr_get_clock_id<'tcx>(
286280 . to_i32 ( )
287281}
288282
289- fn translate_clock_id < ' tcx > ( ecx : & MiriInterpCx < ' tcx > , raw_id : i32 ) -> InterpResult < ' tcx , ClockId > {
290- // To ensure compatibility with PTHREAD_COND_INITIALIZER on all platforms ,
291- // we can't just compare with CLOCK_REALTIME: on Solarish, PTHREAD_COND_INITIALIZER
292- // makes the clock 0 but CLOCK_REALTIME is 3.
293- Ok ( if raw_id == ecx. eval_libc_i32 ( "CLOCK_REALTIME" ) || raw_id == 0 {
283+ fn cond_translate_clock_id < ' tcx > (
284+ ecx : & MiriInterpCx < ' tcx > ,
285+ raw_id : i32 ,
286+ ) -> InterpResult < ' tcx , ClockId > {
287+ Ok ( if raw_id == ecx. eval_libc_i32 ( "CLOCK_REALTIME" ) {
294288 ClockId :: Realtime
295289 } else if raw_id == ecx. eval_libc_i32 ( "CLOCK_MONOTONIC" ) {
296290 ClockId :: Monotonic
@@ -313,10 +307,9 @@ fn condattr_set_clock_id<'tcx>(
313307 )
314308}
315309
316- // pthread_cond_t.
310+ // pthread_cond_t can be only 4 bytes in size, depending on the platform .
317311// We ignore the platform layout and store our own fields:
318312// - id: u32
319- // - clock: i32
320313
321314fn cond_id_offset < ' tcx > ( ecx : & MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , u64 > {
322315 let offset = match & * ecx. tcx . sess . target . os {
@@ -344,30 +337,6 @@ fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
344337 Ok ( offset)
345338}
346339
347- fn cond_clock_offset < ' tcx > ( ecx : & MiriInterpCx < ' tcx > ) -> u64 {
348- // macOS doesn't have a clock attribute, but to keep the code uniform we store
349- // a clock ID in the pthread_cond_t anyway. There's enough space.
350- let offset = 8 ;
351-
352- // Sanity-check this against PTHREAD_COND_INITIALIZER (but only once):
353- // the clock must start out as CLOCK_REALTIME.
354- static SANITY : AtomicBool = AtomicBool :: new ( false ) ;
355- if !SANITY . swap ( true , Ordering :: Relaxed ) {
356- let static_initializer = ecx. eval_path ( & [ "libc" , "PTHREAD_COND_INITIALIZER" ] ) ;
357- let id_field = static_initializer
358- . offset ( Size :: from_bytes ( offset) , ecx. machine . layouts . i32 , ecx)
359- . unwrap ( ) ;
360- let id = ecx. read_scalar ( & id_field) . unwrap ( ) . to_i32 ( ) . unwrap ( ) ;
361- let id = translate_clock_id ( ecx, id) . expect ( "static initializer should be valid" ) ;
362- assert ! (
363- matches!( id, ClockId :: Realtime ) ,
364- "PTHREAD_COND_INITIALIZER is incompatible with our pthread_cond layout: clock is not CLOCK_REALTIME"
365- ) ;
366- }
367-
368- offset
369- }
370-
371340#[ derive( Debug , Clone , Copy ) ]
372341enum ClockId {
373342 Realtime ,
@@ -390,14 +359,9 @@ fn cond_get_id<'tcx>(
390359) -> InterpResult < ' tcx , CondvarId > {
391360 let cond = ecx. deref_pointer ( cond_ptr) ?;
392361 let address = cond. ptr ( ) . addr ( ) . bytes ( ) ;
393- let id = ecx. condvar_get_or_create_id ( & cond, cond_id_offset ( ecx) ?, |ecx| {
394- let raw_id = if ecx. tcx . sess . target . os == "macos" {
395- ecx. eval_libc_i32 ( "CLOCK_REALTIME" )
396- } else {
397- cond_get_clock_id ( ecx, cond_ptr) ?
398- } ;
399- let clock_id = translate_clock_id ( ecx, raw_id) ?;
400- Ok ( Some ( Box :: new ( AdditionalCondData { address, clock_id } ) ) )
362+ let id = ecx. condvar_get_or_create_id ( & cond, cond_id_offset ( ecx) ?, |_ecx| {
363+ // This used the static initializer. The clock there is always CLOCK_REALTIME.
364+ Ok ( Some ( Box :: new ( AdditionalCondData { address, clock_id : ClockId :: Realtime } ) ) )
401365 } ) ?;
402366
403367 // Check that the mutex has not been moved since last use.
@@ -411,19 +375,6 @@ fn cond_get_id<'tcx>(
411375 Ok ( id)
412376}
413377
414- fn cond_get_clock_id < ' tcx > (
415- ecx : & MiriInterpCx < ' tcx > ,
416- cond_ptr : & OpTy < ' tcx > ,
417- ) -> InterpResult < ' tcx , i32 > {
418- ecx. deref_pointer_and_read (
419- cond_ptr,
420- cond_clock_offset ( ecx) ,
421- ecx. libc_ty_layout ( "pthread_cond_t" ) ,
422- ecx. machine . layouts . i32 ,
423- ) ?
424- . to_i32 ( )
425- }
426-
427378impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
428379pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
429380 fn pthread_mutexattr_init ( & mut self , attr_op : & OpTy < ' tcx > ) -> InterpResult < ' tcx , ( ) > {
@@ -624,15 +575,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
624575 fn pthread_mutex_destroy ( & mut self , mutex_op : & OpTy < ' tcx > ) -> InterpResult < ' tcx , ( ) > {
625576 let this = self . eval_context_mut ( ) ;
626577
578+ // Reading the field also has the side-effect that we detect double-`destroy`
579+ // since we make the field unint below.
627580 let id = mutex_get_id ( this, mutex_op) ?;
628581
629582 if this. mutex_is_locked ( id) {
630583 throw_ub_format ! ( "destroyed a locked mutex" ) ;
631584 }
632585
633- // Destroying an uninit pthread_mutex is UB, so check to make sure it's not uninit.
634- mutex_get_id ( this, mutex_op) ?;
635-
636586 // This might lead to false positives, see comment in pthread_mutexattr_destroy
637587 this. write_uninit (
638588 & this. deref_pointer_as ( mutex_op, this. libc_ty_layout ( "pthread_mutex_t" ) ) ?,
@@ -734,15 +684,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
734684 fn pthread_rwlock_destroy ( & mut self , rwlock_op : & OpTy < ' tcx > ) -> InterpResult < ' tcx , ( ) > {
735685 let this = self . eval_context_mut ( ) ;
736686
687+ // Reading the field also has the side-effect that we detect double-`destroy`
688+ // since we make the field unint below.
737689 let id = rwlock_get_id ( this, rwlock_op) ?;
738690
739691 if this. rwlock_is_locked ( id) {
740692 throw_ub_format ! ( "destroyed a locked rwlock" ) ;
741693 }
742694
743- // Destroying an uninit pthread_rwlock is UB, so check to make sure it's not uninit.
744- rwlock_get_id ( this, rwlock_op) ?;
745-
746695 // This might lead to false positives, see comment in pthread_mutexattr_destroy
747696 this. write_uninit (
748697 & this. deref_pointer_as ( rwlock_op, this. libc_ty_layout ( "pthread_rwlock_t" ) ) ?,
@@ -832,7 +781,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
832781 } else {
833782 condattr_get_clock_id ( this, attr_op) ?
834783 } ;
835- let clock_id = translate_clock_id ( this, clock_id) ?;
784+ let clock_id = cond_translate_clock_id ( this, clock_id) ?;
836785
837786 let cond = this. deref_pointer ( cond_op) ?;
838787 let address = cond. ptr ( ) . addr ( ) . bytes ( ) ;
@@ -930,11 +879,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
930879 }
931880
932881 fn pthread_cond_destroy ( & mut self , cond_op : & OpTy < ' tcx > ) -> InterpResult < ' tcx , ( ) > {
933- //NOTE: Destroying an uninit pthread_cond is UB. Make sure it's not uninit,
934- // by accessing at least once all of its fields that we use.
935-
936882 let this = self . eval_context_mut ( ) ;
937883
884+ // Reading the field also has the side-effect that we detect double-`destroy`
885+ // since we make the field unint below.
938886 let id = cond_get_id ( this, cond_op) ?;
939887 if this. condvar_is_awaited ( id) {
940888 throw_ub_format ! ( "destroying an awaited conditional variable" ) ;
0 commit comments