Skip to content

LLVM poisons partially undef constant, leading to infinite loops. #21996

Closed
@eddyb

Description

@eddyb
#![feature(asm)]

// Isomorphic to Option<usize>.
#[derive(Copy)]
enum Foo {
    Yes(usize),
    No
}

// All these functions are necessary to trigger the bug.
fn swap(x: &mut Foo, y: &mut Foo) {
    let tmp = *x;
    *x = *y;
    *y = tmp;
}

fn replace(x: &mut Foo, mut y: Foo) -> Foo {
    swap(x, &mut y);
    y
}

fn take(x: &mut Foo) -> Foo {
    static NO_FOO: Foo = Foo::No;
    replace(x, NO_FOO)
}

fn take2(x: &mut Foo) -> Foo {
    take(x)
}

fn main() {
    let mut iter = Foo::Yes(5);
    while let Foo::Yes(_) = take2(&mut iter) {
        unsafe {
            // Just to keep the loop alive.
            asm!(""::::"volatile");
        }
    }
}

This happens only after the recent LLVM upgrade. The culprit seems to be half of NO_FOO:

@NO_FOO = internal constant { i64, [8 x i8] } { i64 1, [8 x i8] undef }
; ...
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* bitcast ({ i64, [8 x i8] }* @NO_FOO to i8*), i64 16, i32 8, i1 false)

Changing the memcpy call to copy only 8 bytes instead of 16 (to not touch the undef portion) removes the infinite loop.
cc @dotdash @Aatch

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-codegenArea: Code generation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions