Skip to content

Commit f5394b3

Browse files
author
bors-servo
authored
Auto merge of rust-lang#468 - flier:padding-bytes, r=emilio
Improve struct alignment with padding bytes I known, it is a little tricky or dirty solution, I have to do a lot of calculate for alignment. For example ```c++ typedef struct { long long __clang_max_align_nonce1 __attribute__((__aligned__(__alignof__(long long)))); long double __clang_max_align_nonce2 __attribute__((__aligned__(__alignof__(long double)))); } max_align_t; ``` will be generated as ```rust pub struct _bindgen_ty_1 { pub __clang_max_align_nonce1: ::std::os::raw::c_longlong, _padding_0: u64, pub __clang_max_align_nonce2: f64, _padding_1: u64, } fn bindgen_test_layout__bindgen_ty_1() { assert_eq!(::std::mem::size_of::<_bindgen_ty_1>() , 32usize); assert_eq! (0usize , unsafe { & ( * ( 0 as * const _bindgen_ty_1 ) ) . __clang_max_align_nonce1 as * const _ as usize }); assert_eq! (16usize , unsafe { & ( * ( 0 as * const _bindgen_ty_1 ) ) . __clang_max_align_nonce2 as * const _ as usize }); } ``` It may generate wrong layout when use template or multi virtual inheritance. At least, it is a begining, pass all the test cases, and some [complex struct](https://github.com/servo/rust-bindgen/compare/master...flier:padding-bytes?expand=1#diff-eda352138aed047149ebeec72d19979d) in wild.
2 parents 7fa654c + 7fd7070 commit f5394b3

File tree

130 files changed

+4720
-288
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+4720
-288
lines changed

src/clang.rs

+11
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,17 @@ impl Cursor {
499499
unsafe { clang_CXXField_isMutable(self.x) != 0 }
500500
}
501501

502+
/// Get the offset of the field represented by the Cursor.
503+
pub fn offset_of_field(&self) -> Result<usize, LayoutError> {
504+
let offset = unsafe { clang_Cursor_getOffsetOfField(self.x) };
505+
506+
if offset < 0 {
507+
Err(LayoutError::from(offset as i32))
508+
} else {
509+
Ok(offset as usize)
510+
}
511+
}
512+
502513
/// Is this cursor's referent a member function that is declared `static`?
503514
pub fn method_is_static(&self) -> bool {
504515
unsafe { clang_CXXMethod_isStatic(self.x) != 0 }

src/codegen/mod.rs

+98-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
mod helpers;
2+
mod struct_layout;
23

34
use self::helpers::{BlobTyBuilder, attributes};
5+
use self::struct_layout::StructLayoutTracker;
46
use aster;
57

68
use ir::annotations::FieldAccessorKind;
@@ -21,6 +23,7 @@ use ir::var::Var;
2123

2224
use std::borrow::Cow;
2325
use std::cell::Cell;
26+
use std::cmp;
2427
use std::collections::{HashSet, VecDeque};
2528
use std::collections::hash_map::{Entry, HashMap};
2629
use std::fmt::Write;
@@ -723,9 +726,9 @@ impl<'a> Bitfield<'a> {
723726
fn codegen_fields(self,
724727
ctx: &BindgenContext,
725728
fields: &mut Vec<ast::StructField>,
726-
methods: &mut Vec<ast::ImplItem>) {
729+
methods: &mut Vec<ast::ImplItem>)
730+
-> Layout {
727731
use aster::struct_field::StructFieldBuilder;
728-
use std::cmp;
729732
let mut total_width = self.fields
730733
.iter()
731734
.fold(0u32, |acc, f| acc + f.bitfield().unwrap());
@@ -736,10 +739,9 @@ impl<'a> Bitfield<'a> {
736739
debug_assert_eq!(total_width % 8, 0);
737740
let total_width_in_bytes = total_width as usize / 8;
738741

739-
let bitfield_type =
740-
BlobTyBuilder::new(Layout::new(total_width_in_bytes,
741-
total_width_in_bytes))
742-
.build();
742+
let bitfield_layout = Layout::new(total_width_in_bytes,
743+
total_width_in_bytes);
744+
let bitfield_type = BlobTyBuilder::new(bitfield_layout).build();
743745
let field_name = format!("_bitfield_{}", self.index);
744746
let field_ident = ctx.ext_cx().ident_of(&field_name);
745747
let field = StructFieldBuilder::named(&field_name)
@@ -805,6 +807,8 @@ impl<'a> Bitfield<'a> {
805807
methods.extend(items.into_iter());
806808
offset += width;
807809
}
810+
811+
bitfield_layout
808812
}
809813
}
810814

@@ -940,6 +944,7 @@ impl CodeGenerator for CompInfo {
940944
// Also, we need to generate the vtable in such a way it "inherits" from
941945
// the parent too.
942946
let mut fields = vec![];
947+
let mut struct_layout = StructLayoutTracker::new(ctx, self);
943948
if self.needs_explicit_vtable(ctx) {
944949
let vtable =
945950
Vtable::new(item.id(), self.methods(), self.base_members());
@@ -951,6 +956,8 @@ impl CodeGenerator for CompInfo {
951956
.pub_()
952957
.build_ty(vtable_type);
953958

959+
struct_layout.saw_vtable();
960+
954961
fields.push(vtable_field);
955962
}
956963

@@ -985,6 +992,8 @@ impl CodeGenerator for CompInfo {
985992
format!("_base_{}", i)
986993
};
987994

995+
struct_layout.saw_base(base_ty);
996+
988997
let field = StructFieldBuilder::named(field_name)
989998
.pub_()
990999
.build_ty(inner);
@@ -1039,8 +1048,12 @@ impl CodeGenerator for CompInfo {
10391048
let bitfield_fields =
10401049
mem::replace(&mut current_bitfield_fields, vec![]);
10411050
bitfield_count += 1;
1042-
Bitfield::new(bitfield_count, bitfield_fields)
1051+
let bitfield_layout = Bitfield::new(bitfield_count,
1052+
bitfield_fields)
10431053
.codegen_fields(ctx, &mut fields, &mut methods);
1054+
1055+
struct_layout.saw_bitfield(bitfield_layout);
1056+
10441057
current_bitfield_width = None;
10451058
current_bitfield_layout = None;
10461059
}
@@ -1100,6 +1113,11 @@ impl CodeGenerator for CompInfo {
11001113
}
11011114
};
11021115

1116+
if let Some(padding_field) =
1117+
struct_layout.pad_field(&field_name, field_ty, field.offset()) {
1118+
fields.push(padding_field);
1119+
}
1120+
11031121
let is_private = field.annotations()
11041122
.private_fields()
11051123
.unwrap_or(fields_should_be_private);
@@ -1192,8 +1210,11 @@ impl CodeGenerator for CompInfo {
11921210
let bitfield_fields = mem::replace(&mut current_bitfield_fields,
11931211
vec![]);
11941212
bitfield_count += 1;
1195-
Bitfield::new(bitfield_count, bitfield_fields)
1213+
let bitfield_layout = Bitfield::new(bitfield_count,
1214+
bitfield_fields)
11961215
.codegen_fields(ctx, &mut fields, &mut methods);
1216+
1217+
struct_layout.saw_bitfield(bitfield_layout);
11971218
}
11981219
debug_assert!(current_bitfield_fields.is_empty());
11991220

@@ -1203,6 +1224,9 @@ impl CodeGenerator for CompInfo {
12031224
let field = StructFieldBuilder::named("bindgen_union_field")
12041225
.pub_()
12051226
.build_ty(ty);
1227+
1228+
struct_layout.saw_union(layout);
1229+
12061230
fields.push(field);
12071231
}
12081232

@@ -1227,6 +1251,16 @@ impl CodeGenerator for CompInfo {
12271251
warn!("Opaque type without layout! Expect dragons!");
12281252
}
12291253
}
1254+
} else if !is_union && !self.is_unsized(ctx) {
1255+
if let Some(padding_field) =
1256+
layout.and_then(|layout| struct_layout.pad_struct(layout)) {
1257+
fields.push(padding_field);
1258+
}
1259+
1260+
if let Some(align_field) =
1261+
layout.and_then(|layout| struct_layout.align_struct(layout)) {
1262+
fields.push(align_field);
1263+
}
12301264
}
12311265

12321266
// C requires every struct to be addressable, so what C compilers do is
@@ -1296,7 +1330,7 @@ impl CodeGenerator for CompInfo {
12961330
canonical_name);
12971331
}
12981332

1299-
if applicable_template_args.is_empty() && !self.found_unknown_attr() {
1333+
if applicable_template_args.is_empty() {
13001334
for var in self.inner_vars() {
13011335
ctx.resolve_item(*var)
13021336
.codegen(ctx, result, whitelisted_items, &());
@@ -1313,11 +1347,57 @@ impl CodeGenerator for CompInfo {
13131347
::$prefix::mem::align_of::<$ident>());
13141348
let size = layout.size;
13151349
let align = layout.align;
1350+
1351+
let check_struct_align = if align > mem::size_of::<*mut ()>() {
1352+
// FIXME when [RFC 1358](https://github.com/rust-lang/rust/issues/33626) ready
1353+
None
1354+
} else {
1355+
quote_item!(ctx.ext_cx(),
1356+
assert_eq!($align_of_expr, $align);
1357+
)
1358+
};
1359+
1360+
// FIXME when [issue #465](https://github.com/servo/rust-bindgen/issues/465) ready
1361+
let too_many_base_vtables = self.base_members()
1362+
.iter()
1363+
.filter(|base| ctx.resolve_type(base.ty).has_vtable(ctx))
1364+
.count() >
1365+
1;
1366+
1367+
let should_skip_field_offset_checks = item.is_opaque(ctx) ||
1368+
too_many_base_vtables;
1369+
1370+
let check_field_offset = if should_skip_field_offset_checks {
1371+
None
1372+
} else {
1373+
let type_name = ctx.rust_ident(&canonical_name);
1374+
1375+
let asserts = self.fields()
1376+
.iter()
1377+
.filter(|field| field.bitfield().is_none())
1378+
.flat_map(|field| {
1379+
field.name().and_then(|name| {
1380+
field.offset().and_then(|offset| {
1381+
let field_offset = offset / 8;
1382+
let field_name = ctx.rust_ident(name);
1383+
1384+
quote_item!(ctx.ext_cx(),
1385+
assert_eq!(unsafe { &(*(0 as *const $type_name)).$field_name as *const _ as usize }, $field_offset);
1386+
)
1387+
})
1388+
})
1389+
}).collect::<Vec<P<ast::Item>>>();
1390+
1391+
Some(asserts)
1392+
};
1393+
13161394
let item = quote_item!(ctx.ext_cx(),
13171395
#[test]
13181396
fn $fn_name() {
13191397
assert_eq!($size_of_expr, $size);
1320-
assert_eq!($align_of_expr, $align);
1398+
1399+
$check_struct_align
1400+
$check_field_offset
13211401
})
13221402
.unwrap();
13231403
result.push(item);
@@ -2278,22 +2358,20 @@ impl CodeGenerator for ObjCInterface {
22782358

22792359
// Collect the actual used argument names
22802360
let arg_names: Vec<_> = fn_args.iter()
2281-
.map(|ref arg| {
2282-
match arg.pat.node {
2283-
ast::PatKind::Ident(_, ref spanning, _) => {
2284-
spanning.node.name.as_str().to_string()
2285-
}
2286-
_ => {
2287-
panic!("odd argument!");
2288-
}
2361+
.map(|ref arg| match arg.pat.node {
2362+
ast::PatKind::Ident(_, ref spanning, _) => {
2363+
spanning.node.name.as_str().to_string()
2364+
}
2365+
_ => {
2366+
panic!("odd argument!");
22892367
}
22902368
})
22912369
.collect();
22922370

22932371
let methods_and_args =
22942372
ctx.rust_ident(&method.format_method_call(&arg_names));
2295-
let body =
2296-
quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args])
2373+
let body = quote_stmt!(ctx.ext_cx(),
2374+
msg_send![self, $methods_and_args])
22972375
.unwrap();
22982376
let block = ast::Block {
22992377
stmts: vec![body],
@@ -2729,5 +2807,4 @@ mod utils {
27292807
}
27302808
}).collect::<Vec<_>>()
27312809
}
2732-
27332810
}

0 commit comments

Comments
 (0)