rust-lang / rust-lang/rust-bindgen
Wrong memory layout when handle virtual inheritance
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 5.3k
- Forks
- 829
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 15
Description
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,
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the test case in virtual_inheritance.hpp and compare bindgen’s generated B, C, and D layouts with the C++ offsets shown in the issue. Trace how virtual inheritance, alignment, base fields, and A::foo placement are represented; done means the generated bindings match the demonstrated memory layout.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, rust
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100