rust-lang / rust-lang/rust-bindgen

Missing virtual destructors in C++ vtables on Linux x86_64

Open
#3,193 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
5.3k
Forks
829
Avg merge
1d 1h
Merged PRs (30d)
15

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Clone the linked reproduction and run cargo run; compare src/main.cpp and src/main.rs, then inspect the generated vtable with the shown gdb commands. Trace bindgen's C++ vtable generation from the reproduction and verify behavior on Linux x86_64. Done means virtual destructors are represented safely or the generated binding clearly reports that this case is unsupported without misdispatching fn3().

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, rust
Domain
compilers, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.