@@ -50,15 +50,6 @@ fn mutexattr_set_kind<'tcx>(
50
50
/// in `pthread_mutexattr_settype` function.
51
51
const PTHREAD_MUTEX_NORMAL_FLAG : i32 = 0x8000000 ;
52
52
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
-
62
53
/// The mutex kind.
63
54
#[ derive( Debug , Clone , Copy ) ]
64
55
pub enum MutexKind {
@@ -78,7 +69,7 @@ pub struct AdditionalMutexData {
78
69
pub address : u64 ,
79
70
}
80
71
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.
82
73
// We ignore the platform layout and store our own fields:
83
74
// - id: u32
84
75
@@ -131,7 +122,7 @@ fn mutex_create<'tcx>(
131
122
) -> InterpResult < ' tcx > {
132
123
let mutex = ecx. deref_pointer ( mutex_ptr) ?;
133
124
let address = mutex. ptr ( ) . addr ( ) . bytes ( ) ;
134
- let kind = translate_kind ( ecx, kind) ?;
125
+ let kind = mutex_translate_kind ( ecx, kind) ?;
135
126
let data = Box :: new ( AdditionalMutexData { address, kind } ) ;
136
127
ecx. mutex_create ( & mutex, mutex_id_offset ( ecx) ?, Some ( data) ) ?;
137
128
Ok ( ( ) )
@@ -151,7 +142,7 @@ fn mutex_get_id<'tcx>(
151
142
let id = ecx. mutex_get_or_create_id ( & mutex, mutex_id_offset ( ecx) ?, |ecx| {
152
143
// This is called if a static initializer was used and the lock has not been assigned
153
144
// 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) ?;
155
146
156
147
Ok ( Some ( Box :: new ( AdditionalMutexData { kind, address } ) ) )
157
148
} ) ?;
@@ -168,12 +159,12 @@ fn mutex_get_id<'tcx>(
168
159
}
169
160
170
161
/// Returns the kind of a static initializer.
171
- fn kind_from_static_initializer < ' tcx > (
162
+ fn mutex_kind_from_static_initializer < ' tcx > (
172
163
ecx : & MiriInterpCx < ' tcx > ,
173
164
mutex : & MPlaceTy < ' tcx > ,
174
165
) -> InterpResult < ' tcx , MutexKind > {
175
- // Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
176
166
let kind = match & * ecx. tcx . sess . target . os {
167
+ // Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
177
168
"linux" => {
178
169
let offset = if ecx. pointer_size ( ) . bytes ( ) == 8 { 16 } else { 12 } ;
179
170
let kind_place =
@@ -184,13 +175,16 @@ fn kind_from_static_initializer<'tcx>(
184
175
os => throw_unsup_format ! ( "`pthread_mutex` is not supported on {os}" ) ,
185
176
} ;
186
177
187
- translate_kind ( ecx, kind)
178
+ mutex_translate_kind ( ecx, kind)
188
179
}
189
180
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" ) {
192
186
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 ) {
194
188
MutexKind :: Normal
195
189
} else if kind == ecx. eval_libc_i32 ( "PTHREAD_MUTEX_ERRORCHECK" ) {
196
190
MutexKind :: ErrorCheck
@@ -201,7 +195,7 @@ fn translate_kind<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tc
201
195
} )
202
196
}
203
197
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.
205
199
// We ignore the platform layout and store our own fields:
206
200
// - id: u32
207
201
@@ -286,11 +280,11 @@ fn condattr_get_clock_id<'tcx>(
286
280
. to_i32 ( )
287
281
}
288
282
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" ) {
294
288
ClockId :: Realtime
295
289
} else if raw_id == ecx. eval_libc_i32 ( "CLOCK_MONOTONIC" ) {
296
290
ClockId :: Monotonic
@@ -313,10 +307,9 @@ fn condattr_set_clock_id<'tcx>(
313
307
)
314
308
}
315
309
316
- // pthread_cond_t.
310
+ // pthread_cond_t can be only 4 bytes in size, depending on the platform .
317
311
// We ignore the platform layout and store our own fields:
318
312
// - id: u32
319
- // - clock: i32
320
313
321
314
fn cond_id_offset < ' tcx > ( ecx : & MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , u64 > {
322
315
let offset = match & * ecx. tcx . sess . target . os {
@@ -344,30 +337,6 @@ fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
344
337
Ok ( offset)
345
338
}
346
339
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
-
371
340
#[ derive( Debug , Clone , Copy ) ]
372
341
enum ClockId {
373
342
Realtime ,
@@ -390,14 +359,9 @@ fn cond_get_id<'tcx>(
390
359
) -> InterpResult < ' tcx , CondvarId > {
391
360
let cond = ecx. deref_pointer ( cond_ptr) ?;
392
361
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 } ) ) )
401
365
} ) ?;
402
366
403
367
// Check that the mutex has not been moved since last use.
@@ -411,19 +375,6 @@ fn cond_get_id<'tcx>(
411
375
Ok ( id)
412
376
}
413
377
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
-
427
378
impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
428
379
pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
429
380
fn pthread_mutexattr_init ( & mut self , attr_op : & OpTy < ' tcx > ) -> InterpResult < ' tcx , ( ) > {
@@ -624,15 +575,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
624
575
fn pthread_mutex_destroy ( & mut self , mutex_op : & OpTy < ' tcx > ) -> InterpResult < ' tcx , ( ) > {
625
576
let this = self . eval_context_mut ( ) ;
626
577
578
+ // Reading the field also has the side-effect that we detect double-`destroy`
579
+ // since we make the field unint below.
627
580
let id = mutex_get_id ( this, mutex_op) ?;
628
581
629
582
if this. mutex_is_locked ( id) {
630
583
throw_ub_format ! ( "destroyed a locked mutex" ) ;
631
584
}
632
585
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
-
636
586
// This might lead to false positives, see comment in pthread_mutexattr_destroy
637
587
this. write_uninit (
638
588
& this. deref_pointer_as ( mutex_op, this. libc_ty_layout ( "pthread_mutex_t" ) ) ?,
@@ -734,15 +684,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
734
684
fn pthread_rwlock_destroy ( & mut self , rwlock_op : & OpTy < ' tcx > ) -> InterpResult < ' tcx , ( ) > {
735
685
let this = self . eval_context_mut ( ) ;
736
686
687
+ // Reading the field also has the side-effect that we detect double-`destroy`
688
+ // since we make the field unint below.
737
689
let id = rwlock_get_id ( this, rwlock_op) ?;
738
690
739
691
if this. rwlock_is_locked ( id) {
740
692
throw_ub_format ! ( "destroyed a locked rwlock" ) ;
741
693
}
742
694
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
-
746
695
// This might lead to false positives, see comment in pthread_mutexattr_destroy
747
696
this. write_uninit (
748
697
& this. deref_pointer_as ( rwlock_op, this. libc_ty_layout ( "pthread_rwlock_t" ) ) ?,
@@ -832,7 +781,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
832
781
} else {
833
782
condattr_get_clock_id ( this, attr_op) ?
834
783
} ;
835
- let clock_id = translate_clock_id ( this, clock_id) ?;
784
+ let clock_id = cond_translate_clock_id ( this, clock_id) ?;
836
785
837
786
let cond = this. deref_pointer ( cond_op) ?;
838
787
let address = cond. ptr ( ) . addr ( ) . bytes ( ) ;
@@ -930,11 +879,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
930
879
}
931
880
932
881
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
-
936
882
let this = self . eval_context_mut ( ) ;
937
883
884
+ // Reading the field also has the side-effect that we detect double-`destroy`
885
+ // since we make the field unint below.
938
886
let id = cond_get_id ( this, cond_op) ?;
939
887
if this. condvar_is_awaited ( id) {
940
888
throw_ub_format ! ( "destroying an awaited conditional variable" ) ;
0 commit comments