Skip to content

Commit 7373a42

Browse files
author
bors-servo
authored
Auto merge of rust-lang#413 - emilio:debug-array-unaligned, r=fitzgen
codegen: Avoid generating invalid Rust code when a struct is not properly aligned. r? @fitzgen cc rust-lang#412
2 parents 0a770cc + 30a4722 commit 7373a42

File tree

5 files changed

+211
-15
lines changed

5 files changed

+211
-15
lines changed

libbindgen/src/codegen/helpers.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,22 @@ impl BlobTyBuilder {
4949
}
5050

5151
pub fn build(self) -> P<ast::Ty> {
52-
use std::cmp;
52+
let opaque = self.layout.opaque();
5353

54-
let ty_name = match self.layout.align {
55-
8 => "u64",
56-
4 => "u32",
57-
2 => "u16",
58-
1 | _ => "u8",
59-
};
60-
let data_len = if ty_name == "u8" {
61-
self.layout.size
62-
} else {
63-
self.layout.size / cmp::max(self.layout.align, 1)
54+
// FIXME(emilio, #412): We fall back to byte alignment, but there are
55+
// some things that legitimately are more than 8-byte aligned.
56+
//
57+
// Eventually we should be able to `unwrap` here, but...
58+
let ty_name = match opaque.known_rust_type_for_array() {
59+
Some(ty) => ty,
60+
None => {
61+
warn!("Found unknown alignment on code generation!");
62+
"u8"
63+
}
6464
};
6565

66+
let data_len = opaque.array_size().unwrap_or(self.layout.size);
67+
6668
let inner_ty = aster::AstBuilder::new().ty().path().id(ty_name).build();
6769
if data_len == 1 {
6870
inner_ty

libbindgen/src/ir/comp.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,9 @@ impl<'a> CanDeriveCopy<'a> for CompInfo {
893893

894894
if self.kind == CompKind::Union {
895895
if !ctx.options().unstable_rust {
896+
// NOTE: If there's no template parameters we can derive copy
897+
// unconditionally, since arrays are magical for rustc, and
898+
// __BindgenUnionField always implements copy.
896899
return true;
897900
}
898901

libbindgen/src/ir/layout.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,43 @@ impl Layout {
4646
/// When we are treating a type as opaque, it is just a blob with a `Layout`.
4747
pub struct Opaque(pub Layout);
4848

49+
impl Opaque {
50+
/// Return the known rust type we should use to create a correctly-aligned
51+
/// field with this layout.
52+
pub fn known_rust_type_for_array(&self) -> Option<&'static str> {
53+
Some(match self.0.align {
54+
8 => "u64",
55+
4 => "u32",
56+
2 => "u16",
57+
1 => "u8",
58+
_ => return None,
59+
})
60+
}
61+
62+
/// Return the array size that an opaque type for this layout should have if
63+
/// we know the correct type for it, or `None` otherwise.
64+
pub fn array_size(&self) -> Option<usize> {
65+
if self.known_rust_type_for_array().is_some() {
66+
Some(self.0.size / cmp::max(self.0.align, 1))
67+
} else {
68+
None
69+
}
70+
}
71+
}
72+
4973
impl CanDeriveDebug for Opaque {
5074
type Extra = ();
5175

5276
fn can_derive_debug(&self, _: &BindgenContext, _: ()) -> bool {
53-
let size_divisor = cmp::max(1, self.0.align);
54-
self.0.size / size_divisor <= RUST_DERIVE_IN_ARRAY_LIMIT
77+
self.array_size().map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
5578
}
5679
}
5780

5881
impl<'a> CanDeriveCopy<'a> for Opaque {
5982
type Extra = ();
6083

6184
fn can_derive_copy(&self, _: &BindgenContext, _: ()) -> bool {
62-
let size_divisor = cmp::max(1, self.0.align);
63-
self.0.size / size_divisor <= RUST_DERIVE_IN_ARRAY_LIMIT
85+
self.array_size().map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
6486
}
6587

6688
fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
#[repr(C)]
8+
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
9+
impl <T> __BindgenUnionField<T> {
10+
#[inline]
11+
pub fn new() -> Self { __BindgenUnionField(::std::marker::PhantomData) }
12+
#[inline]
13+
pub unsafe fn as_ref(&self) -> &T { ::std::mem::transmute(self) }
14+
#[inline]
15+
pub unsafe fn as_mut(&mut self) -> &mut T { ::std::mem::transmute(self) }
16+
}
17+
impl <T> ::std::default::Default for __BindgenUnionField<T> {
18+
#[inline]
19+
fn default() -> Self { Self::new() }
20+
}
21+
impl <T> ::std::clone::Clone for __BindgenUnionField<T> {
22+
#[inline]
23+
fn clone(&self) -> Self { Self::new() }
24+
}
25+
impl <T> ::std::marker::Copy for __BindgenUnionField<T> { }
26+
impl <T> ::std::fmt::Debug for __BindgenUnionField<T> {
27+
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
28+
fmt.write_str("__BindgenUnionField")
29+
}
30+
}
31+
#[repr(C)]
32+
#[derive(Debug, Copy)]
33+
pub struct rte_ipv4_tuple {
34+
pub src_addr: u32,
35+
pub dst_addr: u32,
36+
pub __bindgen_anon_1: rte_ipv4_tuple__bindgen_ty_1,
37+
}
38+
#[repr(C)]
39+
#[derive(Debug, Copy)]
40+
pub struct rte_ipv4_tuple__bindgen_ty_1 {
41+
pub __bindgen_anon_1: __BindgenUnionField<rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1>,
42+
pub sctp_tag: __BindgenUnionField<u32>,
43+
pub bindgen_union_field: u32,
44+
}
45+
#[repr(C)]
46+
#[derive(Debug, Copy)]
47+
pub struct rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1 {
48+
pub dport: u16,
49+
pub sport: u16,
50+
}
51+
#[test]
52+
fn bindgen_test_layout_rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1() {
53+
assert_eq!(::std::mem::size_of::<rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1>()
54+
, 4usize);
55+
assert_eq!(::std::mem::align_of::<rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1>()
56+
, 2usize);
57+
}
58+
impl Clone for rte_ipv4_tuple__bindgen_ty_1__bindgen_ty_1 {
59+
fn clone(&self) -> Self { *self }
60+
}
61+
#[test]
62+
fn bindgen_test_layout_rte_ipv4_tuple__bindgen_ty_1() {
63+
assert_eq!(::std::mem::size_of::<rte_ipv4_tuple__bindgen_ty_1>() ,
64+
4usize);
65+
assert_eq!(::std::mem::align_of::<rte_ipv4_tuple__bindgen_ty_1>() ,
66+
4usize);
67+
}
68+
impl Clone for rte_ipv4_tuple__bindgen_ty_1 {
69+
fn clone(&self) -> Self { *self }
70+
}
71+
#[test]
72+
fn bindgen_test_layout_rte_ipv4_tuple() {
73+
assert_eq!(::std::mem::size_of::<rte_ipv4_tuple>() , 12usize);
74+
assert_eq!(::std::mem::align_of::<rte_ipv4_tuple>() , 4usize);
75+
}
76+
impl Clone for rte_ipv4_tuple {
77+
fn clone(&self) -> Self { *self }
78+
}
79+
#[repr(C)]
80+
#[derive(Debug, Copy)]
81+
pub struct rte_ipv6_tuple {
82+
pub src_addr: [u8; 16usize],
83+
pub dst_addr: [u8; 16usize],
84+
pub __bindgen_anon_1: rte_ipv6_tuple__bindgen_ty_1,
85+
}
86+
#[repr(C)]
87+
#[derive(Debug, Copy)]
88+
pub struct rte_ipv6_tuple__bindgen_ty_1 {
89+
pub __bindgen_anon_1: __BindgenUnionField<rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1>,
90+
pub sctp_tag: __BindgenUnionField<u32>,
91+
pub bindgen_union_field: u32,
92+
}
93+
#[repr(C)]
94+
#[derive(Debug, Copy)]
95+
pub struct rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1 {
96+
pub dport: u16,
97+
pub sport: u16,
98+
}
99+
#[test]
100+
fn bindgen_test_layout_rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1() {
101+
assert_eq!(::std::mem::size_of::<rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1>()
102+
, 4usize);
103+
assert_eq!(::std::mem::align_of::<rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1>()
104+
, 2usize);
105+
}
106+
impl Clone for rte_ipv6_tuple__bindgen_ty_1__bindgen_ty_1 {
107+
fn clone(&self) -> Self { *self }
108+
}
109+
#[test]
110+
fn bindgen_test_layout_rte_ipv6_tuple__bindgen_ty_1() {
111+
assert_eq!(::std::mem::size_of::<rte_ipv6_tuple__bindgen_ty_1>() ,
112+
4usize);
113+
assert_eq!(::std::mem::align_of::<rte_ipv6_tuple__bindgen_ty_1>() ,
114+
4usize);
115+
}
116+
impl Clone for rte_ipv6_tuple__bindgen_ty_1 {
117+
fn clone(&self) -> Self { *self }
118+
}
119+
#[test]
120+
fn bindgen_test_layout_rte_ipv6_tuple() {
121+
assert_eq!(::std::mem::size_of::<rte_ipv6_tuple>() , 36usize);
122+
assert_eq!(::std::mem::align_of::<rte_ipv6_tuple>() , 4usize);
123+
}
124+
impl Clone for rte_ipv6_tuple {
125+
fn clone(&self) -> Self { *self }
126+
}
127+
#[repr(C)]
128+
#[derive(Copy)]
129+
pub struct rte_thash_tuple {
130+
pub v4: __BindgenUnionField<rte_ipv4_tuple>,
131+
pub v6: __BindgenUnionField<rte_ipv6_tuple>,
132+
pub bindgen_union_field: [u8; 48usize],
133+
}
134+
impl Clone for rte_thash_tuple {
135+
fn clone(&self) -> Self { *self }
136+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
typedef unsigned char uint8_t;
3+
typedef unsigned short uint16_t;
4+
typedef unsigned int uint32_t;
5+
6+
struct rte_ipv4_tuple {
7+
uint32_t src_addr;
8+
uint32_t dst_addr;
9+
union {
10+
struct {
11+
uint16_t dport;
12+
uint16_t sport;
13+
};
14+
uint32_t sctp_tag;
15+
};
16+
};
17+
18+
struct rte_ipv6_tuple {
19+
uint8_t src_addr[16];
20+
uint8_t dst_addr[16];
21+
union {
22+
struct {
23+
uint16_t dport;
24+
uint16_t sport;
25+
};
26+
uint32_t sctp_tag;
27+
};
28+
};
29+
30+
union rte_thash_tuple {
31+
struct rte_ipv4_tuple v4;
32+
struct rte_ipv6_tuple v6;
33+
} __attribute__((aligned(16)));

0 commit comments

Comments
 (0)