SSL lib.rs
Sprache: unbekannt
|
|
Spracherkennung für: .rs vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
// Copyright 2018 The Fuchsia Authors
//
// Licensed under the 2-Clause BSD License <LICENSE-BSD or
// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
// This file may not be copied, modified, or distributed except according to
// those terms.
// After updating the following doc comment, make sure to run the following
// command to update `README.md` based on its contents:
//
// ./generate-readme.sh > README.md
//! *<span style="font-size: 100%; color:grey;">Want to help improve zerocopy?
//! Fill out our [user survey][user-survey]!</span>*
//!
//! ***<span style="font-size: 140%">Fast, safe, <span
//! style="color:red;">compile error</span>. Pick two.</span>***
//!
//! Zerocopy makes zero-cost memory manipulation effortless. We write `unsafe`
//! so you don't have to.
//!
//! # Overview
//!
//! Zerocopy provides four core marker traits, each of which can be derived
//! (e.g., `#[derive(FromZeroes)]`):
//! - [`FromZeroes`] indicates that a sequence of zero bytes represents a valid
//! instance of a type
//! - [`FromBytes`] indicates that a type may safely be converted from an
//! arbitrary byte sequence
//! - [`AsBytes`] indicates that a type may safely be converted *to* a byte
//! sequence
//! - [`Unaligned`] indicates that a type's alignment requirement is 1
//!
//! Types which implement a subset of these traits can then be converted to/from
//! byte sequences with little to no runtime overhead.
//!
//! Zerocopy also provides byte-order aware integer types that support these
//! conversions; see the [`byteorder`] module. These types are especially useful
//! for network parsing.
//!
//! [user-survey]: https://docs.google.com/forms/d/e/1FAIpQLSdzBNTN9tzwsmtyZxRFNL02K36IWCdHWW2ZBckyQS2xiO3i8Q/viewform?usp=published_options
//!
//! # Cargo Features
//!
//! - **`alloc`**
//! By default, `zerocopy` is `no_std`. When the `alloc` feature is enabled,
//! the `alloc` crate is added as a dependency, and some allocation-related
//! functionality is added.
//!
//! - **`byteorder`** (enabled by default)
//! Adds the [`byteorder`] module and a dependency on the `byteorder` crate.
//! The `byteorder` module provides byte order-aware equivalents of the
//! multi-byte primitive numerical types. Unlike their primitive equivalents,
//! the types in this module have no alignment requirement and support byte
//! order conversions. This can be useful in handling file formats, network
//! packet layouts, etc which don't provide alignment guarantees and which may
//! use a byte order different from that of the execution platform.
//!
//! - **`derive`**
//! Provides derives for the core marker traits via the `zerocopy-derive`
//! crate. These derives are re-exported from `zerocopy`, so it is not
//! necessary to depend on `zerocopy-derive` directly.
//!
//! However, you may experience better compile times if you instead directly
//! depend on both `zerocopy` and `zerocopy-derive` in your `Cargo.toml`,
//! since doing so will allow Rust to compile these crates in parallel. To do
//! so, do *not* enable the `derive` feature, and list both dependencies in
//! your `Cargo.toml` with the same leading non-zero version number; e.g:
//!
//! ```toml
//! [dependencies]
//! zerocopy = "0.X"
//! zerocopy-derive = "0.X"
//! ```
//!
//! - **`simd`**
//! When the `simd` feature is enabled, `FromZeroes`, `FromBytes`, and
//! `AsBytes` impls are emitted for all stable SIMD types which exist on the
//! target platform. Note that the layout of SIMD types is not yet stabilized,
//! so these impls may be removed in the future if layout changes make them
//! invalid. For more information, see the Unsafe Code Guidelines Reference
//! page on the [layout of packed SIMD vectors][simd-layout].
//!
//! - **`simd-nightly`**
//! Enables the `simd` feature and adds support for SIMD types which are only
//! available on nightly. Since these types are unstable, support for any type
//! may be removed at any point in the future.
//!
//! [simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html
//!
//! # Security Ethos
//!
//! Zerocopy is expressly designed for use in security-critical contexts. We
//! strive to ensure that that zerocopy code is sound under Rust's current
//! memory model, and *any future memory model*. We ensure this by:
//! - **...not 'guessing' about Rust's semantics.**
//! We annotate `unsafe` code with a precise rationale for its soundness that
//! cites a relevant section of Rust's official documentation. When Rust's
//! documented semantics are unclear, we work with the Rust Operational
//! Semantics Team to clarify Rust's documentation.
//! - **...rigorously testing our implementation.**
//! We run tests using [Miri], ensuring that zerocopy is sound across a wide
//! array of supported target platforms of varying endianness and pointer
//! width, and across both current and experimental memory models of Rust.
//! - **...formally proving the correctness of our implementation.**
//! We apply formal verification tools like [Kani][kani] to prove zerocopy's
//! correctness.
//!
//! For more information, see our full [soundness policy].
//!
//! [Miri]: https://github.com/rust-lang/miri
//! [Kani]: https://github.com/model-checking/kani
//! [soundness policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#soundness
//!
//! # Relationship to Project Safe Transmute
//!
//! [Project Safe Transmute] is an official initiative of the Rust Project to
//! develop language-level support for safer transmutation. The Project consults
//! with crates like zerocopy to identify aspects of safer transmutation that
//! would benefit from compiler support, and has developed an [experimental,
//! compiler-supported analysis][mcp-transmutability] which determines whether,
//! for a given type, any value of that type may be soundly transmuted into
//! another type. Once this functionality is sufficiently mature, zerocopy
//! intends to replace its internal transmutability analysis (implemented by our
//! custom derives) with the compiler-supported one. This change will likely be
//! an implementation detail that is invisible to zerocopy's users.
//!
//! Project Safe Transmute will not replace the need for most of zerocopy's
//! higher-level abstractions. The experimental compiler analysis is a tool for
//! checking the soundness of `unsafe` code, not a tool to avoid writing
//! `unsafe` code altogether. For the foreseeable future, crates like zerocopy
//! will still be required in order to provide higher-level abstractions on top
//! of the building block provided by Project Safe Transmute.
//!
//! [Project Safe Transmute]: https://rust-lang.github.io/rfcs/2835-project-safe-transmute.html
//! [mcp-transmutability]: https://github.com/rust-lang/compiler-team/issues/411
//!
//! # MSRV
//!
//! See our [MSRV policy].
//!
//! [MSRV policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#msrv
//!
//! # Changelog
//!
//! Zerocopy uses [GitHub Releases].
//!
//! [GitHub Releases]: https://github.com/google/zerocopy/releases
// Sometimes we want to use lints which were added after our MSRV.
// `unknown_lints` is `warn` by default and we deny warnings in CI, so without
// this attribute, any unknown lint would cause a CI failure when testing with
// our MSRV.
#![allow(unknown_lints)]
#![deny(renamed_and_removed_lints)]
#![deny(
anonymous_parameters,
deprecated_in_future,
illegal_floating_point_literal_pattern,
late_bound_lifetime_arguments,
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
path_statements,
patterns_in_fns_without_body,
rust_2018_idioms,
trivial_numeric_casts,
unreachable_pub,
unsafe_op_in_unsafe_fn,
unused_extern_crates,
unused_qualifications,
variant_size_differences
)]
#![cfg_attr(
__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS,
deny(fuzzy_provenance_casts, lossy_provenance_casts)
)]
#![deny(
clippy::all,
clippy::alloc_instead_of_core,
clippy::arithmetic_side_effects,
clippy::as_underscore,
clippy::assertions_on_result_states,
clippy::as_conversions,
clippy::correctness,
clippy::dbg_macro,
clippy::decimal_literal_representation,
clippy::get_unwrap,
clippy::indexing_slicing,
clippy::missing_inline_in_public_items,
clippy::missing_safety_doc,
clippy::obfuscated_if_else,
clippy::perf,
clippy::print_stdout,
clippy::std_instead_of_core,
clippy::style,
clippy::suspicious,
clippy::todo,
clippy::undocumented_unsafe_blocks,
clippy::unimplemented,
clippy::unnested_or_patterns,
clippy::unwrap_used,
clippy::use_debug
)]
#![deny(
rustdoc::bare_urls,
rustdoc::broken_intra_doc_links,
rustdoc::invalid_codeblock_attributes,
rustdoc::invalid_html_tags,
rustdoc::invalid_rust_codeblocks,
rustdoc::missing_crate_level_docs,
rustdoc::private_intra_doc_links
)]
// In test code, it makes sense to weight more heavily towards concise, readable
// code over correct or debuggable code.
#![cfg_attr(any(test, kani), allow(
// In tests, you get line numbers and have access to source code, so panic
// messages are less important. You also often unwrap a lot, which would
// make expect'ing instead very verbose.
clippy::unwrap_used,
// In tests, there's no harm to "panic risks" - the worst that can happen is
// that your test will fail, and you'll fix it. By contrast, panic risks in
// production code introduce the possibly of code panicking unexpectedly "in
// the field".
clippy::arithmetic_side_effects,
clippy::indexing_slicing,
))]
#![cfg_attr(not(test), no_std)]
#![cfg_attr(feature = "simd-nightly", feature(stdsimd))]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(
__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS,
feature(layout_for_ptr, strict_provenance)
)]
// This is a hack to allow zerocopy-derive derives to work in this crate. They
// assume that zerocopy is linked as an extern crate, so they access items from
// it as `zerocopy::Xxx`. This makes that still work.
#[cfg(any(feature = "derive", test))]
extern crate self as zerocopy;
#[macro_use]
mod macros;
#[cfg(feature = "byteorder")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "byteorder")))]
pub mod byteorder;
#[doc(hidden)]
pub mod macro_util;
mod post_monomorphization_compile_fail_tests;
mod util;
// TODO(#252): If we make this pub, come up with a better name.
mod wrappers;
#[cfg(feature = "byteorder")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "byteorder")))]
pub use crate::byteorder::*;
pub use crate::wrappers::*;
#[cfg(any(feature = "derive", test))]
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
pub use zerocopy_derive::Unaligned;
// `pub use` separately here so that we can mark it `#[doc(hidden)]`.
//
// TODO(#29): Remove this or add a doc comment.
#[cfg(any(feature = "derive", test))]
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
#[doc(hidden)]
pub use zerocopy_derive::KnownLayout;
use core::{
cell::{self, RefMut},
cmp::Ordering,
fmt::{self, Debug, Display, Formatter},
hash::Hasher,
marker::PhantomData,
mem::{self, ManuallyDrop, MaybeUninit},
num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
},
ops::{Deref, DerefMut},
ptr::{self, NonNull},
slice,
};
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, vec::Vec};
#[cfg(any(feature = "alloc", kani))]
use core::alloc::Layout;
// Used by `TryFromBytes::is_bit_valid`.
#[doc(hidden)]
pub use crate::util::ptr::Ptr;
// For each polyfill, as soon as the corresponding feature is stable, the
// polyfill import will be unused because method/function resolution will prefer
// the inherent method/function over a trait method/function. Thus, we suppress
// the `unused_imports` warning.
//
// See the documentation on `util::polyfills` for more information.
#[allow(unused_imports)]
use crate::util::polyfills::NonNullExt as _;
#[rustversion::nightly]
#[cfg(all(test, not(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)))]
const _: () = {
#[deprecated = "some tests may be skipped due to missing RUSTFLAGS=\"--cfg __INTERNAL_USE_O NLY_NIGHLTY_FEATURES_IN_TESTS\""]
const _WARNING: () = ();
#[warn(deprecated)]
_WARNING
};
/// The target pointer width, counted in bits.
const POINTER_WIDTH_BITS: usize = mem::size_of::<usize>() * 8;
/// The layout of a type which might be dynamically-sized.
///
/// `DstLayout` describes the layout of sized types, slice types, and "slice
/// DSTs" - ie, those that are known by the type system to have a trailing slice
/// (as distinguished from `dyn Trait` types - such types *might* have a
/// trailing slice type, but the type system isn't aware of it).
///
/// # Safety
///
/// Unlike [`core::alloc::Layout`], `DstLayout` is only used to describe full
/// Rust types - ie, those that satisfy the layout requirements outlined by
/// [the reference]. Callers may assume that an instance of `DstLayout`
/// satisfies any conditions imposed on Rust types by the reference.
///
/// If `layout: DstLayout` describes a type, `T`, then it is guaranteed that:
/// - `layout.align` is equal to `T`'s alignment
/// - If `layout.size_info` is `SizeInfo::Sized { size }`, then `T: Sized` and
/// `size_of::<T>() == size`
/// - If `layout.size_info` is `SizeInfo::SliceDst(slice_layout)`, then
/// - `T` is a slice DST
/// - The `size` of an instance of `T` with `elems` trailing slice elements is
/// equal to `slice_layout.offset + slice_layout.elem_size * elems` rounded up
/// to the nearest multiple of `layout.align`. Any bytes in the range
/// `[slice_layout.offset + slice_layout.elem_size * elems, size)` are padding
/// and must not be assumed to be initialized.
///
/// [the reference]: https://doc.rust-lang.org/reference/type-layout.html
#[doc(hidden)]
#[allow(missing_debug_implementations, missing_copy_implementations)]
#[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))]
pub struct DstLayout {
align: NonZeroUsize,
size_info: SizeInfo,
}
#[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))]
enum SizeInfo<E = usize> {
Sized { _size: usize },
SliceDst(TrailingSliceLayout<E>),
}
#[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))]
struct TrailingSliceLayout<E = usize> {
// The offset of the first byte of the trailing slice field. Note that this
// is NOT the same as the minimum size of the type. For example, consider
// the following type:
//
// struct Foo {
// a: u16,
// b: u8,
// c: [u8],
// }
//
// In `Foo`, `c` is at byte offset 3. When `c.len() == 0`, `c` is followed
// by a padding byte.
_offset: usize,
// The size of the element type of the trailing slice field.
_elem_size: E,
}
impl SizeInfo {
/// Attempts to create a `SizeInfo` from `Self` in which `elem_size` is a
/// `NonZeroUsize`. If `elem_size` is 0, returns `None`.
#[allow(unused)]
const fn try_to_nonzero_elem_size(&self) -> Option<SizeInfo<NonZeroUsize>> {
Some(match *self {
SizeInfo::Sized { _size } => SizeInfo::Sized { _size },
SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size }) => {
if let Some(_elem_size) = NonZeroUsize::new(_elem_size) {
SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size })
} else {
return None;
}
}
})
}
}
#[doc(hidden)]
#[derive(Copy, Clone)]
#[cfg_attr(test, derive(Debug))]
#[allow(missing_debug_implementations)]
pub enum _CastType {
_Prefix,
_Suffix,
}
impl DstLayout {
/// The minimum possible alignment of a type.
const MIN_ALIGN: NonZeroUsize = match NonZeroUsize::new(1) {
Some(min_align) => min_align,
None => unreachable!(),
};
/// The maximum theoretic possible alignment of a type.
///
/// For compatibility with future Rust versions, this is defined as the
/// maximum power-of-two that fits into a `usize`. See also
/// [`DstLayout::CURRENT_MAX_ALIGN`].
const THEORETICAL_MAX_ALIGN: NonZeroUsize =
match NonZeroUsize::new(1 << (POINTER_WIDTH_BITS - 1)) {
Some(max_align) => max_align,
None => unreachable!(),
};
/// The current, documented max alignment of a type \[1\].
///
/// \[1\] Per <https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers>:
///
/// The alignment value must be a power of two from 1 up to
/// 2<sup>29</sup>.
#[cfg(not(kani))]
const CURRENT_MAX_ALIGN: NonZeroUsize = match NonZeroUsize::new(1 << 28) {
Some(max_align) => max_align,
None => unreachable!(),
};
/// Constructs a `DstLayout` for a zero-sized type with `repr_align`
/// alignment (or 1). If `repr_align` is provided, then it must be a power
/// of two.
///
/// # Panics
///
/// This function panics if the supplied `repr_align` is not a power of two.
///
/// # Safety
///
/// Unsafe code may assume that the contract of this function is satisfied.
#[doc(hidden)]
#[inline]
pub const fn new_zst(repr_align: Option<NonZeroUsize>) -> DstLayout {
let align = match repr_align {
Some(align) => align,
None => Self::MIN_ALIGN,
};
assert!(align.is_power_of_two());
DstLayout { align, size_info: SizeInfo::Sized { _size: 0 } }
}
/// Constructs a `DstLayout` which describes `T`.
///
/// # Safety
///
/// Unsafe code may assume that `DstLayout` is the correct layout for `T`.
#[doc(hidden)]
#[inline]
pub const fn for_type<T>() -> DstLayout {
// SAFETY: `align` is correct by construction. `T: Sized`, and so it is
// sound to initialize `size_info` to `SizeInfo::Sized { size }`; the
// `size` field is also correct by construction.
DstLayout {
align: match NonZeroUsize::new(mem::align_of::<T>()) {
Some(align) => align,
None => unreachable!(),
},
size_info: SizeInfo::Sized { _size: mem::size_of::<T>() },
}
}
/// Constructs a `DstLayout` which describes `[T]`.
///
/// # Safety
///
/// Unsafe code may assume that `DstLayout` is the correct layout for `[T]`.
const fn for_slice<T>() -> DstLayout {
// SAFETY: The alignment of a slice is equal to the alignment of its
// element type, and so `align` is initialized correctly.
//
// Since this is just a slice type, there is no offset between the
// beginning of the type and the beginning of the slice, so it is
// correct to set `offset: 0`. The `elem_size` is correct by
// construction. Since `[T]` is a (degenerate case of a) slice DST, it
// is correct to initialize `size_info` to `SizeInfo::SliceDst`.
DstLayout {
align: match NonZeroUsize::new(mem::align_of::<T>()) {
Some(align) => align,
None => unreachable!(),
},
size_info: SizeInfo::SliceDst(TrailingSliceLayout {
_offset: 0,
_elem_size: mem::size_of::<T>(),
}),
}
}
/// Like `Layout::extend`, this creates a layout that describes a record
/// whose layout consists of `self` followed by `next` that includes the
/// necessary inter-field padding, but not any trailing padding.
///
/// In order to match the layout of a `#[repr(C)]` struct, this method
/// should be invoked for each field in declaration order. To add trailing
/// padding, call `DstLayout::pad_to_align` after extending the layout for
/// all fields. If `self` corresponds to a type marked with
/// `repr(packed(N))`, then `repr_packed` should be set to `Some(N)`,
/// otherwise `None`.
///
/// This method cannot be used to match the layout of a record with the
/// default representation, as that representation is mostly unspecified.
///
/// # Safety
///
/// If a (potentially hypothetical) valid `repr(C)` Rust type begins with
/// fields whose layout are `self`, and those fields are immediately
/// followed by a field whose layout is `field`, then unsafe code may rely
/// on `self.extend(field, repr_packed)` producing a layout that correctly
/// encompasses those two components.
///
/// We make no guarantees to the behavior of this method if these fragments
/// cannot appear in a valid Rust type (e.g., the concatenation of the
/// layouts would lead to a size larger than `isize::MAX`).
#[doc(hidden)]
#[inline]
pub const fn extend(self, field: DstLayout, repr_packed: Option<NonZeroUsize>) -> Self {
use util::{core_layout::padding_needed_for, max, min};
// If `repr_packed` is `None`, there are no alignment constraints, and
// the value can be defaulted to `THEORETICAL_MAX_ALIGN`.
let max_align = match repr_packed {
Some(max_align) => max_align,
None => Self::THEORETICAL_MAX_ALIGN,
};
assert!(max_align.is_power_of_two());
// We use Kani to prove that this method is robust to future increases
// in Rust's maximum allowed alignment. However, if such a change ever
// actually occurs, we'd like to be notified via assertion failures.
#[cfg(not(kani))]
{
debug_assert!(self.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get());
debug_assert!(field.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get());
if let Some(repr_packed) = repr_packed {
debug_assert!(repr_packed.get() <= DstLayout::CURRENT_MAX_ALIGN.get());
}
}
// The field's alignment is clamped by `repr_packed` (i.e., the
// `repr(packed(N))` attribute, if any) [1].
//
// [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers:
//
// The alignments of each field, for the purpose of positioning
// fields, is the smaller of the specified alignment and the alignment
// of the field's type.
let field_align = min(field.align, max_align);
// The struct's alignment is the maximum of its previous alignment and
// `field_align`.
let align = max(self.align, field_align);
let size_info = match self.size_info {
// If the layout is already a DST, we panic; DSTs cannot be extended
// with additional fields.
SizeInfo::SliceDst(..) => panic!("Cannot extend a DST with additional fields."),
SizeInfo::Sized { _size: preceding_size } => {
// Compute the minimum amount of inter-field padding needed to
// satisfy the field's alignment, and offset of the trailing
// field. [1]
//
// [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers:
//
// Inter-field padding is guaranteed to be the minimum
// required in order to satisfy each field's (possibly
// altered) alignment.
let padding = padding_needed_for(preceding_size, field_align);
// This will not panic (and is proven to not panic, with Kani)
// if the layout components can correspond to a leading layout
// fragment of a valid Rust type, but may panic otherwise (e.g.,
// combining or aligning the components would create a size
// exceeding `isize::MAX`).
let offset = match preceding_size.checked_add(padding) {
Some(offset) => offset,
None => panic!("Adding padding to `self`'s size overflows `usize`."),
};
match field.size_info {
SizeInfo::Sized { _size: field_size } => {
// If the trailing field is sized, the resulting layout
// will be sized. Its size will be the sum of the
// preceeding layout, the size of the new field, and the
// size of inter-field padding between the two.
//
// This will not panic (and is proven with Kani to not
// panic) if the layout components can correspond to a
// leading layout fragment of a valid Rust type, but may
// panic otherwise (e.g., combining or aligning the
// components would create a size exceeding
// `usize::MAX`).
let size = match offset.checked_add(field_size) {
Some(size) => size,
None => panic!("`field` cannot be appended without the total size overflowing `usize`"),
};
SizeInfo::Sized { _size: size }
}
SizeInfo::SliceDst(TrailingSliceLayout {
_offset: trailing_offset,
_elem_size,
}) => {
// If the trailing field is dynamically sized, so too
// will the resulting layout. The offset of the trailing
// slice component is the sum of the offset of the
// trailing field and the trailing slice offset within
// that field.
//
// This will not panic (and is proven with Kani to not
// panic) if the layout components can correspond to a
// leading layout fragment of a valid Rust type, but may
// panic otherwise (e.g., combining or aligning the
// components would create a size exceeding
// `usize::MAX`).
let offset = match offset.checked_add(trailing_offset) {
Some(offset) => offset,
None => panic!("`field` cannot be appended without the total size overflowing `usize`"),
};
SizeInfo::SliceDst(TrailingSliceLayout { _offset: offset, _elem_size })
}
}
}
};
DstLayout { align, size_info }
}
/// Like `Layout::pad_to_align`, this routine rounds the size of this layout
/// up to the nearest multiple of this type's alignment or `repr_packed`
/// (whichever is less). This method leaves DST layouts unchanged, since the
/// trailing padding of DSTs is computed at runtime.
///
/// In order to match the layout of a `#[repr(C)]` struct, this method
/// should be invoked after the invocations of [`DstLayout::extend`]. If
/// `self` corresponds to a type marked with `repr(packed(N))`, then
/// `repr_packed` should be set to `Some(N)`, otherwise `None`.
///
/// This method cannot be used to match the layout of a record with the
/// default representation, as that representation is mostly unspecified.
///
/// # Safety
///
/// If a (potentially hypothetical) valid `repr(C)` type begins with fields
/// whose layout are `self` followed only by zero or more bytes of trailing
/// padding (not included in `self`), then unsafe code may rely on
/// `self.pad_to_align(repr_packed)` producing a layout that correctly
/// encapsulates the layout of that type.
///
/// We make no guarantees to the behavior of this method if `self` cannot
/// appear in a valid Rust type (e.g., because the addition of trailing
/// padding would lead to a size larger than `isize::MAX`).
#[doc(hidden)]
#[inline]
pub const fn pad_to_align(self) -> Self {
use util::core_layout::padding_needed_for;
let size_info = match self.size_info {
// For sized layouts, we add the minimum amount of trailing padding
// needed to satisfy alignment.
SizeInfo::Sized { _size: unpadded_size } => {
let padding = padding_needed_for(unpadded_size, self.align);
let size = match unpadded_size.checked_add(padding) {
Some(size) => size,
None => panic!("Adding padding caused size to overflow `usize`."),
};
SizeInfo::Sized { _size: size }
}
// For DST layouts, trailing padding depends on the length of the
// trailing DST and is computed at runtime. This does not alter the
// offset or element size of the layout, so we leave `size_info`
// unchanged.
size_info @ SizeInfo::SliceDst(_) => size_info,
};
DstLayout { align: self.align, size_info }
}
/// Validates that a cast is sound from a layout perspective.
///
/// Validates that the size and alignment requirements of a type with the
/// layout described in `self` would not be violated by performing a
/// `cast_type` cast from a pointer with address `addr` which refers to a
/// memory region of size `bytes_len`.
///
/// If the cast is valid, `validate_cast_and_convert_metadata` returns
/// `(elems, split_at)`. If `self` describes a dynamically-sized type, then
/// `elems` is the maximum number of trailing slice elements for which a
/// cast would be valid (for sized types, `elem` is meaningless and should
/// be ignored). `split_at` is the index at which to split the memory region
/// in order for the prefix (suffix) to contain the result of the cast, and
/// in order for the remaining suffix (prefix) to contain the leftover
/// bytes.
///
/// There are three conditions under which a cast can fail:
/// - The smallest possible value for the type is larger than the provided
/// memory region
/// - A prefix cast is requested, and `addr` does not satisfy `self`'s
/// alignment requirement
/// - A suffix cast is requested, and `addr + bytes_len` does not satisfy
/// `self`'s alignment requirement (as a consequence, since all instances
/// of the type are a multiple of its alignment, no size for the type will
/// result in a starting address which is properly aligned)
///
/// # Safety
///
/// The caller may assume that this implementation is correct, and may rely
/// on that assumption for the soundness of their code. In particular, the
/// caller may assume that, if `validate_cast_and_convert_metadata` returns
/// `Some((elems, split_at))`, then:
/// - A pointer to the type (for dynamically sized types, this includes
/// `elems` as its pointer metadata) describes an object of size `size <=
/// bytes_len`
/// - If this is a prefix cast:
/// - `addr` satisfies `self`'s alignment
/// - `size == split_at`
/// - If this is a suffix cast:
/// - `split_at == bytes_len - size`
/// - `addr + split_at` satisfies `self`'s alignment
///
/// Note that this method does *not* ensure that a pointer constructed from
/// its return values will be a valid pointer. In particular, this method
/// does not reason about `isize` overflow, which is a requirement of many
/// Rust pointer APIs, and may at some point be determined to be a validity
/// invariant of pointer types themselves. This should never be a problem so
/// long as the arguments to this method are derived from a known-valid
/// pointer (e.g., one derived from a safe Rust reference), but it is
/// nonetheless the caller's responsibility to justify that pointer
/// arithmetic will not overflow based on a safety argument *other than* the
/// mere fact that this method returned successfully.
///
/// # Panics
///
/// `validate_cast_and_convert_metadata` will panic if `self` describes a
/// DST whose trailing slice element is zero-sized.
///
/// If `addr + bytes_len` overflows `usize`,
/// `validate_cast_and_convert_metadata` may panic, or it may return
/// incorrect results. No guarantees are made about when
/// `validate_cast_and_convert_metadata` will panic. The caller should not
/// rely on `validate_cast_and_convert_metadata` panicking in any particular
/// condition, even if `debug_assertions` are enabled.
#[allow(unused)]
const fn validate_cast_and_convert_metadata(
&self,
addr: usize,
bytes_len: usize,
cast_type: _CastType,
) -> Option<(usize, usize)> {
// `debug_assert!`, but with `#[allow(clippy::arithmetic_side_effects)]`.
macro_rules! __debug_assert {
($e:expr $(, $msg:expr)?) => {
debug_assert!({
#[allow(clippy::arithmetic_side_effects)]
let e = $e;
e
} $(, $msg)?);
};
}
// Note that, in practice, `self` is always a compile-time constant. We
// do this check earlier than needed to ensure that we always panic as a
// result of bugs in the program (such as calling this function on an
// invalid type) instead of allowing this panic to be hidden if the cast
// would have failed anyway for runtime reasons (such as a too-small
// memory region).
//
// TODO(#67): Once our MSRV is 1.65, use let-else:
// https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements
let size_info = match self.size_info.try_to_nonzero_elem_size() {
Some(size_info) => size_info,
None => panic!("attempted to cast to slice type with zero-sized element"),
};
// Precondition
__debug_assert!(addr.checked_add(bytes_len).is_some(), "`addr` + `bytes_len` > usize::MAX");
// Alignment checks go in their own block to avoid introducing variables
// into the top-level scope.
{
// We check alignment for `addr` (for prefix casts) or `addr +
// bytes_len` (for suffix casts). For a prefix cast, the correctness
// of this check is trivial - `addr` is the address the object will
// live at.
//
// For a suffix cast, we know that all valid sizes for the type are
// a multiple of the alignment (and by safety precondition, we know
// `DstLayout` may only describe valid Rust types). Thus, a
// validly-sized instance which lives at a validly-aligned address
// must also end at a validly-aligned address. Thus, if the end
// address for a suffix cast (`addr + bytes_len`) is not aligned,
// then no valid start address will be aligned either.
let offset = match cast_type {
_CastType::_Prefix => 0,
_CastType::_Suffix => bytes_len,
};
// Addition is guaranteed not to overflow because `offset <=
// bytes_len`, and `addr + bytes_len <= usize::MAX` is a
// precondition of this method. Modulus is guaranteed not to divide
// by 0 because `align` is non-zero.
#[allow(clippy::arithmetic_side_effects)]
if (addr + offset) % self.align.get() != 0 {
return None;
}
}
let (elems, self_bytes) = match size_info {
SizeInfo::Sized { _size: size } => {
if size > bytes_len {
return None;
}
(0, size)
}
SizeInfo::SliceDst(TrailingSliceLayout { _offset: offset, _elem_size: elem_size }) => {
// Calculate the maximum number of bytes that could be consumed
// - any number of bytes larger than this will either not be a
// multiple of the alignment, or will be larger than
// `bytes_len`.
let max_total_bytes =
util::round_down_to_next_multiple_of_alignment(bytes_len, self.align);
// Calculate the maximum number of bytes that could be consumed
// by the trailing slice.
//
// TODO(#67): Once our MSRV is 1.65, use let-else:
// https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements
let max_slice_and_padding_bytes = match max_total_bytes.checked_sub(offset) {
Some(max) => max,
// `bytes_len` too small even for 0 trailing slice elements.
None => return None,
};
// Calculate the number of elements that fit in
// `max_slice_and_padding_bytes`; any remaining bytes will be
// considered padding.
//
// Guaranteed not to divide by zero: `elem_size` is non-zero.
#[allow(clippy::arithmetic_side_effects)]
let elems = max_slice_and_padding_bytes / elem_size.get();
// Guaranteed not to overflow on multiplication: `usize::MAX >=
// max_slice_and_padding_bytes >= (max_slice_and_padding_bytes /
// elem_size) * elem_size`.
//
// Guaranteed not to overflow on addition:
// - max_slice_and_padding_bytes == max_total_bytes - offset
// - elems * elem_size <= max_slice_and_padding_bytes == max_total_bytes - offset
// - elems * elem_size + offset <= max_total_bytes <= usize::MAX
#[allow(clippy::arithmetic_side_effects)]
let without_padding = offset + elems * elem_size.get();
// `self_bytes` is equal to the offset bytes plus the bytes
// consumed by the trailing slice plus any padding bytes
// required to satisfy the alignment. Note that we have computed
// the maximum number of trailing slice elements that could fit
// in `self_bytes`, so any padding is guaranteed to be less than
// the size of an extra element.
//
// Guaranteed not to overflow:
// - By previous comment: without_padding == elems * elem_size +
// offset <= max_total_bytes
// - By construction, `max_total_bytes` is a multiple of
// `self.align`.
// - At most, adding padding needed to round `without_padding`
// up to the next multiple of the alignment will bring
// `self_bytes` up to `max_total_bytes`.
#[allow(clippy::arithmetic_side_effects)]
let self_bytes = without_padding
+ util::core_layout::padding_needed_for(without_padding, self.align);
(elems, self_bytes)
}
};
__debug_assert!(self_bytes <= bytes_len);
let split_at = match cast_type {
_CastType::_Prefix => self_bytes,
// Guaranteed not to underflow:
// - In the `Sized` branch, only returns `size` if `size <=
// bytes_len`.
// - In the `SliceDst` branch, calculates `self_bytes <=
// max_toatl_bytes`, which is upper-bounded by `bytes_len`.
#[allow(clippy::arithmetic_side_effects)]
_CastType::_Suffix => bytes_len - self_bytes,
};
Some((elems, split_at))
}
}
/// A trait which carries information about a type's layout that is used by the
/// internals of this crate.
///
/// This trait is not meant for consumption by code outside of this crate. While
/// the normal semver stability guarantees apply with respect to which types
/// implement this trait and which trait implementations are implied by this
/// trait, no semver stability guarantees are made regarding its internals; they
/// may change at any time, and code which makes use of them may break.
///
/// # Safety
///
/// This trait does not convey any safety guarantees to code outside this crate.
#[doc(hidden)] // TODO: Remove this once KnownLayout is used by other APIs
pub unsafe trait KnownLayout {
// The `Self: Sized` bound makes it so that `KnownLayout` can still be
// object safe. It's not currently object safe thanks to `const LAYOUT`, and
// it likely won't be in the future, but there's no reason not to be
// forwards-compatible with object safety.
#[doc(hidden)]
fn only_derive_is_allowed_to_implement_this_trait()
where
Self: Sized;
#[doc(hidden)]
const LAYOUT: DstLayout;
/// SAFETY: The returned pointer has the same address and provenance as
/// `bytes`. If `Self` is a DST, the returned pointer's referent has `elems`
/// elements in its trailing slice. If `Self` is sized, `elems` is ignored.
#[doc(hidden)]
fn raw_from_ptr_len(bytes: NonNull<u8>, elems: usize) -> NonNull<Self>;
}
// SAFETY: Delegates safety to `DstLayout::for_slice`.
unsafe impl<T: KnownLayout> KnownLayout for [T] {
#[allow(clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait()
where
Self: Sized,
{
}
const LAYOUT: DstLayout = DstLayout::for_slice::<T>();
// SAFETY: `.cast` preserves address and provenance. The returned pointer
// refers to an object with `elems` elements by construction.
#[inline(always)]
fn raw_from_ptr_len(data: NonNull<u8>, elems: usize) -> NonNull<Self> {
// TODO(#67): Remove this allow. See NonNullExt for more details.
#[allow(unstable_name_collisions)]
NonNull::slice_from_raw_parts(data.cast::<T>(), elems)
}
}
#[rustfmt::skip]
impl_known_layout!(
(),
u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64,
bool, char,
NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32,
NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize
);
#[rustfmt::skip]
impl_known_layout!(
T => Option<T>,
T: ?Sized => PhantomData<T>,
T => Wrapping<T>,
T => MaybeUninit<T>,
T: ?Sized => *const T,
T: ?Sized => *mut T,
);
impl_known_layout!(const N: usize, T => [T; N]);
safety_comment! {
/// SAFETY:
/// `str` and `ManuallyDrop<[T]>` [1] have the same representations as
/// `[u8]` and `[T]` repsectively. `str` has different bit validity than
/// `[u8]`, but that doesn't affect the soundness of this impl.
///
/// [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html:
///
/// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
/// validity as `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.
unsafe_impl_known_layout!(#[repr([u8])] str);
unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] ManuallyDrop<T>);
}
/// Analyzes whether a type is [`FromZeroes`].
///
/// This derive analyzes, at compile time, whether the annotated type satisfies
/// the [safety conditions] of `FromZeroes` and implements `FromZeroes` if it is
/// sound to do so. This derive can be applied to structs, enums, and unions;
/// e.g.:
///
/// ```
/// # use zerocopy_derive::FromZeroes;
/// #[derive(FromZeroes)]
/// struct MyStruct {
/// # /*
/// ...
/// # */
/// }
///
/// #[derive(FromZeroes)]
/// #[repr(u8)]
/// enum MyEnum {
/// # Variant0,
/// # /*
/// ...
/// # */
/// }
///
/// #[derive(FromZeroes)]
/// union MyUnion {
/// # variant: u8,
/// # /*
/// ...
/// # */
/// }
/// ```
///
/// [safety conditions]: trait@FromZeroes#safety
///
/// # Analysis
///
/// *This section describes, roughly, the analysis performed by this derive to
/// determine whether it is sound to implement `FromZeroes` for a given type.
/// Unless you are modifying the implementation of this derive, or attempting to
/// manually implement `FromZeroes` for a type yourself, you don't need to read
/// this section.*
///
/// If a type has the following properties, then this derive can implement
/// `FromZeroes` for that type:
///
/// - If the type is a struct, all of its fields must be `FromZeroes`.
/// - If the type is an enum, it must be C-like (meaning that all variants have
/// no fields) and it must have a variant with a discriminant of `0`. See [the
/// reference] for a description of how discriminant values are chosen.
/// - The type must not contain any [`UnsafeCell`]s (this is required in order
/// for it to be sound to construct a `&[u8]` and a `&T` to the same region of
/// memory). The type may contain references or pointers to `UnsafeCell`s so
/// long as those values can themselves be initialized from zeroes
/// (`FromZeroes` is not currently implemented for, e.g.,
/// `Option<&UnsafeCell<_>>`, but it could be one day).
///
/// This analysis is subject to change. Unsafe code may *only* rely on the
/// documented [safety conditions] of `FromZeroes`, and must *not* rely on the
/// implementation details of this derive.
///
/// [the reference]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations
/// [`UnsafeCell`]: core::cell::UnsafeCell
///
/// ## Why isn't an explicit representation required for structs?
///
/// Neither this derive, nor the [safety conditions] of `FromZeroes`, requires
/// that structs are marked with `#[repr(C)]`.
///
/// Per the [Rust reference](reference),
///
/// > The representation of a type can change the padding between fields, but
/// does not change the layout of the fields themselves.
///
/// [reference]: https://doc.rust-lang.org/reference/type-layout.html#representations
///
/// Since the layout of structs only consists of padding bytes and field bytes,
/// a struct is soundly `FromZeroes` if:
/// 1. its padding is soundly `FromZeroes`, and
/// 2. its fields are soundly `FromZeroes`.
///
/// The answer to the first question is always yes: padding bytes do not have
/// any validity constraints. A [discussion] of this question in the Unsafe Code
/// Guidelines Working Group concluded that it would be virtually unimaginable
/// for future versions of rustc to add validity constraints to padding bytes.
///
/// [discussion]: https://github.com/rust-lang/unsafe-code-guidelines/issues/174
///
/// Whether a struct is soundly `FromZeroes` therefore solely depends on whether
/// its fields are `FromZeroes`.
// TODO(#146): Document why we don't require an enum to have an explicit `repr`
// attribute.
#[cfg(any(feature = "derive", test))]
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
pub use zerocopy_derive::FromZeroes;
/// Types whose validity can be checked at runtime, allowing them to be
/// conditionally converted from byte slices.
///
/// WARNING: Do not implement this trait yourself! Instead, use
/// `#[derive(TryFromBytes)]`.
///
/// `TryFromBytes` types can safely be deserialized from an untrusted sequence
/// of bytes by performing a runtime check that the byte sequence contains a
/// valid instance of `Self`.
///
/// `TryFromBytes` is ignorant of byte order. For byte order-aware types, see
/// the [`byteorder`] module.
///
/// # What is a "valid instance"?
///
/// In Rust, each type has *bit validity*, which refers to the set of bit
/// patterns which may appear in an instance of that type. It is impossible for
/// safe Rust code to produce values which violate bit validity (ie, values
/// outside of the "valid" set of bit patterns). If `unsafe` code produces an
/// invalid value, this is considered [undefined behavior].
///
/// Rust's bit validity rules are currently being decided, which means that some
/// types have three classes of bit patterns: those which are definitely valid,
/// and whose validity is documented in the language; those which may or may not
/// be considered valid at some point in the future; and those which are
/// definitely invalid.
///
/// Zerocopy takes a conservative approach, and only considers a bit pattern to
/// be valid if its validity is a documenteed guarantee provided by the
/// language.
///
/// For most use cases, Rust's current guarantees align with programmers'
/// intuitions about what ought to be valid. As a result, zerocopy's
/// conservatism should not affect most users. One notable exception is unions,
/// whose bit validity is very up in the air; zerocopy does not permit
/// implementing `TryFromBytes` for any union type.
///
/// If you are negatively affected by lack of support for a particular type,
/// we encourage you to let us know by [filing an issue][github-repo].
///
/// # Safety
///
/// On its own, `T: TryFromBytes` does not make any guarantees about the layout
/// or representation of `T`. It merely provides the ability to perform a
/// validity check at runtime via methods like [`try_from_ref`].
///
/// Currently, it is not possible to stably implement `TryFromBytes` other than
/// by using `#[derive(TryFromBytes)]`. While there are `#[doc(hidden)]` items
/// on this trait that provide well-defined safety invariants, no stability
/// guarantees are made with respect to these items. In particular, future
/// releases of zerocopy may make backwards-breaking changes to these items,
/// including changes that only affect soundness, which may cause code which
/// uses those items to silently become unsound.
///
/// [undefined behavior]: https://raphlinus.github.io/programming/rust/2018/08/17/undefined-behavior.html
/// [github-repo]: https://github.com/google/zerocopy
/// [`try_from_ref`]: TryFromBytes::try_from_ref
// TODO(#5): Update `try_from_ref` doc link once it exists
#[doc(hidden)]
pub unsafe trait TryFromBytes {
/// Does a given memory range contain a valid instance of `Self`?
///
/// # Safety
///
/// ## Preconditions
///
/// The memory referenced by `candidate` may only be accessed via reads for
/// the duration of this method call. This prohibits writes through mutable
/// references and through [`UnsafeCell`]s. There may exist immutable
/// references to the same memory which contain `UnsafeCell`s so long as:
/// - Those `UnsafeCell`s exist at the same byte ranges as `UnsafeCell`s in
/// `Self`. This is a bidirectional property: `Self` may not contain
/// `UnsafeCell`s where other references to the same memory do not, and
/// vice-versa.
/// - Those `UnsafeCell`s are never used to perform mutation for the
/// duration of this method call.
///
/// The memory referenced by `candidate` may not be referenced by any
/// mutable references even if these references are not used to perform
/// mutation.
///
/// `candidate` is not required to refer to a valid `Self`. However, it must
/// satisfy the requirement that uninitialized bytes may only be present
/// where it is possible for them to be present in `Self`. This is a dynamic
/// property: if, at a particular byte offset, a valid enum discriminant is
/// set, the subsequent bytes may only have uninitialized bytes as
/// specificed by the corresponding enum.
///
/// Formally, given `len = size_of_val_raw(candidate)`, at every byte
/// offset, `b`, in the range `[0, len)`:
/// - If, in all instances `s: Self` of length `len`, the byte at offset `b`
/// in `s` is initialized, then the byte at offset `b` within `*candidate`
/// must be initialized.
/// - Let `c` be the contents of the byte range `[0, b)` in `*candidate`.
/// Let `S` be the subset of valid instances of `Self` of length `len`
/// which contain `c` in the offset range `[0, b)`. If, for all instances
/// of `s: Self` in `S`, the byte at offset `b` in `s` is initialized,
/// then the byte at offset `b` in `*candidate` must be initialized.
///
/// Pragmatically, this means that if `*candidate` is guaranteed to
/// contain an enum type at a particular offset, and the enum discriminant
/// stored in `*candidate` corresponds to a valid variant of that enum
/// type, then it is guaranteed that the appropriate bytes of `*candidate`
/// are initialized as defined by that variant's bit validity (although
/// note that the variant may contain another enum type, in which case the
/// same rules apply depending on the state of its discriminant, and so on
/// recursively).
///
/// ## Postconditions
///
/// Unsafe code may assume that, if `is_bit_valid(candidate)` returns true,
/// `*candidate` contains a valid `Self`.
///
/// # Panics
///
/// `is_bit_valid` may panic. Callers are responsible for ensuring that any
/// `unsafe` code remains sound even in the face of `is_bit_valid`
/// panicking. (We support user-defined validation routines; so long as
/// these routines are not required to be `unsafe`, there is no way to
/// ensure that these do not generate panics.)
///
/// [`UnsafeCell`]: core::cell::UnsafeCell
#[doc(hidden)]
unsafe fn is_bit_valid(candidate: Ptr<'_, Self>) -> bool;
/// Attempts to interpret a byte slice as a `Self`.
///
/// `try_from_ref` validates that `bytes` contains a valid `Self`, and that
/// it satisfies `Self`'s alignment requirement. If it does, then `bytes` is
/// reinterpreted as a `Self`.
///
/// Note that Rust's bit validity rules are still being decided. As such,
/// there exist types whose bit validity is ambiguous. See the
/// `TryFromBytes` docs for a discussion of how these cases are handled.
// TODO(#251): In a future in which we distinguish between `FromBytes` and
// `RefFromBytes`, this requires `where Self: RefFromBytes` to disallow
// interior mutability.
#[inline]
#[doc(hidden)] // TODO(#5): Finalize name before remove this attribute.
fn try_from_ref(bytes: &[u8]) -> Option<&Self>
where
Self: KnownLayout,
{
let maybe_self = Ptr::from(bytes).try_cast_into_no_leftover::<Self>()?;
// SAFETY:
// - Since `bytes` is an immutable reference, we know that no mutable
// references exist to this memory region.
// - Since `[u8]` contains no `UnsafeCell`s, we know there are no
// `&UnsafeCell` references to this memory region.
// - Since we don't permit implementing `TryFromBytes` for types which
// contain `UnsafeCell`s, there are no `UnsafeCell`s in `Self`, and so
// the requirement that all references contain `UnsafeCell`s at the
// same offsets is trivially satisfied.
// - All bytes of `bytes` are initialized.
//
// This call may panic. If that happens, it doesn't cause any soundness
// issues, as we have not generated any invalid state which we need to
// fix before returning.
if unsafe { !Self::is_bit_valid(maybe_self) } {
return None;
}
// SAFETY:
// - Preconditions for `as_ref`:
// - `is_bit_valid` guarantees that `*maybe_self` contains a valid
// `Self`. Since `&[u8]` does not permit interior mutation, this
// cannot be invalidated after this method returns.
// - Since the argument and return types are immutable references,
// Rust will prevent the caller from producing any mutable
// references to the same memory region.
// - Since `Self` is not allowed to contain any `UnsafeCell`s and the
// same is true of `[u8]`, interior mutation is not possible. Thus,
// no mutation is possible. For the same reason, there is no
// mismatch between the two types in terms of which byte ranges are
// referenced as `UnsafeCell`s.
// - Since interior mutation isn't possible within `Self`, there's no
// way for the returned reference to be used to modify the byte range,
// and thus there's no way for the returned reference to be used to
// write an invalid `[u8]` which would be observable via the original
// `&[u8]`.
Some(unsafe { maybe_self.as_ref() })
}
}
/// Types for which a sequence of bytes all set to zero represents a valid
/// instance of the type.
///
/// Any memory region of the appropriate length which is guaranteed to contain
/// only zero bytes can be viewed as any `FromZeroes` type with no runtime
/// overhead. This is useful whenever memory is known to be in a zeroed state,
/// such memory returned from some allocation routines.
///
/// # Implementation
///
/// **Do not implement this trait yourself!** Instead, use
/// [`#[derive(FromZeroes)]`][derive] (requires the `derive` Cargo feature);
/// e.g.:
///
/// ```
/// # use zerocopy_derive::FromZeroes;
/// #[derive(FromZeroes)]
/// struct MyStruct {
/// # /*
/// ...
/// # */
/// }
///
/// #[derive(FromZeroes)]
/// #[repr(u8)]
/// enum MyEnum {
/// # Variant0,
/// # /*
/// ...
/// # */
/// }
///
/// #[derive(FromZeroes)]
/// union MyUnion {
/// # variant: u8,
/// # /*
/// ...
/// # */
/// }
/// ```
///
/// This derive performs a sophisticated, compile-time safety analysis to
/// determine whether a type is `FromZeroes`.
///
/// # Safety
///
/// *This section describes what is required in order for `T: FromZeroes`, and
/// what unsafe code may assume of such types. If you don't plan on implementing
/// `FromZeroes` manually, and you don't plan on writing unsafe code that
/// operates on `FromZeroes` types, then you don't need to read this section.*
///
/// If `T: FromZeroes`, then unsafe code may assume that:
/// - It is sound to treat any initialized sequence of zero bytes of length
/// `size_of::<T>()` as a `T`.
/// - Given `b: &[u8]` where `b.len() == size_of::<T>()`, `b` is aligned to
/// `align_of::<T>()`, and `b` contains only zero bytes, it is sound to
/// construct a `t: &T` at the same address as `b`, and it is sound for both
/// `b` and `t` to be live at the same time.
///
/// If a type is marked as `FromZeroes` which violates this contract, it may
/// cause undefined behavior.
///
/// `#[derive(FromZeroes)]` only permits [types which satisfy these
/// requirements][derive-analysis].
///
#[cfg_attr(
feature = "derive",
doc = "[derive]: zerocopy_derive::FromZeroes",
doc = "[derive-analysis]: zerocopy_derive::FromZeroes#analysis"
)]
#[cfg_attr(
not(feature = "derive"),
doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeroes.html"),
doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeroes.html#analysis"),
)]
pub unsafe trait FromZeroes {
// The `Self: Sized` bound makes it so that `FromZeroes` is still object
// safe.
#[doc(hidden)]
fn only_derive_is_allowed_to_implement_this_trait()
where
Self: Sized;
/// Overwrites `self` with zeroes.
///
/// Sets every byte in `self` to 0. While this is similar to doing `*self =
/// Self::new_zeroed()`, it differs in that `zero` does not semantically
/// drop the current value and replace it with a new one - it simply
/// modifies the bytes of the existing value.
///
/// # Examples
///
/// ```
/// # use zerocopy::FromZeroes;
/// # use zerocopy_derive::*;
/// #
/// #[derive(FromZeroes)]
/// #[repr(C)]
/// struct PacketHeader {
/// src_port: [u8; 2],
/// dst_port: [u8; 2],
/// length: [u8; 2],
/// checksum: [u8; 2],
/// }
///
/// let mut header = PacketHeader {
/// src_port: 100u16.to_be_bytes(),
/// dst_port: 200u16.to_be_bytes(),
/// length: 300u16.to_be_bytes(),
/// checksum: 400u16.to_be_bytes(),
/// };
///
/// header.zero();
///
/// assert_eq!(header.src_port, [0, 0]);
/// assert_eq!(header.dst_port, [0, 0]);
/// assert_eq!(header.length, [0, 0]);
/// assert_eq!(header.checksum, [0, 0]);
/// ```
#[inline(always)]
fn zero(&mut self) {
let slf: *mut Self = self;
let len = mem::size_of_val(self);
// SAFETY:
// - `self` is guaranteed by the type system to be valid for writes of
// size `size_of_val(self)`.
// - `u8`'s alignment is 1, and thus `self` is guaranteed to be aligned
// as required by `u8`.
// - Since `Self: FromZeroes`, the all-zeroes instance is a valid
// instance of `Self.`
//
// TODO(#429): Add references to docs and quotes.
unsafe { ptr::write_bytes(slf.cast::<u8>(), 0, len) };
}
/// Creates an instance of `Self` from zeroed bytes.
///
/// # Examples
///
/// ```
/// # use zerocopy::FromZeroes;
/// # use zerocopy_derive::*;
/// #
/// #[derive(FromZeroes)]
/// #[repr(C)]
/// struct PacketHeader {
/// src_port: [u8; 2],
/// dst_port: [u8; 2],
/// length: [u8; 2],
/// checksum: [u8; 2],
/// }
///
/// let header: PacketHeader = FromZeroes::new_zeroed();
///
/// assert_eq!(header.src_port, [0, 0]);
/// assert_eq!(header.dst_port, [0, 0]);
/// assert_eq!(header.length, [0, 0]);
/// assert_eq!(header.checksum, [0, 0]);
/// ```
#[inline(always)]
fn new_zeroed() -> Self
where
Self: Sized,
{
// SAFETY: `FromZeroes` says that the all-zeroes bit pattern is legal.
unsafe { mem::zeroed() }
}
/// Creates a `Box<Self>` from zeroed bytes.
///
/// This function is useful for allocating large values on the heap and
/// zero-initializing them, without ever creating a temporary instance of
/// `Self` on the stack. For example, `<[u8; 1048576]>::new_box_zeroed()`
/// will allocate `[u8; 1048576]` directly on the heap; it does not require
/// storing `[u8; 1048576]` in a temporary variable on the stack.
///
/// On systems that use a heap implementation that supports allocating from
/// pre-zeroed memory, using `new_box_zeroed` (or related functions) may
/// have performance benefits.
///
/// Note that `Box<Self>` can be converted to `Arc<Self>` and other
/// container types without reallocation.
///
/// # Panics
///
/// Panics if allocation of `size_of::<Self>()` bytes fails.
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
#[inline]
fn new_box_zeroed() -> Box<Self>
where
Self: Sized,
{
// If `T` is a ZST, then return a proper boxed instance of it. There is
// no allocation, but `Box` does require a correct dangling pointer.
let layout = Layout::new::<Self>();
if layout.size() == 0 {
return Box::new(Self::new_zeroed());
}
// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
let ptr = unsafe { alloc::alloc::alloc_zeroed(layout).cast::<Self>() };
if ptr.is_null() {
alloc::alloc::handle_alloc_error(layout);
}
// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
Box::from_raw(ptr)
}
}
/// Creates a `Box<[Self]>` (a boxed slice) from zeroed bytes.
///
/// This function is useful for allocating large values of `[Self]` on the
/// heap and zero-initializing them, without ever creating a temporary
/// instance of `[Self; _]` on the stack. For example,
/// `u8::new_box_slice_zeroed(1048576)` will allocate the slice directly on
/// the heap; it does not require storing the slice on the stack.
///
/// On systems that use a heap implementation that supports allocating from
/// pre-zeroed memory, using `new_box_slice_zeroed` may have performance
/// benefits.
///
/// If `Self` is a zero-sized type, then this function will return a
/// `Box<[Self]>` that has the correct `len`. Such a box cannot contain any
/// actual information, but its `len()` property will report the correct
/// value.
///
/// # Panics
///
/// * Panics if `size_of::<Self>() * len` overflows.
--> --------------------
--> maximum size reached
--> --------------------
[ Verzeichnis aufwärts0.121unsichere Verbindung
]
|
2026-04-02
|