Skip to content

Missing virtual destructors in C++ vtables on Linux x86_64 #3193

Open
@DevilishSpirits

Description

@DevilishSpirits

Bug

I am using a large C++ library which makes heavy use of virtual functions and virtual destructor. I am using bindgen's vtable generation which miss virtual destructors on Linux x86_64.

I made a simple repository that exhibit this bug : https://github.com/DevilishSpirits/rust-bindgen-vtable-april25, clone and cargo run it. fn3() should be printed if bindgen correctly generated the vtable.

The src/main.cpp file define a class with pure virtual functions fn1(), fn2() and fn3(), then this class is derived with implementations that echo fnx() on screen. The level of indirection in the C++ is because I reproduced the style of the library I am using.

Both src/main.cpp and src/main.rs contain an example that create the object then call fn3() and destroy the object. While the C++ code echo fn3(), the Rust code echo fn1(). I inspected the vtables using gdb which show that there are 2 virtual destructor prepended in the vtable :

(gdb) info vtbl this
vtable for 'BugIllustrationImpl' @ 0x5555555a8eb0 (subobject @ 0x5555555bfa20):
[0]: 0x55555555b890 <BugIllustrationImpl::~BugIllustrationImpl()>
[1]: 0x55555555b8be <BugIllustrationImpl::~BugIllustrationImpl()>
[2]: 0x55555555b8ea <BugIllustrationImpl::fn1()>
[3]: 0x55555555b908 <BugIllustrationImpl::fn2()>

Rust does not include these virtual destructors and is off by 2 pointers and hence call fn1() instead of fn3() :

(gdb) p *bug_vtable
$1 = aa::BugIllustration__bindgen_vtable {
	BugIllustration_fn1: 0x55555555b890 <BugIllustrationImpl::~BugIllustrationImpl()>,
	BugIllustration_fn2: 0x55555555b8be <BugIllustrationImpl::~BugIllustrationImpl()>,
	BugIllustration_fn3: 0x55555555b8ea <BugIllustrationImpl::fn1()>
}

Expected behavior

I expect bindgen to include pointers to the virtual destructor in the vtable or an opaque padding to allow read-only usage of the vtable.

Expected behavior 2

If that is too difficult to implement, at least bindgen should detect that virtual destructor are in use and generate a fake vtable such as the one below :

/// Virtual destructors detected: vtable not generated
#[repr(C, align(8))] // ← shouldn't bindgen explicitely align the struct???
pub struct BugIllustration__bindgen_vtable {
	/// Virtual destructors detected: vtable not generated
	///
	/// Bindgen currently does not support vtable generation of C++ class with 
	/// virtual destructors. See https://example.com/some/bug/or/link
	pub __virtual_destructors_detected: std::convert::Infallible,
}

This clearly tell the user that bindgen attempted to generate the vtable but that it ran into a limitation.
The user can also use the vtable reference and pass it around for it own needs.
Then if bindgen get support for these vtable, existing code is unlikely to break.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions