rust-bindgen icon indicating copy to clipboard operation
rust-bindgen copied to clipboard

Making type template opaque has undesired behavior

Open upsuper opened this issue 8 years ago • 3 comments

Input C/C++ Header

template<typename T>
struct Foo {
  void* a;
};

template<typename T>
class Bar {
  Foo<T> m;
};

class Baz {
  Bar<int> m;
};

Bindgen Invocation

$ bindgen input.hpp --opaque-type Foo

Actual Results

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Foo {
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Bar {
    pub m: u8,
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct Baz {
    pub m: Bar,
}
#[test]
fn bindgen_test_layout_Baz() {
    assert_eq!(::std::mem::size_of::<Baz>() , 8usize , concat ! (
               "Size of: " , stringify ! ( Baz ) ));
    assert_eq! (::std::mem::align_of::<Baz>() , 8usize , concat ! (
                "Alignment of " , stringify ! ( Baz ) ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const Baz ) ) . m as * const _ as usize } ,
                0usize , concat ! (
                "Alignment of field: " , stringify ! ( Baz ) , "::" ,
                stringify ! ( m ) ));
}
impl Clone for Baz {
    fn clone(&self) -> Self { *self }
}
#[test]
fn __bindgen_test_layout_Bar_open0_int_close0_instantiation() {
    assert_eq!(::std::mem::size_of::<Bar>() , 8usize , concat ! (
               "Size of template specialization: " , stringify ! ( Bar ) ));
    assert_eq!(::std::mem::align_of::<Bar>() , 8usize , concat ! (
               "Alignment of template specialization: " , stringify ! ( Bar )
               ));
}

Expected Results

As can be seen from the C++ code, Foo should have a pointer size, and Bar and Baz as well. However, Bar and Baz in this case only have 1 byte, while the layout test asserts they have 8 bytes.

Bar probably should have something like [u8; 8usize] or [usize; 2usize] instead.

upsuper avatar Jul 30 '17 09:07 upsuper

Oh wow. Yeah, we should be doing much better with generating opaque blobs here.

fitzgen avatar Jul 31 '17 18:07 fitzgen

I think the same thing happens when bindgen decides a type is opaque by itself (as opposed to forcing it with --opaque-type) ( due to #362 for example):

template <int> struct has_int_template { int y; };

has_int_template<0> function();

produces this:

extern "C" {
    #[link_name = "\u{1}_Z8functionv"]
    pub fn function() -> u8;
}

which is returning an object of the wrong size.

bsilver8192 avatar Mar 12 '22 06:03 bsilver8192

Looks like u8 is coming from ToOpaque::get_layout's fallback to Layout::for_size(ctx, 1). That seems unlikely to result in valid bindings. I'm not sure how to gracefully refuse to generate bindings for types which trigger that codepath though, and panicing while generating code is less friendly because then you can't even use other bindings which might be correct.

bsilver8192 avatar Mar 12 '22 06:03 bsilver8192