-
Notifications
You must be signed in to change notification settings - Fork 706
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
rustified_non_exhaustive_enum() can still cause UB at runtime? #1763
Comments
If the C library can return values that are not valid under the enum type, that's not the fault of This should definitely be documented somewhere, but I think that a better way of representing "rusty" enums would be using a union, i.e.: #[repr(C, u32)]
enum RustyEnum {
VariantOne,
VariantTwo,
}
union ActualType {
rusty: RustyEnum,
catchAll: u32,
} Then, while you can pass the enums into a function via That said, I think that this is really kind of an extreme case, and if your enum has unrepresented values being returned, the API should be fixed-- it's possible to get UB from external APIs easily and this is just another case of extra care being required to avoid it. |
Thanks for quick reply, @clarfon. I feel obliged to give a bit more context given I've tagged you out of nowhere: bindgen allows multiple modes of representing C enums [1], default being a plain number type + a set of constants: pub const XML_ATTRIBUTE_CDATA: xmlAttributeType = 1;
pub const XML_ATTRIBUTE_ID: xmlAttributeType = 2;
pub type xmlAttributeType = u32; Which is safe in a way that the author of a higher-level Rust wrapper library creates a Rust enum manually and must ensure the numeric values are safely converted to it. Another mode #[repr(u32)]
pub enum xmlAttributeType {
XML_ATTRIBUTE_CDATA = 1,
XML_ATTRIBUTE_ID = 2,
} This issue is about a rather subtle thing: the [1] your suggestion being a possible addition to it, but I don't have necessary knowledge/experience to consider it. |
Yeah, you're definitely right in the fact that it's still UB, This definitely should be mentioned in the nomicon at least. |
Yeah, this was documented after a bunch of discussion in #1757, but let me know if I'm missing something. TLDR: yeah, non_exhaustive can still be useful for some use cases, but it does not prevent UB. |
Oh, sorry, btw, when I wrote it github was ~down so my second comment didn't get posted.. More improvements to the documentation / book here would most definitely be welcome :) |
Okays I'll submit a little documentation improvement later. |
I'm researching what bindgen::Builder options to use for my -sys crate.
The rustified_enum() is clearly marked as potentially causing undefined behavior as described in rust-lang/rust#36927 and #667:
The newer rustified_non_exhaustive_enum(), introduced in #1554, that does the same but marks the enum as
#[non_exhaustive]
is not marked as potentially dangerous, and is even mentioned as a solution inrustified_enum()
docs (above).rustified_non_exhaustive_enum() indeed seems to be used in the wild with assumption the UB cannot occur, e.g. in cholcombe973/libparted-sys#6.
However, I've been reading the RFC 2008 that introduces #[non_exhaustive] by @clarfon, and it doesn't seem to imply any such guarantees. Quite the contrary, it even mentions that compiler may (continue to) remove the wildcard arm (emphasis mine):
It seems that
#[non_exhaustive]
is a compile-time check that doesn't have any effect on generated code, i.e. that there is still a chance of UB even withrustified_non_exhaustive_enum()
? Or maybe there is some piece I'm missing that makes it safe (compiler being more cautious than RFC)?For clarity I'm talking about the case where a C library returns an int value that doesn't map to any variants of the enum as known at compile time. I'll be happy to submit a PR to make docstrings clear once we answer the question here.
The text was updated successfully, but these errors were encountered: