Skip to content

Miscompilation: wrong branch taken on x86_64 #112767

Closed
@cbeuw

Description

@cbeuw

Fuzzer generated code then minimised

use std::ptr;

pub fn dump_var(
    f: usize,
    var0: usize,
    val0: i32,
    var1: usize,
    val1: i32,
    var2: usize,
    val2: i32,
    var3: usize,
    val3: i32,
) {
    println!("fn{f}:_{var0} = {val0}, _{var1} = {val1}, _{var2} = {val2}, _{var3} = {val3}");
}

unsafe fn fn2(mut _2: *mut i32) {
    println!("entering fn2");
    let mut np: *mut i128 = ptr::null_mut();
    let mut npp = ptr::addr_of_mut!(np);
    let mut byte: u8 = 0;
    let byte_ptr = ptr::addr_of_mut!(byte);
    let mut discr: i128 = 0;
    let mut _16 = ptr::addr_of_mut!(discr);
    *_16 = 19769033156256055278156766228563896803_i128;
    fn3(npp, byte_ptr, [0; 4], _2, 0, *_16);
    loop {
        npp = ptr::addr_of_mut!(_16);
        match discr {
            3 => {
                discr = 0;
                fn3(npp, byte_ptr, [0; 4], _2, *_16, *_16);
            }
            _ => return,
        }
    }
}

pub unsafe fn fn3(
    mut _5: *mut *mut i128,
    byte_ptr: *mut u8,
    mut _7: [i64; 4],
    mut _8: *mut i32,
    mut _9: i128,
    mut big_num: i128,
) {
    println!("entering fn3");
    (*_5) = ptr::addr_of_mut!(big_num);
    *byte_ptr = 0;
    fn4(big_num, *_8, _5, _9, *_5);
    _7 = [0; 4];
}

pub unsafe fn fn4(
    big_num: i128,
    mut _7: i32,
    mut _8: *mut *mut i128,
    mut _12: i128,
    mut _13: *mut i128,
) {
    println!("entering fn4");
    (*_13) = 0; // This cannot change big_num as it was passed by value
    match big_num {
        19769033156256055278156766228563896803 => {
            println!("right branch");
            (*_8) = ptr::addr_of_mut!(_12);
            fn5(_7)
        }
        _ => {
            println!("wrong branch");
            return;
        }
    }
}

pub fn fn5(mut _1: i32) {
    println!("entering fn5");
    dump_var(5, 1, _1, 0, 0, 0, 0, 0, 0);
}

pub fn main() {
    let mut _6: i32 = 0;
    let _16 = ptr::addr_of_mut!(_6);
    unsafe { fn2(_16) }
}

Miri reports no UB under either aliasing model, and it should print

entering fn2
entering fn3
entering fn4
right branch
entering fn5
fn5:_1 = 0, _0 = 0, _0 = 0, _0 = 0

With -Zmir-opt-level=0 -Copt-level>=2, it takes the wrong branch in fn4 and doesn't call fn5.

$ rustc -Zmir-opt-level=0 -Copt-level=2 repro.rs && ./repro
entering fn2
entering fn3
entering fn4
wrong branch

Only reproducible on x86_64, not aarch64

rustc 1.72.0-nightly (3b2073f07 2023-06-17)
binary: rustc
commit-hash: 3b2073f0762cff4d3d625bb10017e0ce4e7abe50
commit-date: 2023-06-17
host: x86_64-unknown-linux-gnu
release: 1.72.0-nightly
LLVM version: 16.0.5

cc @nikic

Metadata

Metadata

Assignees

Labels

A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-raw-pointersArea: raw pointers, MaybeUninit, NonNullA-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