Skip to content

Misoptimisation of complex control flow only under low mir-opt-level #112061

Closed
@cbeuw

Description

@cbeuw

Apologies for the not-very-readable reproduction. It was generated by a fuzzer and this is the best I can minimise it to.

use std::ptr;
pub fn print_var(v: u8) {
    println!("{v}");
}
pub unsafe fn fn12_rs() -> ([u128; 7], *mut i8, *mut bool) {
    let mut v2: bool = false;
    let mut v8: u64 = 0;
    let mut v9: usize = 0;
    let mut v12: *mut u8 = ptr::null_mut();
    let mut v17: *mut bool = ptr::null_mut();
    let mut v20: [u8; 8] = Default::default();
    let mut v21: [u8; 8] = Default::default();
    let mut v31: (bool, u8, usize, f32) = Default::default();
    let mut v33: ([u128; 7], *mut i8, *mut bool) = ([0; 7], ptr::null_mut(), ptr::null_mut());
    let mut v39: (usize, [u128; 7], ([u32; 6], usize, *mut [u32; 6]), [u32; 2]) =
        (0, [0; 7], ([0; 6], 0, ptr::null_mut()), [0; 2]);
    let mut ret: ([u128; 7], *mut i8, *mut bool) = ([0; 7], ptr::null_mut(), ptr::null_mut());
    ret.2 = core::ptr::addr_of_mut!(v2);
    'l0: loop {
        v12 = core::ptr::addr_of_mut!(v20[v9]);
        v20 = [197_u8; 8];
        v9 = 2_usize;
        'l1: loop {
            match *v12 {
                197 => {
                    // Taken
                    v8 = 13978819448286864680_u64;
                    v33.2 = ret.2;
                    match v39.0 {
                        0 => {
                            // Taken
                            'l2: loop {
                                v20 = [11_u8; 8]; // What LLVM with low mir-opt prints
                                (*v12) = 22; // What Miri prints
                                'l3: loop {
                                    v21 = v20;
                                    match v8 {
                                        13978819448286864680 => {
                                            // Taken
                                            v39.2 .0 = [2262110980_u32; 6];
                                            v8 = !13152832795211590855_u64;
                                            v39.0 = 6;
                                            v17 = v33.2;
                                            v33.2 = core::ptr::addr_of_mut!(v31.0);
                                            v31.1 = *v12;
                                            (*v17) = true;
                                            v20 = v21;
                                            match v39.0 {
                                                6 => {
                                                    // Taken
                                                    print_var(v31.1);
                                                }
                                                0 => continue 'l2,
                                                _ => return ret,
                                            }
                                        }
                                        _ => continue 'l0,
                                    }
                                }
                            }
                        }
                        _ => return ret,
                    }
                }
                4 => {
                    v12 = core::ptr::addr_of_mut!(v20[v9]);
                }
                _ => return ret,
            }
        }
    }
}
pub fn main() {
    unsafe {
        fn12_rs();
    }
}

The program has no UB under -Zmiri-tree-borrows, and Miri prints 22, this is also the result with -Zmir-opt-level>=2 -Copt-level=3

% rustc -Zmir-opt-level=2 -Copt-level=3 minimised.rs && ./minimised
22

Very strangely, if you drop mir-opt-level to 0 or 1, the result becomes 11 which is wrong.

% rustc -Zmir-opt-level=1 -Copt-level=3 minimised.rs && ./minimised
11

Reproducible on both Apple Silicon macOS and x86_64 Linux

rustc 1.71.0-nightly (a2b1646c5 2023-05-25)
binary: rustc
commit-hash: a2b1646c597329d0a25efa3889b66650f65de1de
commit-date: 2023-05-25
host: aarch64-apple-darwin
release: 1.71.0-nightly
LLVM version: 16.0.4
rustc 1.71.0-nightly (a2b1646c5 2023-05-25)
binary: rustc
commit-hash: a2b1646c597329d0a25efa3889b66650f65de1de
commit-date: 2023-05-25
host: x86_64-unknown-linux-gnu
release: 1.71.0-nightly
LLVM version: 16.0.4

cc @RalfJung @nikic

Metadata

Metadata

Assignees

Labels

A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-rustlantisA miscompilation found by RustlantisI-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-highHigh priorityT-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