Skip to content

Aliasing-related miscompile in CopyProp #146423

@saethlin

Description

@saethlin

Reduced example from rustlantis, which is accepted by Miri using Tree Borrows without optimizations enabled:

#![feature(custom_mir, core_intrinsics)]
#![allow(internal_features)]

use std::intrinsics::mir::*;

#[custom_mir(dialect = "runtime")]
fn main() {
    mir!{
        let _1;
        let _2;
        let _3;
        let _4;
        {
            _1 = core::ptr::addr_of_mut!(_2);
            _3 = Move(_1);
            _4 = Move(_1);
            Call(*_1 = fn1(Move(_3), _4), ReturnTo(bb1), UnwindUnreachable())
        }
        bb1 = {
            Return()
        }
    }
}

#[custom_mir(dialect = "runtime")]
fn fn1(_1: *mut *const u8, _2: *mut *const u8) -> *const u8 {
    mir!{
        let _3;
        {
            _3 = 0;
            RET = core::ptr::addr_of!(_3);
            Return()
        }
    }
}

This program is accepted without any optimizations, but with CopyProp enabled:

MIRIFLAGS="-Zmiri-tree-borrows -Zmir-enable-passes=+CopyProp" cargo +nightly miri run

Miri reports UB:

error: Undefined Behavior: read access through <264> (root of the allocation) at alloc126[0x0] is forbidden
  --> src/main.rs:17:13
   |
17 |             Call(*_1 = fn1(Move(_3), _4), ReturnTo(bb1), UnwindUnreachable())
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
   |
   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
   = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
   = help: the accessed tag <264> (root of the allocation) is foreign to the protected tag <265> (i.e., it is not a child)
   = help: this foreign read access would cause the protected tag <265> (currently Active) to become Disabled
   = help: protected tags must never be Disabled
help: the accessed tag <264> was created here
  --> src/main.rs:17:13
   |
17 |             Call(*_1 = fn1(Move(_3), _4), ReturnTo(bb1), UnwindUnreachable())
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: the protected tag <265> was created here, in the initial state Reserved
  --> src/main.rs:30:13
   |
30 |             _3 = 0;
   |             ^^^^^^
help: the protected tag <265> later transitioned to Active due to a child write access at offsets [0x0..0x8]
  --> src/main.rs:30:13
   |
30 |             _3 = 0;
   |             ^^^^^^
   = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
   = note: BACKTRACE (of the first span):
   = note: inside `main` at src/main.rs:17:13: 17:78

The errant transformation is this:

 fn main() -> () {
     let mut _0: ();
     let mut _1: *mut *const u8;
     let mut _2: *const u8;
     let mut _3: *mut *const u8;
     let mut _4: *mut *const u8;
 
     bb0: {
         _1 = &raw mut _2;
-        _3 = move _1;
-        _4 = move _1;
-        (*_1) = fn1(move _3, copy _4) -> [return: bb1, unwind unreachable];
+        (*_1) = fn1(move _1, copy _1) -> [return: bb1, unwind unreachable];
     }
 
     bb1: {
         return;
     }
 }

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-mir-optArea: MIR optimizationsA-rustlantisA miscompilation found by RustlantisC-bugCategory: This is a bug.I-miscompileIssue: Correct Rust code lowers to incorrect machine codeP-highHigh priorityS-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueT-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