codegen: Do generate field offset checks for classes with multiple bases.

The bug only affects virtual inheritance, so instead disable layout
tests in the test that we know is broken. Not generating layout tests is
wrong anyways, because the offset would be wrong.
This commit is contained in:
Emilio Cobos Álvarez 2022-11-30 13:13:51 +01:00
parent a9d4198531
commit aa9849ba06
5 changed files with 148 additions and 87 deletions

View File

@ -0,0 +1,130 @@
#![allow(
dead_code,
non_snake_case,
non_camel_case_types,
non_upper_case_globals
)]
#[repr(C)]
pub struct A__bindgen_vtable {}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct A {
pub vtable_: *const A__bindgen_vtable,
pub member: ::std::os::raw::c_int,
}
#[test]
fn bindgen_test_layout_A() {
const UNINIT: ::std::mem::MaybeUninit<A> =
::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<A>(),
16usize,
concat!("Size of: ", stringify!(A))
);
assert_eq!(
::std::mem::align_of::<A>(),
8usize,
concat!("Alignment of ", stringify!(A))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).member) as usize - ptr as usize },
8usize,
concat!("Offset of field: ", stringify!(A), "::", stringify!(member))
);
}
impl Default for A {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
unsafe {
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
s.assume_init()
}
}
}
#[repr(C)]
pub struct B__bindgen_vtable {}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct B {
pub vtable_: *const B__bindgen_vtable,
pub member2: *mut ::std::os::raw::c_void,
}
#[test]
fn bindgen_test_layout_B() {
const UNINIT: ::std::mem::MaybeUninit<B> =
::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<B>(),
16usize,
concat!("Size of: ", stringify!(B))
);
assert_eq!(
::std::mem::align_of::<B>(),
8usize,
concat!("Alignment of ", stringify!(B))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).member2) as usize - ptr as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(B),
"::",
stringify!(member2)
)
);
}
impl Default for B {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
unsafe {
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
s.assume_init()
}
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct C {
pub _base: A,
pub _base_1: B,
pub member3: f32,
}
#[test]
fn bindgen_test_layout_C() {
const UNINIT: ::std::mem::MaybeUninit<C> =
::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<C>(),
40usize,
concat!("Size of: ", stringify!(C))
);
assert_eq!(
::std::mem::align_of::<C>(),
8usize,
concat!("Alignment of ", stringify!(C))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).member3) as usize - ptr as usize },
32usize,
concat!(
"Offset of field: ",
stringify!(C),
"::",
stringify!(member3)
)
);
}
impl Default for C {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
unsafe {
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
s.assume_init()
}
}
}

View File

@ -10,27 +10,6 @@
pub struct A {
pub foo: ::std::os::raw::c_int,
}
#[test]
fn bindgen_test_layout_A() {
const UNINIT: ::std::mem::MaybeUninit<A> =
::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<A>(),
4usize,
concat!("Size of: ", stringify!(A))
);
assert_eq!(
::std::mem::align_of::<A>(),
4usize,
concat!("Alignment of ", stringify!(A))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).foo) as usize - ptr as usize },
0usize,
concat!("Offset of field: ", stringify!(A), "::", stringify!(foo))
);
}
#[repr(C)]
pub struct B__bindgen_vtable(::std::os::raw::c_void);
#[repr(C)]
@ -39,27 +18,6 @@ pub struct B {
pub vtable_: *const B__bindgen_vtable,
pub bar: ::std::os::raw::c_int,
}
#[test]
fn bindgen_test_layout_B() {
const UNINIT: ::std::mem::MaybeUninit<B> =
::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<B>(),
16usize,
concat!("Size of: ", stringify!(B))
);
assert_eq!(
::std::mem::align_of::<B>(),
8usize,
concat!("Alignment of ", stringify!(B))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).bar) as usize - ptr as usize },
8usize,
concat!("Offset of field: ", stringify!(B), "::", stringify!(bar))
);
}
impl Default for B {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
@ -77,27 +35,6 @@ pub struct C {
pub vtable_: *const C__bindgen_vtable,
pub baz: ::std::os::raw::c_int,
}
#[test]
fn bindgen_test_layout_C() {
const UNINIT: ::std::mem::MaybeUninit<C> =
::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<C>(),
16usize,
concat!("Size of: ", stringify!(C))
);
assert_eq!(
::std::mem::align_of::<C>(),
8usize,
concat!("Alignment of ", stringify!(C))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).baz) as usize - ptr as usize },
8usize,
concat!("Offset of field: ", stringify!(C), "::", stringify!(baz))
);
}
impl Default for C {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
@ -114,19 +51,6 @@ pub struct D {
pub _base_1: B,
pub bazz: ::std::os::raw::c_int,
}
#[test]
fn bindgen_test_layout_D() {
assert_eq!(
::std::mem::size_of::<D>(),
40usize,
concat!("Size of: ", stringify!(D))
);
assert_eq!(
::std::mem::align_of::<D>(),
8usize,
concat!("Alignment of ", stringify!(D))
);
}
impl Default for D {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();

View File

@ -0,0 +1,15 @@
class A {
virtual void Foo();
int member;
};
class B {
virtual void Bar();
void* member2;
};
class C : public A, public B {
float member3;
};

View File

@ -1,4 +1,5 @@
// bindgen-flags: --no-layout-tests
// FIXME: Enable layout tests when #465 is fixed.
class A {
int foo;
};

View File

@ -2193,16 +2193,7 @@ impl CodeGenerator for CompInfo {
})
};
// FIXME when [issue #465](https://github.com/rust-lang/rust-bindgen/issues/465) ready
let too_many_base_vtables = self
.base_members()
.iter()
.filter(|base| base.ty.has_vtable(ctx))
.count() >
1;
let should_skip_field_offset_checks =
is_opaque || too_many_base_vtables;
let should_skip_field_offset_checks = is_opaque;
let check_field_offset = if should_skip_field_offset_checks
{