Skip to content

Are all referents contiguous? #594

@joshlf

Description

@joshlf

Consider the following code:

use zerocopy::{Immutable, IntoBytes};

fn as_bytes<T: ?Sized + IntoBytes + Immutable>(t: &T) -> &[u8] {
    let len = size_of_val(t);
    let ptr: *const T = t;
    // SAFETY:
    // - By `T: IntoBytes`, all of the bytes in `*t` are initialized to valid `u8`s
    // - By `T: Immutable`, `T` does not permit interior mutation, and neither does `[u8]`
    // - The constructed pointer's referent has the same bytes as `*t`. By invariant on `&T`,
    //   this means that the referent is either zero-sized or lives in a single allocation which
    //   lives for at least as long as the lifetime of the input/output references to this function.
    unsafe { core::ptr::slice_from_raw_parts(ptr.cast::<u8>(), len) }
}

This safety comment implicitly assumes that *t is contiguous. If it isn't (e.g., if it contains bytes at addresses 1 and 3 but not 2), then the safety comment is wrong, and the code is unsound since the returned reference refers to bytes which may not be allocated, may not be initialized, may be subject to interior mutation, etc.

This makes me think that we basically need to guarantee that all pointers refer to contiguous sets of bytes, or else tons of unsafe code is unsound, and it would be very difficult to write sound unsafe code. Every time you did a transmute, you'd need to reason about whether the referents of the source and destination types had the same "holes".

Should we just bite the bullet and guarantee that all referents are contiguous in memory? Have we already guaranteed this somewhere that I'm not aware of?

cc @jswrenn

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions