Skip to content

Wrong expected union size with Rust union #908

@tmfink

Description

@tmfink

This issue can be reproduced by adding --unstable-union to tests/headers/16-byte-alignment.h.

Input C/C++ Header

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;

struct rte_ipv4_tuple {
    uint32_t src_addr;
    uint32_t dst_addr;
    union {
        struct {
            uint16_t dport;
            uint16_t sport;
        };
        uint32_t sctp_tag;
    };
};

struct rte_ipv6_tuple {
    uint8_t src_addr[16];
    uint8_t dst_addr[16];
    union {
        struct {
            uint16_t dport;
            uint16_t sport;
        };
        uint32_t    sctp_tag;
    };
};

union rte_thash_tuple {
    struct rte_ipv4_tuple   v4;
    struct rte_ipv6_tuple   v6;
} __attribute__((aligned(16)));

Bindgen Invocation

$ bindgen input.h --with-derive-hash --unstable-rust

Actual Results

Bindgen generates:

/* automatically generated by rust-bindgen */

#[repr(C)]
#[derive(Copy)]
pub struct rte_ipv4_tuple {
    pub src_addr: u32,
    pub dst_addr: u32,
    pub __bindgen_anon_1: rte_ipv4_tuple__bindgen_ty_1,
}
#[repr(C)]
#[derive(Copy)]
pub union rte_ipv4_tuple__bindgen_ty_1 {
    pub __bindgen_anon_1: rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1,
    pub sctp_tag: u32,
}
#[repr(C)]
#[derive(Debug, Copy, Hash)]
pub struct rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1 {
    pub dport: u16,
    pub sport: u16,
}
#[test]
fn bindgen_test_layout_rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1() {
    assert_eq!(::std::mem::size_of::<rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1>()
               , 4usize , concat ! (
               "Size of: " , stringify ! (
               rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1 ) ));
    assert_eq! (::std::mem::align_of::<rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1>()
                , 2usize , concat ! (
                "Alignment of " , stringify ! (
                rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1 ) ));
    assert_eq! (unsafe {
                & (
                * ( 0 as * const rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1 )
                ) . dport as * const _ as usize } , 0usize , concat ! (
                "Alignment of field: " , stringify ! (
                rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1 ) , "::" ,
                stringify ! ( dport ) ));
    assert_eq! (unsafe {
                & (
                * ( 0 as * const rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1 )
                ) . sport as * const _ as usize } , 2usize , concat ! (
                "Alignment of field: " , stringify ! (
                rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1 ) , "::" ,
                stringify ! ( sport ) ));
}
impl Clone for rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1 {
    fn clone(&self) -> Self { *self }
}
#[test]
fn bindgen_test_layout_rte_ipv4_tuple__bindgen_ty_1() {
    assert_eq!(::std::mem::size_of::<rte_ipv4_tuple__bindgen_ty_1>() , 4usize
               , concat ! (
               "Size of: " , stringify ! ( rte_ipv4_tuple__bindgen_ty_1 ) ));
    assert_eq! (::std::mem::align_of::<rte_ipv4_tuple__bindgen_ty_1>() ,
                4usize , concat ! (
                "Alignment of " , stringify ! ( rte_ipv4_tuple__bindgen_ty_1 )
                ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const rte_ipv4_tuple__bindgen_ty_1 ) ) .
                sctp_tag as * const _ as usize } , 0usize , concat ! (
                "Alignment of field: " , stringify ! (
                rte_ipv4_tuple__bindgen_ty_1 ) , "::" , stringify ! ( sctp_tag
                ) ));
}
impl Clone for rte_ipv4_tuple__bindgen_ty_1 {
    fn clone(&self) -> Self { *self }
}
#[test]
fn bindgen_test_layout_rte_ipv4_tuple() {
    assert_eq!(::std::mem::size_of::<rte_ipv4_tuple>() , 12usize , concat ! (
               "Size of: " , stringify ! ( rte_ipv4_tuple ) ));
    assert_eq! (::std::mem::align_of::<rte_ipv4_tuple>() , 4usize , concat ! (
                "Alignment of " , stringify ! ( rte_ipv4_tuple ) ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const rte_ipv4_tuple ) ) . src_addr as * const
                _ as usize } , 0usize , concat ! (
                "Alignment of field: " , stringify ! ( rte_ipv4_tuple ) , "::"
                , stringify ! ( src_addr ) ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const rte_ipv4_tuple ) ) . dst_addr as * const
                _ as usize } , 4usize , concat ! (
                "Alignment of field: " , stringify ! ( rte_ipv4_tuple ) , "::"
                , stringify ! ( dst_addr ) ));
}
impl Clone for rte_ipv4_tuple {
    fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Copy)]
