Skip to content

Do not insert dummy fields into bitfields in cases where this would cause misalignment. - #3431

Open
flowerhack wants to merge 1 commit into
rust-lang:mainfrom
flowerhack:fix-bindgen-alignment
Open

Do not insert dummy fields into bitfields in cases where this would cause misalignment.#3431
flowerhack wants to merge 1 commit into
rust-lang:mainfrom
flowerhack:fix-bindgen-alignment

Conversation

@flowerhack

Copy link
Copy Markdown

Suppose you have the following C++ code:

// reproduce.h
struct __attribute__((aligned(8))) StructWithBitfieldAndDouble {
  unsigned int bitfield: 32;
  double standard_field;
};

// reproduce.cpp
 #include "reproduce.h"
 #include <iostream>
int main() {
  std::cout << "cpp_size=" << sizeof(SomeStruct) << std::endl;
  std::cout << "cpp_align=" << alignof(SomeStruct) << std::endl;
  return 0;
}

As of right now, Bindgen will produce the following Rust code:

 #[repr(C)]
 #[repr(align(8))]
 #[derive(Debug, Default, Copy, Clone)]
pub struct StructWithBitfieldAndDouble {
  pub _bindgen_align: [u64; 0],
  pub _bitfield_1: __BindgenBitfieldUnit<[u8, 4usize]>,
  pub standard_field: f64,
}

If Bindgen compiles this targeting a 32-bit architecture, the C++ struct will be 16 bytes in size (as one would expect, based on the aligned(8)), but the Rust struct will be only 12 bytes in size (because the alignment of u64 is 4, so _bindgen_align, as a zero-length struct, ends up occupying 0 bytes of space, and the struct's overall size will thus be 12).

This occurs because of the way dummy fields are added to bitfields as per #3247.

We should check that the target primitive's alignment is greater-than-or-equal-to the explicitly-defined alignment in these cases, and fall back to simply using the explicit alignment in those cases.

@flowerhack
flowerhack force-pushed the fix-bindgen-alignment branch from f4ecf5c to f3a08ef Compare August 12, 2026 22:46
cause misalignment.

Suppose you have the following C++ code:

```
// reproduce.h
struct __attribute__((aligned(8))) StructWithBitfieldAndDouble {
  unsigned int bitfield: 32;
  double standard_field;
};

// reproduce.cpp
 #include "reproduce.h"
 #include <iostream>
int main() {
  std::cout << "cpp_size=" << sizeof(SomeStruct) << std::endl;
  std::cout << "cpp_align=" << alignof(SomeStruct) << std::endl;
  return 0;
}
```

As of right now, Bindgen will produce the following Rust code:

```
 #[repr(C)]
 #[repr(align(8))]
 #[derive(Debug, Default, Copy, Clone)]
pub struct StructWithBitfieldAndDouble {
  pub _bindgen_align: [u64; 0],
  pub _bitfield_1: __BindgenBitfieldUnit<[u8, 4usize]>,
  pub standard_field: f64,
}
```

If Bindgen compiles this targeting a 32-bit architecture, the C++ struct
will be 16 bytes in size (as one would expect, based on the `aligned(8)`),
but the Rust struct will be only 12 bytes in size (because the alignment
of u64 is 4, so _bindgen_align, as a zero-length struct, ends up
occupying 0 bytes of space, and the struct's overall size will thus be
12).

This occurs because of the way dummy fields are added to bitfields as
per rust-lang#3247.

We should check that the target primitive's alignment is
greater-than-or-equal-to the explicitly-defined alignment in these
cases, and fall back to simply using the explicit alignment in those
cases.
@flowerhack
flowerhack force-pushed the fix-bindgen-alignment branch from f3a08ef to 191f933 Compare August 12, 2026 22:53
@flowerhack

Copy link
Copy Markdown
Author

r? @pvdrz

Hi, I'm new! but I read the CONTRIBUTING.md and believe I'm following all the guidelines there; let me know if I missed anything.

I didn't see any kind of LLM policy, but, in case there is one and I missed it:

  • I used Gemini to help determine the root cause of the compilation failure we saw in Chromium, which was caused by this particular bit of Bindgen code.
  • I verified Gemini's reasoning myself (the code in Chromium that caused the failure was code I wrote myself, so I was familiar with the area and confident I could evaluate it).
  • I used Gemini to minimize the test case we had for demonstrating this failure.
  • The fix, the commit message and all comments were written by myself.
  • I used Bindgen's standard workflow for generating expectation files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants