@@ -49,7 +49,7 @@ use std::{
4949use rustc_ast:: Mutability ;
5050use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
5151use rustc_index:: { Idx , IndexVec } ;
52- use rustc_middle:: mir;
52+ use rustc_middle:: { mir, ty :: Ty } ;
5353use rustc_span:: Span ;
5454use rustc_target:: abi:: { Align , HasDataLayout , Size } ;
5555
@@ -200,18 +200,38 @@ enum AtomicAccessType {
200200 Rmw ,
201201}
202202
203- /// Type of write operation: allocating memory
204- /// non-atomic writes and deallocating memory
205- /// are all treated as writes for the purpose
206- /// of the data-race detector.
203+ /// Type of a non-atomic read operation.
207204#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
208- enum NaWriteType {
205+ pub enum NaReadType {
206+ /// Standard unsynchronized write.
207+ Read ,
208+
209+ // An implicit read generated by a retag.
210+ Retag ,
211+ }
212+
213+ impl NaReadType {
214+ fn description ( self ) -> & ' static str {
215+ match self {
216+ NaReadType :: Read => "non-atomic read" ,
217+ NaReadType :: Retag => "retag read" ,
218+ }
219+ }
220+ }
221+
222+ /// Type of a non-atomic write operation: allocating memory, non-atomic writes, and
223+ /// deallocating memory are all treated as writes for the purpose of the data-race detector.
224+ #[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
225+ pub enum NaWriteType {
209226 /// Allocate memory.
210227 Allocate ,
211228
212229 /// Standard unsynchronized write.
213230 Write ,
214231
232+ // An implicit write generated by a retag.
233+ Retag ,
234+
215235 /// Deallocate memory.
216236 /// Note that when memory is deallocated first, later non-atomic accesses
217237 /// will be reported as use-after-free, not as data races.
@@ -224,44 +244,64 @@ impl NaWriteType {
224244 match self {
225245 NaWriteType :: Allocate => "creating a new allocation" ,
226246 NaWriteType :: Write => "non-atomic write" ,
247+ NaWriteType :: Retag => "retag write" ,
227248 NaWriteType :: Deallocate => "deallocation" ,
228249 }
229250 }
230251}
231252
232253#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
233254enum AccessType {
234- NaRead ,
255+ NaRead ( NaReadType ) ,
235256 NaWrite ( NaWriteType ) ,
236257 AtomicLoad ,
237258 AtomicStore ,
238259 AtomicRmw ,
239260}
240261
241262impl AccessType {
242- fn description ( self ) -> & ' static str {
243- match self {
244- AccessType :: NaRead => "non-atomic read" ,
263+ fn description ( self , ty : Option < Ty < ' _ > > , size : Option < Size > ) -> String {
264+ let mut msg = String :: new ( ) ;
265+
266+ if let Some ( size) = size {
267+ msg. push_str ( & format ! ( "{}-byte {}" , size. bytes( ) , msg) )
268+ }
269+
270+ msg. push_str ( match self {
271+ AccessType :: NaRead ( w) => w. description ( ) ,
245272 AccessType :: NaWrite ( w) => w. description ( ) ,
246273 AccessType :: AtomicLoad => "atomic load" ,
247274 AccessType :: AtomicStore => "atomic store" ,
248275 AccessType :: AtomicRmw => "atomic read-modify-write" ,
276+ } ) ;
277+
278+ if let Some ( ty) = ty {
279+ msg. push_str ( & format ! ( " of type `{}`" , ty) ) ;
249280 }
281+
282+ msg
250283 }
251284
252285 fn is_atomic ( self ) -> bool {
253286 match self {
254287 AccessType :: AtomicLoad | AccessType :: AtomicStore | AccessType :: AtomicRmw => true ,
255- AccessType :: NaRead | AccessType :: NaWrite ( _) => false ,
288+ AccessType :: NaRead ( _ ) | AccessType :: NaWrite ( _) => false ,
256289 }
257290 }
258291
259292 fn is_read ( self ) -> bool {
260293 match self {
261- AccessType :: AtomicLoad | AccessType :: NaRead => true ,
294+ AccessType :: AtomicLoad | AccessType :: NaRead ( _ ) => true ,
262295 AccessType :: NaWrite ( _) | AccessType :: AtomicStore | AccessType :: AtomicRmw => false ,
263296 }
264297 }
298+
299+ fn is_retag ( self ) -> bool {
300+ matches ! (
301+ self ,
302+ AccessType :: NaRead ( NaReadType :: Retag ) | AccessType :: NaWrite ( NaWriteType :: Retag )
303+ )
304+ }
265305}
266306
267307/// Memory Cell vector clock metadata
@@ -502,12 +542,14 @@ impl MemoryCellClocks {
502542 & mut self ,
503543 thread_clocks : & mut ThreadClockSet ,
504544 index : VectorIdx ,
545+ read_type : NaReadType ,
505546 current_span : Span ,
506547 ) -> Result < ( ) , DataRace > {
507548 trace ! ( "Unsynchronized read with vectors: {:#?} :: {:#?}" , self , thread_clocks) ;
508549 if !current_span. is_dummy ( ) {
509550 thread_clocks. clock [ index] . span = current_span;
510551 }
552+ thread_clocks. clock [ index] . set_read_type ( read_type) ;
511553 if self . write_was_before ( & thread_clocks. clock ) {
512554 let race_free = if let Some ( atomic) = self . atomic ( ) {
513555 // We must be ordered-after all atomic accesses, reads and writes.
@@ -875,7 +917,8 @@ impl VClockAlloc {
875917 /// This finds the two racing threads and the type
876918 /// of data-race that occurred. This will also
877919 /// return info about the memory location the data-race
878- /// occurred in.
920+ /// occurred in. The `ty` parameter is used for diagnostics, letting
921+ /// the user know which type was involved in the access.
879922 #[ cold]
880923 #[ inline( never) ]
881924 fn report_data_race < ' tcx > (
@@ -885,6 +928,7 @@ impl VClockAlloc {
885928 access : AccessType ,
886929 access_size : Size ,
887930 ptr_dbg : Pointer < AllocId > ,
931+ ty : Option < Ty < ' _ > > ,
888932 ) -> InterpResult < ' tcx > {
889933 let ( current_index, current_clocks) = global. current_thread_state ( thread_mgr) ;
890934 let mut other_size = None ; // if `Some`, this was a size-mismatch race
@@ -908,7 +952,7 @@ impl VClockAlloc {
908952 write_clock = mem_clocks. write ( ) ;
909953 ( AccessType :: NaWrite ( mem_clocks. write_type ) , mem_clocks. write . 0 , & write_clock)
910954 } else if let Some ( idx) = Self :: find_gt_index ( & mem_clocks. read , & current_clocks. clock ) {
911- ( AccessType :: NaRead , idx, & mem_clocks. read )
955+ ( AccessType :: NaRead ( mem_clocks . read [ idx ] . read_type ( ) ) , idx, & mem_clocks. read )
912956 // Finally, mixed-size races.
913957 } else if access. is_atomic ( ) && let Some ( atomic) = mem_clocks. atomic ( ) && atomic. size != access_size {
914958 // This is only a race if we are not synchronized with all atomic accesses, so find
@@ -950,37 +994,33 @@ impl VClockAlloc {
950994 Err ( err_machine_stop ! ( TerminationInfo :: DataRace {
951995 involves_non_atomic,
952996 extra,
997+ retag_explain: access. is_retag( ) || other_access. is_retag( ) ,
953998 ptr: ptr_dbg,
954999 op1: RacingOp {
955- action: if let Some ( other_size) = other_size {
956- format!( "{}-byte {}" , other_size. bytes( ) , other_access. description( ) )
957- } else {
958- other_access. description( ) . to_owned( )
959- } ,
1000+ action: other_access. description( None , other_size) ,
9601001 thread_info: other_thread_info,
9611002 span: other_clock. as_slice( ) [ other_thread. index( ) ] . span_data( ) ,
9621003 } ,
9631004 op2: RacingOp {
964- action: if other_size. is_some( ) {
965- format!( "{}-byte {}" , access_size. bytes( ) , access. description( ) )
966- } else {
967- access. description( ) . to_owned( )
968- } ,
1005+ action: access. description( ty, other_size. map( |_| access_size) ) ,
9691006 thread_info: current_thread_info,
9701007 span: current_clocks. clock. as_slice( ) [ current_index. index( ) ] . span_data( ) ,
9711008 } ,
9721009 } ) ) ?
9731010 }
9741011
975- /// Detect data-races for an unsynchronized read operation, will not perform
1012+ /// Detect data-races for an unsynchronized read operation. It will not perform
9761013 /// data-race detection if `race_detecting()` is false, either due to no threads
9771014 /// being created or if it is temporarily disabled during a racy read or write
9781015 /// operation for which data-race detection is handled separately, for example
979- /// atomic read operations.
1016+ /// atomic read operations. The `ty` parameter is used for diagnostics, letting
1017+ /// the user know which type was read.
9801018 pub fn read < ' tcx > (
9811019 & self ,
9821020 alloc_id : AllocId ,
9831021 access_range : AllocRange ,
1022+ read_type : NaReadType ,
1023+ ty : Option < Ty < ' _ > > ,
9841024 machine : & MiriMachine < ' _ , ' _ > ,
9851025 ) -> InterpResult < ' tcx > {
9861026 let current_span = machine. current_span ( ) ;
@@ -992,17 +1032,18 @@ impl VClockAlloc {
9921032 alloc_ranges. iter_mut ( access_range. start , access_range. size )
9931033 {
9941034 if let Err ( DataRace ) =
995- mem_clocks. read_race_detect ( & mut thread_clocks, index, current_span)
1035+ mem_clocks. read_race_detect ( & mut thread_clocks, index, read_type , current_span)
9961036 {
9971037 drop ( thread_clocks) ;
9981038 // Report data-race.
9991039 return Self :: report_data_race (
10001040 global,
10011041 & machine. threads ,
10021042 mem_clocks,
1003- AccessType :: NaRead ,
1043+ AccessType :: NaRead ( read_type ) ,
10041044 access_range. size ,
10051045 Pointer :: new ( alloc_id, Size :: from_bytes ( mem_clocks_range. start ) ) ,
1046+ ty,
10061047 ) ;
10071048 }
10081049 }
@@ -1012,12 +1053,17 @@ impl VClockAlloc {
10121053 }
10131054 }
10141055
1015- // Shared code for detecting data-races on unique access to a section of memory
1016- fn unique_access < ' tcx > (
1056+ /// Detect data-races for an unsynchronized write operation. It will not perform
1057+ /// data-race detection if `race_detecting()` is false, either due to no threads
1058+ /// being created or if it is temporarily disabled during a racy read or write
1059+ /// operation. The `ty` parameter is used for diagnostics, letting
1060+ /// the user know which type was written.
1061+ pub fn write < ' tcx > (
10171062 & mut self ,
10181063 alloc_id : AllocId ,
10191064 access_range : AllocRange ,
10201065 write_type : NaWriteType ,
1066+ ty : Option < Ty < ' _ > > ,
10211067 machine : & mut MiriMachine < ' _ , ' _ > ,
10221068 ) -> InterpResult < ' tcx > {
10231069 let current_span = machine. current_span ( ) ;
@@ -1042,6 +1088,7 @@ impl VClockAlloc {
10421088 AccessType :: NaWrite ( write_type) ,
10431089 access_range. size ,
10441090 Pointer :: new ( alloc_id, Size :: from_bytes ( mem_clocks_range. start ) ) ,
1091+ ty,
10451092 ) ;
10461093 }
10471094 }
@@ -1050,37 +1097,6 @@ impl VClockAlloc {
10501097 Ok ( ( ) )
10511098 }
10521099 }
1053-
1054- /// Detect data-races for an unsynchronized write operation, will not perform
1055- /// data-race threads if `race_detecting()` is false, either due to no threads
1056- /// being created or if it is temporarily disabled during a racy read or write
1057- /// operation
1058- pub fn write < ' tcx > (
1059- & mut self ,
1060- alloc_id : AllocId ,
1061- range : AllocRange ,
1062- machine : & mut MiriMachine < ' _ , ' _ > ,
1063- ) -> InterpResult < ' tcx > {
1064- self . unique_access ( alloc_id, range, NaWriteType :: Write , machine)
1065- }
1066-
1067- /// Detect data-races for an unsynchronized deallocate operation, will not perform
1068- /// data-race threads if `race_detecting()` is false, either due to no threads
1069- /// being created or if it is temporarily disabled during a racy read or write
1070- /// operation
1071- pub fn deallocate < ' tcx > (
1072- & mut self ,
1073- alloc_id : AllocId ,
1074- size : Size ,
1075- machine : & mut MiriMachine < ' _ , ' _ > ,
1076- ) -> InterpResult < ' tcx > {
1077- self . unique_access (
1078- alloc_id,
1079- alloc_range ( Size :: ZERO , size) ,
1080- NaWriteType :: Deallocate ,
1081- machine,
1082- )
1083- }
10841100}
10851101
10861102impl < ' mir , ' tcx : ' mir > EvalContextPrivExt < ' mir , ' tcx > for MiriInterpCx < ' mir , ' tcx > { }
@@ -1279,7 +1295,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
12791295 let alloc_meta = this. get_alloc_extra ( alloc_id) ?. data_race . as_ref ( ) . unwrap ( ) ;
12801296 trace ! (
12811297 "Atomic op({}) with ordering {:?} on {:?} (size={})" ,
1282- access. description( ) ,
1298+ access. description( None , None ) ,
12831299 & atomic,
12841300 place. ptr( ) ,
12851301 size. bytes( )
@@ -1307,6 +1323,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
13071323 alloc_id,
13081324 Size :: from_bytes ( mem_clocks_range. start ) ,
13091325 ) ,
1326+ None ,
13101327 )
13111328 . map ( |_| true ) ;
13121329 }
0 commit comments