Skip to content

Remove obsolete safety proofs #2423

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

Merged
merged 2 commits into from
Mar 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 31 additions & 73 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
// This file may not be copied, modified, or distributed except according to
// those terms.

use core::{cell::UnsafeCell, mem::MaybeUninit as CoreMaybeUninit, ptr::NonNull};
use core::{
cell::{Cell, UnsafeCell},
mem::MaybeUninit as CoreMaybeUninit,
ptr::NonNull,
};

use super::*;

Expand Down Expand Up @@ -96,32 +100,14 @@ safety_comment! {
unsafe_impl!(bool: Immutable, FromZeros, IntoBytes, Unaligned);
assert_unaligned!(bool);
/// SAFETY:
/// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
/// closure:
/// - Given `t: *mut bool` and `let r = *mut u8`, `r` refers to an object
/// of the same size as that referred to by `t`. This is true because
/// `bool` and `u8` have the same size (1 byte) [1]. Neither `r` nor `t`
/// contain `UnsafeCell`s because neither `bool` nor `u8` do [3].
/// - The impl must only return `true` for its argument if the original
/// `Maybe<bool>` refers to a valid `bool`. We only return true if the
/// `u8` value is 0 or 1, and both of these are valid values for `bool`.
/// [2]
/// The impl must only return `true` for its argument if the original
/// `Maybe<bool>` refers to a valid `bool`. We only return true if the `u8`
/// value is 0 or 1, and both of these are valid values for `bool` [1].
///
/// [1] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#primitive-data-layout:
///
/// The size of most primitives is given in this table.
///
/// | Type | `size_of::<Type>() ` |
/// |-----------|----------------------|
/// | `bool` | 1 |
/// | `u8`/`i8` | 1 |
///
/// [2] Per https://doc.rust-lang.org/1.81.0/reference/types/boolean.html:
/// [1] Per https://doc.rust-lang.org/1.81.0/reference/types/boolean.html:
///
/// The value false has the bit pattern 0x00 and the value true has the
/// bit pattern 0x01.
///
/// [3] TODO(#429): Justify this claim.
unsafe_impl!(=> TryFromBytes for bool; |byte| {
let byte = byte.transmute::<u8, invariant::Valid, _>();
*byte.unaligned_as_ref() < 2
Expand All @@ -144,27 +130,14 @@ safety_comment! {
/// [1] https://doc.rust-lang.org/1.81.0/reference/types/textual.html
unsafe_impl!(char: Immutable, FromZeros, IntoBytes);
/// SAFETY:
/// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
/// closure:
/// - Given `t: *mut char` and `let r = *mut u32`, `r` refers to an object
/// of the same size as that referred to by `t`. This is true because
/// `char` and `u32` have the same size [1]. Neither `r` nor `t` contain
/// `UnsafeCell`s because neither `char` nor `u32` do [3].
/// - The impl must only return `true` for its argument if the original
/// `Maybe<char>` refers to a valid `char`. `char::from_u32` guarantees
/// that it returns `None` if its input is not a valid `char`. [2]
///
/// [1] Per https://doc.rust-lang.org/nightly/reference/types/textual.html#layout-and-bit-validity:
/// The impl must only return `true` for its argument if the original
/// `Maybe<char>` refers to a valid `char`. `char::from_u32` guarantees that
/// it returns `None` if its input is not a valid `char` [1].
///
/// `char` is guaranteed to have the same size and alignment as `u32` on
/// all platforms.
///
/// [2] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32:
/// [1] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32:
///
/// `from_u32()` will return `None` if the input is not a valid value for
/// a `char`.
///
/// [3] TODO(#429): Justify this claim.
unsafe_impl!(=> TryFromBytes for char; |c| {
let c = c.transmute::<Unalign<u32>, invariant::Valid, _>();
let c = c.read_unaligned().into_inner();
Expand Down Expand Up @@ -192,20 +165,9 @@ safety_comment! {
/// [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#str-layout
unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unaligned);
/// SAFETY:
/// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
/// closure:
/// - Given `t: *mut str` and `let r = *mut [u8]`, `r` refers to an object
/// of the same size as that referred to by `t`. This is true because
/// `str` and `[u8]` have the same representation. [1] Neither `t` nor
/// `r` contain `UnsafeCell`s because `[u8]` doesn't, and both `t` and
/// `r` have that representation.
/// - The impl must only return `true` for its argument if the original
/// `Maybe<str>` refers to a valid `str`. `str::from_utf8` guarantees
/// that it returns `Err` if its input is not a valid `str`. [2]
///
/// [1] Per https://doc.rust-lang.org/1.81.0/reference/types/textual.html:
///
/// A value of type `str` is represented the same was as `[u8]`.
/// The impl must only return `true` for its argument if the original
/// `Maybe<str>` refers to a valid `str`. `str::from_utf8` guarantees that
/// it returns `Err` if its input is not a valid `str` [1].
///
/// [2] Per https://doc.rust-lang.org/core/str/fn.from_utf8.html#errors:
///
Expand Down Expand Up @@ -303,25 +265,6 @@ safety_comment! {
unsafe_impl!(NonZeroI128: Immutable, IntoBytes);
unsafe_impl!(NonZeroUsize: Immutable, IntoBytes);
unsafe_impl!(NonZeroIsize: Immutable, IntoBytes);
/// SAFETY:
/// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
/// closure:
/// - Given `t: *mut NonZeroXxx` and `let r = *mut xxx`, `r` refers to an
/// object of the same size as that referred to by `t`. This is true
/// because `NonZeroXxx` and `xxx` have the same size. [1] Neither `r`
/// nor `t` refer to any `UnsafeCell`s because neither `NonZeroXxx` [2]
/// nor `xxx` do.
/// - The impl must only return `true` for its argument if the original
/// `Maybe<NonZeroXxx>` refers to a valid `NonZeroXxx`. The only `xxx`
/// which is not also a valid `NonZeroXxx` is 0. [1]
///
/// [1] Per https://doc.rust-lang.org/1.81.0/core/num/type.NonZeroU16.html:
///
/// `NonZeroU16` is guaranteed to have the same layout and bit validity as
/// `u16` with the exception that `0` is not a valid instance.
///
/// [2] `NonZeroXxx` self-evidently does not contain `UnsafeCell`s. This is
/// not a proof, but we are accepting this as a known risk per #1358.
unsafe_impl_try_from_bytes_for_nonzero!(
NonZeroU8[u8],
NonZeroI8[i8],
Expand Down Expand Up @@ -862,6 +805,21 @@ safety_comment! {
}
assert_unaligned!(ManuallyDrop<()>, ManuallyDrop<u8>);

impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for Cell<T>[UnsafeCell<T>]);
impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for Cell<T>[UnsafeCell<T>]);
impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for Cell<T>[UnsafeCell<T>]);
impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for Cell<T>[UnsafeCell<T>]);
safety_comment! {
/// SAFETY:
/// `Cell<T>` has the same in-memory representation as `T` [1], and thus has
/// the same alignment as `T`.
///
/// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.Cell.html#memory-layout:
///
/// `Cell<T>` has the same in-memory representation as its inner type `T`.
unsafe_impl!(T: ?Sized + Unaligned => Unaligned for Cell<T>);
}

impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>[<T>]);
impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>[<T>]);
impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>[<T>]);
Expand Down
22 changes: 10 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ pub use crate::r#ref::*;
pub use crate::wrappers::*;

use core::{
cell::UnsafeCell,
cell::{Cell, UnsafeCell},
cmp::Ordering,
fmt::{self, Debug, Display, Formatter},
hash::Hasher,
Expand Down Expand Up @@ -983,29 +983,27 @@ impl_known_layout!(const N: usize, T => [T; N]);

safety_comment! {
/// SAFETY:
/// `str`, `ManuallyDrop<[T]>` [1], and `UnsafeCell<T>` [2] have the same
/// representations as `[u8]`, `[T]`, and `T` repsectively. `str` has
/// different bit validity than `[u8]`, but that doesn't affect the
/// soundness of this impl.
/// `str` has the same representation as `[u8]`. `ManuallyDrop<T>` [1],
/// `UnsafeCell<T>` [2], and `Cell<T>` [3] have the same representation as
/// `T`.
///
/// [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html:
/// [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html:
///
/// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
/// validity as `T`
///
/// [2] Per https://doc.rust-lang.org/core/cell/struct.UnsafeCell.html#memory-layout:
/// [2] Per https://doc.rust-lang.org/1.85.0/core/cell/struct.UnsafeCell.html#memory-layout:
///
/// `UnsafeCell<T>` has the same in-memory representation as its inner
/// type `T`.
///
/// TODO(#429):
/// - Add quotes from docs.
/// - Once [1] (added in
/// https://github.com/rust-lang/rust/pull/115522) is available on stable,
/// quote the stable docs instead of the nightly docs.
/// [3] Per https://doc.rust-lang.org/1.85.0/core/cell/struct.Cell.html#memory-layout:
///
/// `Cell<T>` has the same in-memory representation as `T`.
unsafe_impl_known_layout!(#[repr([u8])] str);
unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] ManuallyDrop<T>);
unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] UnsafeCell<T>);
unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] Cell<T>);
}

