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

Bitfield enums in return position violate the Linux 32-bit ABI #941

Closed
jryans opened this issue Sep 2, 2017 · 2 comments
Closed

Bitfield enums in return position violate the Linux 32-bit ABI #941

jryans opened this issue Sep 2, 2017 · 2 comments

Comments

@jryans
Copy link

jryans commented Sep 2, 2017

Input C/C++ Header

enum class OriginFlags : char {
  UserAgent = 0x01,
  User      = 0x02,
  Author    = 0x04,
  All       = 0x07,
};

OriginFlags GetFlags();

Bindgen Invocation

$ bindgen origin-flags.h -o origin_flags_bindings_32.rs --bitfield-enum OriginFlags -- -x c++ -std=c++14 -m32

Actual Results

/* automatically generated by rust-bindgen */

pub const OriginFlags_UserAgent: OriginFlags = OriginFlags(1);
pub const OriginFlags_User: OriginFlags = OriginFlags(2);
pub const OriginFlags_Author: OriginFlags = OriginFlags(4);
pub const OriginFlags_All: OriginFlags = OriginFlags(7);
impl ::std::ops::BitOr<OriginFlags> for OriginFlags {
    type
    Output
    =
    Self;
    #[inline]
    fn bitor(self, other: Self) -> Self { OriginFlags(self.0 | other.0) }
}
impl ::std::ops::BitOrAssign for OriginFlags {
    #[inline]
    fn bitor_assign(&mut self, rhs: OriginFlags) { self.0 |= rhs.0; }
}
impl ::std::ops::BitAnd<OriginFlags> for OriginFlags {
    type
    Output
    =
    Self;
    #[inline]
    fn bitand(self, other: Self) -> Self { OriginFlags(self.0 & other.0) }
}
impl ::std::ops::BitAndAssign for OriginFlags {
    #[inline]
    fn bitand_assign(&mut self, rhs: OriginFlags) { self.0 &= rhs.0; }
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct OriginFlags(pub ::std::os::raw::c_char);
extern "C" {
    #[link_name = "_Z8GetFlagsv"]
    pub fn GetFlags() -> OriginFlags;
}

Expected Results

Bitfield enum mode uses a struct on the Rust side, but C++ treats this as a primitive type. Since the Linux 32-bit ABI treats structs vs. primitives in return position differently, this leads to nonsense behavior.

I encountered this in several places while working on Stylo. As a workaround, we lied to bindgen about the return type and replaced it with the primitive value:

http://searchfox.org/mozilla-central/search?q=bitfield+enums&case=true&regexp=false&path=

@emilio
Copy link
Contributor

emilio commented Sep 2, 2017

Thanks for reporting, this is pretty much known, and depending on rust-lang/rust#43036, mostly.

@pvdrz
Copy link
Contributor

pvdrz commented Sep 19, 2022

#[repr(transparent)] has been stable for a while, and OriginFlags is tagged as such. Do we need to do anything else here?

@pvdrz pvdrz closed this as completed Oct 12, 2022
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

4 participants