-
Notifications
You must be signed in to change notification settings - Fork 717
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
Fix test case from #2246 #2248
Fix test case from #2246 #2248
Conversation
065d903
to
7cc3a34
Compare
mm.. test passes only because test doesn't include case about: typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
struct A {
uint8_t a;
uint16_t b;
uint8_t c;
} __attribute__((aligned(2)));
struct B {
uint8_t a;
uint16_t b;
uint8_t c;
} __attribute__((aligned(2), packed));
#include <assert.h>
#include <stdio.h>
int main() {
printf("%lu %lu\n", sizeof(struct A), sizeof(struct B));
assert(sizeof(struct A) == sizeof(struct B));
} |
is this the answer? #[repr(C, align(2))]
#[derive(Debug, Default, Copy, Clone)]
pub struct B(B__packed);
#[repr(C, packed)]
#[derive(Debug, Default, Copy, Clone)]
pub struct B__packed {
pub a: u8,
pub b: u16,
pub c: u8,
} #[test]
fn bindgen_test_layout_B() {
const UNINIT: ::std::mem::MaybeUninit<B> =
::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<B>(),
4usize,
concat!("Size of: ", stringify!(B))
);
assert_eq!(
::std::mem::align_of::<B>(),
2usize,
concat!("Alignment of ", stringify!(B))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).0.a) as usize - ptr as usize },
0usize,
concat!("Offset of field: ", stringify!(B), "::", stringify!(a))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).0.b) as usize - ptr as usize },
1usize,
concat!("Offset of field: ", stringify!(B), "::", stringify!(b))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).0.c) as usize - ptr as usize },
3usize,
concat!("Offset of field: ", stringify!(B), "::", stringify!(c))
);
} |
cc0ce21
to
ec4094f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still a few problems, but I think I made enough proof of concept how it works.
Now, packed struct also getting align attribute because I couldn't remove those case from requires_explicit_align
Also bitfield got problem. I need your advice for this case.
Except for those 2 cases, everything seems working.
The design probably is not very good. I feel like bindgen may already have a tool to handle those wrapper types.
src/codegen/struct_layout.rs
Outdated
@@ -365,7 +365,7 @@ impl<'a> StructLayoutTracker<'a> { | |||
return true; | |||
} | |||
|
|||
if self.max_field_align >= layout.align { | |||
if !self.is_packed && self.max_field_align >= layout.align { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to check if it has explicit align in C code to avoid packed-only also get align attribute in rust side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused about this change, can you elaborate? What case does this make a difference on?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because packed or aligned cases are already being handled well, I need to check packed and aligned case here:
https://github.com/rust-lang/rust-bindgen/pull/2248/files#diff-01720a19d4518b9c16feea9cefbee210a853a1c99d1e9b19aec23e72877e52f0R2019-R2023
Without change, any packed type will not be marked as explicit_align. So the new handling condition doesn't hit.
The new problem introduced by this is only packed struct is also marked as aligned. Does bindgen have a feature to dinstinguish it?
Because the estimated size for clang is different, it looks like to be distinguishable.
"packed".to_string() | ||
} else { | ||
format!("packed({})", n) | ||
}; | ||
attributes.push(attributes::repr_list(&["C", &packed_repr])); | ||
} else { | ||
attributes.push(attributes::repr("C")); | ||
} | ||
|
||
if ctx.options().rust_features().repr_align { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why removing the feature-check for repr(align)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
accidently happened during multiple revision 😂
.unwrap(); | ||
result.push(quote! { | ||
#attributes | ||
#[repr(C, align(#align))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably better if it'd be #[repr(transparent)]
, that'd match the ABI exactly, though I don't think it would matter in practice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't work. we need align
here but transparent seems doesn't accept other things.
error[E0692]: transparent struct cannot have other repr hints
--> tests/packed-align-conflict.rs:16:8
|
16 | #[repr(transparent, align(2))]
|
src/codegen/struct_layout.rs
Outdated
@@ -365,7 +365,7 @@ impl<'a> StructLayoutTracker<'a> { | |||
return true; | |||
} | |||
|
|||
if self.max_field_align >= layout.align { | |||
if !self.is_packed && self.max_field_align >= layout.align { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused about this change, can you elaborate? What case does this make a difference on?
pub i: ::std::os::raw::c_int, | ||
} | ||
#[derive(Debug, Default, Copy, Clone)] | ||
#[repr(C, align(2))] | ||
pub struct AlignedToTwo(AlignedToTwo__packed); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be public, how do folks access the fields otherwise? More to the point, we should try to only add this wrapper when absolutely needed (I think packed && max_field_align < explicit_align
, right?), and also we should probably impl Deref
and DerefMut
on the struct to get more convenient access / avoid most code breakage as a result of this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About Deref, Is there another wrapper mechanism to do it? Or this is the first place to add those Deref stuff?
The condition is logically right but I have no idea how to do yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Counter example about the condition.
// sizeof(B) == 6
struct B {
uint8_t a;
uint16_t b;
uint8_t c;
} __attribute__((aligned(2), packed));
This is packed but not max_field_align < explicit_align
(2 < 2).
The key idea we need to complete this task is distinguishing it from
// sizeof(B) == 4
struct B {
uint8_t a;
uint16_t b;
uint8_t c;
} __attribute__(packed));
2f67f2a
to
03837ca
Compare
aa0db92
to
8f31017
Compare
I added the last commit to check the CI result. I don't believe that's the correct way. Please suppose I am not understanding the remaining problems and how bindgen handle packed and aligned. |
@emilio do you have advices? |
@emilio can I get advice for remaining issues? |
Sorry for the lag, it's on my list of things to do. I plan to dig a bit into how C++ compilers treat repr+aligned hints because I'm not super-convinced there's a way to emulate it in Rust, but if you've done that research and can point to it it'd be extremely helpful. |
I think emulating in rust is done here. I forgot the datails now but If you need explanation, I can review it again. If bindgen cannot distinguish explicitly aligned and implicitly aligned struct, could you guide me to how to get clang-calcuated size and bindgen-calculated size for the struct? Then I will try to detect which alignment used by them. |
☔ The latest upstream changes (presumably #2284) made this pull request unmergeable. Please resolve the merge conflicts. |
Can I kindly ask that this gets looked at please? |
I've seen several issues and PRs discussing problems with |
close #2246
fix align codegen of #2240
fix align codegen of #2159
fix align codegen of #1538