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

Can get vtables wrong when inheriting from a template type parameter #851

Open
fitzgen opened this issue Jul 25, 2017 · 2 comments
Open

Comments

@fitzgen
Copy link
Member

fitzgen commented Jul 25, 2017

Input C/C++ Header

// bindgen-flags: --enable-cxx-namespaces -- -std=c++14

template<typename T>
struct DerivedMaybeHasVtable : public T {
  public:
    int x;
};

struct BaseWithVtable {
    int y;
    virtual void hello();
};

struct BaseWithoutVtable {
    int z;
    void hello();
};

static DerivedMaybeHasVtable<BaseWithVtable> YES_VTABLE;
static DerivedMaybeHasVtable<BaseWithoutVtable> NO_VTABLE;

Actual Results

running 4 tests
test root::bindgen_test_layout_BaseWithVtable ... ok
test root::__bindgen_test_layout_DerivedMaybeHasVtable_open0_BaseWithoutVtable_close0_instantiation ... ok
test root::bindgen_test_layout_BaseWithoutVtable ... ok
test root::__bindgen_test_layout_DerivedMaybeHasVtable_open0_BaseWithVtable_close0_instantiation ... FAILED

failures:

---- root::__bindgen_test_layout_DerivedMaybeHasVtable_open0_BaseWithVtable_close0_instantiation stdout ----
	thread 'root::__bindgen_test_layout_DerivedMaybeHasVtable_open0_BaseWithVtable_close0_instantiation' panicked at 'assertion failed: `(left == right)`
  left: `24`,
 right: `16`: Size of template specialization: root :: DerivedMaybeHasVtable < root :: BaseWithVtable >', /tmp/bindings.rs.KLHxFQ:83:8
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
   0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace
             at /checkout/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::_print
             at /checkout/src/libstd/sys_common/backtrace.rs:71
   2: std::panicking::default_hook::{{closure}}
             at /checkout/src/libstd/sys_common/backtrace.rs:60
             at /checkout/src/libstd/panicking.rs:380
   3: std::panicking::default_hook
             at /checkout/src/libstd/panicking.rs:390
   4: std::panicking::rust_panic_with_hook
             at /checkout/src/libstd/panicking.rs:611
   5: std::panicking::begin_panic_new
             at /checkout/src/libstd/panicking.rs:553
   6: std::panicking::begin_panic_fmt
             at /checkout/src/libstd/panicking.rs:521
   7: bindgen_test_one::root::__bindgen_test_layout_DerivedMaybeHasVtable_open0_BaseWithVtable_close0_instantiation
   8: <F as test::FnBox<T>>::call_box
             at /checkout/src/libtest/lib.rs:1477
             at /checkout/src/libcore/ops/function.rs:143
             at /checkout/src/libtest/lib.rs:138
   9: __rust_maybe_catch_panic
             at /checkout/src/libpanic_unwind/lib.rs:98


failures:
    root::__bindgen_test_layout_DerivedMaybeHasVtable_open0_BaseWithVtable_close0_instantiation

test result: FAILED. 3 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

Expected Results

We figure out how to support types that may or may not have a vtable.

@fitzgen
Copy link
Member Author

fitzgen commented Jul 25, 2017

I think for this bug (and for #586 with a similar approach) we can do something like

  1. Change the has_vtable analysis to instead of compute a bool for every type, compute
pub enum HasVtable {
    // Yes, this definitely has a vtable.
    Yes,

    // No, this definitely doews not have a vtable.
    No,

    // This is a template class/struct that derives from each of the given
    // template type parameters. If any of these items are replaced by a
    // type that has a vtable at instantiation time, then the instantiation will
    // have a vtable.
    Maybe(Vec<ItemId>)
}
  1. In the emitted bindings, spit out a trait like:
trait BindgenMaybeVtable {
    type VtablePtr;
}
  1. For every type where we computed HasVtable::Yes or HasVtable::No, in our bindings, emit impls like
impl BindgenMaybeVtable for YesVtable {
    type VtablePtr = <insert the TryToRustTy output of YesVtable's vtable>;
}

impl BindgenMaybeVtable for NoVtable {
    type VtablePtr = ::std::marker::PhantomData<u8>;
}
  1. For every generic type where we computed HasVtable::Maybe, emit code like
impl<T, U, ...> BindgenMaybeVtable for MaybeVtable<T, U, ...> {
    type VtablePtr = ???
}

... and I think we need specialization to fill in ??? here :-/

@fitzgen
Copy link
Member Author

fitzgen commented Jul 25, 2017

Although for single inheritance it would be easy.

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

No branches or pull requests

1 participant