Skip to content

Commit

Permalink
Implement FromBytes and AsBytes for raw pointers
Browse files Browse the repository at this point in the history
Previously, we omitted these impls out of a fear of creating a footgun
in which it would be too easy to mistakenly transmute into a type with
internal safety invariants. Recently, this omission meant that I was
unable to get rid of a number of lines of `unsafe` code in a codebase
that used raw pointers, and it made me realize that it is more important
to enable this use case than to avoid a theoretical footgun.

Closes #170
  • Loading branch information
joshlf committed May 20, 2023
1 parent 31e6146 commit cde1c00
Showing 1 changed file with 30 additions and 3 deletions.
33 changes: 30 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,30 @@ safety_comment! {
unsafe_impl!(isize: FromZeroes, FromBytes, AsBytes);
}

safety_comment! {
/// SAFETY:
/// - Raw pointers to `Sized` types have the same size and alignment as
/// `usize` [1]
/// - We know that any bit pattern is valid for a raw pointer to a `Sized`
/// type because it is a safe operation to `as` cast from a `usize`
/// - We know that raw pointers to `Sized` types do not contain
/// uninitialized or padding bytes - and more generally that it is always
/// valid to view the bytes of a raw pointer to a `Sized` type as a `[u8]`
/// - because it is a safe operation to `as` cast such a pointer to a
/// `usize`
///
/// TODO: Make the bit validity argument in terms of the reference once bit
/// validity is described in the reference
///
/// [1] https://doc.rust-lang.org/reference/type-layout.html#pointers-and-references-layout
unsafe_impl!(T: Sized => FromZeroes for *const T);
unsafe_impl!(T: Sized => FromBytes for *const T);
unsafe_impl!(T: Sized => AsBytes for *const T);
unsafe_impl!(T: Sized => FromZeroes for *mut T);
unsafe_impl!(T: Sized => FromBytes for *mut T);
unsafe_impl!(T: Sized => AsBytes for *mut T);
}

safety_comment! {
/// SAFETY:
/// - `FromZeroes`, `FromBytes`: the `{f32,f64}::from_bits` constructors'
Expand Down Expand Up @@ -3976,6 +4000,12 @@ mod tests {
assert_impls!(f32: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(f64: FromZeroes, FromBytes, AsBytes, !Unaligned);

// Implements none of the ZC traits.
struct NotZerocopy;

assert_impls!(*const NotZerocopy: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(*mut NotZerocopy: FromZeroes, FromBytes, AsBytes, !Unaligned);

assert_impls!(bool: FromZeroes, AsBytes, Unaligned, !FromBytes);
assert_impls!(char: FromZeroes, AsBytes, !FromBytes, !Unaligned);
assert_impls!(str: FromZeroes, AsBytes, Unaligned, !FromBytes);
Expand Down Expand Up @@ -4006,9 +4036,6 @@ mod tests {
assert_impls!(Option<NonZeroUsize>: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroIsize>: FromZeroes, FromBytes, AsBytes, !Unaligned);

// Implements none of the ZC traits.
struct NotZerocopy;

assert_impls!(PhantomData<NotZerocopy>: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(PhantomData<[u8]>: FromZeroes, FromBytes, AsBytes, Unaligned);

Expand Down

0 comments on commit cde1c00

Please sign in to comment.