Skip to content
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

Wrong memory layout when handle virtual inheritance #465

Open
flier opened this issue Feb 1, 2017 · 4 comments
Open

Wrong memory layout when handle virtual inheritance #465

flier opened this issue Feb 1, 2017 · 4 comments
Labels

Comments

@flier
Copy link
Contributor

flier commented Feb 1, 2017

Consider the test case in virtual_inheritance.hpp, C++ will generate memory layout as

&d = 0x7fff566a88b0
offset_of(A::foo)=32
offset_of(B::foo=32
offset_of(C::foo=32
offset_of(B::bar)=24
offset_of(C::baz)=8
offset_of(D::bazz)=28
a = 0x7fff566a88d0
offset_of(A::foo)=0
b = 0x7fff566a88c0
offset_of(A::foo)=16
offset_of(C::baz)=8
c = 0x7fff566a88b0
offset_of(A::foo)=32
offset_of(C::baz)=8
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>

class A {
public:
  int foo;
};

class B: public virtual A {
public:
  int bar;
};

class C: public virtual A {
public:
  int baz;
};

class D: public C, public B {
public:
  int bazz;
};

int main() {
    D d;

int main() {
    D d;

    printf("&d = %p\n", &d);

    printf("offset_of(A::foo)=%lu\n", (uintptr_t)&d.foo - (uintptr_t)&d);
    printf("offset_of(B::foo=%lu\n", (uintptr_t)&((B *)&d)->foo - (uintptr_t)&d);
    printf("offset_of(C::foo=%lu\n", (uintptr_t)&((C *)&d)->foo - (uintptr_t)&d);
    printf("offset_of(B::bar)=%lu\n", (uintptr_t)&d.bar - (uintptr_t)&d);
    printf("offset_of(C::baz)=%lu\n", (uintptr_t)&d.baz - (uintptr_t)&d);
    printf("offset_of(D::bazz)=%lu\n", (uintptr_t)&d.bazz - (uintptr_t)&d);

    A *a = &d;

    printf("a = %p\n", a);

    printf("offset_of(A::foo)=%lu\n", (uintptr_t)&a->foo - (uintptr_t)a);

    B *b = &d;

    printf("b = %p\n", b);

    printf("offset_of(A::foo)=%lu\n", (uintptr_t)&b->foo - (uintptr_t)b);
    printf("offset_of(C::baz)=%lu\n", (uintptr_t)&b->bar - (uintptr_t)b);

    C *c = &d;

    printf("c = %p\n", c);

    printf("offset_of(A::foo)=%lu\n", (uintptr_t)&c->foo - (uintptr_t)c);
    printf("offset_of(C::baz)=%lu\n", (uintptr_t)&c->baz - (uintptr_t)c);
}

bindgen will generate memory layout as

#[repr(C)]
#[derive(Debug, Copy)]
pub struct B {
    pub vtable_: *const B__bindgen_vtable,
    pub bar: ::std::os::raw::c_int,
}

#[repr(C)]
#[derive(Debug, Copy)]
pub struct C {
    pub vtable_: *const C__bindgen_vtable,
    pub baz: ::std::os::raw::c_int,
}

#[repr(C)]
#[derive(Debug, Copy)]
pub struct D {
    pub _base: C,
    pub _base_1: B,
    pub bazz: ::std::os::raw::c_int,
}

First, both C and B will be aligned to 16 bytes, it cause D::bazz be aligned to 32 bytes rather than 28 bytes.
Second, A::foo should be generated and following D::bazz.

#[repr(C)]
#[derive(Debug, Copy)]
pub struct D {
    pub vtable_c: *const C__bindgen_vtable,
    pub baz: ::std::os::raw::c_int,
    pub vtable_b: *const B__bindgen_vtable,
    pub bar: ::std::os::raw::c_int,
    pub bazz: ::std::os::raw::c_int,
    pub foo: ::std::os::raw::c_int,
}
@emilio
Copy link
Contributor

emilio commented Feb 1, 2017

Yeah, I believe this partially a dupe of #380, though the foo thing is of course right.

@emilio
Copy link
Contributor

emilio commented Feb 1, 2017

This is clearly a bug btw, and thanks for the report (it's deeply appreciated, as usual :))

@emilio emilio added the bug label Feb 1, 2017
@flier
Copy link
Contributor Author

flier commented Feb 1, 2017

No problem, I'm working on the alignment issue, the layout test cases failed on it, just disable all the alignment tests when two or more virtual inheritances

@emilio
Copy link
Contributor

emilio commented Feb 1, 2017

That's awesome, thanks for working on that! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants