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

Wrong layout for packed struct with bitfields #981

Open
helloqirun opened this issue Sep 12, 2017 · 8 comments
Open

Wrong layout for packed struct with bitfields #981

helloqirun opened this issue Sep 12, 2017 · 8 comments

Comments

@helloqirun
Copy link

I am using this script https://gist.github.com/fitzgen/187381e358f60efa8194d0b276b4d11a.

The hashtag for my bindgen version is 4dd4ac7 .

$ ./b.sh bindgen abc.h

clang-4.0: warning: treating 'c-header' input as 'c++-header' when in C++ mode, this behavior is deprecated [-Wdeprecated]
ERROR:bindgen::codegen::struct_layout: Calculated wrong layout for _bindgen_ty_1, too more 3 bytes
error[E0530]: function parameters cannot shadow statics
 --> /tmp/bindings-Og3Z2F.rs:3:1686
  |
3 | # [ repr ( C ) ] # [ derive ( Debug , Copy ) ] pub struct a { pub _bitfield_1 : u8 , pub __bindgen_padding_0 : [ u8 ; 3usize ] , pub __bindgen_align : [ u32 ; 0usize ] , } # [ test ] fn bindgen_test_layout_a ( ) { assert_eq ! ( :: std :: mem :: size_of :: < a > ( ) , 4usize , concat ! ( "Size of: " , stringify ! ( a ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < a > ( ) , 4usize , concat ! ( "Alignment of " , stringify ! ( a ) ) ) ; } impl Clone for a { fn clone ( & self ) -> Self { * self } } impl a { # [ inline ] pub fn b ( & self ) -> :: std :: os :: raw :: c_uint { let mut unit_field_val : u8 = unsafe { :: std :: mem :: uninitialized ( ) } ; unsafe { :: std :: ptr :: copy_nonoverlapping ( & self . _bitfield_1 as * const _ as * const u8 , & mut unit_field_val as * mut u8 as * mut u8 , :: std :: mem :: size_of :: < u8 > ( ) , ) } ; let mask = 7u64 as u8 ; let val = ( unit_field_val & mask ) >> 0usize ; unsafe { :: std :: mem :: transmute ( val as u32 ) } } # [ inline ] pub fn set_b ( & mut self , val : :: std :: os :: raw :: c_uint ) { let mask = 7u64 as u8 ; let val = val as u32 as u8 ; let mut unit_field_val : u8 = unsafe { :: std :: mem :: uninitialized ( ) } ; unsafe { :: std :: ptr :: copy_nonoverlapping ( & self . _bitfield_1 as * const _ as * const u8 , & mut unit_field_val as * mut u8 as * mut u8 , :: std :: mem :: size_of :: < u8 > ( ) , ) } ; unit_field_val &= ! mask ; unit_field_val |= ( val << 0usize ) & mask ; unsafe { :: std :: ptr :: copy_nonoverlapping ( & unit_field_val as * const _ as * const u8 , & mut self . _bitfield_1 as * mut _ as * mut u8 , :: std :: mem :: size_of :: < u8 > ( ) , ) ; } } # [ inline ] pub fn new_bitfield_1 ( b : :: std :: os :: raw :: c_uint ) -> u8 { ( 0 | ( ( b as u32 as u8 ) << 0usize ) & ( 7u64 as u8 ) ) } } # [ repr ( C , packed ) ] # [ derive ( Debug , Copy ) ] pub struct _bindgen_ty_1 { pub _bitfield_1 : [ u32 ; 2usize ] , pub __bindgen_align : [ u8 ; 0usize ] , } # [ test ] fn bindgen_test_layout__bindgen_ty_1 ( ) { assert_eq ! ( :: std :: mem :: size_of :: < _bindgen_ty_1 > ( ) , 5usize , concat ! ( "Size of: " , stringify ! ( _bindgen_ty_1 ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < _bindgen_ty_1 > ( ) , 1usize , concat ! ( "Alignment of " , stringify ! ( _bindgen_ty_1 ) ) ) ; } impl Clone for _bindgen_ty_1 { fn clone ( & self ) -> Self { * self } } impl _bindgen_ty_1 { # [ inline ] pub fn new_bitfield_1 ( ) -> u64 { 0 } } extern "C" {
  |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      ^ cannot be named the same as a static
4 |  # [ link_name = "b" ]
5 |  pub static mut  b  :  _bindgen_ty_1 ;
  |  ------------------------------------- a static `b` is defined here

error: aborting due to previous error

Interesting: bindgen emitted Rust code that won't compile!

$ cat abc.h

