Skip to content

Fix an UB in layout tests #2055

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

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2084,8 +2084,12 @@ impl CodeGenerator for CompInfo {
.count() >
1;


// The offset of #[repr(C)] union is always 0, don't need to recheck it.
let is_not_packed_union = is_union && !packed;

let should_skip_field_offset_checks =
is_opaque || too_many_base_vtables;
is_opaque || too_many_base_vtables || is_not_packed_union;

let check_field_offset = if should_skip_field_offset_checks
{
Expand All @@ -2105,8 +2109,26 @@ impl CodeGenerator for CompInfo {

Some(quote! {
assert_eq!(
unsafe {
&(*(::#prefix::ptr::null::<#canonical_ident>())).#field_name as *const _ as usize
{
// Create an instance of #canonical_ident struct from zero bit pattern
const STRUCT_SIZE: usize = std::mem::size_of::<#canonical_ident>();
let buffer = [0u8; STRUCT_SIZE];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not guaranteed to be aligned right? I think using std::mem::zeroed should be better.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed

Though, I don't catch why there is a wrong alignment. AFAIU, In case of mem::zeroed the padding bytes are not zeroed but the total behavior is the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, let's say you have a struct with an u32 member. The compiler would make sure that that is aligned appropriately, but if you use a flat array of u8s then it's not.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emilio
Ok, thank you. Replaced it with mem::zeroed

let struct_instance = unsafe {
// It's safe since #canonical_ident struct allows zero bit pattern
std::mem::transmute::<[u8; STRUCT_SIZE], #canonical_ident>(buffer)
};
// Get the pointers to the struct and its field
let struct_ptr = &struct_instance as *const #canonical_ident;
let field_ptr = std::ptr::addr_of!(struct_instance.#field_name);

// Get the offset of the field
let struct_address = struct_ptr as usize;
let field_address = field_ptr as usize;

//Do not call the destructor
std::mem::forget(struct_instance);

field_address.checked_sub(struct_address).unwrap()
},
#field_offset,
concat!("Offset of field: ", stringify!(#canonical_ident), "::", stringify!(#field_name))
Expand Down
198 changes: 120 additions & 78 deletions tests/expectations/tests/16-byte-alignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,24 @@ fn bindgen_test_layout_rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1() {
)
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1>(
)))
.dport as *const _ as usize
{
const STRUCT_SIZE: usize = std::mem::size_of::<
rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1,
>();
let buffer = [0u8; STRUCT_SIZE];
let struct_instance = unsafe {
std::mem::transmute::<
[u8; STRUCT_SIZE],
rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1,
>(buffer)
};
let struct_ptr = &struct_instance
as *const rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1;
let field_ptr = std::ptr::addr_of!(struct_instance.dport);
let struct_address = struct_ptr as usize;
let field_address = field_ptr as usize;
std::mem::forget(struct_instance);
field_address.checked_sub(struct_address).unwrap()
},
0usize,
concat!(
Expand All @@ -57,10 +71,24 @@ fn bindgen_test_layout_rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1() {
)
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1>(
)))
.sport as *const _ as usize
{
const STRUCT_SIZE: usize = std::mem::size_of::<
rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1,
>();
let buffer = [0u8; STRUCT_SIZE];
let struct_instance = unsafe {
std::mem::transmute::<
[u8; STRUCT_SIZE],
rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1,
>(buffer)
};
let struct_ptr = &struct_instance
as *const rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1;
let field_ptr = std::ptr::addr_of!(struct_instance.sport);
let struct_address = struct_ptr as usize;
let field_address = field_ptr as usize;
std::mem::forget(struct_instance);
field_address.checked_sub(struct_address).unwrap()
},
2usize,
concat!(
Expand All @@ -83,19 +111,6 @@ fn bindgen_test_layout_rte_ipv4_tuple__bindgen_ty_1() {
4usize,
concat!("Alignment of ", stringify!(rte_ipv4_tuple__bindgen_ty_1))
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<rte_ipv4_tuple__bindgen_ty_1>())).sctp_tag
as *const _ as usize
},
0usize,
concat!(
"Offset of field: ",
stringify!(rte_ipv4_tuple__bindgen_ty_1),
"::",
stringify!(sctp_tag)
)
);
}
impl Default for rte_ipv4_tuple__bindgen_ty_1 {
fn default() -> Self {
Expand All @@ -119,9 +134,18 @@ fn bindgen_test_layout_rte_ipv4_tuple() {
concat!("Alignment of ", stringify!(rte_ipv4_tuple))
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<rte_ipv4_tuple>())).src_addr as *const _
as usize
{
const STRUCT_SIZE: usize = std::mem::size_of::<rte_ipv4_tuple>();
let buffer = [0u8; STRUCT_SIZE];
let struct_instance = unsafe {
std::mem::transmute::<[u8; STRUCT_SIZE], rte_ipv4_tuple>(buffer)
};
let struct_ptr = &struct_instance as *const rte_ipv4_tuple;
let field_ptr = std::ptr::addr_of!(struct_instance.src_addr);
let struct_address = struct_ptr as usize;
let field_address = field_ptr as usize;
std::mem::forget(struct_instance);
field_address.checked_sub(struct_address).unwrap()
},
0usize,
concat!(
Expand All @@ -132,9 +156,18 @@ fn bindgen_test_layout_rte_ipv4_tuple() {
)
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<rte_ipv4_tuple>())).dst_addr as *const _
as usize
{
const STRUCT_SIZE: usize = std::mem::size_of::<rte_ipv4_tuple>();
let buffer = [0u8; STRUCT_SIZE];
let struct_instance = unsafe {
std::mem::transmute::<[u8; STRUCT_SIZE], rte_ipv4_tuple>(buffer)
};
let struct_ptr = &struct_instance as *const rte_ipv4_tuple;
let field_ptr = std::ptr::addr_of!(struct_instance.dst_addr);
let struct_address = struct_ptr as usize;
let field_address = field_ptr as usize;
std::mem::forget(struct_instance);
field_address.checked_sub(struct_address).unwrap()
},
4usize,
concat!(
Expand Down Expand Up @@ -192,10 +225,24 @@ fn bindgen_test_layout_rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1() {
)
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1>(
)))
.dport as *const _ as usize
{
const STRUCT_SIZE: usize = std::mem::size_of::<
rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1,
>();
let buffer = [0u8; STRUCT_SIZE];
let struct_instance = unsafe {
std::mem::transmute::<
[u8; STRUCT_SIZE],
rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1,
>(buffer)
};
let struct_ptr = &struct_instance
as *const rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1;
let field_ptr = std::ptr::addr_of!(struct_instance.dport);
let struct_address = struct_ptr as usize;
let field_address = field_ptr as usize;
std::mem::forget(struct_instance);
field_address.checked_sub(struct_address).unwrap()
},
0usize,
concat!(
Expand All @@ -206,10 +253,24 @@ fn bindgen_test_layout_rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1() {
)
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1>(
)))
.sport as *const _ as usize
{
const STRUCT_SIZE: usize = std::mem::size_of::<
rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1,
>();
let buffer = [0u8; STRUCT_SIZE];
let struct_instance = unsafe {
std::mem::transmute::<
[u8; STRUCT_SIZE],
rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1,
>(buffer)
};
let struct_ptr = &struct_instance
as *const rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1;
let field_ptr = std::ptr::addr_of!(struct_instance.sport);
let struct_address = struct_ptr as usize;
let field_address = field_ptr as usize;
std::mem::forget(struct_instance);
field_address.checked_sub(struct_address).unwrap()
},
2usize,
concat!(
Expand All @@ -232,19 +293,6 @@ fn bindgen_test_layout_rte_ipv6_tuple__bindgen_ty_1() {
4usize,
concat!("Alignment of ", stringify!(rte_ipv6_tuple__bindgen_ty_1))
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<rte_ipv6_tuple__bindgen_ty_1>())).sctp_tag
as *const _ as usize
},
0usize,
concat!(
"Offset of field: ",
stringify!(rte_ipv6_tuple__bindgen_ty_1),
"::",
stringify!(sctp_tag)
)
);
}
impl Default for rte_ipv6_tuple__bindgen_ty_1 {
fn default() -> Self {
Expand All @@ -268,9 +316,18 @@ fn bindgen_test_layout_rte_ipv6_tuple() {
concat!("Alignment of ", stringify!(rte_ipv6_tuple))
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<rte_ipv6_tuple>())).src_addr as *const _
as usize
{
const STRUCT_SIZE: usize = std::mem::size_of::<rte_ipv6_tuple>();
let buffer = [0u8; STRUCT_SIZE];
let struct_instance = unsafe {
std::mem::transmute::<[u8; STRUCT_SIZE], rte_ipv6_tuple>(buffer)
};
let struct_ptr = &struct_instance as *const rte_ipv6_tuple;
let field_ptr = std::ptr::addr_of!(struct_instance.src_addr);
let struct_address = struct_ptr as usize;
let field_address = field_ptr as usize;
std::mem::forget(struct_instance);
field_address.checked_sub(struct_address).unwrap()
},
0usize,
concat!(
Expand All @@ -281,9 +338,18 @@ fn bindgen_test_layout_rte_ipv6_tuple() {
)
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<rte_ipv6_tuple>())).dst_addr as *const _
as usize
{
const STRUCT_SIZE: usize = std::mem::size_of::<rte_ipv6_tuple>();
let buffer = [0u8; STRUCT_SIZE];
let struct_instance = unsafe {
std::mem::transmute::<[u8; STRUCT_SIZE], rte_ipv6_tuple>(buffer)
};
let struct_ptr = &struct_instance as *const rte_ipv6_tuple;
let field_ptr = std::ptr::addr_of!(struct_instance.dst_addr);
let struct_address = struct_ptr as usize;
let field_address = field_ptr as usize;
std::mem::forget(struct_instance);
field_address.checked_sub(struct_address).unwrap()
},
16usize,
concat!(
Expand Down Expand Up @@ -322,30 +388,6 @@ fn bindgen_test_layout_rte_thash_tuple() {
16usize,
concat!("Alignment of ", stringify!(rte_thash_tuple))
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<rte_thash_tuple>())).v4 as *const _ as usize
},
0usize,
concat!(
"Offset of field: ",
stringify!(rte_thash_tuple),
"::",
stringify!(v4)
)
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<rte_thash_tuple>())).v6 as *const _ as usize
},
0usize,
concat!(
"Offset of field: ",
stringify!(rte_thash_tuple),
"::",
stringify!(v6)
)
);
}
impl Default for rte_thash_tuple {
fn default() -> Self {
Expand Down
Loading