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 from .wrapping_offset(isize::MIN).wrapping_offset(isize::MIN) #112526

Closed
cbeuw opened this issue Jun 11, 2023 · 5 comments
Closed
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-medium Medium priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@cbeuw
Copy link
Contributor

cbeuw commented Jun 11, 2023

Again, fuzzer generated code and minimised to surface Rust. Miri reports no UB under either aliasing model.

extern crate core;
use core::ptr;

pub fn dump_var(val0: u16) {
    println!("{val0}");
}

// extern "C" {
//     fn dump_var(x: u16);
// }
// #[no_mangle]
pub unsafe fn fn10_rs() -> *const *mut i64 {
    let mut _16: usize = 0;
    let mut _23: i128 = 0;
    let mut isize_min: isize = 0;
    let mut _46: i64 = 0;
    let mut _107: i16 = 0;
    let mut _47: u16 = 0;
    let mut _88: usize = 0;

    let mut _31: *mut u8 = ptr::null_mut();
    let mut _33: *mut *mut i64 = ptr::null_mut();
    let mut _81: *const i128 = ptr::null();
    let mut _90: *mut u8 = ptr::null_mut();
    let mut _177: *mut i64 = ptr::null_mut();

    let mut _44: ((u64, u64, u8), u32, f32) = Default::default();
    let mut _61: ((u64, u64, u8), u32, f32) = Default::default();
    let mut tup: (((u64, u64, u8), u32, f32), bool) = Default::default();
    let mut _95: (((u64, u64, u8), u32, f32), bool) = Default::default();

    'bb2: loop {
        let two: u16 = 2;
        _44.0 .2 = 1;
        _31 = core::ptr::addr_of_mut!(_44.0 .2);
        _23 = 11;
        'bb45: loop {
            (*_31) = 1;
            isize_min = isize::MIN;
            'bb65: loop {
                let tup_ptr = core::ptr::addr_of_mut!(tup);
                _31 = core::ptr::addr_of_mut!((*tup_ptr).0 .0 .2);
                _16 = 18215089233857363959_usize;
                match isize_min {
                    isize::MIN => {
                        _90 = _31.wrapping_offset(isize::MIN);
                        _95.0 = _44;
                        _46 = 42;
                        _81 = core::ptr::addr_of!(_23);
                        _44 = tup.0;
                        _88 = _16;
                        'bb80: loop {
                            _31 = _90.wrapping_offset(isize_min);
                            match *_81 {
                                11 => 'bb88: loop {
                                    let tup_ptr2 = core::ptr::addr_of_mut!(tup);
                                    (*tup_ptr2) = _95;
                                    isize_min = _107 as isize;
                                    _47 = two >> *_31;
                                    (*tup_ptr) = _95;
                                    match _88 {
                                        18215089233857363959 => {
                                            *_31 = _61.0 .2.swap_bytes();
                                            _88 = (*tup_ptr2).0 .2 as usize;
                                            _33 = core::ptr::addr_of_mut!(_177);
                                            match _46 {
                                                42 => {
                                                    (*_33) = core::ptr::addr_of_mut!(_46);
                                                    match *_177 {
                                                        42 => {
                                                            dump_var(_47);
                                                            return core::ptr::addr_of!(_177);
                                                        }
                                                        _ => continue 'bb2,
                                                    }
                                                }
                                                _ => match *_81 {
                                                    11 => continue 'bb88,
                                                    _ => continue 'bb65,
                                                },
                                            }
                                        }
                                        0 => continue 'bb80,
                                        _ => continue 'bb65,
                                    }
                                },
                                _ => continue 'bb65,
                            }
                        }
                    }
                    _ => continue 'bb45,
                }
            }
        }
    }
}

pub fn main() {
    unsafe {
        fn10_rs();
    }
}

The correct output is 1, evaluated from two >> *_31 where _31 points to 1 after having been roundtripped with two .wrapping_offset(isize::MIN).

It outputs 2 with -Copt-level >= 1.

% rustc -Copt-level=0 repro.rs && ./repro
1
% rustc -Copt-level=1 repro.rs && ./repro
2

Not sure if rustc is emitting LLVM IR with UB or it's a bug in LLVM. llvm-reduce gave me this which calls dump_var(2) with opt -O1: https://godbolt.org/z/q6GWPq9qs, but the GEP indices don't look right.

target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "arm64-apple-macosx11.0.0"

define ptr @fn10_rs() {
start:
  %_17 = alloca { { { i64, i64, i8, [7 x i8] }, i32, float }, i8, [7 x i8] }, align 8
  %tup = alloca { { { i64, i64, i8, [7 x i8] }, i32, float }, i8, [7 x i8] }, align 8
  %0 = getelementptr { i64, i64, i8, [7 x i8] }, ptr %tup, i64 -384307168202282325, i32 1
  %1 = getelementptr i8, ptr %0, i64 -9223372036854775808
  call void @llvm.memcpy.p0.p0.i64(ptr %tup, ptr %_17, i64 40, i1 false)
  %_18 = load i8, ptr %1, align 8
  %2 = zext i8 %_18 to i16
  %_47 = lshr i16 2, %2
  call void @dump_var(i16 %_47)
  ret ptr null
}

; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0

declare void @dump_var(i16)

attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }

cc @RalfJung @nikic

@clubby789
Copy link
Contributor

searched nightlies: from nightly-2022-06-01 to nightly-2023-06-11
regressed nightly: nightly-2023-03-26
searched commit range: 8be3c2b...0c61c7a
regressed commit: 0c61c7a -> #109474 -> LLVM 16 upgrade

bisected with cargo-bisect-rustc v0.6.6

Host triple: x86_64-unknown-linux-gnu
Reproduce with:

cargo bisect-rustc --start 2022-06-01 --script script.sh --prompt 

@clubby789 clubby789 added the A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. label Jun 11, 2023
@jyn514 jyn514 added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness labels Jun 11, 2023
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Jun 11, 2023
@jyn514 jyn514 added regression-from-stable-to-stable Performance or correctness regression from one stable version to another. A-raw-pointers Area: raw pointers, MaybeUninit, NonNull labels Jun 11, 2023
@nikic nikic self-assigned this Jun 12, 2023
@nikic
Copy link
Contributor

nikic commented Jun 12, 2023

Reduced: llvm/llvm-project#63266

@apiraino
Copy link
Contributor

WG-prioritization assigning priority (Zulip discussion).

@rustbot label -I-prioritize P-medium

@rustbot rustbot added P-medium Medium priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Jun 12, 2023
@nikic
Copy link
Contributor

nikic commented Jul 3, 2023

This has been fixed upstream.

@nikic
Copy link
Contributor

nikic commented Aug 13, 2023

Fixed by #114048.

Godbolt: https://rustc.godbolt.org/z/nq5WPf8G4

@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-medium Medium priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. 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