Skip to content

Bitfields should be packed into earlier fields if alignment allows so. #1377

@xxks-kkk

Description

@xxks-kkk

Per the discussion with @emilio on issue #687, I create this new issue for better tracking.

Input C/C++ Header

I have the following structure definition in C

/**  * Data used by Set Features / Get Features \ref SPDK_NVME_FEAT_ASYNC_EVENT_CONFIGURATION  */ union spdk_nvme_feat_async_event_configuration { uint32_t raw; struct { union spdk_nvme_critical_warning_state crit_warn; uint32_t ns_attr_notice: 1; uint32_t fw_activation_notice: 1; uint32_t telemetry_log_notice: 1; uint32_t reserved: 21;	} bits; }; SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_async_event_configuration) == 4, "Incorrect size");

It is translated as

/// Data used by Set Features / Get Features \ref SPDK_NVME_FEAT_ASYNC_EVENT_CONFIGURATION #[repr(C)] #[derive(Copy, Clone)] pub union spdk_nvme_feat_async_event_configuration { pub raw: u32, pub bits: spdk_nvme_feat_async_event_configuration__bindgen_ty_1, _bindgen_union_align: u32 } #[repr(C)] #[derive(Copy, Clone)] pub struct spdk_nvme_feat_async_event_configuration__bindgen_ty_1 { pub crit_warn: spdk_nvme_critical_warning_state, pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize], u32>, pub __bindgen_align: [u32; 0usize] }

However, during cargo test, the following test is failed

 bindgen_test_layout_spdk_nvme_feat_async_event_configuration bindgen_test_layout_spdk_nvme_feat_async_event_configuration__bindgen_ty_1 

The corresponding test is

#[test] fn bindgen_test_layout_spdk_nvme_feat_async_event_configuration() { assert_eq!(::std::mem::size_of::<spdk_nvme_feat_async_event_configuration>(), 4usize, concat!( "Size of: " , stringify ! ( spdk_nvme_feat_async_event_configuration ) )); assert_eq!(::std::mem::align_of::<spdk_nvme_feat_async_event_configuration>(), 4usize, concat!( "Alignment of " , stringify ! ( spdk_nvme_feat_async_event_configuration ) )); assert_eq!(unsafe { &(*(::std::ptr::null::<spdk_nvme_feat_async_event_configuration>())).raw as *const _ as usize }, 0usize, concat!( "Offset of field: " , stringify ! ( spdk_nvme_feat_async_event_configuration ) , "::" , stringify ! ( raw ) )); assert_eq!(unsafe { &(*(::std::ptr::null::<spdk_nvme_feat_async_event_configuration>())).bits as *const _ as usize }, 0usize, concat!( "Offset of field: " , stringify ! ( spdk_nvme_feat_async_event_configuration ) , "::" , stringify ! ( bits ) )); }

and the failure happens at

thread 'bindgen_test_layout_spdk_nvme_feat_async_event_configuration' panicked at 'assertion failed: `(left == right)` left: `8`, right: `4`: Size of: spdk_nvme_feat_async_event_configuration', /home/zeyuanhu/rustfs/rust-spdk/target/debug/build/rust-spdk-3c1fe41f551c8d38/out/bindings.rs:14005:5 thread 'bindgen_test_layout_spdk_nvme_feat_async_event_configuration__bindgen_ty_1' panicked at 'assertion failed: `(left == right)` left: `8`, right: `4`: Size of: spdk_nvme_feat_async_event_configuration__bindgen_ty_1', /home/zeyuanhu/rustfs/rust-spdk/target/debug/build/rust-spdk-3c1fe41f551c8d38/out/bindings.rs:13938:5 

From what I see, the union is 4 bytes on C but becomes 8 bytes in its corresponding Rust translation.

The spdk_nvme_critical_warning_state inside spdk_nvme_feat_async_event_configuration reported above is defined as

union spdk_nvme_critical_warning_state { uint8_traw; struct { uint8_tavailable_spare: 1; uint8_ttemperature: 1; uint8_tdevice_reliability: 1; uint8_tread_only: 1; uint8_tvolatile_memory_backup: 1; uint8_treserved: 3;	} bits; }; SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_critical_warning_state) == 1, "Incorrect size");

Bindgen Invocation

 let bindings = bindgen::Builder::default() .clang_arg(include_path) // The input header we would like to generate // bindings for. .header("src/wrapper.h") .blacklist_type("IPPORT_.*") // https://github.com/rust-lang-nursery/rust-bindgen/issues/687 .blacklist_type("max_align_t") // https://github.com/rust-lang-nursery/rust-bindgen/issues/550 // Finish the builder and generate the bindings. .generate() // Unwrap the Result and panic on failure. .expect("Unable to generate bindings");

Actual Results

See above.

Expected Results

union structure expected to be 4 bytes large but got 8 bytes instead.

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