-
Notifications
You must be signed in to change notification settings - Fork 707
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
More bitfield brokenness #743
Comments
The System V ABI for x86-64 says:
Which I interpret to mean that bitfields can reuse padding elements. In other words, for bitfield considerations, the struct looks like: struct Foo {
unsigned long dummy : 32;
unsigned long foo : 1; /* Yay, I fit in the upper 32 bits of dummy's 64-bit qword! */
unsigned long bar : POINTER_WIDTH;
}; I suppose there's a reason why bitfields tend to be buggy in complex ABI situations. P.S. The MSVC ABI does something very different for bitfield layout. |
Yeah, I'm aware of the Bitfields are buggy because of how we represent structs. Doing the math to see at which offset the bitfield is is easy (and clang gives us a lot of info), but getting the next field to align properly is somewhat hard, given rust doesn't give a lot of control about it. We could of course treat structs as a bucket of bytes and do reads at the offsets clang gives us... But that'd be barely usable for normal structs. We could also use |
I don't think this would actually be that terrible if we generated getters and setters. It would require a breaking version bump, of course. The other option is to move padding insertion into its own phase before codegen and represent it explicitly in the IR. This should help us see these "oh look at all that room for bitfields" situations better, as well as those bugs where we're conservative about deriving because there could be lots of padding we don't know about yet. |
I've observed this when trying to generate bindings for Mesa's NIR compiler. In particular, for typedef struct {
nir_dest dest;
bool saturate;
unsigned write_mask : 16;
} nir_alu_dest; Bindgen attempts to align pub struct nir_alu_dest {
pub dest: nir_dest,
pub saturate: bool,
pub _bitfield_align_1: [u16; 0],
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize]>,
pub __bindgen_padding_0: [u8; 5usize],
} However, this is wrong because C puts it immediately after the boolean. I also have no idea what's up with the 5B padding at the end. That one makes no sense to me at all. |
@gfxstrand do the layout tests catch this issue? What is That said, can mesa use a |
Sure, I can try to reduce the example a bit. As for |
Here's a reduced example: struct S {
void *p;
bool b;
unsigned u : 16;
}; It produces #[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct S {
pub p: *mut ::std::os::raw::c_void,
pub b: bool,
pub _bitfield_align_1: [u16; 0],
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize]>,
pub __bindgen_padding_0: [u8; 5usize],
} which is pretty much the same, down to the weird 5B padding at the end. |
While investigating #739, I found out that the following:
Generates what I think it's correct code:
But apparently isn't, and Clang manages to stick the first bitfield after the int (wat).
The following is also incorrect, generating the right layout but the wrong offset:
We generate an
int
, then one word when we stick the two bitfields, but clang does the first bit at offset 32 (right after theint
), and the other 63 bits after the gap, in the nextu64
.Sigh.
The text was updated successfully, but these errors were encountered: