@@ -191,7 +191,8 @@ struct AtomicMemoryCellClocks {
191
191
/// The size of accesses to this atomic location.
192
192
/// We use this to detect non-synchronized mixed-size accesses. Since all accesses must be
193
193
/// aligned to their size, this is sufficient to detect imperfectly overlapping accesses.
194
- size : Size ,
194
+ /// `None` indicates that we saw multiple different sizes, which is okay as long as all accesses are reads.
195
+ size : Option < Size > ,
195
196
}
196
197
197
198
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
@@ -265,6 +266,14 @@ impl AccessType {
265
266
let mut msg = String :: new ( ) ;
266
267
267
268
if let Some ( size) = size {
269
+ if size == Size :: ZERO {
270
+ // In this case there were multiple read accesss with different sizes and then a write.
271
+ // We will be reporting *one* of the other reads, but we don't have enough information
272
+ // to determine which one had which size.
273
+ assert ! ( self == AccessType :: AtomicLoad ) ;
274
+ assert ! ( ty. is_none( ) ) ;
275
+ return format ! ( "multiple differently-sized atomic loads, including one load" ) ;
276
+ }
268
277
msg. push_str ( & format ! ( "{}-byte {}" , size. bytes( ) , msg) )
269
278
}
270
279
@@ -305,8 +314,7 @@ impl AccessType {
305
314
}
306
315
}
307
316
308
- /// Memory Cell vector clock metadata
309
- /// for data-race detection.
317
+ /// Per-byte vector clock metadata for data-race detection.
310
318
#[ derive( Clone , PartialEq , Eq , Debug ) ]
311
319
struct MemoryCellClocks {
312
320
/// The vector-clock timestamp and the thread that did the last non-atomic write. We don't need
@@ -325,8 +333,8 @@ struct MemoryCellClocks {
325
333
read : VClock ,
326
334
327
335
/// Atomic access, acquire, release sequence tracking clocks.
328
- /// For non-atomic memory in the common case this
329
- /// value is set to None .
336
+ /// For non-atomic memory this value is set to None.
337
+ /// For atomic memory, each byte carries this information .
330
338
atomic_ops : Option < Box < AtomicMemoryCellClocks > > ,
331
339
}
332
340
@@ -336,7 +344,7 @@ impl AtomicMemoryCellClocks {
336
344
read_vector : Default :: default ( ) ,
337
345
write_vector : Default :: default ( ) ,
338
346
sync_vector : Default :: default ( ) ,
339
- size,
347
+ size : Some ( size ) ,
340
348
}
341
349
}
342
350
}
@@ -383,17 +391,23 @@ impl MemoryCellClocks {
383
391
& mut self ,
384
392
thread_clocks : & ThreadClockSet ,
385
393
size : Size ,
394
+ write : bool ,
386
395
) -> Result < & mut AtomicMemoryCellClocks , DataRace > {
387
396
match self . atomic_ops {
388
397
Some ( ref mut atomic) => {
389
398
// We are good if the size is the same or all atomic accesses are before our current time.
390
- if atomic. size == size {
399
+ if atomic. size == Some ( size) {
391
400
Ok ( atomic)
392
401
} else if atomic. read_vector <= thread_clocks. clock
393
402
&& atomic. write_vector <= thread_clocks. clock
394
403
{
395
- // This is now the new size that must be used for accesses here.
396
- atomic. size = size;
404
+ // We are fully ordered after all previous accesses, so we can change the size.
405
+ atomic. size = Some ( size) ;
406
+ Ok ( atomic)
407
+ } else if !write && atomic. write_vector <= thread_clocks. clock {
408
+ // This is a read, and it is ordered after the last write. It's okay for the
409
+ // sizes to mismatch, as long as no writes with a different size occur later.
410
+ atomic. size = None ;
397
411
Ok ( atomic)
398
412
} else {
399
413
Err ( DataRace )
@@ -499,7 +513,7 @@ impl MemoryCellClocks {
499
513
Ok ( ( ) )
500
514
}
501
515
502
- /// Detect data-races with an atomic read, caused by a non-atomic access that does
516
+ /// Detect data-races with an atomic read, caused by a non-atomic write that does
503
517
/// not happen-before the atomic-read.
504
518
fn atomic_read_detect (
505
519
& mut self ,
@@ -508,14 +522,10 @@ impl MemoryCellClocks {
508
522
access_size : Size ,
509
523
) -> Result < ( ) , DataRace > {
510
524
trace ! ( "Atomic read with vectors: {:#?} :: {:#?}" , self , thread_clocks) ;
511
- let atomic = self . atomic_access ( thread_clocks, access_size) ?;
525
+ let atomic = self . atomic_access ( thread_clocks, access_size, /*write*/ false ) ?;
512
526
atomic. read_vector . set_at_index ( & thread_clocks. clock , index) ;
513
- // Make sure the last non-atomic write and all non-atomic reads were before this access.
514
- if self . write_was_before ( & thread_clocks. clock ) && self . read <= thread_clocks. clock {
515
- Ok ( ( ) )
516
- } else {
517
- Err ( DataRace )
518
- }
527
+ // Make sure the last non-atomic write was before this access.
528
+ if self . write_was_before ( & thread_clocks. clock ) { Ok ( ( ) ) } else { Err ( DataRace ) }
519
529
}
520
530
521
531
/// Detect data-races with an atomic write, either with a non-atomic read or with
@@ -527,7 +537,7 @@ impl MemoryCellClocks {
527
537
access_size : Size ,
528
538
) -> Result < ( ) , DataRace > {
529
539
trace ! ( "Atomic write with vectors: {:#?} :: {:#?}" , self , thread_clocks) ;
530
- let atomic = self . atomic_access ( thread_clocks, access_size) ?;
540
+ let atomic = self . atomic_access ( thread_clocks, access_size, /*write*/ true ) ?;
531
541
atomic. write_vector . set_at_index ( & thread_clocks. clock , index) ;
532
542
// Make sure the last non-atomic write and all non-atomic reads were before this access.
533
543
if self . write_was_before ( & thread_clocks. clock ) && self . read <= thread_clocks. clock {
@@ -552,11 +562,9 @@ impl MemoryCellClocks {
552
562
}
553
563
thread_clocks. clock . index_mut ( index) . set_read_type ( read_type) ;
554
564
if self . write_was_before ( & thread_clocks. clock ) {
565
+ // We must be ordered-after all atomic writes.
555
566
let race_free = if let Some ( atomic) = self . atomic ( ) {
556
- // We must be ordered-after all atomic accesses, reads and writes.
557
- // This ensures we don't mix atomic and non-atomic accesses.
558
567
atomic. write_vector <= thread_clocks. clock
559
- && atomic. read_vector <= thread_clocks. clock
560
568
} else {
561
569
true
562
570
} ;
@@ -957,9 +965,7 @@ impl VClockAlloc {
957
965
let mut other_size = None ; // if `Some`, this was a size-mismatch race
958
966
let write_clock;
959
967
let ( other_access, other_thread, other_clock) =
960
- // First check the atomic-nonatomic cases. If it looks like multiple
961
- // cases apply, this one should take precedence, else it might look like
962
- // we are reporting races between two non-atomic reads.
968
+ // First check the atomic-nonatomic cases.
963
969
if !access. is_atomic ( ) &&
964
970
let Some ( atomic) = mem_clocks. atomic ( ) &&
965
971
let Some ( idx) = Self :: find_gt_index ( & atomic. write_vector , & active_clocks. clock )
@@ -977,10 +983,10 @@ impl VClockAlloc {
977
983
} else if let Some ( idx) = Self :: find_gt_index ( & mem_clocks. read , & active_clocks. clock ) {
978
984
( AccessType :: NaRead ( mem_clocks. read [ idx] . read_type ( ) ) , idx, & mem_clocks. read )
979
985
// Finally, mixed-size races.
980
- } else if access. is_atomic ( ) && let Some ( atomic) = mem_clocks. atomic ( ) && atomic. size != access_size {
986
+ } else if access. is_atomic ( ) && let Some ( atomic) = mem_clocks. atomic ( ) && atomic. size != Some ( access_size) {
981
987
// This is only a race if we are not synchronized with all atomic accesses, so find
982
988
// the one we are not synchronized with.
983
- other_size = Some ( atomic. size ) ;
989
+ other_size = Some ( atomic. size . unwrap_or ( Size :: ZERO ) ) ;
984
990
if let Some ( idx) = Self :: find_gt_index ( & atomic. write_vector , & active_clocks. clock )
985
991
{
986
992
( AccessType :: AtomicStore , idx, & atomic. write_vector )
@@ -1007,10 +1013,7 @@ impl VClockAlloc {
1007
1013
assert ! ( !involves_non_atomic) ;
1008
1014
Some ( "overlapping unsynchronized atomic accesses must use the same access size" )
1009
1015
} else if access. is_read ( ) && other_access. is_read ( ) {
1010
- assert ! ( involves_non_atomic) ;
1011
- Some (
1012
- "overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only" ,
1013
- )
1016
+ panic ! ( "there should be no same-size read-read races" )
1014
1017
} else {
1015
1018
None
1016
1019
} ;
0 commit comments