pub struct rte_ipv6_tuple {
    pub src_addr: [u8; 16usize],
    pub dst_addr: [u8; 16usize],
    pub __bindgen_anon_1: rte_ipv6_tuple__bindgen_ty_1,
}
#[repr(C)]
#[derive(Copy)]
pub union rte_ipv6_tuple__bindgen_ty_1 {
    pub __bindgen_anon_1: rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1,
    pub sctp_tag: u32,
}
#[repr(C)]
#[derive(Debug, Copy, Hash)]
pub struct rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1 {
    pub dport: u16,
    pub sport: u16,
}
#[test]
fn bindgen_test_layout_rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1() {
    assert_eq!(::std::mem::size_of::<rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1>()
               , 4usize , concat ! (
               "Size of: " , stringify ! (
               rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1 ) ));
    assert_eq! (::std::mem::align_of::<rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1>()
                , 2usize , concat ! (
                "Alignment of " , stringify ! (
                rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1 ) ));
    assert_eq! (unsafe {
                & (
                * ( 0 as * const rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1 )
                ) . dport as * const _ as usize } , 0usize , concat ! (
                "Alignment of field: " , stringify ! (
                rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1 ) , "::" ,
                stringify ! ( dport ) ));
    assert_eq! (unsafe {
                & (
                * ( 0 as * const rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1 )
                ) . sport as * const _ as usize } , 2usize , concat ! (
                "Alignment of field: " , stringify ! (
                rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1 ) , "::" ,
                stringify ! ( sport ) ));
}
impl Clone for rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1 {
    fn clone(&self) -> Self { *self }
}
#[test]
fn bindgen_test_layout_rte_ipv6_tuple__bindgen_ty_1() {
    assert_eq!(::std::mem::size_of::<rte_ipv6_tuple__bindgen_ty_1>() , 4usize
               , concat ! (
               "Size of: " , stringify ! ( rte_ipv6_tuple__bindgen_ty_1 ) ));
    assert_eq! (::std::mem::align_of::<rte_ipv6_tuple__bindgen_ty_1>() ,
                4usize , concat ! (
                "Alignment of " , stringify ! ( rte_ipv6_tuple__bindgen_ty_1 )
                ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const rte_ipv6_tuple__bindgen_ty_1 ) ) .
                sctp_tag as * const _ as usize } , 0usize , concat ! (
                "Alignment of field: " , stringify ! (
                rte_ipv6_tuple__bindgen_ty_1 ) , "::" , stringify ! ( sctp_tag
                ) ));
}
impl Clone for rte_ipv6_tuple__bindgen_ty_1 {
    fn clone(&self) -> Self { *self }
}
#[test]
fn bindgen_test_layout_rte_ipv6_tuple() {
    assert_eq!(::std::mem::size_of::<rte_ipv6_tuple>() , 36usize , concat ! (
               "Size of: " , stringify ! ( rte_ipv6_tuple ) ));
    assert_eq! (::std::mem::align_of::<rte_ipv6_tuple>() , 4usize , concat ! (
                "Alignment of " , stringify ! ( rte_ipv6_tuple ) ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const rte_ipv6_tuple ) ) . src_addr as * const
                _ as usize } , 0usize , concat ! (
                "Alignment of field: " , stringify ! ( rte_ipv6_tuple ) , "::"
                , stringify ! ( src_addr ) ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const rte_ipv6_tuple ) ) . dst_addr as * const
                _ as usize } , 16usize , concat ! (
                "Alignment of field: " , stringify ! ( rte_ipv6_tuple ) , "::"
                , stringify ! ( dst_addr ) ));
}
impl Clone for rte_ipv6_tuple {
    fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Copy)]
pub union rte_thash_tuple {
    pub v4: rte_ipv4_tuple,
    pub v6: rte_ipv6_tuple,
}
#[test]
fn bindgen_test_layout_rte_thash_tuple() {
    assert_eq!(::std::mem::size_of::<rte_thash_tuple>() , 48usize , concat ! (
               "Size of: " , stringify ! ( rte_thash_tuple ) ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const rte_thash_tuple ) ) . v4 as * const _ as
                usize } , 0usize , concat ! (
                "Alignment of field: " , stringify ! ( rte_thash_tuple ) ,
                "::" , stringify ! ( v4 ) ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const rte_thash_tuple ) ) . v6 as * const _ as
                usize } , 0usize , concat ! (
                "Alignment of field: " , stringify ! ( rte_thash_tuple ) ,
                "::" , stringify ! ( v6 ) ));
}
impl Clone for rte_thash_tuple {
    fn clone(&self) -> Self { *self }
}

Compiling bindings (after adding a main function) leads to:

$ rustc --test test.rs -o test  # build test harness
...
$ ./test
running 7 tests
test bindgen_test_layout_rte_ipv4_tuple__bindgen_ty_1 ... ok
test bindgen_test_layout_rte_ipv6_tuple ... ok
test bindgen_test_layout_rte_ipv6_tuple__bindgen_ty_1 ... ok
test bindgen_test_layout_rte_ipv4_tuple ... ok
test bindgen_test_layout_rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1 ... ok
test bindgen_test_layout_rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1 ... ok
test bindgen_test_layout_rte_thash_tuple ... FAILED

failures:

---- bindgen_test_layout_rte_thash_tuple stdout ----
        thread 'bindgen_test_layout_rte_thash_tuple' panicked at 'assertion failed: `(left == right)` (left: `36`, right: `48`): Size of: rte_thash_tuple', tests/16-byte-alignment.rs:199
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Expected Results

Predicted and actual union sizes match.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions