Skip to content

Miscompilation with FFI bool return type on AArch64 #159244

Description

@Timbals

View all comments

I tried this C and Rust code:

struct Bools {
    _Bool a;
    _Bool b;
};

_Bool get_a(struct Bools bools) {
    return bools.a;
}
#[repr(C)]
struct Bools {
    a: bool,
    b: bool,
}

#[link(name = "get_a")]
unsafe extern "C" {
    safe fn get_a(bools: Bools) -> bool;
}

pub fn broken() -> i32 {
    let bools = Bools { a: false, b: true };
    if get_a(bools) {
        123
    } else {
        321
    }
}

pub fn main() {
    if broken() == 123 {
        unreachable!();
    }
}

with gcc -c get_a.c -o get_a.o -O1 && ar rcs libget_a.a get_a.o && rustc main.rs -L . -C opt-level=1 && ./main.

I expected to see this happen: clean program exit, because the value of a should get round-tripped and broken should return 321.

Instead, this happened:

thread 'main' (17324) panicked at main.rs:23:9:
internal error: entered unreachable code

This is caused by rustc emitting the bool return type as i1 zeroext to LLVM, but that is incorrect, because the AArch64 call ABI does not guarantee that the unused bits of the register are zeroed ("any unused bits in the register have unspecified value").

bools is passed in a single register. The get_a function is a single ret instruction and doesn't touch the registers at all.
The if gets turned into a cmp w0, #0 which compares the lower 32 bits of register, including the value of b, to 0.

This is similar to #97463 which was fixed in #97800, but only covered integer types.

I originally encountered this as spurious Java exception because the jni-rs ExceptionCheck has a bool return type.

LLM disclosure

I used LLMs to help find the cause of my initial issue, and discover resources for areas I wasn't familiar enough with (rustc internals, JNI, LLVM, AArch64 calling convention).
This issue and the reproducer were written and verified by me (a human).

Meta

rustc --version --verbose:

rustc 1.99.0-nightly (77cf889bc 2026-07-12)
binary: rustc
commit-hash: 77cf889bc178ddb44d6a1c78e5a820b5abb31d8d
commit-date: 2026-07-12
host: aarch64-unknown-linux-gnu
release: 1.99.0-nightly
LLVM version: 22.1.8

gcc --version:

gcc (Debian 14.2.0-19) 14.2.0
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Backtrace

thread 'main' (17324) panicked at main.rs:23:9:
internal error: entered unreachable code
stack backtrace:
   0: __rustc::rust_begin_unwind
             at /rustc/77cf889bc178ddb44d6a1c78e5a820b5abb31d8d/library/std/src/panicking.rs:679:5
   1: core::panicking::panic_fmt
             at /rustc/77cf889bc178ddb44d6a1c78e5a820b5abb31d8d/library/core/src/panicking.rs:80:14
   2: core::panicking::panic
             at /rustc/77cf889bc178ddb44d6a1c78e5a820b5abb31d8d/library/core/src/panicking.rs:150:5
   3: main::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ABIArea: Concerning the application binary interface (ABI)A-FFIArea: Foreign function interface (FFI)A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-bugCategory: This is a bug.I-miscompileIssue: Correct Rust code lowers to incorrect machine codeI-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessO-AArch64Armv8-A or later processors in AArch64 modeP-criticalCritical priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions