rust-lang / rust-lang/rust-bindgen

`long double` alignment tests fail on riscv32

Open
#3,491 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
5.3k
Forks
829
Avg merge
1d 1h
Merged PRs (30d)
15

Description

When updating my project from 0.72.1 to bindgen 0.73.2, I started seeing this error.

header.h:

struct foo
{
    long long x;
    long double y;
};

bindgen header.h -- --target=riscv32-unknown-none-elf produces:

/* automatically generated by rust-bindgen 0.73.2 */

#[repr(C)]
#[repr(align(16))]
#[derive(Debug, Copy, Clone)]
pub struct foo {
    pub x: ::std::os::raw::c_longlong,
    pub y: u128,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
    ["Size of foo"][::std::mem::size_of::<foo>() - 32usize];
    ["Alignment of foo"][::std::mem::align_of::<foo>() - 16usize];
    ["Offset of field: foo::x"][::std::mem::offset_of!(foo, x) - 0usize];
    ["Offset of field: foo::y"][::std::mem::offset_of!(foo, y) - 16usize];
};

This does not compile because the offset of y in the rust struct is 8, but in the C struct it is 16:

error[E0080]: attempt to compute `8_usize - 16_usize`, which would overflow
  --> bindings.rs:15:33
   |
15 |     ["Offset of field: foo::y"][::core::mem::offset_of!(foo, y) - 16usize];
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here

The issue is that the long double has an alignment of 16 in riscv32, but it is represented as a u128, which has an alignment of 8 on riscv32.

I bisected the problem and found that this commit is the first that breaks things: https://github.com/rust-lang/rust-bindgen/commit/64f0939766c792822bd03c6733972e7e1067724e

On the immediate ancestor (cf8faab), I see this result instead, with 8 bytes of padding in between x and y:

/* automatically generated by rust-bindgen 0.73.1 */

#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
#[repr(C, align(8))]
pub struct __BindgenOpaqueArray8<T>(pub T);
impl<T: Copy + Default, const N: usize> Default for __BindgenOpaqueArray8<[T; N]> {
    fn default() -> Self {
        Self([<T as Default>::default(); N])
    }
}
#[repr(C)]
#[repr(align(16))]
#[derive(Debug, Copy, Clone)]
pub struct foo {
    pub x: ::core::ffi::c_longlong,
    pub __bindgen_padding_0: __BindgenOpaqueArray8<[u8; 8usize]>,
    pub y: u128,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
    ["Size of foo"][::core::mem::size_of::<foo>() - 32usize];
    ["Alignment of foo"][::core::mem::align_of::<foo>() - 16usize];
    ["Offset of field: foo::x"][::core::mem::offset_of!(foo, x) - 0usize];
    ["Offset of field: foo::y"][::core::mem::offset_of!(foo, y) - 16usize];
};

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the issue with header.h and bindgen header.h -- --target=riscv32-unknown-none-elf, then inspect the generated bindings.rs and the change introduced by commit 64f0939766c792822bd03c6733972e7e1067724. Compare it with the 0.73.1 output. Done means the generated struct places y at offset 16 on riscv32 and the compile-time layout checks pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.