-
-
Notifications
You must be signed in to change notification settings - Fork 107
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
Consider checking returned enums for validity #123
Comments
Note: there was long discussion about enums in gtk-rs/gdk#154 |
Problem: |
Solution 3. |
🤣 |
@GuillaumeGomez, @sdroege as #354 appeared again, we need decide what to do. |
So to put it simply: we have the choice between safety and performance. So I propose we add both (the performance will be |
What exactly is the proposal to do here, the API to be added? |
If I remember correctly, the status quo right now is no more safer than what remains after the changes in #354. |
@johncf: I agree on this, that's why I propose to add both. The "safe" one will use |
@GuillaumeGomez That change can come later after we land these changes. Basically, this was what you had proposed to do while converting from integers to enums. That would be a pervasive change too with a more profound effect overall. |
@GuillaumeGomez Actually it can be done a bit more efficiently like this: #[repr(C)]
pub enum Test {
A = 0,
B = 1,
C = 2,
D = 3,
}
fn toTest(v: u32) -> Test {
match v {
0..4 => unsafe { std::mem::transmute(v) },
_ => panic!("Bad!"),
}
} Then again, I should remind you that what this would prevent are only rare upstream bugs. Rust users will never need to use this function (even indirectly). |
The |
@johncf: Wo, you just solved both issues! However it's not for sure that every values follow in the enums unfortunately. :-/ |
@sdroege @GuillaumeGomez Yes, true. But most of the time, they are... But that was not the point I was trying to make!! 😭 It's that plain |
Anyways, as far the current changes are concerned, if everyone's on-board, I'll proceed to create a Gtk PR (which will also be huge ~4000 lines reduction). |
Fine by me. |
I think it's all fine as-is, let's worry about that another time. Also for bitflags you probably want to use the In the case of enums (and flags), this can btw happen without a bug anywhere if the bindings were generated for an older version of the C library, and a new enum value or flag was added. |
Alright, then I'll PR Gtk and Pango repositories soon. |
Panicking seems a bit extreme though, maybe we can match all other values to the |
@sdroege Yes. This why we redefine enums without repr(C) and added __Nonexhaustive(()) too prevent int conversion. So library user mostly don't see ffi enums. |
Yes that's all good :) The problem is that on the FFI side there might be values returned that are not part of the FFI enum. But as those are repr(C) and with integers, maybe it's ok if those are transmuted to an integer later, and then passed through a conversion trait for getting the non-FFI enum. |
Related rust-lang/rust-memory-model#41 |
So it seems to do anything safely here we could do:
Comments? Edit: Instead of not doing anything about 1), we could also use plain integers in the sys crates for functions, etc and require explicit conversion there already. But that seems suboptimal API-wise. |
@sdroege Sounds okay... I understand that And regarding |
A configuration could be added to that, but generally the safe thing to do is to assume that the C library can add new values without breaking compatibility. Also this is how things are currently done already.
It's not necessarily broken code. There are completely valid scenarios when the C library starts returning values that are unknown at the Rust side, like when a new version of the C library adds a new value but the Rust side was not updated yet (and does not have to, the C library could do this change in a backwards compatible way). |
@sdroege, 1) IMHO if we really need |
It's not really needed, no, but then you would need to map to some other value (
Panic is a problem because it makes backwards compatible upgrades of the C library a breaking upgrade at the Rust level. And while it's true that nobody will check Using |
Also the existing FromGlib seems sufficient for that, you don't need (and don't want) to return a Result<,> from there. In the end this is all no different from e.g. |
I think it would be good if we could find any examples of such a "backwards-compatible" change occurring in the past. If no such examples could be found, it might be good to get the perspective from a core Gtk developer about their stance on the subject, before adding And, ideally, we should not add |
So alternative of direct reexport is this? (I use values instead ffi as converting in match cases don't works).
|
(Not core Gtk developer here, but GStreamer core developer and 10+ years GLib/GIO/GObject contributor)
The problem is that you can't detect these cases automatically, so you have to assume by default that enums can be extended (as that is the more general case). Configuration could be added to override that on a per-enum basis. Note also that nowadays we add
The direct re-export gives you undefined behaviour. The way how it is done now should be safe at least (ignoring for now that |
|
Ah! Good to know :)
Maybe behind some kind of "debug" feature? |
@sdroege Thanks for the example. I only now found out that all Gtk 3 versions ship shared objects with their major version set to 0 (e.g. libgtk-3.so.0.2200.15 for 3.22). Sorry I was unaware of this; I always assumed that the major version would be 22 in that case, which we can specify to the linker (which, when I thought about it, is not a very good idea). Since all Gtk3 versions are considered to have "fully backwards-compatible API," I realized that this is indeed unavoidable. (I guess things cannot always be as clean as you want it to be...) |
I was thinking about the implementation part of this, and it seems like it might be easier to define the sys enum types as |
A cleaner solution might be: rust-lang/rfcs#2008 But it might be a long wait. |
Part of enums has negative values (ex. GtkTextBufferTargetInfo). |
@johncf You agreed that the re-export would not go? @sdroege So fixed version of enum, will look like this?
|
Note: size of enum changed from 1 to 8. But maybe in GUI application it really don't matter. |
@EPashkin That would be one option, yes. I think ideally we would not use enums in the sys crates, but just an integer of the appropriate size plus constants (see discussion in the nikomatsakis/rust-memory-model repository). I'm not sure if i32 is always correct though, the rules for the underlying integer type of C enums is not trivial IIRC. And yours would fail for values > 2**31 |
That's right... Unless rfc#2008 is implemented in a way that helps with this situation. |
@sdroege Problem with integers that it will be allow to group in function calls. So |
Enums in C are unfortunately not always "int", quoting the standard:
In practice, enums are "int" or "unsigned int" usually, depending on whether they contain signed values or values >= 2**31. Also I believe GI writes down enum values as signed integers, and bitfields (aka flags) as unsigned integers (but please check that before depending on it). |
Note: this maybe need reworking when rust-lang/rust-memory-model#41 fixed on rust side. |
Also note that this is still not 100% correct, see discussion in there. It should be fine in practice though. |
It might be a good idea to test if the enums we get from the other side have valid values. This could require using newtype
c_int
wrappers instead of enums in the sys layer and implementing conversions between that and Rust enums.The text was updated successfully, but these errors were encountered: