Bitfields should be packed into earlier fields if alignment allows so. #1377
Open
Description
opened on Aug 30, 2018
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_t raw;
struct {
uint8_t available_spare : 1;
uint8_t temperature : 1;
uint8_t device_reliability : 1;
uint8_t read_only : 1;
uint8_t volatile_memory_backup : 1;
uint8_t reserved : 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.
Activity