Skip to content

Commit 93ca281

Browse files
committed
Improve trait safety documentation
For each of our unsafe traits, clarify who can skip reading the Safety section. For each of our unsafe traits (except for `Unaligned`): - Clarify that it must be sound to construct `&[u8]` and `&T` to the same memory region (this addresses #8) - Clarify that, in order to implement the trait, the type's fields need to satisfy the same requirements, but don't actually need to implement the trait - Clarify that, in order to implement the trait, the type must not contain any `UnsafeCell`s Closes #8
1 parent 4faad6e commit 93ca281

File tree

1 file changed

+82
-20
lines changed

1 file changed

+82
-20
lines changed

src/lib.rs

+82-20
Original file line numberDiff line numberDiff line change
@@ -199,19 +199,40 @@ mod zerocopy {
199199
///
200200
/// # Safety
201201
///
202-
/// If `T: FromZeroes`, then unsafe code may assume that it is sound to treat
203-
/// any initialized sequence of zero bytes of length `size_of::<T>()` as a `T`.
202+
/// *This section describes what is required in order for `T: FromZeroes`, and
203+
/// what unsafe code may assume of such types. `#[derive(FromZeroes)]` only
204+
/// permits types which satisfy these requirements. If you don't plan on
205+
/// implementing `FromZeroes` manually, and you don't plan on writing unsafe
206+
/// code that operates on `FromZeroes` types, then you don't need to read this
207+
/// section.*
208+
///
209+
/// If `T: FromZeroes`, then unsafe code may assume that:
210+
/// - It is sound to treat any initialized sequence of zero bytes of length
211+
/// `size_of::<T>()` as a `T`.
212+
/// - Given `b: &[u8]` where `b.len() == size_of::<T>()`, `b` is aligned to
213+
/// `align_of::<T>()`, and `b` contains only zero bytes, it is sound to
214+
/// construct a `t: &T` at the same address as `b`, and it is sound for both
215+
/// `b` and `t` to be live at the same time.
216+
///
204217
/// If a type is marked as `FromZeroes` which violates this contract, it may
205218
/// cause undefined behavior.
206219
///
207-
/// If a type has the following properties, then it is safe to implement
220+
/// If a type has the following properties, then it is sound to implement
208221
/// `FromZeroes` for that type:
209-
/// - If the type is a struct, all of its fields must implement `FromZeroes`
222+
/// - If the type is a struct, all of its fields must satisfy the requirements
223+
/// to be `FromZeroes` (they do not actually have to be `FromZeroes`).
210224
/// - If the type is an enum, it must be C-like (meaning that all variants have
211-
/// no fields) and it must have a variant with a discriminant of `0` (see [the
212-
/// reference] for a description of how discriminant values are chosen)
225+
/// no fields) and it must have a variant with a discriminant of `0`. See [the
226+
/// reference] for a description of how discriminant values are chosen.
227+
/// - The type must not contain any [`UnsafeCell`]s (this is required in order
228+
/// for it to be sound to construct a `&[u8]` and a `&T` to the same region of
229+
/// memory). The type may contain references or pointers to `UnsafeCell`s so
230+
/// long as those values can themselves be initialized from zeroes
231+
/// (`FromZeroes` is not currently implemented for, e.g.,
232+
/// `Option<&UnsafeCell<_>>`, but it could be one day).
213233
///
214234
/// [the reference]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations
235+
/// [`UnsafeCell`]: core::cell::UnsafeCell
215236
///
216237
/// # Rationale
217238
///
@@ -420,22 +441,40 @@ pub unsafe trait FromZeroes {
420441
///
421442
/// # Safety
422443
///
423-
/// If `T: FromBytes`, then unsafe code may assume that it is sound to treat any
424-
/// initialized sequence of bytes of length `size_of::<T>()` as a `T`. If a type
425-
/// is marked as `FromBytes` which violates this contract, it may cause
426-
/// undefined behavior.
444+
/// *This section describes what is required in order for `T: FromBytes`, and
445+
/// what unsafe code may assume of such types. `#[derive(FromBytes)]` only
446+
/// permits types which satisfy these requirements. If you don't plan on
447+
/// implementing `FromBytes` manually, and you don't plan on writing unsafe code
448+
/// that operates on `FromBytes` types, then you don't need to read this
449+
/// section.*
450+
///
451+
/// If `T: FromBytes`, then unsafe code may assume that:
452+
/// - It is sound to treat any initialized sequence of bytes of length
453+
/// `size_of::<T>()` as a `T`.
454+
/// - Given `b: &[u8]` where `b.len() == size_of::<T>()` and `b` is aligned to
455+
/// `align_of::<T>()`, it is sound to construct a `t: &T` at the same address
456+
/// as `b`, and it is sound for both `b` and `t` to be live at the same time.
457+
///
458+
/// If a type is marked as `FromBytes` which violates this contract, it may
459+
/// cause undefined behavior.
427460
///
428-
/// If a type has the following properties, then it is safe to implement
461+
/// If a type has the following properties, then it is sound to implement
429462
/// `FromBytes` for that type:
430-
/// - If the type is a struct, all of its fields must implement `FromBytes`
463+
/// - If the type is a struct, all of its fields must satisfy the requirements
464+
/// to be `FromBytes` (they do not actually have to be `FromBytes`)
431465
/// - If the type is an enum:
432-
/// - It must be a C-like enum (meaning that all variants have no fields)
466+
/// - It must be a C-like enum (meaning that all variants have no fields).
433467
/// - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`,
434468
/// `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`).
435469
/// - The maximum number of discriminants must be used (so that every possible
436470
/// bit pattern is a valid one). Be very careful when using the `C`,
437471
/// `usize`, or `isize` representations, as their size is
438472
/// platform-dependent.
473+
/// - The type must not contain any [`UnsafeCell`]s (this is required in order
474+
/// for it to be sound to construct a `&[u8]` and a `&T` to the same region of
475+
/// memory).
476+
///
477+
/// [`UnsafeCell`]: core::cell::UnsafeCell
439478
///
440479
/// # Rationale
441480
///
@@ -546,27 +585,43 @@ pub unsafe trait FromBytes: FromZeroes {
546585
///
547586
/// # Safety
548587
///
549-
/// If `T: AsBytes`, then unsafe code may assume that it is sound to treat any
550-
/// instance of the type as an immutable `[u8]` of length `size_of::<T>()`. If a
551-
/// type is marked as `AsBytes` which violates this contract, it may cause
588+
/// *This section describes what is required in order for `T: AsBytes`, and what
589+
/// unsafe code may assume of such types. `#[derive(AsBytes)]` only permits
590+
/// types which satisfy these requirements. If you don't plan on implementing
591+
/// `AsBytes` manually, and you don't plan on writing unsafe code that operates
592+
/// on `AsBytes` types, then you don't need to read this section.*
593+
///
594+
/// If `T: AsBytes`, then unsafe code may assume that:
595+
/// - It is sound to treat any `t: T` as an immutable `[u8]` of length
596+
/// `size_of_val(t)`.
597+
/// - Given `t: &T`, it is sound to construct a `b: &[u8]` where `b.len() ==
598+
/// size_of_val(t)` at the same address as `t`, and it is sound for both `b`
599+
/// and `t` to be live at the same time.
600+
///
601+
/// If a type is marked as `AsBytes` which violates this contract, it may cause
552602
/// undefined behavior.
553603
///
554-
/// If a type has the following properties, then it is safe to implement
555-
/// `AsBytes` for that type
604+
/// If a type has the following properties, then it is sound to implement
605+
/// `AsBytes` for that type:
556606
/// - If the type is a struct:
557607
/// - It must have a defined representation (`repr(C)`, `repr(transparent)`,
558608
/// or `repr(packed)`).
559-
/// - All of its fields must be `AsBytes`
609+
/// - All of its fields must satisfy the requirements to be `AsBytes` (they do
610+
/// not actually have to be `AsBytes`).
560611
/// - Its layout must have no padding. This is always true for
561612
/// `repr(transparent)` and `repr(packed)`. For `repr(C)`, see the layout
562613
/// algorithm described in the [Rust Reference].
563614
/// - If the type is an enum:
564-
/// - It must be a C-like enum (meaning that all variants have no fields)
615+
/// - It must be a C-like enum (meaning that all variants have no fields).
565616
/// - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`,
566617
/// `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`).
618+
/// - The type must not contain any [`UnsafeCell`]s (this is required in order
619+
/// for it to be sound to construct a `&[u8]` and a `&T` to the same region of
620+
/// memory).
567621
///
568622
/// [type-layout]: https://doc.rust-lang.org/reference/type-layout.html
569623
/// [Rust Reference]: https://doc.rust-lang.org/reference/type-layout.html
624+
/// [`UnsafeCell`]: core::cell::UnsafeCell
570625
pub unsafe trait AsBytes {
571626
// The `Self: Sized` bound makes it so that this function doesn't prevent
572627
// `AsBytes` from being object safe. Note that other `AsBytes` methods
@@ -692,6 +747,13 @@ pub unsafe trait AsBytes {
692747
///
693748
/// # Safety
694749
///
750+
/// *This section describes what is required in order for `T: Unaligned`, and
751+
/// what unsafe code may assume of such types. `#[derive(Unaligned)]` only
752+
/// permits types which satisfy these requirements. If you don't plan on
753+
/// implementing `Unaligned` manually, and you don't plan on writing unsafe code
754+
/// that operates on `Unaligned` types, then you don't need to read this
755+
/// section.*
756+
///
695757
/// If `T: Unaligned`, then unsafe code may assume that it is sound to produce a
696758
/// reference to `T` at any memory location regardless of alignment. If a type
697759
/// is marked as `Unaligned` which violates this contract, it may cause

0 commit comments

Comments
 (0)