You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
UpgradedSendStream transmute seems to be super unsound #3500
Firstly, it's unclear what guarantees repr(transparent) confers here, impossible does have size_of == 0 but it's not exactly a zero-sized type (rust-lang/unsafe-code-guidelines#485). The repr(transparent) RFC is not clear about this, and it's quite shaky ground to rely on, especially since empty ("impossible") types are one place Rust does sometimes perform layout optimizations. There's an assertion guard against that for Neutered but it's not clear how transitive this stuff is (rust-lang/unsafe-code-guidelines#486)
Empty types can and do affect enum representations. SendBuf<B> has the following definition:
There's nothing preventing the compiler from realizing that Buf(Neutered<...>) is impossible and deciding to not include it as a discriminant choice. The asserts in this code are insufficient to check that.
This code seems to work fine under the current compiler but I wouldn't rely on that.
For historical reference, this was discussed in #2831 and determined it wasn't unsound. Could be we got it wrong in there, I'm just including it for context.
Also stepping back a bit this pattern here is extremely weird and has almost no comments explaining what it does or justifying its safety. It's worth considering moving away from this model anyway, if possible.
There's nothing preventing the compiler from realizing that Buf(Neutered<...>) is impossible and deciding to not include it as a discriminant choice. The asserts in this code are insufficient to check that.
There is no such thing as “not include it as a discriminant choice” as that would be an observable behaviour for repr(usize) and break things related to such enums. Servo for example include uninhabited variants in repr(u32) enums specifically to skip a few variant discriminants to make the actually inhabited variants have their discriminants coincide with other enums. See discussions on the explicit discriminants Rust RFC. I am on PTO with a smartphone with a broken screen so you’ll excuse me for the lack of links in this comment hopefully.
Ven 22 déc 2023, à 16:09, Ralf Jung a écrit :
Basically the question is, for two repr($int) enum, if they have the same variants in the same order and all fields have the same layout, then do the two enums have the same layout? I don't see any way this could not be the case; AFAIK layout is completely laid down for repr(usize). So I think just like repr(transparent) is "transitive" through repr(C), it should also be "transitive" through repr($int). At least I'd say we should make such a guarantee; I don't know if we do.
Activity
seanmonstar commentedon Dec 21, 2023
For historical reference, this was discussed in #2831 and determined it wasn't unsound. Could be we got it wrong in there, I'm just including it for context.
Manishearth commentedon Dec 21, 2023
Yeah, that discussion seems to focus on whether
Neutered<B>is constructed; not about whether the transmute is safe.Manishearth commentedon Dec 21, 2023
Also stepping back a bit this pattern here is extremely weird and has almost no comments explaining what it does or justifying its safety. It's worth considering moving away from this model anyway, if possible.
seanmonstar commentedon Dec 21, 2023
cc @nox, you'll remember this better than I.
[-]UpgradedSendStream transmute is super unsound[/-][+]UpgradedSendStream transmute seems to be super unsound[/+]RalfJung commentedon Dec 22, 2023
Agreed.
nox commentedon Dec 23, 2023
RalfJung commentedon Dec 23, 2023
Ah sorry I had missed that this enum is
repr(usize). That indeed makes a difference.Manishearth commentedon Dec 23, 2023
@RalfJung does that also work with the transitivity assumption?
RalfJung commentedon Dec 23, 2023
Not sure which assumption exactly you mean?
Basically the question is, for two
repr($int)enum, if they have the same variants in the same order and all fields have the same layout, then do the two enums have the same layout? I don't see any way this could not be the case; AFAIK layout is completely laid down forrepr(usize). So I think just likerepr(transparent)is "transitive" throughrepr(C), it should also be "transitive" throughrepr($int). At least I'd say we should make such a guarantee; I don't know if we do.Whether that's actually implemented properly for uninhabited types (rust-lang/unsafe-code-guidelines#485), I don't know.
Manishearth commentedon Dec 23, 2023
Okay, good to know, thanks!
seanmonstar commentedon Jan 19, 2024
So did that extra information mean that this is fine after all? Or do we need to adjust something?
Manishearth commentedon Jan 22, 2024
I think it's still potentially an issue given:
but the bigger issue is a non-issue it seems.