Skip to content

Trait for safe all-zero byte initialization (v2) #840

Description

@DanielEScherzer

Proposal

Problem statement

When dealing with FFI types, especially those that will be initialized by code on the other side of the FFI boundary, creating a new instance of those types generally requires using unsafe { core::mem::zeroed() } at each site, unless some shortcut is added to the specific type.

It is good practice to document why code marked as unsafe is actually safe (e.g. as enforced by the clippy::undocumented_unsafe_blocks lint). Each place that the type is initialized is going to have similar documentation.

Motivating examples or use cases

In the git2 crate there are dozens of cases where std::mem::zeroed() is used for creation before initialization is done with FFI, e.g. (https://github.com/rust-lang/git2-rs/blob/da6c126f7733329d82748e710266af1c61591bdd/src/repo.rs#L2199-L2204)

        unsafe {
            let mut raw_opts = mem::zeroed();
            try_call!(raw::git_checkout_init_options(
                &mut raw_opts,
                raw::GIT_CHECKOUT_OPTIONS_VERSION
            ));
            // ...

Solution sketch

/// Indicates that a type is valid with all-zero bytes
///
/// # Safety
///
/// Marking a type as `ZeroInitable` requires that an all-zero byte-pattern
/// represent a valid instance of the type.
pub unsafe trait ZeroInitable: Sized {

    fn zeroed() -> Self {
        // SAFETY: Per the safety requirements of the trait, an all-zero
        // byte-pattern is valid for this type
        unsafe { core::mem::zeroed() }
    }

}

Alternatives

Not do this, and keep using core::mem::zeroed()

Links and related work

There was a previous similar proposal at #107 for a derive-able trait, but this proposal is different in a few ways, most notably that the trait is not derivable, and thus the compiler doesn't need any new logic or language handling, so the feedback on the prior proposal that "It runs up against lang-team concerns, like safe transmute and related efforts." does not apply. The new proposed trait is also explicitly unsafe - the existence of the trait does not affect any memory safety, and the implementation of the trait indicates that a developer has explicitly confirmed that an all-zero byte-pattern is valid, the same as calling core::mem::zeroed().

The Default trait is used to indicate that a particular byte representation is a good "default" representation, but for FFI types this may not be very applicable, especially when the initialization needs to be done with an FFI call, and rust just needs to create some instance of the object.

What happens now?

This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.

Possible responses

The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):

  • We think this problem seems worth solving, and the standard library might be the right place to solve it.
  • We think that this probably doesn't belong in the standard library.

Second, if there's a concrete solution:

  • We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
  • We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-libsRelevant to the libraries subteam, which will review and decide on the PR/issue.api-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions