GVN optimizes this function
#[unsafe(no_mangle)]
#[inline(never)]
pub fn indirect(x: &(&i32,), out: fn(i32), clobber: fn()) {
out(*(*x).0);
clobber();
out(*(*x).0);
}
to remove the apparently redundant second load of the inner integer.
However, if we call that function as follows...
static mut DATA: i32 = 0;
fn main() {
let ptr = &raw mut DATA;
let nested_shr: &(&i32,) = unsafe { &*(&raw const ptr as *const (&i32,)) };
indirect(nested_shr, |x| println!("{x}"), || unsafe { DATA = 1 });
}
then this optimization changes the resulting program behavior. Neither SB nor TB flag UB in this program, making the optimization unsound under our current models.
This issue was previously fixed in GVN by #133474 but got re-introduced by #132527. The example needs to use &(&i32,) instead of &&i32 to bypass a check that was recently added to GVN. I cannot tell if that check is ineffective to fix the actual problem it was meant to fix, but it is certainly ineffective for this issue.
Arguably this is more of a defect in the model than in GVN, but it could be non-trivial to fix / the fix might cause problems on its own. This is basically an instance of rust-lang/unsafe-code-guidelines#593. Under the current model, GVN has to prove that the shared reference was constructed properly (i.e., that it went through a retag) before it can assume that the pointee is truly immutable.
Cc @rust-lang/opsem @rust-lang/wg-mir-opt @cjgillot @dianqk
GVN optimizes this function
to remove the apparently redundant second load of the inner integer.
However, if we call that function as follows...
then this optimization changes the resulting program behavior. Neither SB nor TB flag UB in this program, making the optimization unsound under our current models.
This issue was previously fixed in GVN by #133474 but got re-introduced by #132527. The example needs to use
&(&i32,)instead of&&i32to bypass a check that was recently added to GVN. I cannot tell if that check is ineffective to fix the actual problem it was meant to fix, but it is certainly ineffective for this issue.Arguably this is more of a defect in the model than in GVN, but it could be non-trivial to fix / the fix might cause problems on its own. This is basically an instance of rust-lang/unsafe-code-guidelines#593. Under the current model, GVN has to prove that the shared reference was constructed properly (i.e., that it went through a retag) before it can assume that the pointee is truly immutable.
Cc @rust-lang/opsem @rust-lang/wg-mir-opt @cjgillot @dianqk