Description
The following tests capture some of the interactions between aliasing and concurrency.
While the optimizations below may introduce a data-race, any such execution is undefined due to aliasing violations: they'd need to access memory through a reference that's not derived from the &mut
.
I don't see any immediate harm in these being allowed, but I found these being allowed by Rust and LLVM-IR interesting, to say the least.
The comments capture what I believe is the "status-quo", everyone should decide for themselves whether they think those executions should be allowed or forbidden:
pub fn test0(b: &mut u32){
loop {
let a = AtomicU32::from_mut(b);
if a.load(Ordering::Relaxed) != 0 { // may be downgraded to non-atomic access
break;
}
}
*b = 42;
}
pub fn test1(b: &mut u32) -> u32 {
let x = *b;
fence(Ordering::Release); // may be re-ordered above load; analogous for store-release
x
}
pub fn test2(b: &mut u32) {
*b = 42;
fence(Ordering::Release); // may be re-ordered above store; analogous for store-release
}
pub fn test3(b: &mut u32) {
fence(Ordering::Acquire); // analogous for load-acquire
*b = 42; // may be re-ordered above fence
}
pub fn test4(b: &mut u32) -> u32 {
fence(Ordering::Acquire); // analogous for load-acquire
*b // may be re-ordered above fence
}
The examples above are very simple and don't involve allocation APIs.
The following references include many other examples, some of which may be interesting to adapt to Rust.
Particularly interesting are those involving concurrency and "lifetime start"/"end" (memory being allocated/deallocated).
- Sung-Hwan Lee reported: A miscompilation bug in LICMPass (concurrency) llvm/llvm-project#64188
- Hans Boehm: memory_order_relaxed and optimizations
- David Goldblatt: P3292
- Stephen Dolan: https://www.youtube.com/watch?v=cILLfXBBITg