Include a Span in VClock
This commit is contained in:
parent
e82a604a88
commit
d1184ae58d
src/tools/miri
src
tests/fail
data_race
alloc_read_race.stderralloc_write_race.stderratomic_read_na_write_race1.stderratomic_read_na_write_race2.stderratomic_write_na_read_race1.stderratomic_write_na_read_race2.stderratomic_write_na_write_race1.stderratomic_write_na_write_race2.stderrdangling_thread_async_race.stderrdangling_thread_race.stderrdealloc_read_race1.stderrdealloc_read_race_stack.stderrdealloc_write_race1.stderrdealloc_write_race_stack.stderrenable_after_join_to_main.stderrfence_after_load.stderrread_write_race.stderrread_write_race_stack.stderrrelax_acquire_race.stderrrelease_seq_race.stderrrelease_seq_race_same_thread.stderrrmw_race.stderrstack_pop_race.stderrwrite_write_race.stderrwrite_write_race_stack.stderr
stacked_borrows
@ -50,8 +50,11 @@
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_middle::mir;
|
||||
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 @@ fn apply_acquire_fence(&mut self) {
|
||||
/// 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 @@ fn atomic_read_detect(
|
||||
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 @@ fn atomic_write_detect(
|
||||
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 @@ fn atomic_write_detect(
|
||||
/// 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 {
|
||||
@ -621,30 +633,35 @@ fn atomic_compare_exchange_scalar(
|
||||
/// 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();
|
||||
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);
|
||||
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());
|
||||
}
|
||||
// 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(())
|
||||
}
|
||||
@ -682,6 +699,7 @@ pub fn new_allocation(
|
||||
thread_mgr: &ThreadManager<'_, '_>,
|
||||
len: Size,
|
||||
kind: MemoryKind<MiriMemoryKind>,
|
||||
current_span: Span,
|
||||
) -> VClockAlloc {
|
||||
let (alloc_timestamp, alloc_index) = match kind {
|
||||
// User allocated and stack memory should track allocation.
|
||||
@ -693,7 +711,10 @@ pub fn new_allocation(
|
||||
)
|
||||
| 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.
|
||||
@ -704,7 +725,7 @@ pub fn new_allocation(
|
||||
| MiriMemoryKind::ExternStatic
|
||||
| MiriMemoryKind::Tls,
|
||||
)
|
||||
| MemoryKind::CallerLocation => (0, VectorIdx::MAX_INDEX),
|
||||
| MemoryKind::CallerLocation => (VTimestamp::NONE, VectorIdx::MAX_INDEX),
|
||||
};
|
||||
VClockAlloc {
|
||||
alloc_ranges: RefCell::new(RangeMap::new(
|
||||
@ -735,7 +756,7 @@ fn find_gt_index(l: &VClock, r: &VClock) -> Option<VectorIdx> {
|
||||
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 {
|
||||
@ -762,7 +783,7 @@ fn report_data_race<'tcx>(
|
||||
) -> 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
|
||||
@ -799,14 +820,19 @@ fn report_data_race<'tcx>(
|
||||
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)
|
||||
@ -840,12 +866,14 @@ pub fn read<'tcx>(
|
||||
range: AllocRange,
|
||||
machine: &MiriMachine<'_, '_>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let current_span = machine.current_span();
|
||||
let global = machine.data_race.as_ref().unwrap();
|
||||
if global.race_detecting() {
|
||||
let (index, clocks) = global.current_thread_state(&machine.threads);
|
||||
let (index, mut clocks) = global.current_thread_state_mut(&machine.threads);
|
||||
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,
|
||||
@ -871,11 +899,15 @@ fn unique_access<'tcx>(
|
||||
write_type: WriteType,
|
||||
machine: &mut MiriMachine<'_, '_>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let current_span = machine.current_span();
|
||||
let global = machine.data_race.as_mut().unwrap();
|
||||
if global.race_detecting() {
|
||||
let (index, clocks) = global.current_thread_state(&machine.threads);
|
||||
let (index, mut clocks) = global.current_thread_state_mut(&machine.threads);
|
||||
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,
|
||||
@ -1100,6 +1132,7 @@ fn validate_atomic_op<A: Debug + Copy>(
|
||||
size.bytes()
|
||||
);
|
||||
|
||||
let current_span = this.machine.current_span();
|
||||
// Perform the atomic operation.
|
||||
data_race.maybe_perform_sync_operation(
|
||||
&this.machine.threads,
|
||||
@ -1124,6 +1157,7 @@ fn validate_atomic_op<A: Debug + Copy>(
|
||||
// This conservatively assumes all operations have release semantics
|
||||
Ok(true)
|
||||
},
|
||||
current_span,
|
||||
)?;
|
||||
|
||||
// Log changes to atomic memory.
|
||||
@ -1303,7 +1337,12 @@ fn find_vector_index_reuse_candidate(&self) -> Option<VectorIdx> {
|
||||
// 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
|
||||
@ -1320,7 +1359,7 @@ pub fn thread_created(&mut self, thread_mgr: &ThreadManager<'_, '_>, thread: Thr
|
||||
// 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.
|
||||
@ -1360,8 +1399,8 @@ pub fn thread_created(&mut self, thread_mgr: &ThreadManager<'_, '_>, thread: Thr
|
||||
|
||||
// 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
|
||||
@ -1427,13 +1466,13 @@ pub fn thread_joined(
|
||||
/// 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();
|
||||
@ -1463,12 +1502,13 @@ fn maybe_perform_sync_operation<'tcx>(
|
||||
&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(())
|
||||
@ -1501,10 +1541,10 @@ pub fn validate_lock_acquire(&self, lock: &VClock, thread: ThreadId) {
|
||||
/// 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
|
||||
@ -1514,10 +1554,15 @@ pub fn validate_lock_release(&self, lock: &mut VClock, thread: ThreadId) {
|
||||
/// 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
|
||||
|
@ -160,6 +160,7 @@ fn init_once_begin(&mut self, id: InitOnceId) {
|
||||
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();
|
||||
let init_once = &mut this.machine.threads.sync.init_onces[id];
|
||||
|
||||
assert_eq!(
|
||||
@ -172,7 +173,7 @@ fn init_once_complete(&mut self, id: InitOnceId) -> InterpResult<'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.
|
||||
@ -188,6 +189,7 @@ fn init_once_complete(&mut self, id: InitOnceId) -> InterpResult<'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();
|
||||
let init_once = &mut this.machine.threads.sync.init_onces[id];
|
||||
assert_eq!(
|
||||
init_once.status,
|
||||
@ -197,7 +199,7 @@ fn init_once_fail(&mut self, id: InitOnceId) -> InterpResult<'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 one waiting thread, so they can go ahead and try to init this.
|
||||
|
@ -359,6 +359,7 @@ fn mutex_lock(&mut self, id: MutexId, thread: ThreadId) {
|
||||
/// return `None`.
|
||||
fn mutex_unlock(&mut self, id: MutexId, expected_owner: ThreadId) -> Option<usize> {
|
||||
let this = self.eval_context_mut();
|
||||
let current_span = this.machine.current_span();
|
||||
let mutex = &mut this.machine.threads.sync.mutexes[id];
|
||||
if let Some(current_owner) = mutex.owner {
|
||||
// Mutex is locked.
|
||||
@ -375,7 +376,11 @@ fn mutex_unlock(&mut self, id: MutexId, expected_owner: ThreadId) -> Option<usiz
|
||||
// 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);
|
||||
}
|
||||
@ -454,6 +459,7 @@ fn rwlock_reader_lock(&mut self, id: RwLockId, reader: ThreadId) {
|
||||
/// 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();
|
||||
let rwlock = &mut this.machine.threads.sync.rwlocks[id];
|
||||
match rwlock.readers.entry(reader) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
@ -470,7 +476,11 @@ fn rwlock_reader_unlock(&mut self, id: RwLockId, reader: ThreadId) -> bool {
|
||||
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.
|
||||
@ -511,6 +521,7 @@ fn rwlock_writer_lock(&mut self, id: RwLockId, writer: ThreadId) {
|
||||
#[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();
|
||||
let rwlock = &mut this.machine.threads.sync.rwlocks[id];
|
||||
if let Some(current_writer) = rwlock.writer {
|
||||
if current_writer != expected_writer {
|
||||
@ -523,8 +534,16 @@ fn rwlock_writer_unlock(&mut self, id: RwLockId, expected_writer: ThreadId) -> b
|
||||
// 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.
|
||||
//
|
||||
@ -595,12 +614,13 @@ fn condvar_wait(&mut self, id: CondvarId, thread: ThreadId, lock: CondvarLock) {
|
||||
fn condvar_signal(&mut self, id: CondvarId) -> Option<(ThreadId, CondvarLock)> {
|
||||
let this = self.eval_context_mut();
|
||||
let current_thread = this.get_active_thread();
|
||||
let current_span = this.machine.current_span();
|
||||
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 {
|
||||
@ -628,12 +648,13 @@ fn futex_wait(&mut self, addr: u64, thread: ThreadId, bitset: u32) {
|
||||
fn futex_wake(&mut self, addr: u64, bitset: u32) -> Option<ThreadId> {
|
||||
let this = self.eval_context_mut();
|
||||
let current_thread = this.get_active_thread();
|
||||
let current_span = this.machine.current_span();
|
||||
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.
|
||||
|
@ -13,6 +13,7 @@
|
||||
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;
|
||||
@ -617,6 +618,7 @@ fn get_ready_callback(
|
||||
fn thread_terminated(
|
||||
&mut self,
|
||||
mut data_race: Option<&mut data_race::GlobalState>,
|
||||
current_span: Span,
|
||||
) -> Vec<Pointer<Provenance>> {
|
||||
let mut free_tls_statics = Vec::new();
|
||||
{
|
||||
@ -634,7 +636,7 @@ fn thread_terminated(
|
||||
}
|
||||
// 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
|
||||
@ -813,8 +815,9 @@ fn start_regular_thread(
|
||||
let mut state = tls::TlsDtorsState::default();
|
||||
Box::new(move |m| state.on_stack_empty(m))
|
||||
});
|
||||
let current_span = this.machine.current_span();
|
||||
if let Some(data_race) = &mut this.machine.data_race {
|
||||
data_race.thread_created(&this.machine.threads, new_thread_id);
|
||||
data_race.thread_created(&this.machine.threads, new_thread_id, current_span);
|
||||
}
|
||||
|
||||
// Write the current thread-id, switch to the next thread later
|
||||
@ -1041,7 +1044,10 @@ fn terminate_active_thread(&mut self) -> InterpResult<'tcx> {
|
||||
assert!(thread.stack.is_empty(), "only threads with an empty stack can be terminated");
|
||||
thread.state = ThreadState::Terminated;
|
||||
|
||||
for ptr in this.machine.threads.thread_terminated(this.machine.data_race.as_mut()) {
|
||||
let current_span = this.machine.current_span();
|
||||
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(())
|
||||
|
@ -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 @@ fn from(id: u32) -> Self {
|
||||
|
||||
/// 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<Ordering> {
|
||||
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 @@ pub fn as_slice(&self) -> &[VTimestamp] {
|
||||
#[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 @@ fn get_mut_with_min_len(&mut self, min_len: usize) -> &mut [VTimestamp] {
|
||||
/// 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 @@ pub fn join(&mut self, other: &Self) {
|
||||
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<VectorIdx> 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<VectorIdx> 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 @@ fn index(&self, index: VectorIdx) -> &VTimestamp {
|
||||
#[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
|
||||
@ -449,4 +512,5 @@ fn assert_order(l: &[VTimestamp], r: &[VTimestamp], o: Option<Ordering>) {
|
||||
"Invalid alt (>=):\n l: {l:?}\n r: {r:?}"
|
||||
);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
@ -258,7 +258,7 @@ fn new(init: Scalar<Provenance>) -> Self {
|
||||
// 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()),
|
||||
|
@ -35,6 +35,17 @@ pub enum TerminationInfo {
|
||||
link_name: Symbol,
|
||||
span: SpanData,
|
||||
},
|
||||
DataRace {
|
||||
op1: RacingOp,
|
||||
op2: RacingOp,
|
||||
ptr: Pointer,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct RacingOp {
|
||||
pub action: String,
|
||||
pub thread_info: String,
|
||||
pub span: SpanData,
|
||||
}
|
||||
|
||||
impl fmt::Display for TerminationInfo {
|
||||
@ -55,6 +66,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
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,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -167,7 +184,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,
|
||||
};
|
||||
@ -205,6 +222,13 @@ 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)),
|
||||
(None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
|
||||
(None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
|
||||
],
|
||||
_ => vec![],
|
||||
};
|
||||
(title, helps)
|
||||
|
@ -956,6 +956,7 @@ fn adjust_allocation<'b>(
|
||||
&ecx.machine.threads,
|
||||
alloc.size(),
|
||||
kind,
|
||||
ecx.machine.current_span(),
|
||||
)
|
||||
});
|
||||
let buffer_alloc = ecx.machine.weak_memory.then(weak_memory::AllocState::new_allocation);
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `<unnamed>`
|
||||
LL | *pointer.load(Ordering::Relaxed)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on thread `<unnamed>` and Allocate on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> $DIR/alloc_read_race.rs:LL:CC
|
||||
|
|
||||
LL | ... *pointer.load(Ordering::Relaxed)
|
||||
| ^
|
||||
help: The Allocate on thread `<unnamed>` is here
|
||||
--> $DIR/alloc_read_race.rs:LL:CC
|
||||
|
|
||||
LL | pointer.store(Box::into_raw(Box::new_uninit()), Ordering::Relaxed);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread `<unnamed>
|
||||
LL | *pointer.load(Ordering::Relaxed) = 2;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `<unnamed>` and Allocate on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/alloc_write_race.rs:LL:CC
|
||||
|
|
||||
LL | ... *pointer.load(Ordering::Relaxed) = 2;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: The Allocate on thread `<unnamed>` is here
|
||||
--> $DIR/alloc_write_race.rs:LL:CC
|
||||
|
|
||||
LL | .store(Box::into_raw(Box::<usize>::new_uninit()) as *mut usize, Ordering::Relaxed);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Atomic Load on thread `<un
|
||||
LL | (&*c.0).load(Ordering::SeqCst)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Atomic Load on thread `<unnamed>` is here
|
||||
--> $DIR/atomic_read_na_write_race1.rs:LL:CC
|
||||
|
|
||||
LL | ... (&*c.0).load(Ordering::SeqCst)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/atomic_read_na_write_race1.rs:LL:CC
|
||||
|
|
||||
LL | *(c.0 as *mut usize) = 32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread `<unnamed>
|
||||
LL | *atomic_ref.get_mut() = 32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `<unnamed>` and Atomic Load on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/atomic_read_na_write_race2.rs:LL:CC
|
||||
|
|
||||
LL | ... *atomic_ref.get_mut() = 32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: The Atomic Load on thread `<unnamed>` is here
|
||||
--> $DIR/atomic_read_na_write_race2.rs:LL:CC
|
||||
|
|
||||
LL | atomic_ref.load(Ordering::SeqCst)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `<unnamed>`
|
||||
LL | *atomic_ref.get_mut()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on thread `<unnamed>` and Atomic Store on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> RUSTLIB/core/src/ptr/mod.rs:LL:CC
|
||||
|
|
||||
LL | }
|
||||
| ^
|
||||
help: The Atomic Store on thread `<unnamed>` is here
|
||||
--> $DIR/atomic_write_na_read_race1.rs:LL:CC
|
||||
|
|
||||
LL | atomic_ref.store(32, Ordering::SeqCst)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Atomic Store on thread `<u
|
||||
LL | (&*c.0).store(32, Ordering::SeqCst);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on thread `<unnamed>` and Read on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Atomic Store on thread `<unnamed>` is here
|
||||
--> $DIR/atomic_write_na_read_race2.rs:LL:CC
|
||||
|
|
||||
LL | ... (&*c.0).store(32, Ordering::SeqCst);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> RUSTLIB/core/src/ptr/mod.rs:LL:CC
|
||||
|
|
||||
LL | }
|
||||
| ^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Atomic Store on thread `<u
|
||||
LL | (&*c.0).store(64, Ordering::SeqCst);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Atomic Store on thread `<unnamed>` is here
|
||||
--> $DIR/atomic_write_na_write_race1.rs:LL:CC
|
||||
|
|
||||
LL | ... (&*c.0).store(64, Ordering::SeqCst);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/atomic_write_na_write_race1.rs:LL:CC
|
||||
|
|
||||
LL | *(c.0 as *mut usize) = 32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread `<unnamed>
|
||||
LL | *atomic_ref.get_mut() = 32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `<unnamed>` and Atomic Store on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/atomic_write_na_write_race2.rs:LL:CC
|
||||
|
|
||||
LL | ... *atomic_ref.get_mut() = 32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: The Atomic Store on thread `<unnamed>` is here
|
||||
--> $DIR/atomic_write_na_write_race2.rs:LL:CC
|
||||
|
|
||||
LL | atomic_ref.store(64, Ordering::SeqCst);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread `<unnamed>
|
||||
LL | *c.0 = 64;
|
||||
| ^^^^^^^^^ Data race detected between Write on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/dangling_thread_async_race.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 64;
|
||||
| ^^^^^^^^^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/dangling_thread_async_race.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 32;
|
||||
| ^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +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 `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Write on thread `main` is here
|
||||
--> $DIR/dangling_thread_race.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 64;
|
||||
| ^^^^^^^^^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/dangling_thread_race.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 32;
|
||||
| ^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -9,6 +9,21 @@ LL | | std::mem::align_of::<usize>(),
|
||||
LL | | );
|
||||
| |_____________^ Data race detected between Deallocate on thread `<unnamed>` and Read on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Deallocate on thread `<unnamed>` is here
|
||||
--> $DIR/dealloc_read_race1.rs:LL:CC
|
||||
|
|
||||
LL | / __rust_dealloc(
|
||||
LL | |
|
||||
LL | | ptr.0 as *mut _,
|
||||
LL | | std::mem::size_of::<usize>(),
|
||||
LL | | std::mem::align_of::<usize>(),
|
||||
LL | | );
|
||||
| |_____________^
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> RUSTLIB/core/src/ptr/mod.rs:LL:CC
|
||||
|
|
||||
LL | }
|
||||
| ^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Deallocate on thread `<unn
|
||||
LL | }
|
||||
| ^ Data race detected between Deallocate on thread `<unnamed>` and Read on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Deallocate on thread `<unnamed>` is here
|
||||
--> $DIR/dealloc_read_race_stack.rs:LL:CC
|
||||
|
|
||||
LL | }
|
||||
| ^
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> $DIR/dealloc_read_race_stack.rs:LL:CC
|
||||
|
|
||||
LL | *pointer.load(Ordering::Acquire)
|
||||
| ^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -9,6 +9,21 @@ LL | | std::mem::align_of::<usize>(),
|
||||
LL | | );
|
||||
| |_____________^ Data race detected between Deallocate on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Deallocate on thread `<unnamed>` is here
|
||||
--> $DIR/dealloc_write_race1.rs:LL:CC
|
||||
|
|
||||
LL | / __rust_dealloc(
|
||||
LL | |
|
||||
LL | | ptr.0 as *mut _,
|
||||
LL | | std::mem::size_of::<usize>(),
|
||||
LL | | std::mem::align_of::<usize>(),
|
||||
LL | | );
|
||||
| |_____________^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/dealloc_write_race1.rs:LL:CC
|
||||
|
|
||||
LL | *ptr.0 = 2;
|
||||
| ^^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Deallocate on thread `<unn
|
||||
LL | }
|
||||
| ^ Data race detected between Deallocate on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Deallocate on thread `<unnamed>` is here
|
||||
--> $DIR/dealloc_write_race_stack.rs:LL:CC
|
||||
|
|
||||
LL | }
|
||||
| ^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/dealloc_write_race_stack.rs:LL:CC
|
||||
|
|
||||
LL | *pointer.load(Ordering::Acquire) = 3;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread `<unnamed>
|
||||
LL | *c.0 = 64;
|
||||
| ^^^^^^^^^ Data race detected between Write on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/enable_after_join_to_main.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 64;
|
||||
| ^^^^^^^^^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/enable_after_join_to_main.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 32;
|
||||
| ^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +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 `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Write on thread `main` is here
|
||||
--> $DIR/fence_after_load.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { V = 2 }
|
||||
| ^^^^^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/fence_after_load.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { V = 1 }
|
||||
| ^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread `<unnamed>
|
||||
LL | *c.0 = 64;
|
||||
| ^^^^^^^^^ Data race detected between Write on thread `<unnamed>` and Read on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/read_write_race.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 64;
|
||||
| ^^^^^^^^^
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> RUSTLIB/core/src/ptr/mod.rs:LL:CC
|
||||
|
|
||||
LL | }
|
||||
| ^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `<unnamed>`
|
||||
LL | stack_var
|
||||
| ^^^^^^^^^ Data race detected between Read on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> $DIR/read_write_race_stack.rs:LL:CC
|
||||
|
|
||||
LL | sleep(Duration::from_millis(200));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/read_write_race_stack.rs:LL:CC
|
||||
|
|
||||
LL | *pointer.load(Ordering::Acquire) = 3;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `<unnamed>`
|
||||
LL | *c.0
|
||||
| ^^^^ Data race detected between Read on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> $DIR/relax_acquire_race.rs:LL:CC
|
||||
|
|
||||
LL | if SYNC.load(Ordering::Acquire) == 2 {
|
||||
| ^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/relax_acquire_race.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 1;
|
||||
| ^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `<unnamed>`
|
||||
LL | *c.0
|
||||
| ^^^^ Data race detected between Read on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> $DIR/release_seq_race.rs:LL:CC
|
||||
|
|
||||
LL | if SYNC.load(Ordering::Acquire) == 3 {
|
||||
| ^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/release_seq_race.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 1;
|
||||
| ^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `<unnamed>`
|
||||
LL | *c.0
|
||||
| ^^^^ Data race detected between Read on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> $DIR/release_seq_race_same_thread.rs:LL:CC
|
||||
|
|
||||
LL | if SYNC.load(Ordering::Acquire) == 2 {
|
||||
| ^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/release_seq_race_same_thread.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 1;
|
||||
| ^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Read on thread `<unnamed>`
|
||||
LL | *c.0
|
||||
| ^^^^ Data race detected between Read on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> $DIR/rmw_race.rs:LL:CC
|
||||
|
|
||||
LL | if SYNC.load(Ordering::Acquire) == 3 {
|
||||
| ^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/rmw_race.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 1;
|
||||
| ^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +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 `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Deallocate on thread `main` is here
|
||||
--> $DIR/stack_pop_race.rs:LL:CC
|
||||
|
|
||||
LL | }
|
||||
| ^
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> RUSTLIB/core/src/ptr/mod.rs:LL:CC
|
||||
|
|
||||
LL | }
|
||||
| ^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread `<unnamed>
|
||||
LL | *c.0 = 64;
|
||||
| ^^^^^^^^^ Data race detected between Write on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/write_write_race.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 64;
|
||||
| ^^^^^^^^^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/write_write_race.rs:LL:CC
|
||||
|
|
||||
LL | *c.0 = 32;
|
||||
| ^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread `<unnamed>
|
||||
LL | stack_var = 1usize;
|
||||
| ^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/write_write_race_stack.rs:LL:CC
|
||||
|
|
||||
LL | stack_var = 1usize;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/write_write_race_stack.rs:LL:CC
|
||||
|
|
||||
LL | *pointer.load(Ordering::Acquire) = 3;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread `<unnamed>
|
||||
LL | *p = 5;
|
||||
| ^^^^^^ Data race detected between Write on thread `<unnamed>` and Read on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/retag_data_race_read.rs:LL:CC
|
||||
|
|
||||
LL | *p = 5;
|
||||
| ^^^^^^
|
||||
help: The Read on thread `<unnamed>` is here
|
||||
--> $DIR/retag_data_race_read.rs:LL:CC
|
||||
|
|
||||
LL | let t1 = std::thread::spawn(move || thread_1(p));
|
||||
| ^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
@ -4,6 +4,16 @@ error: Undefined Behavior: Data race detected between Write on thread `<unnamed>
|
||||
LL | *p = 5;
|
||||
| ^^^^^^ Data race detected between Write on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
||||
|
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/retag_data_race_write.rs:LL:CC
|
||||
|
|
||||
LL | *p = 5;
|
||||
| ^^^^^^
|
||||
help: The Write on thread `<unnamed>` is here
|
||||
--> $DIR/retag_data_race_write.rs:LL:CC
|
||||
|
|
||||
LL | let _r = &mut *p;
|
||||
| ^^^^^^^
|
||||
= 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
|
||||
= note: BACKTRACE:
|
||||
|
Loading…
Reference in New Issue
Block a user