safety_comment! {
Expand Down
36 changes: 30 additions & 6 deletions src/pointer/transmute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// those terms.

use core::{
cell::UnsafeCell,
cell::{Cell, UnsafeCell},
mem::{ManuallyDrop, MaybeUninit},
num::Wrapping,
ptr::NonNull,
Expand Down Expand Up @@ -405,20 +405,44 @@ safety_comment! {
unsafe_impl_invariants_eq!(T => T, Wrapping<T>);

/// SAFETY:
/// - `Unalign<T>` has the same size as `T` [1].
/// - Per [1], `Unalign<T>` has the same bit validity as `T`. Technically
/// - `UnsafeCell<T>` has the same size as `T` [1].
/// - Per [1], `UnsafeCell<T>` has the same bit validity as `T`. Technically
/// the term "representation" doesn't guarantee this, but the subsequent
/// sentence in the documentation makes it clear that this is the
/// intention.
///
/// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout:
///
/// `UnsafeCell<T>` has the same in-memory representation as its inner type
/// `T`. A consequence of this guarantee is that it is possible to convert
/// between `T` and `UnsafeCell<T>`.
/// `UnsafeCell<T>` has the same in-memory representation as its inner
/// type `T`. A consequence of this guarantee is that it is possible to
/// convert between `T` and `UnsafeCell<T>`.
unsafe_impl_for_transparent_wrapper!(T: ?Sized => UnsafeCell<T>);

/// SAFETY:
/// - `Cell<T>` has the same size as `T` [1].
/// - Per [1], `Cell<T>` has the same bit validity as `T`. Technically the
/// term "representation" doesn't guarantee this, but it does promise to
/// have the "same memory layout and caveats as `UnsafeCell<T>`." The
/// `UnsafeCell` docs [2] make it clear that bit validity is the intention
/// even if that phrase isn't used.
///
/// [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.Cell.html#memory-layout:
///
/// `Cell<T>` has the same memory layout and caveats as `UnsafeCell<T>`.
/// In particular, this means that `Cell<T>` has the same in-memory
/// representation as its inner type `T`.
///
/// [2] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout:
///
/// `UnsafeCell<T>` has the same in-memory representation as its inner
/// type `T`. A consequence of this guarantee is that it is possible to
/// convert between `T` and `UnsafeCell<T>`.
unsafe_impl_for_transparent_wrapper!(T: ?Sized => Cell<T>);
}

impl_transitive_transmute_from!(T: ?Sized => Cell<T> => T => UnsafeCell<T>);
impl_transitive_transmute_from!(T: ?Sized => UnsafeCell<T> => T => Cell<T>);

// SAFETY: `MaybeUninit<T>` has no validity requirements. Currently this is not
// explicitly guaranteed, but it's obvious from `MaybeUninit`'s documentation
// that this is the intention:
Expand Down
6 changes: 0 additions & 6 deletions src/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,6 @@ safety_comment! {
/// `UnsafeCell`s exactly when `T` does.
/// - `TryFromBytes`: `Unalign<T>` has the same the same bit validity as
/// `T`, so `T::is_bit_valid` is a sound implementation of `is_bit_valid`.
/// Furthermore:
/// - Since `T` and `Unalign<T>` have the same layout, they have the same
/// size (as required by `unsafe_impl!`).
/// - Since `T` and `Unalign<T>` have the same fields, they have
/// `UnsafeCell`s at the same byte ranges (as required by
/// `unsafe_impl!`).
impl_or_verify!(T => Unaligned for Unalign<T>);
impl_or_verify!(T: Immutable => Immutable for Unalign<T>);
impl_or_verify!(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Unaligned` is not satisfie
AtomicBool
AtomicI8
AtomicU8
Cell<T>
F32<O>
F64<O>
I128<O>
I16<O>
and $N others
note: required by a bound in `takes_unaligned`
--> tests/ui-nightly/diagnostic-not-implemented-unaligned.rs:21:23
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Unaligned` is not satisfie
AtomicBool
AtomicI8
AtomicU8
Cell<T>
F32<O>
F64<O>
I128<O>
I16<O>
and $N others
note: required by a bound in `takes_unaligned`
--> tests/ui-stable/diagnostic-not-implemented-unaligned.rs:21:23
Expand Down
2 changes: 1 addition & 1 deletion zerocopy-derive/tests/ui-nightly/derive_transparent.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,10 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Unaligned` is not satisfie
AtomicBool
AtomicI8
AtomicU8
Cell<T>
F32<O>
F64<O>
I128<O>
I16<O>
and $N others
note: required for `TransparentStruct<NotZerocopy>` to implement `zerocopy::Unaligned`
--> tests/ui-nightly/derive_transparent.rs:24:32
Expand Down
6 changes: 3 additions & 3 deletions zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied
AtomicBool
AtomicI8
AtomicU8
Cell<T>
F32<O>
F64<O>
I128<O>
I16<O>
and $N others
= help: see issue #48214
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -210,10 +210,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied
AtomicBool
AtomicI8
AtomicU8
Cell<T>
F32<O>
F64<O>
I128<O>
I16<O>
and $N others
= help: see issue #48214
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -234,10 +234,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied
AtomicBool
AtomicI8
AtomicU8
Cell<T>
F32<O>
F64<O>
I128<O>
I16<O>
and $N others
= help: see issue #48214
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand Down
4 changes: 2 additions & 2 deletions zerocopy-derive/tests/ui-nightly/struct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied
AtomicBool
AtomicI8
AtomicU8
Cell<T>
F32<O>
F64<O>
I128<O>
I16<O>
and $N others
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand Down Expand Up @@ -386,10 +386,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied
AtomicBool
AtomicI8
AtomicU8
Cell<T>
F32<O>
F64<O>
I128<O>
I16<O>
and $N others
note: required for `IntoBytes11<AU16>` to implement `zerocopy::IntoBytes`
--> tests/ui-nightly/struct.rs:150:10
Expand Down
2 changes: 1 addition & 1 deletion zerocopy-derive/tests/ui-stable/derive_transparent.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,10 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Unaligned` is not satisfie
AtomicBool
AtomicI8
AtomicU8
Cell<T>
F32<O>
F64<O>
I128<O>
I16<O>
and $N others
note: required for `TransparentStruct<NotZerocopy>` to implement `zerocopy::Unaligned`
--> tests/ui-stable/derive_transparent.rs:24:32
Expand Down
Loading
Loading