Dealing with bindgen generated padding

I'm trying to compile a c library wrapped to a -sys crate with bindgen (libsamplerate-sys). The library has a struct SRC_DATA, which on my x86_64 machine has the same amount of fields in Rust as the original C one, however when compiled on armhf (raspberry pi) bindgen adds a additional field __bindgen_padding_0. Now how should I initialize this struct? If I don't initialize the padding field it won't compile on the rpi, conversely if I do initialize it it won't compile on x86...
Original struct:

typedef struct
{	const float	*data_in ;
	float	*data_out ;

	long	input_frames, output_frames ;
	long	input_frames_used, output_frames_gen ;

	int		end_of_input ;

	double	src_ratio ;
} SRC_DATA ;

Bindgen generated on x86

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct SRC_DATA {
    pub data_in: *const f32,
    pub data_out: *mut f32,
    pub input_frames: ::std::os::raw::c_long,
    pub output_frames: ::std::os::raw::c_long,
    pub input_frames_used: ::std::os::raw::c_long,
    pub output_frames_gen: ::std::os::raw::c_long,
    pub end_of_input: ::std::os::raw::c_int,
    pub src_ratio: f64,
}

Bindgen generated on rpi:

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct SRC_DATA {
    pub data_in: *const f32,
    pub data_out: *mut f32,
    pub input_frames: ::std::os::raw::c_long,
    pub output_frames: ::std::os::raw::c_long,
    pub input_frames_used: ::std::os::raw::c_long,
    pub output_frames_gen: ::std::os::raw::c_long,
    pub end_of_input: ::std::os::raw::c_int,
    pub __bindgen_padding_0: u32 ,
    pub src_ratio: f64,
}

Previously I've used derive_default() in bindgen and ..Default::default() in struct initialization but something was changed in Rust since and there is no default value of raw pointer types anymore (these are in the struct), so this doesn't compile as well. From what I've read implementing the default trait for bulitin types is not possible (forbidden by the compiler, deemed unsafe).

Only options left that i see now is detecting the architecture at compile time, detecting if the struct has the field (is it possible?) or somehow mangling the bindgen-generated code. These solutions seem unelegant and prone to problems, am I missing something?

1 Like

One solution is

impl Default for SRC_DATA {
    fn default() -> Self {
        unsafe { std::mem::zeroed() }
    }
}

Does the struct actually change in C between platforms? Do the C headers tweak the alignment?

If the header is the same on both platforms and it's just a plain struct, then that padding field may be actually invalid, and caused by an old/buggy/incompatible version of LLVM/libclang on RPI.

Usually bindgen headers generated one platform are valid on all platforms, because #[repr(C)] already emulates platform-specific behaviors of C.

1 Like

@mbrubeck Thank you very much for this solution :slightly_smiling_face:
@kornel It's just a plain struct, there's no preprocessor magic in the header as far as I can see. The version of llvm on my rpi is 3.9 as it's still running debian 9. I'll upgrade it to Debian 10 and see if it changes anything.

On Debian 10 witch clang 7.0.1 the situation is the same. The bindgen-generated code on RPi has the padding field added.