struct a {
  unsigned b : 3;
};
struct __attribute__((packed)) {
  unsigned : 6;
  unsigned : 32;
} b;
@fitzgen
Copy link
Member

fitzgen commented Sep 12, 2017

Thanks for the bug report :)

@fitzgen
Copy link
Member

fitzgen commented Sep 12, 2017

The argument shadowing is a dupe of #840

But I am going to test the layout issue without the shadowing and see if that is its own bug.

@fitzgen fitzgen changed the title Calculated wrong layout Wrong layout for packed struct with bitfields Sep 12, 2017
@fitzgen
Copy link
Member

fitzgen commented Sep 12, 2017

Here is a modified version of the test case with just the packed + bitfield layout issues:

struct __attribute__((packed)) PackedWithBitfields {
    unsigned six_bits : 6;
    unsigned thirty_two_bits : 32;
};

Which results in this:

running 1 test
test bindgen_test_layout_PackedWithBitfields ... FAILED

failures:

---- bindgen_test_layout_PackedWithBitfields stdout ----
	thread 'bindgen_test_layout_PackedWithBitfields' panicked at 'assertion failed: `(left == right)`
  left: `8`,
 right: `5`: Size of: PackedWithBitfields', /home/fitzgen/scratch/output.rs:11:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.


failures:
    bindgen_test_layout_PackedWithBitfields

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

@helloqirun
Copy link
Author

Hi Nick, here is a simpler case.

The two cases reported here are reduced from the same testcase.

$ ./b.sh bindgen abc.h

clang-4.0: warning: treating 'c-header' input as 'c++-header' when in C++ mode, this behavior is deprecated [-Wdeprecated]
abc.h:2:12: warning: width of anonymous bit-field (632 bits) exceeds width of its type; value will be truncated to 32 bits [-Wbitfield-width]
  unsigned : 632;
           ^
1 warning generated.
abc.h:2:12: warning: width of anonymous bit-field (632 bits) exceeds width of its type; value will be truncated to 32 bits [-Wbitfield-width], err: false
ERROR:bindgen::codegen::struct_layout: Calculated wrong layout for _bindgen_ty_1, too more 48 bytes
error[E0277]: the trait bound `[u8; 128]: std::fmt::Debug` is not satisfied
 --> /tmp/bindings-UWtj35.rs:3:75
  |
3 | # [ repr ( C ) ] # [ derive ( Debug , Copy ) ] pub struct _bindgen_ty_1 { pub _bitfield_1 : [ u8 ; 128usize ] , pub __bindgen_align : [ u64 ; 0usize ] , } # [ test ] fn bindgen_test_layout__bindgen_ty_1 ( ) { assert_eq ! ( :: std :: mem :: size_of :: < _bindgen_ty_1 > ( ) , 80usize , concat ! ( "Size of: " , stringify ! ( _bindgen_ty_1 ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < _bindgen_ty_1 > ( ) , 8usize , concat ! ( "Alignment of " , stringify ! ( _bindgen_ty_1 ) ) ) ; } impl Clone for _bindgen_ty_1 { fn clone ( & self ) -> Self { * self } } extern "C" {
  |                                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[u8; 128]` cannot be formatted using `:?`; if it is defined in your crate, add `#[derive(Debug)]` or manually implement it
  |
  = help: the trait `std::fmt::Debug` is not implemented for `[u8; 128]`
  = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[u8; 128]`
  = note: required for the cast to the object type `std::fmt::Debug`

error: aborting due to previous error

Interesting: bindgen emitted Rust code that won't compile!

$ cat abc.h

struct {
  unsigned : 632;
} a;

@fitzgen
Copy link
Member

fitzgen commented Sep 12, 2017

Hi Nick, here is a simpler case.

I think this is actually a slightly different bug: we aren't taking into account bitfield allocation units' widths when determining if we can derive various traits or somethign like that.

I'll file a new issue.

@fitzgen
Copy link
Member

fitzgen commented Sep 12, 2017

Filed #982

@fitzgen
Copy link
Member

fitzgen commented Nov 1, 2017

A couple more instances of this bug:

struct WithBitfieldAndAttrPacked {
    unsigned : 7;
    unsigned a;
} __attribute__((packed));

#pragma pack(1)
struct WithBitfieldAndPacked {
    unsigned : 7;
    unsigned a;
};

@johalun
Copy link

johalun commented Jan 30, 2018

Is this still a problem? I'm running into this error using bindgen 0.30.0 with code

struct region_descriptor {
	uint64_t rd_limit:16;		/* segment extent */
	uint64_t rd_base:64 __packed;	/* base address  */
} __packed;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants