Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Miscompilation: wrong branch taken on x86_64 #112767

Closed
cbeuw opened this issue Jun 18, 2023 · 6 comments
Closed

Miscompilation: wrong branch taken on x86_64 #112767

cbeuw opened this issue Jun 18, 2023 · 6 comments
Assignees
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-raw-pointers Area: raw pointers, MaybeUninit, NonNull I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness P-high High priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@cbeuw
Copy link
Contributor

cbeuw commented Jun 18, 2023

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

@cbeuw
Copy link
Contributor Author

cbeuw commented Jun 18, 2023

There is a pointer to a stack allocation that outlasts its lifetime:
(*_8) = ptr::addr_of_mut!(_12);

But this isn't llvm/llvm-project#51838, as -Cllvm-args=-protect-from-escaped-allocas=true doesn't prevent the miscompilation, and this dangling pointer is never dereferenced, even in not taken branches

@jyn514 jyn514 added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness A-raw-pointers Area: raw pointers, MaybeUninit, NonNull labels Jun 18, 2023
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Jun 18, 2023
@nikic
Copy link
Contributor

nikic commented Jun 21, 2023

Likely SDAG bug.

BISECT: NOT running pass (1376) X86 DAG->DAG Instruction Selection on function (_ZN4test3fn317h707ba6185b238b46E)

@nikic
Copy link
Contributor

nikic commented Jun 21, 2023

If I'm reading the assembly right, this should be a reduction of the issue: llvm/llvm-project#63430

@apiraino
Copy link
Contributor

WG-prioritization assigning priority (Zulip discussion).

@rustbot label -I-prioritize +P-high +T-compiler

@rustbot rustbot added P-high High priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Jun 21, 2023
@nikic
Copy link
Contributor

nikic commented Jun 23, 2023

Fixed upstream by llvm/llvm-project@81ec494.

@nikic
Copy link
Contributor

nikic commented Aug 13, 2023

Fixed by #114048

Godbolt: https://rustc.godbolt.org/z/6eTqszPWx

@nikic nikic closed this as completed Aug 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-raw-pointers Area: raw pointers, MaybeUninit, NonNull I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness P-high High priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants
@nikic @apiraino @cbeuw @jyn514 @rustbot and others