Closed
Description
As there is a write through a *const
derived pointer, this code has UB under Stacked Borrows, but is fine under Tree Borrows,
pub fn first() -> bool {
let mut a = (0., true);
let b = (0., false);
let a_ptr_and_b = (core::ptr::addr_of_mut!(a), b);
let got = unsafe { second(a_ptr_and_b.0, a_ptr_and_b, true, true) };
return got;
}
unsafe fn second(
a_ptr: *mut (f32, bool),
a_ptr_and_b: (*mut (f32, bool), (f64, bool)),
t: bool,
t_copy: bool,
) -> bool {
let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1 .1) as *mut bool;
let t_or_t = t | t_copy;
let t_xor_t = t ^ t_copy;
(*b_bool_ptr) = t_or_t ^ t_xor_t;
let unused = a_ptr_and_b;
return a_ptr_and_b.1.1 == (*a_ptr).1;
}
pub fn main() {
println!("{}", first());
}
-C opt-level=0
results in true
(which Miri agrees and is the right result), but -C opt-level=3
miscompiles it to print false
% rustc -Zmir-opt-level=0 -C opt-level=0 repro.rs && ./repro
true
% rustc -Zmir-opt-level=0 -C opt-level=3 repro.rs && ./repro
false
Interestingly, if you remove unused
in function second
, the miscompilation goes away. -Zmir-opt-level=0
is required to prevent mir-opt from doing this.
Directly getting a *mut
through addr_of_mut!
in the first line of second
also makes the bug go away.
rustc --version -v
rustc 1.71.0-nightly (2a8221dbd 2023-05-11)
binary: rustc
commit-hash: 2a8221dbdfd180a2d56d4b0089f4f3952d8c2bcd
commit-date: 2023-05-11
host: aarch64-apple-darwin
release: 1.71.0-nightly
LLVM version: 16.0.2