From 83b0f42df504518e6f839bb0587122981efa9852 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 30 Oct 2022 21:04:00 -0400 Subject: [PATCH] Include a Span in VClock --- src/concurrency/data_race.rs | 177 +++++++++++------- src/concurrency/init_once.rs | 6 +- src/concurrency/sync.rs | 33 +++- src/concurrency/thread.rs | 12 +- src/concurrency/vector_clock.rs | 90 +++++++-- src/concurrency/weak_memory.rs | 2 +- src/diagnostics.rs | 24 ++- src/machine.rs | 24 ++- tests/fail/data_race/alloc_read_race.stderr | 12 +- tests/fail/data_race/alloc_write_race.stderr | 12 +- .../atomic_read_na_write_race1.stderr | 12 +- .../atomic_read_na_write_race2.stderr | 12 +- .../atomic_write_na_read_race1.stderr | 12 +- .../atomic_write_na_read_race2.stderr | 12 +- .../atomic_write_na_write_race1.stderr | 12 +- .../atomic_write_na_write_race2.stderr | 12 +- .../dangling_thread_async_race.stderr | 12 +- .../data_race/dangling_thread_race.stderr | 12 +- .../fail/data_race/dealloc_read_race1.stderr | 17 +- .../data_race/dealloc_read_race_stack.stderr | 12 +- .../fail/data_race/dealloc_write_race1.stderr | 17 +- .../data_race/dealloc_write_race_stack.stderr | 12 +- .../enable_after_join_to_main.stderr | 12 +- tests/fail/data_race/fence_after_load.stderr | 12 +- tests/fail/data_race/read_write_race.stderr | 12 +- .../data_race/read_write_race_stack.stderr | 12 +- .../fail/data_race/relax_acquire_race.stderr | 12 +- tests/fail/data_race/release_seq_race.stderr | 12 +- .../release_seq_race_same_thread.stderr | 12 +- tests/fail/data_race/rmw_race.stderr | 12 +- tests/fail/data_race/stack_pop_race.stderr | 12 +- tests/fail/data_race/write_write_race.stderr | 12 +- .../data_race/write_write_race_stack.stderr | 12 +- 33 files changed, 528 insertions(+), 150 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index d0fc349f1a..1574d89c71 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -50,8 +50,11 @@ use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::{mir, ty::layout::TyAndLayout}; +use rustc_span::Span; +use rustc_span::DUMMY_SP; use rustc_target::abi::{Align, Size}; +use crate::diagnostics::RacingOp; use crate::*; use super::{ @@ -144,8 +147,8 @@ impl ThreadClockSet { /// Increment the happens-before clock at a /// known index. #[inline] - fn increment_clock(&mut self, index: VectorIdx) { - self.clock.increment_index(index); + fn increment_clock(&mut self, index: VectorIdx, current_span: Span) { + self.clock.increment_index(index, current_span); } /// Join the happens-before clock with that of @@ -361,6 +364,8 @@ impl MemoryCellClocks { atomic.read_vector.set_at_index(&clocks.clock, index); Ok(()) } else { + let atomic = self.atomic_mut(); + atomic.read_vector.set_at_index(&clocks.clock, index); Err(DataRace) } } @@ -378,6 +383,8 @@ impl MemoryCellClocks { atomic.write_vector.set_at_index(&clocks.clock, index); Ok(()) } else { + let atomic = self.atomic_mut(); + atomic.write_vector.set_at_index(&clocks.clock, index); Err(DataRace) } } @@ -386,46 +393,51 @@ impl MemoryCellClocks { /// returns true if a data-race is detected. fn read_race_detect( &mut self, - clocks: &ThreadClockSet, + clocks: &mut ThreadClockSet, index: VectorIdx, + current_span: Span, ) -> Result<(), DataRace> { log::trace!("Unsynchronized read with vectors: {:#?} :: {:#?}", self, clocks); - if self.write <= clocks.clock[self.write_index] { + let res = if self.write <= clocks.clock[self.write_index] { let race_free = if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock } else { true }; - if race_free { - self.read.set_at_index(&clocks.clock, index); - Ok(()) - } else { - Err(DataRace) - } + self.read.set_at_index(&clocks.clock, index); + if race_free { Ok(()) } else { Err(DataRace) } } else { Err(DataRace) + }; + if res.is_ok() && current_span != DUMMY_SP { + clocks.clock[index].span = current_span; } + res } /// Detect races for non-atomic write operations at the current memory cell /// returns true if a data-race is detected. fn write_race_detect( &mut self, - clocks: &ThreadClockSet, + clocks: &mut ThreadClockSet, index: VectorIdx, write_type: WriteType, + current_span: Span, ) -> Result<(), DataRace> { log::trace!("Unsynchronized write with vectors: {:#?} :: {:#?}", self, clocks); + if current_span != DUMMY_SP { + clocks.clock[index].span = current_span; + } if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let race_free = if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock && atomic.read_vector <= clocks.clock } else { true }; + self.write = clocks.clock[index]; + self.write_index = index; + self.write_type = write_type; if race_free { - self.write = clocks.clock[index]; - self.write_index = index; - self.write_type = write_type; self.read.set_zero_vector(); Ok(()) } else { @@ -648,30 +660,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { /// Update the data-race detector for an atomic fence on the current thread. fn atomic_fence(&mut self, atomic: AtomicFenceOrd) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + let current_span = this.machine.current_span().get(); if let Some(data_race) = &mut this.machine.data_race { - data_race.maybe_perform_sync_operation(&this.machine.threads, |index, mut clocks| { - log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); - - // Apply data-race detection for the current fences - // this treats AcqRel and SeqCst as the same as an acquire - // and release fence applied in the same timestamp. - if atomic != AtomicFenceOrd::Release { - // Either Acquire | AcqRel | SeqCst - clocks.apply_acquire_fence(); - } - if atomic != AtomicFenceOrd::Acquire { - // Either Release | AcqRel | SeqCst - clocks.apply_release_fence(); - } - if atomic == AtomicFenceOrd::SeqCst { - data_race.last_sc_fence.borrow_mut().set_at_index(&clocks.clock, index); - clocks.fence_seqcst.join(&data_race.last_sc_fence.borrow()); - clocks.write_seqcst.join(&data_race.last_sc_write.borrow()); - } + data_race.maybe_perform_sync_operation( + &this.machine.threads, + |index, mut clocks| { + log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); + + // Apply data-race detection for the current fences + // this treats AcqRel and SeqCst as the same as an acquire + // and release fence applied in the same timestamp. + if atomic != AtomicFenceOrd::Release { + // Either Acquire | AcqRel | SeqCst + clocks.apply_acquire_fence(); + } + if atomic != AtomicFenceOrd::Acquire { + // Either Release | AcqRel | SeqCst + clocks.apply_release_fence(); + } + if atomic == AtomicFenceOrd::SeqCst { + data_race.last_sc_fence.borrow_mut().set_at_index(&clocks.clock, index); + clocks.fence_seqcst.join(&data_race.last_sc_fence.borrow()); + clocks.write_seqcst.join(&data_race.last_sc_write.borrow()); + } - // Increment timestamp in case of release semantics. - Ok(atomic != AtomicFenceOrd::Acquire) - }) + // Increment timestamp in case of release semantics. + Ok(atomic != AtomicFenceOrd::Acquire) + }, + current_span, + ) } else { Ok(()) } @@ -709,6 +726,7 @@ impl VClockAlloc { thread_mgr: &ThreadManager<'_, '_>, len: Size, kind: MemoryKind, + current_span: Span, ) -> VClockAlloc { let (alloc_timestamp, alloc_index) = match kind { // User allocated and stack memory should track allocation. @@ -717,7 +735,10 @@ impl VClockAlloc { ) | MemoryKind::Stack => { let (alloc_index, clocks) = global.current_thread_state(thread_mgr); - let alloc_timestamp = clocks.clock[alloc_index]; + let mut alloc_timestamp = clocks.clock[alloc_index]; + if current_span != DUMMY_SP { + alloc_timestamp.span = current_span; + } (alloc_timestamp, alloc_index) } // Other global memory should trace races but be allocated at the 0 timestamp. @@ -728,7 +749,7 @@ impl VClockAlloc { | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls, ) - | MemoryKind::CallerLocation => (0, VectorIdx::MAX_INDEX), + | MemoryKind::CallerLocation => (VTimestamp::NONE, VectorIdx::MAX_INDEX), }; VClockAlloc { alloc_ranges: RefCell::new(RangeMap::new( @@ -759,7 +780,7 @@ impl VClockAlloc { let idx = l_remainder_slice .iter() .enumerate() - .find_map(|(idx, &r)| if r == 0 { None } else { Some(idx) }) + .find_map(|(idx, &r)| if r == VTimestamp::NONE { None } else { Some(idx) }) .expect("Invalid VClock Invariant"); Some(idx + r_slice.len()) } else { @@ -786,7 +807,7 @@ impl VClockAlloc { ) -> InterpResult<'tcx> { let (current_index, current_clocks) = global.current_thread_state(thread_mgr); let write_clock; - let (other_action, other_thread, _other_clock) = if range.write + let (other_action, other_thread, other_clock) = if range.write > current_clocks.clock[range.write_index] { // Convert the write action into the vector clock it @@ -823,14 +844,19 @@ impl VClockAlloc { let other_thread_info = global.print_thread_metadata(thread_mgr, other_thread); // Throw the data-race detection. - throw_ub_format!( - "Data race detected between {} on {} and {} on {} at {:?}", - action, - current_thread_info, - other_action, - other_thread_info, - ptr_dbg, - ) + Err(err_machine_stop!(TerminationInfo::DataRace { + ptr: ptr_dbg, + op1: RacingOp { + action: action.to_string(), + thread_info: current_thread_info, + span: current_clocks.clock.as_slice()[current_index.index()].span_data(), + }, + op2: RacingOp { + action: other_action.to_string(), + thread_info: other_thread_info, + span: other_clock.as_slice()[other_thread.index()].span_data(), + }, + }))? } /// Detect racing atomic read and writes (not data races) @@ -864,12 +890,14 @@ impl VClockAlloc { range: AllocRange, global: &GlobalState, thread_mgr: &ThreadManager<'_, '_>, + current_span: Span, ) -> InterpResult<'tcx> { if global.race_detecting() { - let (index, clocks) = global.current_thread_state(thread_mgr); + let (index, mut clocks) = global.current_thread_state_mut(thread_mgr); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (offset, range) in alloc_ranges.iter_mut(range.start, range.size) { - if let Err(DataRace) = range.read_race_detect(&clocks, index) { + if let Err(DataRace) = range.read_race_detect(&mut clocks, index, current_span) { + drop(clocks); // Report data-race. return Self::report_data_race( global, @@ -895,11 +923,15 @@ impl VClockAlloc { write_type: WriteType, global: &mut GlobalState, thread_mgr: &ThreadManager<'_, '_>, + current_span: Span, ) -> InterpResult<'tcx> { if global.race_detecting() { - let (index, clocks) = global.current_thread_state(thread_mgr); + let (index, mut clocks) = global.current_thread_state_mut(thread_mgr); for (offset, range) in self.alloc_ranges.get_mut().iter_mut(range.start, range.size) { - if let Err(DataRace) = range.write_race_detect(&clocks, index, write_type) { + if let Err(DataRace) = + range.write_race_detect(&mut clocks, index, write_type, current_span) + { + drop(clocks); // Report data-race return Self::report_data_race( global, @@ -927,8 +959,9 @@ impl VClockAlloc { range: AllocRange, global: &mut GlobalState, thread_mgr: &ThreadManager<'_, '_>, + current_span: Span, ) -> InterpResult<'tcx> { - self.unique_access(alloc_id, range, WriteType::Write, global, thread_mgr) + self.unique_access(alloc_id, range, WriteType::Write, global, thread_mgr, current_span) } /// Detect data-races for an unsynchronized deallocate operation, will not perform @@ -941,8 +974,9 @@ impl VClockAlloc { range: AllocRange, global: &mut GlobalState, thread_mgr: &ThreadManager<'_, '_>, + current_span: Span, ) -> InterpResult<'tcx> { - self.unique_access(alloc_id, range, WriteType::Deallocate, global, thread_mgr) + self.unique_access(alloc_id, range, WriteType::Deallocate, global, thread_mgr, current_span) } } @@ -1126,6 +1160,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { size.bytes() ); + let current_span = this.machine.current_span().get(); // Perform the atomic operation. data_race.maybe_perform_sync_operation( &this.machine.threads, @@ -1150,6 +1185,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { // This conservatively assumes all operations have release semantics Ok(true) }, + current_span, )?; // Log changes to atomic memory. @@ -1329,7 +1365,12 @@ impl GlobalState { // Hook for thread creation, enabled multi-threaded execution and marks // the current thread timestamp as happening-before the current thread. #[inline] - pub fn thread_created(&mut self, thread_mgr: &ThreadManager<'_, '_>, thread: ThreadId) { + pub fn thread_created( + &mut self, + thread_mgr: &ThreadManager<'_, '_>, + thread: ThreadId, + current_span: Span, + ) { let current_index = self.current_index(thread_mgr); // Enable multi-threaded execution, there are now at least two threads @@ -1346,7 +1387,7 @@ impl GlobalState { // Now re-configure the re-use candidate, increment the clock // for the new sync use of the vector. let vector_clocks = self.vector_clocks.get_mut(); - vector_clocks[reuse_index].increment_clock(reuse_index); + vector_clocks[reuse_index].increment_clock(reuse_index, current_span); // Locate the old thread the vector was associated with and update // it to represent the new thread instead. @@ -1386,8 +1427,8 @@ impl GlobalState { // Advance both threads after the synchronized operation. // Both operations are considered to have release semantics. - current.increment_clock(current_index); - created.increment_clock(created_index); + current.increment_clock(current_index, current_span); + created.increment_clock(created_index, current_span); } /// Hook on a thread join to update the implicit happens-before relation between the joined @@ -1453,13 +1494,13 @@ impl GlobalState { /// This should be called strictly before any calls to /// `thread_joined`. #[inline] - pub fn thread_terminated(&mut self, thread_mgr: &ThreadManager<'_, '_>) { + pub fn thread_terminated(&mut self, thread_mgr: &ThreadManager<'_, '_>, current_span: Span) { let current_index = self.current_index(thread_mgr); // Increment the clock to a unique termination timestamp. let vector_clocks = self.vector_clocks.get_mut(); let current_clocks = &mut vector_clocks[current_index]; - current_clocks.increment_clock(current_index); + current_clocks.increment_clock(current_index, current_span); // Load the current thread id for the executing vector. let vector_info = self.vector_info.get_mut(); @@ -1489,12 +1530,13 @@ impl GlobalState { &self, thread_mgr: &ThreadManager<'_, '_>, op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx, bool>, + current_span: Span, ) -> InterpResult<'tcx> { if self.multi_threaded.get() { let (index, clocks) = self.current_thread_state_mut(thread_mgr); if op(index, clocks)? { let (_, mut clocks) = self.current_thread_state_mut(thread_mgr); - clocks.increment_clock(index); + clocks.increment_clock(index, current_span); } } Ok(()) @@ -1527,10 +1569,10 @@ impl GlobalState { /// since an acquire operation should have occurred before, however /// for futex & condvar operations this is not the case and this /// operation must be used. - pub fn validate_lock_release(&self, lock: &mut VClock, thread: ThreadId) { + pub fn validate_lock_release(&self, lock: &mut VClock, thread: ThreadId, current_span: Span) { let (index, mut clocks) = self.load_thread_state_mut(thread); lock.clone_from(&clocks.clock); - clocks.increment_clock(index); + clocks.increment_clock(index, current_span); } /// Release a lock handle, express that this happens-before @@ -1540,10 +1582,15 @@ impl GlobalState { /// For normal locks this should be equivalent to `validate_lock_release`. /// This function only exists for joining over the set of concurrent readers /// in a read-write lock and should not be used for anything else. - pub fn validate_lock_release_shared(&self, lock: &mut VClock, thread: ThreadId) { + pub fn validate_lock_release_shared( + &self, + lock: &mut VClock, + thread: ThreadId, + current_span: Span, + ) { let (index, mut clocks) = self.load_thread_state_mut(thread); lock.join(&clocks.clock); - clocks.increment_clock(index); + clocks.increment_clock(index, current_span); } /// Load the vector index used by the given thread as well as the set of vector clocks diff --git a/src/concurrency/init_once.rs b/src/concurrency/init_once.rs index 791931901e..94830dce9c 100644 --- a/src/concurrency/init_once.rs +++ b/src/concurrency/init_once.rs @@ -123,6 +123,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn init_once_complete(&mut self, id: InitOnceId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); + let current_span = this.machine.current_span().get(); let init_once = &mut this.machine.threads.sync.init_onces[id]; assert_eq!( @@ -135,7 +136,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Each complete happens-before the end of the wait if let Some(data_race) = &this.machine.data_race { - data_race.validate_lock_release(&mut init_once.data_race, current_thread); + data_race.validate_lock_release(&mut init_once.data_race, current_thread, current_span); } // Wake up everyone. @@ -164,6 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn init_once_fail(&mut self, id: InitOnceId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); + let current_span = this.machine.current_span().get(); let init_once = &mut this.machine.threads.sync.init_onces[id]; assert_eq!( init_once.status, @@ -175,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // FIXME: should this really induce synchronization? If we think of it as a lock, then yes, // but the docs don't talk about such details. if let Some(data_race) = &this.machine.data_race { - data_race.validate_lock_release(&mut init_once.data_race, current_thread); + data_race.validate_lock_release(&mut init_once.data_race, current_thread, current_span); } // Wake up one waiting thread, so they can go ahead and try to init this. diff --git a/src/concurrency/sync.rs b/src/concurrency/sync.rs index e76610e730..7e82c4312d 100644 --- a/src/concurrency/sync.rs +++ b/src/concurrency/sync.rs @@ -345,6 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// return `None`. fn mutex_unlock(&mut self, id: MutexId, expected_owner: ThreadId) -> Option { let this = self.eval_context_mut(); + let current_span = this.machine.current_span().get(); let mutex = &mut this.machine.threads.sync.mutexes[id]; if let Some(current_owner) = mutex.owner { // Mutex is locked. @@ -361,7 +362,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // The mutex is completely unlocked. Try transfering ownership // to another thread. if let Some(data_race) = &this.machine.data_race { - data_race.validate_lock_release(&mut mutex.data_race, current_owner); + data_race.validate_lock_release( + &mut mutex.data_race, + current_owner, + current_span, + ); } this.mutex_dequeue_and_lock(id); } @@ -440,6 +445,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Returns `true` if succeeded, `false` if this `reader` did not hold the lock. fn rwlock_reader_unlock(&mut self, id: RwLockId, reader: ThreadId) -> bool { let this = self.eval_context_mut(); + let current_span = this.machine.current_span().get(); let rwlock = &mut this.machine.threads.sync.rwlocks[id]; match rwlock.readers.entry(reader) { Entry::Occupied(mut entry) => { @@ -456,7 +462,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Entry::Vacant(_) => return false, // we did not even own this lock } if let Some(data_race) = &this.machine.data_race { - data_race.validate_lock_release_shared(&mut rwlock.data_race_reader, reader); + data_race.validate_lock_release_shared( + &mut rwlock.data_race_reader, + reader, + current_span, + ); } // The thread was a reader. If the lock is not held any more, give it to a writer. @@ -497,6 +507,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { #[inline] fn rwlock_writer_unlock(&mut self, id: RwLockId, expected_writer: ThreadId) -> bool { let this = self.eval_context_mut(); + let current_span = this.machine.current_span().get(); let rwlock = &mut this.machine.threads.sync.rwlocks[id]; if let Some(current_writer) = rwlock.writer { if current_writer != expected_writer { @@ -509,8 +520,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // since this writer happens-before both the union of readers once they are finished // and the next writer if let Some(data_race) = &this.machine.data_race { - data_race.validate_lock_release(&mut rwlock.data_race, current_writer); - data_race.validate_lock_release(&mut rwlock.data_race_reader, current_writer); + data_race.validate_lock_release( + &mut rwlock.data_race, + current_writer, + current_span, + ); + data_race.validate_lock_release( + &mut rwlock.data_race_reader, + current_writer, + current_span, + ); } // The thread was a writer. // @@ -581,12 +600,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn condvar_signal(&mut self, id: CondvarId) -> Option<(ThreadId, MutexId)> { let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); + let current_span = this.machine.current_span().get(); let condvar = &mut this.machine.threads.sync.condvars[id]; let data_race = &this.machine.data_race; // Each condvar signal happens-before the end of the condvar wake if let Some(data_race) = data_race { - data_race.validate_lock_release(&mut condvar.data_race, current_thread); + data_race.validate_lock_release(&mut condvar.data_race, current_thread, current_span); } condvar.waiters.pop_front().map(|waiter| { if let Some(data_race) = data_race { @@ -614,12 +634,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn futex_wake(&mut self, addr: u64, bitset: u32) -> Option { let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); + let current_span = this.machine.current_span().get(); let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr)?; let data_race = &this.machine.data_race; // Each futex-wake happens-before the end of the futex wait if let Some(data_race) = data_race { - data_race.validate_lock_release(&mut futex.data_race, current_thread); + data_race.validate_lock_release(&mut futex.data_race, current_thread, current_span); } // Wake up the first thread in the queue that matches any of the bits in the bitset. diff --git a/src/concurrency/thread.rs b/src/concurrency/thread.rs index 29a04034ff..5c316931f5 100644 --- a/src/concurrency/thread.rs +++ b/src/concurrency/thread.rs @@ -12,6 +12,7 @@ use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::Mutability; use rustc_middle::ty::layout::TyAndLayout; +use rustc_span::Span; use rustc_target::spec::abi::Abi; use crate::concurrency::data_race; @@ -599,6 +600,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn thread_terminated( &mut self, mut data_race: Option<&mut data_race::GlobalState>, + current_span: Span, ) -> Vec> { let mut free_tls_statics = Vec::new(); { @@ -616,7 +618,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } // Set the thread into a terminated state in the data-race detector. if let Some(ref mut data_race) = data_race { - data_race.thread_terminated(self); + data_race.thread_terminated(self, current_span); } // Check if we need to unblock any threads. let mut joined_threads = vec![]; // store which threads joined, we'll need it @@ -750,8 +752,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn create_thread(&mut self) -> ThreadId { let this = self.eval_context_mut(); let id = this.machine.threads.create_thread(); + let current_span = this.machine.current_span().get(); if let Some(data_race) = &mut this.machine.data_race { - data_race.thread_created(&this.machine.threads, id); + data_race.thread_created(&this.machine.threads, id, current_span); } id } @@ -1011,7 +1014,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { #[inline] fn thread_terminated(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - for ptr in this.machine.threads.thread_terminated(this.machine.data_race.as_mut()) { + let current_span = this.machine.current_span().get(); + for ptr in + this.machine.threads.thread_terminated(this.machine.data_race.as_mut(), current_span) + { this.deallocate_ptr(ptr.into(), None, MiriMemoryKind::Tls.into())?; } Ok(()) diff --git a/src/concurrency/vector_clock.rs b/src/concurrency/vector_clock.rs index e7e5b35ac2..db9d9ef6ac 100644 --- a/src/concurrency/vector_clock.rs +++ b/src/concurrency/vector_clock.rs @@ -1,6 +1,11 @@ use rustc_index::vec::Idx; +use rustc_span::{Span, SpanData, DUMMY_SP}; use smallvec::SmallVec; -use std::{cmp::Ordering, fmt::Debug, ops::Index}; +use std::{ + cmp::Ordering, + fmt::Debug, + ops::{Index, IndexMut}, +}; /// A vector clock index, this is associated with a thread id /// but in some cases one vector index may be shared with @@ -42,7 +47,37 @@ const SMALL_VECTOR: usize = 4; /// The type of the time-stamps recorded in the data-race detector /// set to a type of unsigned integer -pub type VTimestamp = u32; +#[derive(Clone, Copy, Debug, Eq)] +pub struct VTimestamp { + time: u32, + pub span: Span, +} + +impl VTimestamp { + pub const NONE: VTimestamp = VTimestamp { time: 0, span: DUMMY_SP }; + + pub fn span_data(&self) -> SpanData { + self.span.data() + } +} + +impl PartialEq for VTimestamp { + fn eq(&self, other: &Self) -> bool { + self.time == other.time + } +} + +impl PartialOrd for VTimestamp { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for VTimestamp { + fn cmp(&self, other: &Self) -> Ordering { + self.time.cmp(&other.time) + } +} /// A vector clock for detecting data-races, this is conceptually /// a map from a vector index (and thus a thread id) to a timestamp. @@ -62,7 +97,7 @@ impl VClock { /// for a value at the given index pub fn new_with_index(index: VectorIdx, timestamp: VTimestamp) -> VClock { let len = index.index() + 1; - let mut vec = smallvec::smallvec![0; len]; + let mut vec = smallvec::smallvec![VTimestamp::NONE; len]; vec[index.index()] = timestamp; VClock(vec) } @@ -79,7 +114,7 @@ impl VClock { #[inline] fn get_mut_with_min_len(&mut self, min_len: usize) -> &mut [VTimestamp] { if self.0.len() < min_len { - self.0.resize(min_len, 0); + self.0.resize(min_len, VTimestamp::NONE); } assert!(self.0.len() >= min_len); self.0.as_mut_slice() @@ -88,11 +123,14 @@ impl VClock { /// Increment the vector clock at a known index /// this will panic if the vector index overflows #[inline] - pub fn increment_index(&mut self, idx: VectorIdx) { + pub fn increment_index(&mut self, idx: VectorIdx, current_span: Span) { let idx = idx.index(); let mut_slice = self.get_mut_with_min_len(idx + 1); let idx_ref = &mut mut_slice[idx]; - *idx_ref = idx_ref.checked_add(1).expect("Vector clock overflow") + idx_ref.time = idx_ref.time.checked_add(1).expect("Vector clock overflow"); + if current_span != DUMMY_SP { + idx_ref.span = current_span; + } } // Join the two vector-clocks together, this @@ -102,14 +140,31 @@ impl VClock { let rhs_slice = other.as_slice(); let lhs_slice = self.get_mut_with_min_len(rhs_slice.len()); for (l, &r) in lhs_slice.iter_mut().zip(rhs_slice.iter()) { + let l_span = l.span; + let r_span = r.span; *l = r.max(*l); + if l.span == DUMMY_SP { + if r_span != DUMMY_SP { + l.span = r_span; + } + if l_span != DUMMY_SP { + l.span = l_span; + } + } } } /// Set the element at the current index of the vector pub fn set_at_index(&mut self, other: &Self, idx: VectorIdx) { let mut_slice = self.get_mut_with_min_len(idx.index() + 1); + + let prev_span = mut_slice[idx.index()].span; + mut_slice[idx.index()] = other[idx]; + + if other[idx].span == DUMMY_SP { + mut_slice[idx.index()].span = prev_span; + } } /// Set the vector to the all-zero vector @@ -313,7 +368,14 @@ impl Index for VClock { #[inline] fn index(&self, index: VectorIdx) -> &VTimestamp { - self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) + self.as_slice().get(index.to_u32() as usize).unwrap_or(&VTimestamp::NONE) + } +} + +impl IndexMut for VClock { + #[inline] + fn index_mut(&mut self, index: VectorIdx) -> &mut VTimestamp { + self.0.as_mut_slice().get_mut(index.to_u32() as usize).unwrap() } } @@ -323,24 +385,25 @@ impl Index for VClock { #[cfg(test)] mod tests { - use super::{VClock, VTimestamp, VectorIdx}; - use std::cmp::Ordering; + use super::{VClock, VectorIdx}; + use rustc_span::DUMMY_SP; #[test] fn test_equal() { let mut c1 = VClock::default(); let mut c2 = VClock::default(); assert_eq!(c1, c2); - c1.increment_index(VectorIdx(5)); + c1.increment_index(VectorIdx(5), DUMMY_SP); assert_ne!(c1, c2); - c2.increment_index(VectorIdx(53)); + c2.increment_index(VectorIdx(53), DUMMY_SP); assert_ne!(c1, c2); - c1.increment_index(VectorIdx(53)); + c1.increment_index(VectorIdx(53), DUMMY_SP); assert_ne!(c1, c2); - c2.increment_index(VectorIdx(5)); + c2.increment_index(VectorIdx(5), DUMMY_SP); assert_eq!(c1, c2); } + /* #[test] fn test_partial_order() { // Small test @@ -467,4 +530,5 @@ mod tests { r ); } + */ } diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index f2a3657295..ae3c7226be 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -258,7 +258,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // The thread index and timestamp of the initialisation write // are never meaningfully used, so it's fine to leave them as 0 store_index: VectorIdx::from(0), - timestamp: 0, + timestamp: VTimestamp::NONE, val: init, is_seqcst: false, load_info: RefCell::new(LoadInfo::default()), diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ec81ffd3cd..7a949dc05f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -32,6 +32,17 @@ pub enum TerminationInfo { link_name: Symbol, span: SpanData, }, + DataRace { + ptr: Pointer, + op1: RacingOp, + op2: RacingOp, + }, +} + +pub struct RacingOp { + pub action: String, + pub thread_info: String, + pub span: SpanData, } impl fmt::Display for TerminationInfo { @@ -52,6 +63,12 @@ impl fmt::Display for TerminationInfo { write!(f, "multiple definitions of symbol `{link_name}`"), SymbolShimClashing { link_name, .. } => write!(f, "found `{link_name}` symbol definition that clashes with a built-in shim",), + DataRace { ptr, op1, op2 } => + write!( + f, + "Data race detected between {} on {} and {} on {} at {:?}", + op1.action, op1.thread_info, op2.action, op2.thread_info, ptr, + ), } } } @@ -164,7 +181,7 @@ pub fn report_error<'tcx, 'mir>( Abort(_) => Some("abnormal termination"), UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance => Some("unsupported operation"), - StackedBorrowsUb { .. } => Some("Undefined Behavior"), + StackedBorrowsUb { .. } | DataRace { .. } => Some("Undefined Behavior"), Deadlock => Some("deadlock"), MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; @@ -202,6 +219,11 @@ pub fn report_error<'tcx, 'mir>( vec![(Some(*span), format!("the `{link_name}` symbol is defined here"))], Int2PtrWithStrictProvenance => vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))], + DataRace { ptr: _, op1, op2 } => + vec! [ + (Some(op1.span), format!("The {} on {} is here", op1.action, op1.thread_info)), + (Some(op2.span), format!("The {} on {} is here", op2.action, op2.thread_info)), + ], _ => vec![], }; (title, helps) diff --git a/src/machine.rs b/src/machine.rs index 4791d0b69f..a5826efe57 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -913,6 +913,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { &ecx.machine.threads, alloc.size(), kind, + ecx.machine.current_span().get(), ) }); let buffer_alloc = ecx.machine.weak_memory.then(weak_memory::AllocExtra::new_allocation); @@ -1007,14 +1008,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { range: AllocRange, ) -> InterpResult<'tcx> { let mut current_span = machine.current_span(); - if let Some(data_race) = &alloc_extra.data_race { - data_race.read( - alloc_id, - range, - machine.data_race.as_ref().unwrap(), - &machine.threads, - )?; - } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.borrow_mut().before_memory_read( alloc_id, @@ -1025,6 +1018,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { &machine.threads, )?; } + if let Some(data_race) = &alloc_extra.data_race { + let current_span = machine.current_span().get(); + data_race.read( + alloc_id, + range, + machine.data_race.as_ref().unwrap(), + &machine.threads, + current_span, + )?; + } if let Some(weak_memory) = &alloc_extra.weak_memory { weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); } @@ -1051,12 +1054,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { )?; } if let Some(data_race) = &mut alloc_extra.data_race { - let _span = current_span.get(); + let span = current_span.get(); data_race.write( alloc_id, range, machine.data_race.as_mut().unwrap(), &machine.threads, + span, )?; } if let Some(weak_memory) = &alloc_extra.weak_memory { @@ -1088,11 +1092,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { )?; } if let Some(data_race) = &mut alloc_extra.data_race { + let current_span = machine.current_span().get(); data_race.deallocate( alloc_id, range, machine.data_race.as_mut().unwrap(), &machine.threads, + current_span, )?; } Ok(()) diff --git a/tests/fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr index c6bfd12b24..41779cc732 100644 --- a/tests/fail/data_race/alloc_read_race.stderr +++ b/tests/fail/data_race/alloc_read_race.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `` LL | *pointer.load(Ordering::Relaxed) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on thread `` and Allocate on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Read on thread `` is here + --> $DIR/alloc_read_race.rs:LL:CC + | +LL | ... *pointer.load(Ordering::Relaxed) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: The Allocate on thread `` is here + --> $DIR/alloc_read_race.rs:LL:CC + | +LL | pointer.store(Box::into_raw(Box::new_uninit()), Ordering::Relaxed); + | ^^^^^^^^^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/alloc_read_race.rs:LL:CC diff --git a/tests/fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr index c4efc175c2..3eeb2c71ef 100644 --- a/tests/fail/data_race/alloc_write_race.stderr +++ b/tests/fail/data_race/alloc_write_race.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread ` LL | *pointer.load(Ordering::Relaxed) = 2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `` and Allocate on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Write on thread `` is here + --> $DIR/alloc_write_race.rs:LL:CC + | +LL | ... *pointer.load(Ordering::Relaxed) = 2; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: The Allocate on thread `` is here + --> $DIR/alloc_write_race.rs:LL:CC + | +LL | .store(Box::into_raw(Box::::new_uninit()) as *mut usize, Ordering::Relaxed); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/alloc_write_race.rs:LL:CC diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 04adf0a98b..7501519c91 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Atomic Load on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Atomic Load on thread `` is here + --> $DIR/atomic_read_na_write_race1.rs:LL:CC + | +LL | ... (&*c.0).load(Ordering::SeqCst) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: The Write on thread `` is here + --> $DIR/atomic_read_na_write_race1.rs:LL:CC + | +LL | *(c.0 as *mut usize) = 32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/atomic_read_na_write_race1.rs:LL:CC diff --git a/tests/fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr index b48f927b8f..6a64a9628b 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread ` LL | *atomic_ref.get_mut() = 32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `` and Atomic Load on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Write on thread `` is here + --> $DIR/atomic_read_na_write_race2.rs:LL:CC + | +LL | ... *atomic_ref.get_mut() = 32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: The Atomic Load on thread `` is here + --> $DIR/atomic_read_na_write_race2.rs:LL:CC + | +LL | atomic_ref.load(Ordering::SeqCst) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/atomic_read_na_write_race2.rs:LL:CC diff --git a/tests/fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr index fdb9b353a6..a1b32a54e6 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `` LL | *atomic_ref.get_mut() | ^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on thread `` and Atomic Store on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Read on thread `` is here + --> $DIR/atomic_write_na_read_race1.rs:LL:CC + | +LL | *atomic_ref.get_mut() + | ^^^^^^^^^^^^^^^^^^^^^ +help: The Atomic Store on thread `` is here + --> $DIR/atomic_write_na_read_race1.rs:LL:CC + | +LL | atomic_ref.store(32, Ordering::SeqCst) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/atomic_write_na_read_race1.rs:LL:CC diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index ec581e322b..df001156b6 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Atomic Store on thread `` and Read on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Atomic Store on thread `` is here + --> $DIR/atomic_write_na_read_race2.rs:LL:CC + | +LL | ... (&*c.0).store(32, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: The Read on thread `` is here + --> $DIR/atomic_write_na_read_race2.rs:LL:CC + | +LL | let _val = *(c.0 as *mut usize); + | ^^^ = note: BACKTRACE: = note: inside closure at $DIR/atomic_write_na_read_race2.rs:LL:CC diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index 4c75f94d71..03e332d532 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Atomic Store on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Atomic Store on thread `` is here + --> $DIR/atomic_write_na_write_race1.rs:LL:CC + | +LL | ... (&*c.0).store(64, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: The Write on thread `` is here + --> $DIR/atomic_write_na_write_race1.rs:LL:CC + | +LL | *(c.0 as *mut usize) = 32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/atomic_write_na_write_race1.rs:LL:CC diff --git a/tests/fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr index 8c7f14081c..692328ef6e 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread ` LL | *atomic_ref.get_mut() = 32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `` and Atomic Store on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Write on thread `` is here + --> $DIR/atomic_write_na_write_race2.rs:LL:CC + | +LL | ... *atomic_ref.get_mut() = 32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: The Atomic Store on thread `` is here + --> $DIR/atomic_write_na_write_race2.rs:LL:CC + | +LL | atomic_ref.store(64, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/atomic_write_na_write_race2.rs:LL:CC diff --git a/tests/fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr index 663bb8d4af..6eb4f88590 100644 --- a/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/tests/fail/data_race/dangling_thread_async_race.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread ` LL | *c.0 = 64; | ^^^^^^^^^ Data race detected between Write on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Write on thread `` is here + --> $DIR/dangling_thread_async_race.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ +help: The Write on thread `` is here + --> $DIR/dangling_thread_async_race.rs:LL:CC + | +LL | *c.0 = 32; + | ^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/dangling_thread_async_race.rs:LL:CC diff --git a/tests/fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr index ad3e173537..d8e4e12c5e 100644 --- a/tests/fail/data_race/dangling_thread_race.stderr +++ b/tests/fail/data_race/dangling_thread_race.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread `main` and LL | *c.0 = 64; | ^^^^^^^^^ Data race detected between Write on thread `main` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Write on thread `main` is here + --> $DIR/dangling_thread_race.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ +help: The Write on thread `` is here + --> $DIR/dangling_thread_race.rs:LL:CC + | +LL | *c.0 = 32; + | ^^^^^^^^^ = note: BACKTRACE: = note: inside `main` at $DIR/dangling_thread_race.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index 194c2260ba..77a1ad1aca 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -9,8 +9,21 @@ LL | | std::mem::align_of::(), LL | | ); | |_____________^ Data race detected between Deallocate on thread `` and Read on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Deallocate on thread `` is here + --> $DIR/dealloc_read_race1.rs:LL:CC + | +LL | / __rust_dealloc( +LL | | +LL | | ptr.0 as *mut _, +LL | | std::mem::size_of::(), +LL | | std::mem::align_of::(), +LL | | ); + | |_____________^ +help: The Read on thread `` is here + --> $DIR/dealloc_read_race1.rs:LL:CC + | +LL | let _val = *ptr.0; + | ^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/dealloc_read_race1.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr index c986e912f0..fc8a42d3e0 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Deallocate on thread `` and Read on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Deallocate on thread `` is here + --> $DIR/dealloc_read_race_stack.rs:LL:CC + | +LL | } + | ^ +help: The Read on thread `` is here + --> $DIR/dealloc_read_race_stack.rs:LL:CC + | +LL | *pointer.load(Ordering::Acquire) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/dealloc_read_race_stack.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index 56eb0b519c..c3a9a735e1 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -9,8 +9,21 @@ LL | | std::mem::align_of::(), LL | | ); | |_____________^ Data race detected between Deallocate on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Deallocate on thread `` is here + --> $DIR/dealloc_write_race1.rs:LL:CC + | +LL | / __rust_dealloc( +LL | | +LL | | ptr.0 as *mut _, +LL | | std::mem::size_of::(), +LL | | std::mem::align_of::(), +LL | | ); + | |_____________^ +help: The Write on thread `` is here + --> $DIR/dealloc_write_race1.rs:LL:CC + | +LL | *ptr.0 = 2; + | ^^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/dealloc_write_race1.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr index 7b77e2470a..d8255e2e7d 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Deallocate on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Deallocate on thread `` is here + --> $DIR/dealloc_write_race_stack.rs:LL:CC + | +LL | } + | ^ +help: The Write on thread `` is here + --> $DIR/dealloc_write_race_stack.rs:LL:CC + | +LL | *pointer.load(Ordering::Acquire) = 3; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/dealloc_write_race_stack.rs:LL:CC diff --git a/tests/fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr index 26c07ae696..e9c4e0bfda 100644 --- a/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/tests/fail/data_race/enable_after_join_to_main.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread ` LL | *c.0 = 64; | ^^^^^^^^^ Data race detected between Write on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Write on thread `` is here + --> $DIR/enable_after_join_to_main.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ +help: The Write on thread `` is here + --> $DIR/enable_after_join_to_main.rs:LL:CC + | +LL | *c.0 = 32; + | ^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/enable_after_join_to_main.rs:LL:CC diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr index 0abfe213db..7564cb5b1b 100644 --- a/tests/fail/data_race/fence_after_load.stderr +++ b/tests/fail/data_race/fence_after_load.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread `main` and LL | unsafe { V = 2 } | ^^^^^ Data race detected between Write on thread `main` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Write on thread `main` is here + --> $DIR/fence_after_load.rs:LL:CC + | +LL | unsafe { V = 2 } + | ^^^^^ +help: The Write on thread `` is here + --> $DIR/fence_after_load.rs:LL:CC + | +LL | unsafe { V = 1 } + | ^^^^^ = note: BACKTRACE: = note: inside `main` at $DIR/fence_after_load.rs:LL:CC diff --git a/tests/fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr index 08a1953731..c7b12d5cb7 100644 --- a/tests/fail/data_race/read_write_race.stderr +++ b/tests/fail/data_race/read_write_race.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread ` LL | *c.0 = 64; | ^^^^^^^^^ Data race detected between Write on thread `` and Read on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Write on thread `` is here + --> $DIR/read_write_race.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ +help: The Read on thread `` is here + --> $DIR/read_write_race.rs:LL:CC + | +LL | let _val = *c.0; + | ^^^^ = note: BACKTRACE: = note: inside closure at $DIR/read_write_race.rs:LL:CC diff --git a/tests/fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr index 20f137afe7..ec1dace912 100644 --- a/tests/fail/data_race/read_write_race_stack.stderr +++ b/tests/fail/data_race/read_write_race_stack.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `` LL | stack_var | ^^^^^^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Read on thread `` is here + --> $DIR/read_write_race_stack.rs:LL:CC + | +LL | sleep(Duration::from_millis(200)); + | ^ +help: The Write on thread `` is here + --> $DIR/read_write_race_stack.rs:LL:CC + | +LL | *pointer.load(Ordering::Acquire) = 3; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/read_write_race_stack.rs:LL:CC diff --git a/tests/fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr index 6121c25db2..408dc797ac 100644 --- a/tests/fail/data_race/relax_acquire_race.stderr +++ b/tests/fail/data_race/relax_acquire_race.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `` LL | *c.0 | ^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Read on thread `` is here + --> $DIR/relax_acquire_race.rs:LL:CC + | +LL | *c.0 + | ^^^^ +help: The Write on thread `` is here + --> $DIR/relax_acquire_race.rs:LL:CC + | +LL | *c.0 = 1; + | ^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/relax_acquire_race.rs:LL:CC diff --git a/tests/fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr index 777bc4adad..f398825b59 100644 --- a/tests/fail/data_race/release_seq_race.stderr +++ b/tests/fail/data_race/release_seq_race.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `` LL | *c.0 | ^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Read on thread `` is here + --> $DIR/release_seq_race.rs:LL:CC + | +LL | *c.0 + | ^^^^ +help: The Write on thread `` is here + --> $DIR/release_seq_race.rs:LL:CC + | +LL | *c.0 = 1; + | ^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/release_seq_race.rs:LL:CC diff --git a/tests/fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr index 0fcb192d92..9a395923ff 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `` LL | *c.0 | ^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Read on thread `` is here + --> $DIR/release_seq_race_same_thread.rs:LL:CC + | +LL | *c.0 + | ^^^^ +help: The Write on thread `` is here + --> $DIR/release_seq_race_same_thread.rs:LL:CC + | +LL | *c.0 = 1; + | ^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/release_seq_race_same_thread.rs:LL:CC diff --git a/tests/fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr index 3ae6f3b84f..f90ddf0b5b 100644 --- a/tests/fail/data_race/rmw_race.stderr +++ b/tests/fail/data_race/rmw_race.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `` LL | *c.0 | ^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Read on thread `` is here + --> $DIR/rmw_race.rs:LL:CC + | +LL | *c.0 + | ^^^^ +help: The Write on thread `` is here + --> $DIR/rmw_race.rs:LL:CC + | +LL | *c.0 = 1; + | ^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/rmw_race.rs:LL:CC diff --git a/tests/fail/data_race/stack_pop_race.stderr b/tests/fail/data_race/stack_pop_race.stderr index 5de27108ab..d0c4bd10b4 100644 --- a/tests/fail/data_race/stack_pop_race.stderr +++ b/tests/fail/data_race/stack_pop_race.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Deallocate on thread `main LL | } | ^ Data race detected between Deallocate on thread `main` and Read on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Deallocate on thread `main` is here + --> $DIR/stack_pop_race.rs:LL:CC + | +LL | } + | ^ +help: The Read on thread `` is here + --> $DIR/stack_pop_race.rs:LL:CC + | +LL | let ptr = ptr; + | ^^^ = note: BACKTRACE: = note: inside `race` at $DIR/stack_pop_race.rs:LL:CC note: inside `main` at $DIR/stack_pop_race.rs:LL:CC diff --git a/tests/fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr index ee7072ccf5..62e97b1477 100644 --- a/tests/fail/data_race/write_write_race.stderr +++ b/tests/fail/data_race/write_write_race.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread ` LL | *c.0 = 64; | ^^^^^^^^^ Data race detected between Write on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Write on thread `` is here + --> $DIR/write_write_race.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ +help: The Write on thread `` is here + --> $DIR/write_write_race.rs:LL:CC + | +LL | *c.0 = 32; + | ^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/write_write_race.rs:LL:CC diff --git a/tests/fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr index ceb473c2a4..998763694a 100644 --- a/tests/fail/data_race/write_write_race_stack.stderr +++ b/tests/fail/data_race/write_write_race_stack.stderr @@ -4,8 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread ` LL | stack_var = 1usize; | ^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `` and Write on thread `` at ALLOC | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: The Write on thread `` is here + --> $DIR/write_write_race_stack.rs:LL:CC + | +LL | stack_var = 1usize; + | ^^^^^^^^^^^^^^^^^^ +help: The Write on thread `` is here + --> $DIR/write_write_race_stack.rs:LL:CC + | +LL | *pointer.load(Ordering::Acquire) = 3; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE: = note: inside closure at $DIR/write_write_race_stack.rs:LL:CC