ensure atomics happen on mutable allocations, and fix futex test
This commit is contained in:
parent
d630671a33
commit
cd2edbfd09
@ -46,6 +46,7 @@
|
|||||||
mem,
|
mem,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use rustc_ast::Mutability;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
use rustc_middle::{mir, ty::layout::TyAndLayout};
|
use rustc_middle::{mir, ty::layout::TyAndLayout};
|
||||||
@ -476,6 +477,17 @@ fn atomic_access_check(&self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResul
|
|||||||
align,
|
align,
|
||||||
CheckInAllocMsg::MemoryAccessTest,
|
CheckInAllocMsg::MemoryAccessTest,
|
||||||
)?;
|
)?;
|
||||||
|
// Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable
|
||||||
|
// memory on many targets (i.e., they segfault if taht memory is mapped read-only), and
|
||||||
|
// atomic loads can be implemented via compare_exchange on some targets. See
|
||||||
|
// <https://github.com/rust-lang/miri/issues/2463>.
|
||||||
|
// We avoid `get_ptr_alloc` since we do *not* want to run the access hooks -- the actual
|
||||||
|
// access will happen later.
|
||||||
|
let (alloc_id, _offset, _prov) =
|
||||||
|
this.ptr_try_get_alloc_id(place.ptr).expect("there are no zero-sized atomic accesses");
|
||||||
|
if this.get_alloc_mutability(alloc_id)? == Mutability::Not {
|
||||||
|
throw_ub_format!("atomic operations cannot be performed on read-only memory");
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
tests/fail/concurrency/read_only_atomic_cmpxchg.rs
Normal file
11
tests/fail/concurrency/read_only_atomic_cmpxchg.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Should not rely on the aliasing model for its failure.
|
||||||
|
//@compile-flags: -Zmiri-disable-stacked-borrows
|
||||||
|
|
||||||
|
use std::sync::atomic::{AtomicI32, Ordering};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
static X: i32 = 0;
|
||||||
|
let x = &X as *const i32 as *const AtomicI32;
|
||||||
|
let x = unsafe { &*x };
|
||||||
|
x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed).unwrap_err(); //~ERROR: atomic operations cannot be performed on read-only memory
|
||||||
|
}
|
15
tests/fail/concurrency/read_only_atomic_cmpxchg.stderr
Normal file
15
tests/fail/concurrency/read_only_atomic_cmpxchg.stderr
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
error: Undefined Behavior: atomic operations cannot be performed on read-only memory
|
||||||
|
--> $DIR/read_only_atomic_cmpxchg.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed).unwrap_err();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ atomic operations cannot be performed on read-only memory
|
||||||
|
|
|
||||||
|
= 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:
|
||||||
|
= note: inside `main` at $DIR/read_only_atomic_cmpxchg.rs:LL:CC
|
||||||
|
|
||||||
|
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
13
tests/fail/concurrency/read_only_atomic_load.rs
Normal file
13
tests/fail/concurrency/read_only_atomic_load.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Should not rely on the aliasing model for its failure.
|
||||||
|
//@compile-flags: -Zmiri-disable-stacked-borrows
|
||||||
|
|
||||||
|
use std::sync::atomic::{AtomicI32, Ordering};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
static X: i32 = 0;
|
||||||
|
let x = &X as *const i32 as *const AtomicI32;
|
||||||
|
let x = unsafe { &*x };
|
||||||
|
// Some targets can implement atomic loads via compare_exchange, so we cannot allow them on
|
||||||
|
// read-only memory.
|
||||||
|
x.load(Ordering::Relaxed); //~ERROR: atomic operations cannot be performed on read-only memory
|
||||||
|
}
|
15
tests/fail/concurrency/read_only_atomic_load.stderr
Normal file
15
tests/fail/concurrency/read_only_atomic_load.stderr
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
error: Undefined Behavior: atomic operations cannot be performed on read-only memory
|
||||||
|
--> $DIR/read_only_atomic_load.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | x.load(Ordering::Relaxed);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ atomic operations cannot be performed on read-only memory
|
||||||
|
|
|
||||||
|
= 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:
|
||||||
|
= note: inside `main` at $DIR/read_only_atomic_load.rs:LL:CC
|
||||||
|
|
||||||
|
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
@ -130,7 +130,7 @@ fn wait_absolute_timeout() {
|
|||||||
fn wait_wake() {
|
fn wait_wake() {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
||||||
static FUTEX: i32 = 0;
|
static mut FUTEX: i32 = 0;
|
||||||
|
|
||||||
let t = thread::spawn(move || {
|
let t = thread::spawn(move || {
|
||||||
thread::sleep(Duration::from_millis(200));
|
thread::sleep(Duration::from_millis(200));
|
||||||
@ -167,7 +167,7 @@ fn wait_wake() {
|
|||||||
fn wait_wake_bitset() {
|
fn wait_wake_bitset() {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
||||||
static FUTEX: i32 = 0;
|
static mut FUTEX: i32 = 0;
|
||||||
|
|
||||||
let t = thread::spawn(move || {
|
let t = thread::spawn(move || {
|
||||||
thread::sleep(Duration::from_millis(200));
|
thread::sleep(Duration::from_millis(200));
|
||||||
@ -277,8 +277,8 @@ fn concurrent_wait_wake() {
|
|||||||
|
|
||||||
// Make sure we got the interesting case (of having woken a thread) at least once, but not *each* time.
|
// Make sure we got the interesting case (of having woken a thread) at least once, but not *each* time.
|
||||||
let woken = WOKEN.load(Ordering::Relaxed);
|
let woken = WOKEN.load(Ordering::Relaxed);
|
||||||
assert!(woken > 0 && woken < rounds);
|
|
||||||
//eprintln!("waking happened {woken} times");
|
//eprintln!("waking happened {woken} times");
|
||||||
|
assert!(woken > 0 && woken < rounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
Loading…
Reference in New Issue
Block a user