You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When I run bindgen with a packed struct containing a flexible array member I get a compilation error because the FAM uses drop.
I can edit the bindgen generated file to wrap FAM inside ManuallyDrop and it compiles successfully and appears to be working. Though I'm not sure if that approach is the right thing to do. Is there a way for bindgen to handle this itself, is there a better way than using ManuallyDrop?
test.h
#pragma pack(1)
typedefstructTest
{
short intHead;
long intTail[];
}
Test;
build.rs
use std::env;use std::path::PathBuf;use bindgen::RustTarget;fnmain(){let bindings = bindgen::Builder::default().header("test.h").flexarray_dst(true).rust_target(RustTarget::Nightly).parse_callbacks(Box::new(bindgen::CargoCallbacks::new())).generate().expect("Unable to generate bindings");let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs")).expect("Unable to write bindings");}
output error
error[E0277]: the size for values of type `FAM` cannot be known at compilation time
--> out/bindings.rs:6:15
|
4 | pub struct Test<FAM: ?Sized = [::std::os::raw::c_long;0]> {
| ----------------------------------------- this type parameter needs to be `Sized`
5 | pub Head:::std::os::raw::c_short,6 | pub Tail:FAM,
| ^^^ doesn't have a size known at compile-time
|
= note: the last field of a packed struct may only have a dynamically sized typeif it does not need drop to be run
bindings.rs output with ManuallyDrop added
/* automatically generated by rust-bindgen 0.70.1 */use std::mem::ManuallyDrop;#[repr(C, packed)]pubstructTest<FAM: ?Sized = [::std::os::raw::c_long;0]>{pubHead:::std::os::raw::c_short,pubTail:ManuallyDrop<FAM>,}#[allow(clippy::unnecessary_operation, clippy::identity_op)]const _:() = {["Size of Test"][::std::mem::size_of::<Test>() - 2usize];["Alignment of Test"][::std::mem::align_of::<Test>() - 1usize];["Offset of field: Test::Head"][::std::mem::offset_of!(Test, Head) - 0usize];["Offset of field: Test::Tail"][::std::mem::offset_of!(Test, Tail) - 2usize];};implTest<[::std::os::raw::c_long]>{pubfnlayout(len:usize) -> ::std::alloc::Layout{unsafe{let p:*constSelf = ::std::ptr::from_raw_parts(::std::ptr::null::<()>(), len);::std::alloc::Layout::for_value_raw(p)}}#[inline]pubfnfixed(&self) -> (&Test<[::std::os::raw::c_long;0]>,usize){unsafe{let(ptr, len) = (selfas*constSelf).to_raw_parts();(&*(ptr as*constTest<[::std::os::raw::c_long;0]>), len)}}#[inline]pubfnfixed_mut(&mutself) -> (&mutTest<[::std::os::raw::c_long;0]>,usize){unsafe{let(ptr, len) = (selfas*mutSelf).to_raw_parts();(&mut*(ptr as*mutTest<[::std::os::raw::c_long;0]>), len)}}}implTest<[::std::os::raw::c_long;0]>{#[doc = r" Convert a sized prefix to an unsized structure with the given length."]#[doc = r""]#[doc = r" SAFETY: Underlying storage is initialized up to at least `len` elements."]pubunsafefnflex_ref(&self,len:usize) -> &Test<[::std::os::raw::c_long]>{Self::flex_ptr(self, len)}#[doc = r" Convert a mutable sized prefix to an unsized structure with the given length."]#[doc = r""]#[doc = r" SAFETY: Underlying storage is initialized up to at least `len` elements."]#[inline]pubunsafefnflex_ref_mut(&mutself,len:usize) -> &mutTest<[::std::os::raw::c_long]>{Self::flex_ptr_mut(self, len).assume_init()}#[doc = r" Construct DST variant from a pointer and a size."]#[doc = r""]#[doc = r" NOTE: lifetime of returned reference is not tied to any underlying storage."]#[doc = r" SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements."]#[inline]pubunsafefnflex_ptr<'unbounded>(ptr:*constSelf,len:usize,) -> &'unbounded Test<[::std::os::raw::c_long]>{&*::std::ptr::from_raw_parts(ptr as*const(), len)}#[doc = r" Construct mutable DST variant from a pointer and a"]#[doc = r" size. The returned `&mut` reference is initialized"]#[doc = r" pointing to memory referenced by `ptr`, but there's"]#[doc = r" no requirement that that memory be initialized."]#[doc = r""]#[doc = r" NOTE: lifetime of returned reference is not tied to any underlying storage."]#[doc = r" SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements."]#[inline]pubunsafefnflex_ptr_mut<'unbounded>(ptr:*mutSelf,len:usize,) -> ::std::mem::MaybeUninit<&'unbounded mutTest<[::std::os::raw::c_long]>>{letmut uninit = ::std::mem::MaybeUninit::<&mutTest<[::std::os::raw::c_long]>>::uninit();(uninit.as_mut_ptr()as*mut*mutTest<[::std::os::raw::c_long]>).write(::std::ptr::from_raw_parts_mut(ptr as*mut(), len));
uninit
}}
The text was updated successfully, but these errors were encountered:
I think using ManuallyDrop is not a good workaround for (I assume) the same reason for the error in the first place: there's no (?) way to drop an unaligned dynamically sized type. In order to drop the value must be copied to an aligned location, but this can't be done because it's dynamically sized. Something like that.
Yeah I think DSTs and packed are intrinsically incompatible, even though the kind of structure you're using is certainly common in C headers.
I do think ManuallyDrop is the best compromise. A packed DST field with a non-trivial drop will just need very bespoke handling. OTOH if it has a trivial drop - as in this case - then ignoring the ManuallyDrop will still be the right result.
When I run bindgen with a packed struct containing a flexible array member I get a compilation error because the FAM uses drop.
I can edit the bindgen generated file to wrap
FAM
insideManuallyDrop
and it compiles successfully and appears to be working. Though I'm not sure if that approach is the right thing to do. Is there a way for bindgen to handle this itself, is there a better way than usingManuallyDrop
?test.h
build.rs
output error
bindings.rs output with ManuallyDrop added
The text was updated successfully, but these errors were encountered: