rust-lang / rust-lang/rust-bindgen

handle more cases of packed and aligned structs when it's safe/correct

Open
#2,725 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement help wanted rust-for-linux
Dominant language
Rust
Stars
5.3k
Forks
829
Avg merge
1d 1h
Merged PRs (30d)
15

Description

When a C struct has both packed and aligned(N) attributes, in some cases bindgen generates a Rust struct with a packed(N) attribute only that has the correct ABI. (Note, I'm assuming GCC semantics for the packed and aligned(N) attributes on the C side.)

In other cases, though, bindgen generates code with both attributes, which doesn't compile under rustc. Many of these cases can be handled correctly by applying only an align(N) attribute; intuitively, this should work if the struct is "naturally packed".

Here is a minimal example:

struct mytest {
        uint32_t a;
        uint32_t b;
} __attribute__((packed, aligned(8)));

# bindgen generates: 

#[repr(C, packed(8))]
#[repr(align(8))]
#[derive(Debug, Copy, Clone)]
pub struct mytest {
    pub a: u32,
    pub b: u32,
}

# but this would be correct and ABI compatible: 

#[repr(C, align(8))]
#[derive(Debug, Copy, Clone)]
pub struct mytest {
    pub a: u32,
    pub b: u32,
}

This comes up for a handful of structs used in bcachefs. I wrote about this in a message to the rust-for-linux email list:
https://lore.kernel.org/rust-for-linux/20240122024711.GC151023@fedora-laptop/T/#m4439be01c0bcfdbaa781c379be3e227358cfab27

From that message:

In general, given a C structure like

struct A {
...
} __packed __aligned(N);

I think a Rust structure can be created with the same size, alignment,
and member offsets in the following cases:

(1) #[repr(packed(N))] will have the same layout if N is <= the
structure's default alignment and all members with a default
alignment >= N naturally have an offset that is a multiple of N.
Also, no member can have an alignment attribute as rustc forbids
this [2].

(2) #[repr(align(N))] will have the same layout if the structure's size
without the packed attribute is equal to the sum of the size of all
its members (i.e., it is "naturally packed"), and the structure's
default alignment is <= N.

It looks like bindgen already mostly handles case (1).

However, bindgen doesn't seem to handle case (2). What do you think of adding the logic to handle that case into bindgen? This would be really helpful for bcachefs with the structs mentioned in the above email.

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

The issue names no implementation file or test; start with bindgen's struct-attribute and layout-generation entry points, using the minimal packed-and-aligned C example as the reproduction. Done means safely emitting only the compatible Rust alignment representation for naturally packed structs while preserving size, alignment, member offsets, and ABI compatibility.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, rust
Domain
tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.