rust-lang / rust-lang/rust-bindgen
`long double` alignment tests fail on riscv32
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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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