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

Macro defining a constant with unsigned long suffix generates unsigned integer #923

Open
SuperHeron opened this issue Aug 20, 2017 · 10 comments

Comments

@SuperHeron
Copy link

Input C/C++ Header

#define CK_INVALID_HANDLE	(0UL)

Bindgen Invocation

bindgen::Builder::default()
    .header("input.h")
    .generate()
    .expect("Unable to generate bindings");

Actual Results

pub const CK_INVALID_HANDLE: ::std::os::raw::c_uint = 0;

Expected Results

pub const CK_INVALID_HANDLE: ::std::os::raw::c_ulong = 0;

The U (unsigned) prefix is taken into account, but not the L (long) one.
This causes types and casts problems.

Debugging logs:
bindgen.txt

@emilio
Copy link
Contributor

emilio commented Aug 20, 2017

Thanks for the report!

For macro definitions we use cexpr, and it only provides an EvalResult::Int, so we choose a type based on the value.

We have a way to customise it from bindgen though, which is using the ParseCallbacks::int_macro type.

Maybe that suits you, otherwise, would you consider filing an issue against https://github.com/jethrogb/rust-cexpr?

Thanks!

@davidben
Copy link

davidben commented Aug 8, 2023

would you consider filing an issue against https://github.com/jethrogb/rust-cexpr?

Looks like this never happened, but someone later filed a bug about this here:
jethrogb/rust-cexpr#16

@davidben
Copy link

davidben commented Aug 8, 2023

Though given this crate is also used to evaluate expressions, there's probably a deeper flaw here that bindgen does not correctly incorporate types when evaluating these.

(This then opens a whole different can of worms around how #if ... evaluates integer expressions slightly differently than the underlying language. But given that most constants are used in code, not preprocessor definitions, I think it's clear bindgen should be evaluating expressions as in the underlying language, taking types into account.)

@pvdrz
Copy link
Contributor

pvdrz commented Aug 8, 2023

There's a more important issue here and it is the fact that rust-cexpr is virtually unmaintained. There's an ongoing effort into moving to cmacro which can handle suffixes correctly iirc: #2369

@ojeda
Copy link
Contributor

ojeda commented Sep 28, 2023

Since ed57762, bindgen generates Rust types, i.e. nowadays the "Actual Results" are:

pub const CK_INVALID_HANDLE: u32 = 0;

@davidben
Copy link

All that did was switch the hardcoded types from c_uint to u32, right? I.e. bindgen is still failing to consume C APIs correctly. It's just doing it differently incorrectly.

@pvdrz
Copy link
Contributor

pvdrz commented Oct 2, 2023

All that did was switch the hardcoded types from c_uint to u32, right? I.e. bindgen is still failing to consume C APIs correctly. It's just doing it differently incorrectly.

yes

davidben added a commit to google/boringssl that referenced this issue Feb 15, 2024
Due to rust-lang/rust-bindgen#923, bindgen
does not evaluate constants correctly. This means arithemetic is done
with the wrong type, and more importantly the output has the wrong type.

Ultimately, this is a bug in bindgen, but as that's remains unfixed,
we'll have to work around it.

rust-openssl's bindgen mode works around this by using the build.rs
bindgen driver and registering a callback to fix the type. This won't
work for some of our consumers, which require a hermetic and
reproducible builds. Instead, apply bssl-sys's workaround at the lib.rs
level. This removes a divergence between bssl-sys and rust-openssl's
bindgen mode.

Fixing these types does not mean we recommending using all of these
constants! Many of the options here are ill-defined or produce even more
ambiguous output than most. XN_FLAG_COMPAT is especially fun because it
change the calling convention! The only option anyone should use is
XN_FLAG_RFC2253, as that's at least a well-defined output.

Fixed: 636
Change-Id: Id34b4a46e0cfd6dcb275477d9bb915bda66c787d
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/66228
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
@joelteply
Copy link

A workaround for this issue was to manually regex replace these values inside your build.rs:

let pattern = Regex::new(r" u32").expect("could not construct regex pattern (1)");
let content = pattern.replace_all(&content, " u64");

@davidben
Copy link

davidben commented Mar 19, 2024

This assumes that there are no other uses of u32 in there. A C header may quite reasonably have constants of different types.

Ultimately the problem here is that bindgen is not correctly consuming C headers. All the information is in there, in a perfectly machine-readable manner. bindgen just throws the information away.

@javierhonduco
Copy link

Just bumped into this one with bindgen@v0.70.1:

#define LOW_PC_MASK  0x000000000000FFFFLLU
error[E0308]: mismatched types
  --> src/bpf/profiler_bindings.rs:78:25
   |
78 |         let mask: u64 = LOW_PC_MASK;
   |                   ---   ^^^^^^^^^^^ expected `u64`, found `u32`
   |                   |
   |                   expected due to this
   |
help: you can convert a `u32` to a `u64`
   |
78 |         let mask: u64 = LOW_PC_MASK.into();
   |          

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants