Skip to content

Safe Rust code miscompilation due to a bug in LLVM's Global Value Numbering #45839

Closed
@RalfJung

Description

@RalfJung

lib/src.rs in the foo crate:

#[inline(never)]
pub fn test(gp1: &mut *const i32, gp2: &mut *const i32, b1: bool, b2: bool) -> (i32, i32) {
    let mut g = 0;
    let mut b = 0;
    let y = 6666;
    let mut x = 7777;
    let mut p = &mut g as *const _;

    {
        let mut q = &mut g;
        let mut r = &mut 8888;

        if b1 {
            p = (&y as *const _).wrapping_offset(1);
        }

        if b2 {
            q = &mut x;
        }

        *gp1 = p.wrapping_offset(1234);
        if q as *const _ == p {
            b = 1;
            *gp2 = (q as *const _).wrapping_offset(1234);
            r = q;
        }

        *r = 42;
    }

    return (b, x);
}

src/main.rs in the main crate:

use std::ptr;

extern crate foo;

pub fn main() {
    let mut x1 = ptr::null();
    let mut x2 = ptr::null();
    let mut gp1 = &mut x1;
    let mut gp2 = &mut x2;

    let (b, x) = foo::test(&mut gp1, &mut gp2, true, true);
    println!("b = {}, x = {}", b, x);
}

This prints b = 1, x = 7777. That is wrong; if b is 1, it must be the case that the then-branch in the q as *const _ == p conditional was taken, so r is &mut x (since b2 is true), so x cannot still be 7777.

This is a bug in LLVM's GVN, see https://bugs.llvm.org/show_bug.cgi?id=35229 for the upstream report and some further analysis.

Original C test case by Gil Hur.

Metadata

Metadata

Assignees

No one assigned

    Labels

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