Skip to content

Commit cde1c00

Browse files
committed
Implement FromBytes and AsBytes for raw pointers
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
1 parent 31e6146 commit cde1c00

File tree

1 file changed

+30
-3
lines changed

1 file changed

+30
-3
lines changed

src/lib.rs

+30-3
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,30 @@ safety_comment! {
773773
unsafe_impl!(isize: FromZeroes, FromBytes, AsBytes);
774774
}
775775

776+
safety_comment! {
777+
/// SAFETY:
778+
/// - Raw pointers to `Sized` types have the same size and alignment as
779+
/// `usize` [1]
780+
/// - We know that any bit pattern is valid for a raw pointer to a `Sized`
781+
/// type because it is a safe operation to `as` cast from a `usize`
782+
/// - We know that raw pointers to `Sized` types do not contain
783+
/// uninitialized or padding bytes - and more generally that it is always
784+
/// valid to view the bytes of a raw pointer to a `Sized` type as a `[u8]`
785+
/// - because it is a safe operation to `as` cast such a pointer to a
786+
/// `usize`
787+
///
788+
/// TODO: Make the bit validity argument in terms of the reference once bit
789+
/// validity is described in the reference
790+
///
791+
/// [1] https://doc.rust-lang.org/reference/type-layout.html#pointers-and-references-layout
792+
unsafe_impl!(T: Sized => FromZeroes for *const T);
793+
unsafe_impl!(T: Sized => FromBytes for *const T);
794+
unsafe_impl!(T: Sized => AsBytes for *const T);
795+
unsafe_impl!(T: Sized => FromZeroes for *mut T);
796+
unsafe_impl!(T: Sized => FromBytes for *mut T);
797+
unsafe_impl!(T: Sized => AsBytes for *mut T);
798+
}
799+
776800
safety_comment! {
777801
/// SAFETY:
778802
/// - `FromZeroes`, `FromBytes`: the `{f32,f64}::from_bits` constructors'
@@ -3976,6 +4000,12 @@ mod tests {
39764000
assert_impls!(f32: FromZeroes, FromBytes, AsBytes, !Unaligned);
39774001
assert_impls!(f64: FromZeroes, FromBytes, AsBytes, !Unaligned);
39784002

4003+
// Implements none of the ZC traits.
4004+
struct NotZerocopy;
4005+
4006+
assert_impls!(*const NotZerocopy: FromZeroes, FromBytes, AsBytes, !Unaligned);
4007+
assert_impls!(*mut NotZerocopy: FromZeroes, FromBytes, AsBytes, !Unaligned);
4008+
39794009
assert_impls!(bool: FromZeroes, AsBytes, Unaligned, !FromBytes);
39804010
assert_impls!(char: FromZeroes, AsBytes, !FromBytes, !Unaligned);
39814011
assert_impls!(str: FromZeroes, AsBytes, Unaligned, !FromBytes);
@@ -4006,9 +4036,6 @@ mod tests {
40064036
assert_impls!(Option<NonZeroUsize>: FromZeroes, FromBytes, AsBytes, !Unaligned);
40074037
assert_impls!(Option<NonZeroIsize>: FromZeroes, FromBytes, AsBytes, !Unaligned);
40084038

4009-
// Implements none of the ZC traits.
4010-
struct NotZerocopy;
4011-
40124039
assert_impls!(PhantomData<NotZerocopy>: FromZeroes, FromBytes, AsBytes, Unaligned);
40134040
assert_impls!(PhantomData<[u8]>: FromZeroes, FromBytes, AsBytes, Unaligned);
40144041

0 commit comments

Comments
 (0)