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

Guarantee behavior of transmuting Option::<T>::None subject to NPO #137323

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

joshlf
Copy link
Contributor

@joshlf joshlf commented Feb 20, 2025

In #115333, we added a guarantee that transmuting from [0u8; N] to Option<P> is sound where P is a pointer type subject to the null pointer optimization (NPO). It would be useful to be able to guarantee the inverse - that a None::<P> value can be transmutes to an array and that will yield [0u8; N].

Closes #117591

@rustbot
Copy link
Collaborator

rustbot commented Feb 20, 2025

r? @tgross35

rustbot has assigned @tgross35.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Feb 20, 2025
@jieyouxu
Copy link
Member

r? libs-api (since this is making a behavior guaranteed)

@rustbot rustbot added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Feb 20, 2025
@rustbot rustbot assigned dtolnay and unassigned tgross35 Feb 20, 2025
@RalfJung
Copy link
Member

Cc @rust-lang/opsem @rust-lang/lang

This will need a t-lang FCP. @joshlf would be good to write a summary for t-lang, knowing that they will lack all the context we have here. :)

@RalfJung RalfJung added T-lang Relevant to the language team, which will review and decide on the PR/issue. needs-fcp This change is insta-stable, so needs a completed FCP to proceed. labels Feb 20, 2025
@RalfJung
Copy link
Member

Looking at the PR itself, the change LGTM.

@dtolnay dtolnay assigned RalfJung and unassigned dtolnay Feb 20, 2025
@dtolnay dtolnay removed T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Feb 20, 2025
@RalfJung RalfJung added S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. I-lang-nominated Nominated for discussion during a lang team meeting. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 21, 2025
@joshlf
Copy link
Contributor Author

joshlf commented Mar 5, 2025

This will need a t-lang FCP. @joshlf would be good to write a summary for t-lang, knowing that they will lack all the context we have here. :)

Currently, zerocopy has the ability to validate at runtime whether a [u8; N] contains a valid Option<&T>. In particular, the NPO guarantees that, if the [u8; N] contains all 0u8 bytes, then it constitutes a valid Option<&T>. We do the same for other types subject to NPO: see e.g. this set of impls.

This works via our TryFromBytes trait. Under the hood, #[derive(TryFromBytes)] synthesizes a predicate over &[u8] - in particular, the TryFromBytes::is_bit_valid method takes a &[u8] (it's actually a different type, but it has the same bit validity and alignment as &[u8]) and determines whether it contains a valid Self.

Eventually, we'd like to not only support going from &[u8] to &T, but from &T to &U for a broader range of pairs of types. We can already support &T -> &U if we can soundly convert &T -> &[u8], but some cases don't satisfy that requirement. For example, consider:

#[repr(C)]
struct T {
    a: u8,
    b: u16,
}

#[repr(C)]
struct U {
    a: bool,
    b: u16,
}

Since T has inter-field padding, it's unsound to convert a &T to a &[u8]. We'd still like to be able to support the &T -> &U case, though. This requires changing TryFromBytes::is_bit_valid to no longer take a &[u8] argument, and to instead take something that we call AsInitialized. An AsInitialized<T> has the invariant that it has initialized bytes wherever T has initialized bytes, but it may be uninitializated in other byte positions. This will permit us to go from &T to &AsInitialized<U>, and have TryFromBytes::is_bit_valid take this &AsInitialized<U> as an argument.

That gets us to this PR: In order to make this change, for each type that currently implements TryFromBytes, we need a guarantee about which bytes are always initialized. Currently, if P is a type subject to NPO, we have no guarantee that an instance of Option<P> has all its bytes initialized. While getting this guarantee in full is blocked on ptr-to-int semantics, this PR is intended as a first step that will at least handle the None case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-lang-nominated Nominated for discussion during a lang team meeting. needs-fcp This change is insta-stable, so needs a completed FCP to proceed. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Guarantee that it is sound to observe the bytes of None::<P> where P is a pointer type subject to NPO
6 participants