Skip to content

#[repr(packed(n))] struct support #433

@cyphar

Description

@cyphar

Split off from #431

Right now, we don't generate structs for #[repr(packed(n))] structures because it appears that there is a fair amount of difficulty generating the correct field alignments due to disparities between the semantics of GCC's __attribute__((aligned(n))) with __attribute__((packed)) and Rust's #[repr(packed(n))]. The below is a quote from #431 describing the problem:


If I'm reading this right, it turns out that #[repr(packed(n))] does not really have a simple native C representation. In Rust, #[repr(packed(n))] indicates that the fields should have the smaller of n and std::mem::align_of<field_type>() as their alignment. While it is true that in C you can specify individual field alignments like so:

struct foo {
  uint64_t foo1 __attribute__((aligned(32)));
  uint32_t foo2 __attribute__((aligned(32)));
  uint16_t foo3 __attribute__((aligned(32)));
  uint8_t foo4 __attribute__((aligned(32)));
  bool foo5 __attribute__((aligned(32)));
} __attribute__((packed));

The issue is that, in Rust, the following struct:

#[repr(C, packed(32))]
struct Foo {
  foo1: u64;
  foo2: u32;
  foo3: u16;
  foo4: u8;
  foo5: bool;
}

Should actually be represented as (depending on your architecture):

struct foo {
  uint64_t foo1 __attribute__((aligned(8)));
  uint32_t foo2 __attribute__((aligned(4)));
  uint16_t foo3 __attribute__((aligned(2)));
  uint8_t foo4 __attribute__((aligned(1)));
  bool foo5 __attribute__((aligned(1)));
} __attribute__((packed));

And it's not clear to me how we can determine what the natural alignment of the constituent types is. And unfortunately, this is critical to making sure that C and Rust code can interoperate with packed structures. It's a bit unfortunate that Rust decided to have different semantics to GCC's alignment extensions. The extra kicker is that (AFAIK) std::mem::align_of::<>() depends on your architecture, so we'd probably have to do lots of extra work to generate the right alignment for each architecture rust supports.

And it's important to note that getting this wrong will almost certainly result in pretty hideous crashes.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions