Skip to content

MIR building optimizes away some place expressions around "_" patterns even with -Zmir-opt-level=0 #99180

Closed
@RalfJung

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions