镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

UpgradedSendStream transmute seems to be super unsound #3500

Open

Description

@Manishearth

https://github.com/hyperium/hyper/blob/1d4ff3597b8e76818c8553dbfa4234cf4208c958/src/proto/h2/mod.rs#L389C8-L397

This isn't sound. Neutered<B> is:

#[repr(transparent)]
struct Neutered<B> {
    _inner: B,
    impossible: Impossible,
}

enum Impossible {}

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:

#[repr(usize)]
enum SendBuf<B> {
    Buf(B),
    Cursor(Cursor<Box<[u8]>>),
    None,
}

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.

Activity

  1. added
    C-bugCategory: bug. Something is wrong. This is bad!
    on Dec 21, 2023
  2. seanmonstar commented on Dec 21, 2023

    @seanmonstar
    Member

    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.

  3. Manishearth commented on Dec 21, 2023

    @Manishearth
    ContributorAuthor

    Yeah, that discussion seems to focus on whether Neutered<B> is constructed; not about whether the transmute is safe.

  4. Manishearth commented on Dec 21, 2023

    @Manishearth
    ContributorAuthor

    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.

  5. seanmonstar commented on Dec 21, 2023

    @seanmonstar
    Member

    cc @nox, you'll remember this better than I.

  6. changed the title [-]UpgradedSendStream transmute is super unsound[/-] [+]UpgradedSendStream transmute seems to be super unsound[/+] on Dec 21, 2023
  7. RalfJung commented on Dec 22, 2023

    @RalfJung
    Contributor

    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.

    Agreed.

  8. nox commented on Dec 23, 2023

    @nox
    Contributor
  9. RalfJung commented on Dec 23, 2023

    @RalfJung
    Contributor

    Ah sorry I had missed that this enum is repr(usize). That indeed makes a difference.

  10. Manishearth commented on Dec 23, 2023

    @Manishearth
    ContributorAuthor

    @RalfJung does that also work with the transitivity assumption?

  11. RalfJung commented on Dec 23, 2023

    @RalfJung
    Contributor

    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 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.

    Whether that's actually implemented properly for uninhabited types (rust-lang/unsafe-code-guidelines#485), I don't know.

  12. Manishearth commented on Dec 23, 2023

    @Manishearth
    ContributorAuthor

    Okay, good to know, thanks!

  13. seanmonstar commented on Jan 19, 2024

    @seanmonstar
    Member

    So did that extra information mean that this is fine after all? Or do we need to adjust something?

  14. Manishearth commented on Jan 22, 2024

    @Manishearth
    ContributorAuthor

    I think it's still potentially an issue given:

    Whether that's actually implemented properly for uninhabited types (rust-lang/unsafe-code-guidelines#485), I don't know.

    but the bigger issue is a non-issue it seems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: bug. Something is wrong. This is bad!

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions