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 expected union size with Rust union #908

Closed
tmfink opened this issue Aug 12, 2017 · 0 comments · Fixed by #909
Closed

Wrong expected union size with Rust union #908

tmfink opened this issue Aug 12, 2017 · 0 comments · Fixed by #909

Comments

@tmfink
Copy link
Contributor

tmfink commented Aug 12, 2017

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.

bors-servo pushed a commit that referenced this issue Aug 14, 2017
Fixes alignment errors with new Rust union type

This fix creates a new private field with the required aligned size. This new
private field ensures that the union has the required size.

This fixes: #908
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 a pull request may close this issue.

1 participant