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

Bindgen generates different type name for va_list on different systems #2631

Open
Morganamilo opened this issue Sep 7, 2023 · 9 comments
Open

Comments

@Morganamilo
Copy link

Input C/C++ Header

typedef __builtin_va_list va_list;
void foo(va_list arg);

Bindgen Invocation

$ bindgen input.h

Actual Results

  • on arm64 macos
/* automatically generated by rust-bindgen 0.68.1 */

pub type va_list = __builtin_va_list;
extern "C" {
    pub fn foo(arg: va_list);
}
pub type __builtin_va_list = *mut ::std::os::raw::c_char;
  • on x64_64 linux
/* automatically generated by rust-bindgen 0.68.1 */

pub type va_list = __builtin_va_list;
extern "C" {
    pub fn foo(arg: *mut __va_list_tag);
}
pub type __builtin_va_list = [__va_list_tag; 1usize];
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct __va_list_tag {
    pub gp_offset: ::std::os::raw::c_uint,
    pub fp_offset: ::std::os::raw::c_uint,
    pub overflow_arg_area: *mut ::std::os::raw::c_void,
    pub reg_save_area: *mut ::std::os::raw::c_void,
}

Expected Results

I expect the name of this type to be the same on both systems regardless of the underlying implementation.

@francisdb
Copy link

francisdb commented Sep 9, 2023

I can confirm this issue, any workaround?

I was trying to use https://github.com/dylanmckay/vsprintf for a function that takes const char* format, va_list args and this works as expected on arm64 but not on x64_64 linux

118 |         let str = vsprintf::vsprintf(format, args).unwrap();
    |                   ------------------         ^^^^ expected `*mut _`, found `[__va_list_tag; 1]`
    |                   |
    |                   arguments to this function are incorrect
    |
    = note: expected raw pointer `*mut _`
                     found array `[libpinmame::__va_list_tag; 1]`

@francisdb
Copy link

francisdb commented Sep 14, 2023

You can test this locally

eg on aarch64

rustup target add x86_64-apple-darwin
bindgen input.h -- --target=x86_64-apple-darwin
#  --target=aarch64-apple-darwin

for now I'm working around as vsprintf can handle both types

#[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
type VaListType = *mut crate::libpinmame::__va_list_tag;
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
type VaListType = crate::libpinmame::va_list;

pub unsafe extern "C" fn pinmame_on_log_message_callback(
    log_level: u32,
    format: *const ::std::os::raw::c_char,
    args: VaListType,
    _user_data: *const ::std::os::raw::c_void,
) {
    let str = unsafe { vsprintf::vsprintf(format, args).unwrap() };
    on_log_message(log_level, str);
}

Not sure if this also applies to linux/windows aarch64.
You can also use --target=... on the cargo build to build for a different architecture.

If some of the devs could confirm this is not a bug but just something we need to handle?

@Morganamilo
Copy link
Author

My packages build out the box on linux/arm64 so this seams to be just a mac thing.

@pvdrz
Copy link
Contributor

pvdrz commented Sep 25, 2023

While I understand this is annoying, there is not much we can do from the bindgen side as clang provides the definitions for these built-in types itself. So the fact that bindgen emits the __builtin_va_list type as an alias for [__va_list_tag; 1usize] on x86_64 is just because that's the definition that clang is exposing, the same logic applies to the aarch64 case. You could use @francisdb 's workaround or blocklist __builtin_va_list and replace it with the alias you consider appropriate.

@Morganamilo
Copy link
Author

The type name is the same in all c (even if the type is a macro). Is there any way bingen could emit a type elias that's consistent regardless of the underlying type?

@pvdrz
Copy link
Contributor

pvdrz commented Sep 25, 2023

So after a little bit more digging it seems the issue we have here is that on C void foo(__va_list_tag arg[1]); is just the same as void foo(__va_list_tag *arg);. A more minimal example would be

void foo(int arg[2]);

which is translated as

pub fn foo(arg: *mut ::std::os::raw::c_int);

instead of

pub fn foo(arg: *mut [::std::os::raw::c_int; 2]);

So this is a particular case of #1561 which was fixed by adding the --use-array-pointers-in-arguments option here #1564.

If I pass this flag to bindgen using the headers you provided, on linux in x86_64 I get the following output:

pub type va_list = __builtin_va_list;
extern "C" {
    pub fn foo(arg: *mut va_list);
}
pub type __builtin_va_list = [__va_list_tag; 1usize];

Which I think is what you want. Let me know if this is correct or not :)

@Morganamilo
Copy link
Author

That flags changes args: *mut va_list to args: *mut __va_list_tag on x86_64 but on arm it stays as arg: mut va_list.

@pvdrz
Copy link
Contributor

pvdrz commented Oct 17, 2023

yeah but the name of the type is the same, isn't that what you wanted?

@Morganamilo
Copy link
Author

Morganamilo commented Oct 17, 2023

No, I have my own rust function that takes a VaList then calls a c function that takes a VaList

extern "C" fn my_function(args: ?) {
	bindgen_generated_function(args)
}

I need to be able to declare my function with the right type for the types to match.

EHfive added a commit to EHfive/libbpf-rs that referenced this issue Mar 26, 2024
EHfive added a commit to EHfive/libbpf-rs that referenced this issue Mar 26, 2024
When using libbpf-sys' bindgen feature, the generated va_list type
varies on different platforms.

Use void pointer as va_list pointer type and transmute pointer of
type use va_list pointer instead for cross platform support.

See rust-lang/rust-bindgen#2631
EHfive added a commit to EHfive/libbpf-rs that referenced this issue Mar 26, 2024
When using libbpf-sys' bindgen feature, the generated va_list type
varies on different platforms.

Use void pointer as va_list pointer type and transmute pointer of
type use va_list pointer instead for cross platform support.

See rust-lang/rust-bindgen#2631
EHfive added a commit to EHfive/libbpf-rs that referenced this issue Mar 26, 2024
When using libbpf-sys' bindgen feature, the generated va_list type
varies on different platforms.

Use void pointer as va_list pointer type and transmute pointer of
type that uses va_list pointer for cross platform support.

See rust-lang/rust-bindgen#2631
danielocfb pushed a commit to libbpf/libbpf-rs that referenced this issue Mar 26, 2024
When using libbpf-sys' bindgen feature, the generated va_list type
varies on different platforms.

Use void pointer as va_list pointer type and transmute pointer of
type that uses va_list pointer for cross platform support.

See rust-lang/rust-bindgen#2631
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants