Test struct field offsets/sizes

This commit is contained in:
Alex Crichton 2015-09-09 23:46:19 -07:00
parent a9adfbf56c
commit 3e5155b345
3 changed files with 124 additions and 70 deletions

View File

@ -109,13 +109,11 @@ fn build_cfg(cfg: &mut ast::CrateConfig, target: &str) {
impl<'a> TestGenerator<'a> {
fn test_type(&mut self, ty: &str) {
let cty = if ty.starts_with("c_") {
let rest = ty[2..].replace("long", " long");
if rest.starts_with("u") {
format!("unsigned {}", &rest[1..])
} else if rest.starts_with("s") && rest != "short" {
format!("signed {}", &rest[1..])
} else {
rest
match &ty[2..].replace("long", " long")[..] {
s if s.starts_with("u") => format!("unsigned {}", &s[1..]),
"short" => format!("short"),
s if s.starts_with("s") => format!("signed {}", &s[1..]),
s => s.to_string(),
}
} else {
(match ty {
@ -126,15 +124,61 @@ impl<'a> TestGenerator<'a> {
self.test_size_align(ty, &cty);
}
fn test_struct(&mut self, ty: &str, _s: &ast::StructDef) {
let cty = if ty.starts_with("pthread") || ty == "glob_t" {
ty.to_string()
} else if ty == "ip6_mreq" {
"struct ipv6_mreq".to_string()
} else {
format!("struct {}", ty)
fn test_struct(&mut self, ty: &str, s: &ast::StructDef) {
let cty = match ty {
t if ty.starts_with("pthread") => t.to_string(),
"glob_t" => "glob_t".to_string(),
"ip6_mreq" => "struct ipv6_mreq".to_string(),
s => format!("struct {}", s),
};
self.test_size_align(ty, &cty);
writeln!(self.rust, r#"
#[test]
fn field_offset_size_{ty}() {{
"#, ty = ty);
for field in s.fields.iter() {
let name = match field.node.kind {
ast::NamedField(name, ast::Public) => name,
ast::NamedField(_, ast::Inherited) => continue,
ast::UnnamedField(..) => panic!("no tuple structs in FFI"),
};
let cname = match &name.to_string()[..] {
s if s.ends_with("_nsec") && ty == "stat" => {
s.replace("_nsec", "spec.tv_nsec")
}
s => s.to_string(),
};
writeln!(self.c, r#"
uint64_t __test_offset_{ty}_{rust_field}() {{
return offsetof({cty}, {c_field});
}}
uint64_t __test_size_{ty}_{rust_field}() {{
{cty}* foo = NULL;
return sizeof(foo->{c_field});
}}
"#, ty = ty, cty = cty, rust_field = name, c_field = cname);
writeln!(self.rust, r#"
extern {{
fn __test_offset_{ty}_{field}() -> u64;
fn __test_size_{ty}_{field}() -> u64;
}}
unsafe {{
let foo = 0 as *const {ty};
same(offset_of!({ty}, {field}),
__test_offset_{ty}_{field}(),
"field offset {field} of {ty}");
same(mem::size_of_val(&(*foo).{field}) as u64,
__test_size_{ty}_{field}(),
"field size {field} of {ty}");
}}
"#, ty = ty, field = name);
}
writeln!(self.rust, r#"
}}
"#);
}
fn test_size_align(&mut self, rust: &str, c: &str) {
@ -150,12 +194,10 @@ impl<'a> TestGenerator<'a> {
fn __test_align_{ty}() -> u64;
}}
unsafe {{
let a = mem::size_of::<{ty}>() as u64;
let b = __test_size_{ty}();
assert!(a == b, "bad size: rust {{}} != c {{}}", a, b);
let a = mem::align_of::<{ty}>() as u64;
let b = __test_align_{ty}();
assert!(a == b, "bad align: rust {{}} != c {{}}", a, b);
same(mem::size_of::<{ty}>() as u64,
__test_size_{ty}(), "size");
same(mem::align_of::<{ty}>() as u64,
__test_align_{ty}(), "align");
}}
}}
"#, ty = rust);

View File

@ -6,5 +6,17 @@ use std::mem;
use libc::*;
use libc::types::os::common::bsd43::*;
fn same(rust: u64, c: u64, attr: &str) {
if rust != c {
panic!("bad {}: rust: {} != c {}", attr, rust, c);
}
}
macro_rules! offset_of {
($ty:ident, $field:ident) => (
(&((*(0 as *const $ty)).$field)) as *const _ as u64
)
}
#[cfg(test)]
include!(concat!(env!("OUT_DIR"), "/all.rs"));

View File

@ -230,11 +230,11 @@ pub mod types {
pub gl_pathv: *mut *mut c_char,
pub gl_offs: size_t,
pub __unused1: *mut c_void,
pub __unused2: *mut c_void,
pub __unused3: *mut c_void,
pub __unused4: *mut c_void,
pub __unused5: *mut c_void,
__unused1: *mut c_void,
__unused2: *mut c_void,
__unused3: *mut c_void,
__unused4: *mut c_void,
__unused5: *mut c_void,
}
#[repr(C)]
@ -491,8 +491,8 @@ pub mod types {
pub st_mtime_nsec: c_long,
pub st_ctime: time_t,
pub st_ctime_nsec: c_long,
pub __unused4: c_long,
pub __unused5: c_long,
__unused4: c_long,
__unused5: c_long,
}
#[repr(C)]
@ -693,7 +693,7 @@ pub mod types {
pub st_mtime_nsec: c_long,
pub st_ctime: time_t,
pub st_ctime_nsec: c_long,
pub __unused: [c_long; 3],
__unused: [c_long; 3],
}
#[repr(C)]
@ -738,7 +738,7 @@ pub mod types {
pub st_mtime_nsec: c_long,
pub st_ctime: time_t,
pub st_ctime_nsec: c_long,
pub __unused: [c_int; 2],
__unused: [c_int; 2],
}
#[repr(C)]
@ -787,18 +787,18 @@ pub mod types {
#[repr(C)]
#[derive(Copy, Clone)] pub struct glob_t {
pub gl_pathc: size_t,
pub __unused1: size_t,
__unused1: size_t,
pub gl_offs: size_t,
pub __unused2: c_int,
__unused2: c_int,
pub gl_pathv: *mut *mut c_char,
pub __unused3: *mut c_void,
__unused3: *mut c_void,
pub __unused4: *mut c_void,
pub __unused5: *mut c_void,
pub __unused6: *mut c_void,
pub __unused7: *mut c_void,
pub __unused8: *mut c_void,
__unused4: *mut c_void,
__unused5: *mut c_void,
__unused6: *mut c_void,
__unused7: *mut c_void,
__unused8: *mut c_void,
}
#[repr(C)]
@ -1021,7 +1021,7 @@ pub mod types {
pub st_lspare: int32_t,
pub st_birthtime: time_t,
pub st_birthtime_nsec: c_long,
pub __unused: [u8; 8],
__unused: [u8; 8],
}
#[repr(C)]
@ -1149,18 +1149,18 @@ pub mod types {
#[repr(C)]
#[derive(Copy, Clone)] pub struct glob_t {
pub gl_pathc: size_t,
pub __unused1: size_t,
__unused1: size_t,
pub gl_offs: size_t,
pub __unused2: c_int,
__unused2: c_int,
pub gl_pathv: *mut *mut c_char,
pub __unused3: *mut c_void,
__unused3: *mut c_void,
pub __unused4: *mut c_void,
pub __unused5: *mut c_void,
pub __unused6: *mut c_void,
pub __unused7: *mut c_void,
pub __unused8: *mut c_void,
__unused4: *mut c_void,
__unused5: *mut c_void,
__unused6: *mut c_void,
__unused7: *mut c_void,
__unused8: *mut c_void,
}
#[repr(C)]
@ -1422,32 +1422,32 @@ pub mod types {
pub gl_offs: c_int,
pub gl_flags: c_int,
pub gl_pathv: *mut *mut c_char,
pub __unused1: *mut c_void,
pub __unused2: *mut c_void,
pub __unused3: *mut c_void,
pub __unused4: *mut c_void,
pub __unused5: *mut c_void,
pub __unused6: *mut c_void,
pub __unused7: *mut c_void,
__unused1: *mut c_void,
__unused2: *mut c_void,
__unused3: *mut c_void,
__unused4: *mut c_void,
__unused5: *mut c_void,
__unused6: *mut c_void,
__unused7: *mut c_void,
}
#[cfg(any(target_os = "netbsd", target_os="openbsd"))]
#[repr(C)]
#[derive(Copy, Clone)] pub struct glob_t {
pub gl_pathc: c_int,
pub __unused1: c_int,
__unused1: c_int,
pub gl_offs: c_int,
pub __unused2: c_int,
__unused2: c_int,
pub gl_pathv: *mut *mut c_char,
pub __unused3: *mut c_void,
__unused3: *mut c_void,
pub __unused4: *mut c_void,
pub __unused5: *mut c_void,
pub __unused6: *mut c_void,
pub __unused7: *mut c_void,
pub __unused8: *mut c_void,
pub __unused9: *mut c_void,
__unused4: *mut c_void,
__unused5: *mut c_void,
__unused6: *mut c_void,
__unused7: *mut c_void,
__unused8: *mut c_void,
__unused9: *mut c_void,
}
#[repr(C)]
@ -2122,18 +2122,18 @@ pub mod types {
#[repr(C)]
#[derive(Copy, Clone)] pub struct glob_t {
pub gl_pathc: size_t,
pub __unused1: c_int,
__unused1: c_int,
pub gl_offs: size_t,
pub __unused2: c_int,
__unused2: c_int,
pub gl_pathv: *mut *mut c_char,
pub __unused3: *mut c_void,
__unused3: *mut c_void,
pub __unused4: *mut c_void,
pub __unused5: *mut c_void,
pub __unused6: *mut c_void,
pub __unused7: *mut c_void,
pub __unused8: *mut c_void,
__unused4: *mut c_void,
__unused5: *mut c_void,
__unused6: *mut c_void,
__unused7: *mut c_void,
__unused8: *mut c_void,
}
#[repr(C)]