Skip to content

Commit aaf8ca4

Browse files
committed
Fix review changes
1 parent 4e74f9f commit aaf8ca4

16 files changed

+107
-21
lines changed

src/data_race.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
//! Relaxed stores now unconditionally block all currently active release sequences and so per-thread tracking of release
1010
//! sequences is not needed.
1111
//!
12+
//! The implementation also models races with memory allocation and deallocation via treating allocation and
13+
//! deallocation as a type of write internally for detecting data-races.
14+
//!
1215
//! This does not explore weak memory orders and so can still miss data-races
1316
//! but should not report false-positives
1417
//!
@@ -192,13 +195,22 @@ struct AtomicMemoryCellClocks {
192195
sync_vector: VClock,
193196
}
194197

198+
/// Type of write operation: allocating memory
199+
/// non-atomic writes and deallocating memory
200+
/// are all treated as writes for the purpose
201+
/// of the data-race detector.
195202
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
196203
enum WriteType {
197204
/// Allocate memory.
198205
Allocate,
206+
199207
/// Standard unsynchronized write.
200208
Write,
201-
/// Deallocate memory
209+
210+
/// Deallocate memory.
211+
/// Some races with deallocation will be missed and instead
212+
/// reported as invalid accesses of freed memory due to
213+
/// the order of checks.
202214
Deallocate,
203215
}
204216
impl WriteType {
@@ -681,7 +693,7 @@ impl VClockAlloc {
681693
let (alloc_index, clocks) = global.current_thread_state();
682694
let alloc_timestamp = clocks.clock[alloc_index];
683695
(alloc_timestamp, alloc_index)
684-
}else{
696+
} else {
685697
(0, VectorIdx::MAX_INDEX)
686698
};
687699
VClockAlloc {
@@ -695,7 +707,7 @@ impl VClockAlloc {
695707
// Find an index, if one exists where the value
696708
// in `l` is greater than the value in `r`.
697709
fn find_gt_index(l: &VClock, r: &VClock) -> Option<VectorIdx> {
698-
log::info!("Find index where not {:?} <= {:?}", l, r);
710+
log::trace!("Find index where not {:?} <= {:?}", l, r);
699711
let l_slice = l.as_slice();
700712
let r_slice = r.as_slice();
701713
l_slice
@@ -1168,7 +1180,7 @@ impl GlobalState {
11681180
vector_info.push(thread)
11691181
};
11701182

1171-
log::info!("Creating thread = {:?} with vector index = {:?}", thread, created_index);
1183+
log::trace!("Creating thread = {:?} with vector index = {:?}", thread, created_index);
11721184

11731185
// Mark the chosen vector index as in use by the thread.
11741186
thread_info[thread].vector_index = Some(created_index);

src/machine.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
480480
let race_alloc = if let Some(data_race) = &memory_extra.data_race {
481481
match kind {
482482
// V-Table generation is lazy and so racy, so do not track races.
483-
// Also V-Tables are read only so no data races can be detected.
483+
// Also V-Tables are read only so no data races can be occur.
484+
// Must be disabled since V-Tables are initialized via interpreter
485+
// writes on demand and can incorrectly cause the data-race detector
486+
// to trigger.
484487
MemoryKind::Vtable => None,
485488
// User allocated and stack memory should track allocation.
486489
MemoryKind::Machine(

tests/compile-fail/data_race/alloc_read_race.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::thread::spawn;
44
use std::ptr::null_mut;
55
use std::sync::atomic::{Ordering, AtomicPtr};
6+
use std::mem::MaybeUninit;
67

78
#[derive(Copy, Clone)]
89
struct EvilSend<T>(pub T);
@@ -12,8 +13,8 @@ unsafe impl<T> Sync for EvilSend<T> {}
1213

1314
pub fn main() {
1415
// Shared atomic pointer
15-
let pointer = AtomicPtr::new(null_mut::<usize>());
16-
let ptr = EvilSend(&pointer as *const AtomicPtr<usize>);
16+
let pointer = AtomicPtr::new(null_mut::<MaybeUninit<usize>>());
17+
let ptr = EvilSend(&pointer as *const AtomicPtr<MaybeUninit<usize>>);
1718

1819
// Note: this is scheduler-dependent
1920
// the operations need to occur in
@@ -28,14 +29,14 @@ pub fn main() {
2829
// Uses relaxed semantics to not generate
2930
// a release sequence.
3031
let pointer = &*ptr.0;
31-
pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed);
32+
pointer.store(Box::into_raw(Box::new(MaybeUninit::uninit())), Ordering::Relaxed);
3233
});
3334

3435
let j2 = spawn(move || {
3536
let pointer = &*ptr.0;
3637

37-
//Note detects with write due to the initialization of memory
38-
*pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1)
38+
// Note: could also error due to reading uninitialized memory, but the data-race detector triggers first.
39+
*pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1)
3940
});
4041

4142
j1.join().unwrap();

tests/compile-fail/data_race/dangling_thread_async_race.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn main() {
2626

2727
// Detach the thread and sleep until it terminates
2828
mem::drop(join);
29-
sleep(Duration::from_millis(1000));
29+
sleep(Duration::from_millis(200));
3030

3131
// Spawn and immediately join a thread
3232
// to execute the join code-path

tests/compile-fail/data_race/dangling_thread_race.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ fn main() {
2424
})
2525
};
2626

27-
// Detatch the thread and sleep until it terminates
27+
// Detach the thread and sleep until it terminates
2828
mem::drop(join);
29-
sleep(Duration::from_millis(1000));
29+
sleep(Duration::from_millis(200));
3030

3131
// Spawn and immediately join a thread
3232
// to execute the join code-path
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// ignore-windows: Concurrency on Windows is not supported yet.
2+
3+
use std::thread::spawn;
4+
5+
#[derive(Copy, Clone)]
6+
struct EvilSend<T>(pub T);
7+
8+
unsafe impl<T> Send for EvilSend<T> {}
9+
unsafe impl<T> Sync for EvilSend<T> {}
10+
11+
extern "Rust" {
12+
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
13+
}
14+
15+
pub fn main() {
16+
// Shared atomic pointer
17+
let pointer: *mut usize = Box::into_raw(Box::new(0usize));
18+
let ptr = EvilSend(pointer);
19+
20+
unsafe {
21+
let j1 = spawn(move || {
22+
__rust_dealloc(ptr.0 as *mut _, std::mem::size_of::<usize>(), std::mem::align_of::<usize>())
23+
});
24+
25+
let j2 = spawn(move || {
26+
// Also an error of the form: Data race detected between Read on Thread(id = 2) and Deallocate on Thread(id = 1)
27+
// but the invalid allocation is detected first.
28+
*ptr.0 //~ ERROR dereferenced after this allocation got freed
29+
});
30+
31+
j1.join().unwrap();
32+
j2.join().unwrap();
33+
}
34+
}

tests/compile-fail/data_race/dealloc_read_race_stack.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub fn main() {
3636

3737
pointer.store(&mut stack_var as *mut _, Ordering::Release);
3838

39-
sleep(Duration::from_millis(1000));
39+
sleep(Duration::from_millis(200));
4040

4141
} //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2)
4242
});

tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub fn main() {
3636

3737
pointer.store(&mut stack_var as *mut _, Ordering::Release);
3838

39-
sleep(Duration::from_millis(1000));
39+
sleep(Duration::from_millis(200));
4040

4141
drop(stack_var);
4242
}); //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2)

0 commit comments

Comments
 (0)