rust-lang / rust-bindgen

Automatically generates Rust FFI bindings to C (and some C++) libraries.
https://rust-lang.github.io/rust-bindgen/
BSD 3-Clause "New" or "Revised" License
4.5k stars 702 forks source link

layout tests fail for max_align_t on debian sid.i386 #2991

Open plugwash opened 5 days ago

plugwash commented 5 days ago

While working on updating the rust-bindgen package in debian sid, I ran into a bindgen layout error with leptonica-sys. After some experimentation this failure seems to be caused by building bindings for stddef.h.

As a reduced testcase the following commands

echo '#include <stddef.h>' > wrapper.h
bindgen wrapper.h

resulted in

/* automatically generated by rust-bindgen 0.70.1 */

pub type wchar_t = ::std::os::raw::c_int;
#[repr(C)]
#[repr(align(8))]
#[derive(Debug, Copy, Clone)]
pub struct max_align_t {
    pub __clang_max_align_nonce1: ::std::os::raw::c_longlong,
    pub __clang_max_align_nonce2: f64,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
    ["Size of max_align_t"][::std::mem::size_of::<max_align_t>() - 24usize];
    ["Alignment of max_align_t"][::std::mem::align_of::<max_align_t>() - 8usize];
    ["Offset of field: max_align_t::__clang_max_align_nonce1"]
        [::std::mem::offset_of!(max_align_t, __clang_max_align_nonce1) - 0usize];
    ["Offset of field: max_align_t::__clang_max_align_nonce2"]
        [::std::mem::offset_of!(max_align_t, __clang_max_align_nonce2) - 8usize];
};

I wrote a small c test program to see what size the c compilers thought max_align_t should have, worryingly gcc and clang gave different results with gcc giving a result of 48 and clang a result of only 24.

max_align_t does not seem to be defined in any system headers, so I presume there is some built-in magic going on in gcc and clang.

pvdrz commented 5 days ago

max_align_t comes from /usr/lib/clang/18/include/__stddef_max_align_t.h on my system:

/*===---- __stddef_max_align_t.h - Definition of max_align_t ---------------===
 *
 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 * See https://llvm.org/LICENSE.txt for license information.
 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 *
 *===-----------------------------------------------------------------------===
 */

#ifndef __CLANG_MAX_ALIGN_T_DEFINED
#define __CLANG_MAX_ALIGN_T_DEFINED

#if defined(_MSC_VER)
typedef double max_align_t;
#elif defined(__APPLE__)
typedef long double max_align_t;
#else
// Define 'max_align_t' to match the GCC definition.
typedef struct {
  long long __clang_max_align_nonce1
      __attribute__((__aligned__(__alignof__(long long))));
  long double __clang_max_align_nonce2
      __attribute__((__aligned__(__alignof__(long double))));
} max_align_t;
#endif

#endif

so it seems clang is trying to match gcc's definition of it. In either case, I think part of the issue here is that long double is not being translated properly by bindgen or something. So definitely a bug in our side.