Skip to content
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

Closed
wants to merge 3 commits into from

Conversation

youknowone
Copy link

@youknowone youknowone commented Jul 26, 2022

close #2246
fix align codegen of #2240
fix align codegen of #2159
fix align codegen of #1538

@youknowone youknowone marked this pull request as draft July 27, 2022 19:03
@youknowone youknowone force-pushed the packed-align-conflict branch 3 times, most recently from 065d903 to 7cc3a34 Compare July 27, 2022 19:43
@youknowone youknowone marked this pull request as ready for review July 27, 2022 19:48
@youknowone youknowone requested a review from emilio July 27, 2022 19:50
@youknowone
Copy link
Author

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));
}

@youknowone
Copy link
Author

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))
    );
}

@youknowone youknowone marked this pull request as draft July 27, 2022 20:07
@youknowone youknowone force-pushed the packed-align-conflict branch 2 times, most recently from cc0ce21 to ec4094f Compare July 27, 2022 21:41
Copy link
Author

@youknowone youknowone left a 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.

@@ -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 {
Copy link
Author

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.

Copy link
Contributor

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?

Copy link
Author

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 {
Copy link
Contributor

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)?

Copy link
Author

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))]
Copy link
Contributor

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.

Copy link
Author

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))]
   |        

@@ -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 {
Copy link
Contributor

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);
Copy link
Contributor

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.

Copy link
Author

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.

Copy link
Author

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));

@youknowone youknowone force-pushed the packed-align-conflict branch 4 times, most recently from 2f67f2a to 03837ca Compare July 28, 2022 20:57
@youknowone
Copy link
Author

youknowone commented Jul 28, 2022

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.

@youknowone
Copy link
Author

@emilio do you have advices?

@youknowone
Copy link
Author

@emilio can I get advice for remaining issues?

@emilio
Copy link
Contributor

emilio commented Aug 18, 2022

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.

@youknowone
Copy link
Author

youknowone commented Aug 18, 2022

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.

@bors-servo
Copy link

☔ The latest upstream changes (presumably #2284) made this pull request unmergeable. Please resolve the merge conflicts.

@CGMossa
Copy link
Contributor

CGMossa commented Apr 10, 2023

Can I kindly ask that this gets looked at please?

@pvdrz
Copy link
Contributor

pvdrz commented Apr 10, 2023

I've seen several issues and PRs discussing problems with packed and align representations. I'll gather some info and have a proper discussion around it with other contributors.

@pvdrz pvdrz deleted the branch rust-lang:master November 2, 2023 17:50
@pvdrz pvdrz closed this Nov 2, 2023
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.

None yet

5 participants