MIR building optimizes away some place expressions around "_" patterns even with -Zmir-opt-level=0 #99180
Description
Consider the following code -- the comments say it all:
fn main() {
let ptr = 32 as *const u8;
// This is UB, and Miri finds it:
//unsafe { let _ptr = std::ptr::addr_of!(*ptr); }
// So this should also be UB, but Miri says nothing:
unsafe { let _ = *ptr; }
// And same for this:
unsafe {
match *ptr { _ => {} }
}
}
Here is the mir-opt-level=0 MIR for this:
fn main() -> () {
let mut _0: (); // return place in scope 0 at place.rs:1:11: 1:11
let _1: *const u8; // in scope 0 at place.rs:2:9: 2:12
let _2: (); // in scope 0 at place.rs:8:5: 8:29
scope 1 {
debug ptr => _1; // in scope 1 at place.rs:2:9: 2:12
scope 2 {
scope 3 {
}
}
scope 4 {
}
}
bb0: {
StorageLive(_1); // scope 0 at place.rs:2:9: 2:12
_1 = const 32_usize as *const u8 (PointerFromExposedAddress); // scope 0 at place.rs:2:15: 2:30
StorageLive(_2); // scope 1 at place.rs:8:5: 8:29
_2 = const (); // scope 2 at place.rs:8:5: 8:29
StorageDead(_2); // scope 1 at place.rs:8:28: 8:29
_0 = const (); // scope 4 at place.rs:12:27: 12:29
StorageDead(_1); // scope 0 at place.rs:14:1: 14:2
return; // scope 0 at place.rs:14:2: 14:2
}
}
Currently, MIR building "loses" the entire place expression somewhere, even though that place expression could cause UB. IMO that is a bug. Can we change MIR building to preserve the place expressions?
We could have a EvalPlace
MIR statement that just computes a place expression and then does nothing with the result. (To be clear, there should be no place-to-value conversion, i.e., no actual load from the *ptr
place. But the place expression itself should be evaluated.) We do have FakeRead
, which works on a place, but (a) its docs talk about "inspecting constants and discriminant values" so that is doing more than just evaluating the place expression, and (b) it is "disallowed after drop elaboration".
Cc @rust-lang/wg-mir-opt in lieu of a "MIR building wg".
Also I think this is related to THIR unsafety checking; MIR unsafety checking does not even complain about some of these *ptr
because they get erased before reaching MIR, but in THIR they would still be visible.
Also related: #79735 rust-lang/unsafe-code-guidelines#261
Activity