In the program below, *ptr += 1; runs without any error and the write takes effect, while changing it to *ptr = 1; is reported as UB.
Program
fn main() {
let mut x = 0i32;
let _fool: *mut i32 = &mut x as *mut i32;
let addr: usize = (&x as *const i32).expose_provenance();
let ptr: *mut i32 = std::ptr::with_exposed_provenance_mut::<i32>(addr);
unsafe {
*ptr += 1; // -- NOT reported
}
println!("x = {x}");
}
Changing *ptr += 1; to *ptr = 1; (plain write, no read) makes Miri report the expected UB, so only the read part of the compound assignment changes the outcome.
Result
*ptr += 1; — runs to completion, no UB, write takes effect:
$ cargo +nightly miri run
Compiling t v0.0.0 (/t)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s
Running `/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/t`
warning: integer-to-pointer cast
--> src/main.rs:5:25
|
5 | let ptr: *mut i32 = std::ptr::with_exposed_provenance_mut::<i32>(addr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
|
= help: this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program
= help: see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation
= help: to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead
= help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics
= help: alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning
x = 1
warning: 1 warning emitted
*ptr = 1; — UB is reported:
$ cargo +nightly miri run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/t`
warning: integer-to-pointer cast
--> src/main.rs:5:25
|
5 | let ptr: *mut i32 = std::ptr::with_exposed_provenance_mut::<i32>(addr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
|
= help: this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program
= help: see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation
= help: to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead
= help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics
= help: alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning
error: Undefined Behavior: attempting a write access using <wildcard> at alloc142[0x0], but no exposed tags have suitable permission in the borrow stack for this location
--> src/main.rs:7:9
|
7 | *ptr = 1; // plain write through wildcard
| ^^^^^^^^ this error occurs as part of an access at alloc142[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error; 1 warning emitted
In the program below, *ptr += 1; runs without any error and the write takes effect, while changing it to *ptr = 1; is reported as UB.
Program
Changing *ptr += 1; to *ptr = 1; (plain write, no read) makes Miri report the expected UB, so only the read part of the compound assignment changes the outcome.
Result
*ptr += 1; — runs to completion, no UB, write takes effect:
*ptr = 1; — UB is reported: