Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct type for returning a C99 `bool` to Rust via the FFI?

A colleague and I have been scratching our heads over how to return a bool from <stdbool.h> (a.k.a. _Bool) back to Rust via the FFI.

We have our C99 code we want to use from Rust:

bool
myfunc(void) {
   ...
}

We let Rust know about myfunc using an extern C block:

extern "C" {
    fn myfunc() -> T;
}

What concrete type should T be?

Rust doesn't have a c_bool in the libc crate, and if you search the internet, you will find various GitHub issues and RFCs where people discuss this, but don't really come to any consensus as to what is both correct and portable:

  • https://github.com/rust-lang/rfcs/issues/1982#issuecomment-297534238
  • https://github.com/rust-lang/rust/issues/14608
  • https://github.com/rust-lang/rfcs/issues/992
  • https://github.com/rust-lang/rust/pull/46156

As far as I can gather:

  • The size of a bool in C99 is undefined other than the fact it must be at least large enough to store true (1) and false (0). In other words, at least one bit long.
  • It could even be one bit wide.
  • Its size might be ABI defined.

This comment suggests that if a C99 bool is passed into a function as a parameter or out of a function as the return value, and the bool is smaller than a C int then it is promoted to the same size as an int. Under this scenario, we can tell Rust T is u32.

All right, but what if (for some reason) a C99 bool is 64 bits wide? Is u32 still safe? Perhaps under this scenario we truncate the 4 most significant bytes, which would be fine, since the 4 least significant bytes are more than enough to represent true and false.

Is my reasoning correct? Until Rust gets a libc::c_bool, what would you use for T and why is it safe and portable for all possible sizes of a C99 bool (>=1 bit)?

like image 952
Edd Barrett Avatar asked Dec 07 '17 22:12

Edd Barrett


1 Answers

As of 2018-02-01, the size of Rust's bool is officially the same as C's _Bool.

This means that bool is the correct type to use in FFI.


The rest of this answer applies to versions of Rust before the official decision was made

Until Rust gets a libc::c_bool, what would you use for T and why is it safe and portable for all possible sizes of a C99 bool (>=1 bit)?

As you've already linked to, the official answer is still "to be determined". That means that the only possibility that is guaranteed to be correct is: nothing.

That's right, as sad as it may be. The only truly safe thing would be to convert your bool to a known, fixed-size integral type, such as u8, for the purpose of FFI. That means you need to marshal it on both sides.


Practically, I'd keep using bool in my FFI code. As people have pointed out, it magically lines up on all the platforms that are in wide use at the moment. If the language decides to make bool FFI compatible, you are good to go. If they decide something else, I'd be highly surprised if they didn't introduce a lint to allow us to catch the errors quickly.

See also:

  • Is bool guaranteed to be 1 byte?
like image 66
Shepmaster Avatar answered Oct 23 '22 15:10

Shepmaster