terminology: allocated object → allocation

This commit is contained in:
Ralf Jung 2025-05-18 14:40:49 +02:00
parent 852f15c0f1
commit f388c987cf
11 changed files with 146 additions and 143 deletions

View file

@ -207,7 +207,7 @@ impl CStr {
/// * `ptr` must be [valid] for reads of bytes up to and including the nul terminator.
/// This means in particular:
///
/// * The entire memory range of this `CStr` must be contained within a single allocated object!
/// * The entire memory range of this `CStr` must be contained within a single allocation!
/// * `ptr` must be non-null even for a zero-length cstr.
///
/// * The memory referenced by the returned `CStr` must not be mutated for

View file

@ -1722,7 +1722,7 @@ pub const fn needs_drop<T: ?Sized>() -> bool;
/// # Safety
///
/// If the computed offset is non-zero, then both the starting and resulting pointer must be
/// either in bounds or at the end of an allocated object. If either pointer is out
/// either in bounds or at the end of an allocation. If either pointer is out
/// of bounds or arithmetic overflow occurs then this operation is undefined behavior.
///
/// The stabilized version of this intrinsic is [`pointer::offset`].

View file

@ -1623,7 +1623,7 @@ mod prim_usize {}
/// * if `size_of_val(t) > 0`, then `t` is dereferenceable for `size_of_val(t)` many bytes
///
/// If `t` points at address `a`, being "dereferenceable" for N bytes means that the memory range
/// `[a, a + N)` is all contained within a single [allocated object].
/// `[a, a + N)` is all contained within a single [allocation].
///
/// For instance, this means that unsafe code in a safe function may assume these invariants are
/// ensured of arguments passed by the caller, and it may assume that these invariants are ensured
@ -1639,7 +1639,7 @@ mod prim_usize {}
/// may be unsound or become unsound in future versions of Rust depending on how this question is
/// decided.
///
/// [allocated object]: ptr#allocated-object
/// [allocation]: ptr#allocation
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_ref {}

View file

@ -482,17 +482,17 @@ impl<T: ?Sized> *const T {
///
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// The resulting pointer "remembers" the [allocated object] that `self` points to
/// The resulting pointer "remembers" the [allocation] that `self` points to
/// (this is called "[Provenance](ptr/index.html#provenance)").
/// The pointer must not be used to read or write other allocated objects.
/// The pointer must not be used to read or write other allocations.
///
/// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
/// `x` and `y` point into the same allocation.
///
/// Compared to [`offset`], this method basically delays the requirement of staying within the
/// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
/// same allocation: [`offset`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
/// can be optimized better and is thus preferable in performance-sensitive code.
@ -500,10 +500,10 @@ impl<T: ?Sized> *const T {
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other
/// words, leaving the allocated object and then re-entering it later is permitted.
/// words, leaving the allocation and then re-entering it later is permitted.
///
/// [`offset`]: #method.offset
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Examples
///
@ -616,7 +616,7 @@ impl<T: ?Sized> *const T {
/// * `self` and `origin` must either
///
/// * point to the same address, or
/// * both be [derived from][crate::ptr#provenance] a pointer to the same [allocated object], and the memory range between
/// * both be [derived from][crate::ptr#provenance] a pointer to the same [allocation], and the memory range between
/// the two pointers must be in bounds of that object. (See below for an example.)
///
/// * The distance between the pointers, in bytes, must be an exact multiple
@ -624,10 +624,10 @@ impl<T: ?Sized> *const T {
///
/// As a consequence, the absolute distance between the pointers, in bytes, computed on
/// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is
/// implied by the in-bounds requirement, and the fact that no allocated object can be larger
/// implied by the in-bounds requirement, and the fact that no allocation can be larger
/// than `isize::MAX` bytes.
///
/// The requirement for pointers to be derived from the same allocated object is primarily
/// The requirement for pointers to be derived from the same allocation is primarily
/// needed for `const`-compatibility: the distance between pointers into *different* allocated
/// objects is not known at compile-time. However, the requirement also exists at
/// runtime and may be exploited by optimizations. If you wish to compute the difference between
@ -636,7 +636,7 @@ impl<T: ?Sized> *const T {
// FIXME: recommend `addr()` instead of `as usize` once that is stable.
///
/// [`add`]: #method.add
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Panics
///
@ -969,12 +969,12 @@ impl<T: ?Sized> *const T {
/// "wrapping around"), must fit in an `isize`.
///
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// [allocation], and the entire memory range between `self` and the result must be in
/// bounds of that allocation. In particular, this range must not "wrap around" the edge
/// of the address space.
///
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// Allocations can never be larger than `isize::MAX` bytes, so if the computed offset
/// stays in bounds of the allocation, it is guaranteed to satisfy the first requirement.
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// safe.
///
@ -983,7 +983,7 @@ impl<T: ?Sized> *const T {
/// enables more aggressive compiler optimizations.
///
/// [`wrapping_sub`]: #method.wrapping_sub
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Examples
///
@ -1073,16 +1073,16 @@ impl<T: ?Sized> *const T {
///
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// The resulting pointer "remembers" the [allocated object] that `self` points to; it must not
/// be used to read or write other allocated objects.
/// The resulting pointer "remembers" the [allocation] that `self` points to; it must not
/// be used to read or write other allocations.
///
/// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
/// `x` and `y` point into the same allocation.
///
/// Compared to [`add`], this method basically delays the requirement of staying within the
/// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
/// same allocation: [`add`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
/// can be optimized better and is thus preferable in performance-sensitive code.
@ -1090,10 +1090,10 @@ impl<T: ?Sized> *const T {
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
/// allocated object and then re-entering it later is permitted.
/// allocation and then re-entering it later is permitted.
///
/// [`add`]: #method.add
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Examples
///
@ -1152,16 +1152,16 @@ impl<T: ?Sized> *const T {
///
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// The resulting pointer "remembers" the [allocated object] that `self` points to; it must not
/// be used to read or write other allocated objects.
/// The resulting pointer "remembers" the [allocation] that `self` points to; it must not
/// be used to read or write other allocations.
///
/// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
/// `x` and `y` point into the same allocation.
///
/// Compared to [`sub`], this method basically delays the requirement of staying within the
/// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
/// same allocation: [`sub`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
/// can be optimized better and is thus preferable in performance-sensitive code.
@ -1169,10 +1169,10 @@ impl<T: ?Sized> *const T {
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
/// allocated object and then re-entering it later is permitted.
/// allocation and then re-entering it later is permitted.
///
/// [`sub`]: #method.sub
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Examples
///
@ -1564,8 +1564,8 @@ impl<T> *const [T] {
/// * The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes,
/// and it must be properly aligned. This means in particular:
///
/// * The entire memory range of this slice must be contained within a single [allocated object]!
/// Slices can never span across multiple allocated objects.
/// * The entire memory range of this slice must be contained within a single [allocation]!
/// Slices can never span across multiple allocations.
///
/// * The pointer must be aligned even for zero-length slices. One
/// reason for this is that enum layout optimizations may rely on references
@ -1586,7 +1586,7 @@ impl<T> *const [T] {
/// See also [`slice::from_raw_parts`][].
///
/// [valid]: crate::ptr#safety
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Panics during const evaluation
///

View file

@ -15,12 +15,12 @@ If any of the following conditions are violated, the result is Undefined Behavio
"wrapping around"), must fit in an `isize`.
* If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
[allocated object], and the entire memory range between `self` and the result must be in
bounds of that allocated object. In particular, this range must not "wrap around" the edge
[allocation], and the entire memory range between `self` and the result must be in
bounds of that allocation. In particular, this range must not "wrap around" the edge
of the address space.
Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
stays in bounds of the allocation, it is guaranteed to satisfy the first requirement.
This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
safe.
@ -29,4 +29,4 @@ difficult to satisfy. The only advantage of this method is that it
enables more aggressive compiler optimizations.
[`wrapping_add`]: #method.wrapping_add
[allocated object]: crate::ptr#allocated-object
[allocation]: crate::ptr#allocation

View file

@ -11,13 +11,13 @@ If any of the following conditions are violated, the result is Undefined Behavio
"wrapping around"), must fit in an `isize`.
* If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
[allocated object], and the entire memory range between `self` and the result must be in
bounds of that allocated object. In particular, this range must not "wrap around" the edge
[allocation], and the entire memory range between `self` and the result must be in
bounds of that allocation. In particular, this range must not "wrap around" the edge
of the address space. Note that "range" here refers to a half-open range as usual in Rust,
i.e., `self..result` for non-negative offsets and `result..self` for negative offsets.
Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
stays in bounds of the allocation, it is guaranteed to satisfy the first requirement.
This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
safe.
@ -26,4 +26,4 @@ difficult to satisfy. The only advantage of this method is that it
enables more aggressive compiler optimizations.
[`wrapping_offset`]: #method.wrapping_offset
[allocated object]: crate::ptr#allocated-object
[allocation]: crate::ptr#allocation

View file

@ -19,10 +19,10 @@
//! pointer. The following points are only concerned with non-zero-sized accesses.
//! * A [null] pointer is *never* valid.
//! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer be
//! *dereferenceable*. The [provenance] of the pointer is used to determine which [allocated
//! object] it is derived from; a pointer is dereferenceable if the memory range of the given size
//! starting at the pointer is entirely contained within the bounds of that allocated object. Note
//! that in Rust, every (stack-allocated) variable is considered a separate allocated object.
//! *dereferenceable*. The [provenance] of the pointer is used to determine which [allocation]
//! it is derived from; a pointer is dereferenceable if the memory range of the given size
//! starting at the pointer is entirely contained within the bounds of that allocation. Note
//! that in Rust, every (stack-allocated) variable is considered a separate allocation.
//! * All accesses performed by functions in this module are *non-atomic* in the sense
//! of [atomic operations] used to synchronize between threads. This means it is
//! undefined behavior to perform two concurrent accesses to the same location from different
@ -30,7 +30,7 @@
//! includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot
//! be used for inter-thread synchronization.
//! * The result of casting a reference to a pointer is valid for as long as the
//! underlying object is live and no reference (just raw pointers) is used to
//! underlying allocation is live and no reference (just raw pointers) is used to
//! access the same memory. That is, reference and pointer accesses cannot be
//! interleaved.
//!
@ -95,24 +95,26 @@
//!
//! [valid value]: ../../reference/behavior-considered-undefined.html#invalid-values
//!
//! ## Allocated object
//! ## Allocation
//!
//! An *allocated object* is a subset of program memory which is addressable
//! <a id="allocated-object"></a> <!-- keep old URLs working -->
//!
//! An *allocation* is a subset of program memory which is addressable
//! from Rust, and within which pointer arithmetic is possible. Examples of
//! allocated objects include heap allocations, stack-allocated variables,
//! allocations include heap allocations, stack-allocated variables,
//! statics, and consts. The safety preconditions of some Rust operations -
//! such as `offset` and field projections (`expr.field`) - are defined in
//! terms of the allocated objects on which they operate.
//! terms of the allocations on which they operate.
//!
//! An allocated object has a base address, a size, and a set of memory
//! addresses. It is possible for an allocated object to have zero size, but
//! such an allocated object will still have a base address. The base address
//! of an allocated object is not necessarily unique. While it is currently the
//! case that an allocated object always has a set of memory addresses which is
//! An allocation has a base address, a size, and a set of memory
//! addresses. It is possible for an allocation to have zero size, but
//! such an allocation will still have a base address. The base address
//! of an allocation is not necessarily unique. While it is currently the
//! case that an allocation always has a set of memory addresses which is
//! fully contiguous (i.e., has no "holes"), there is no guarantee that this
//! will not change in the future.
//!
//! For any allocated object with `base` address, `size`, and a set of
//! For any allocation with `base` address, `size`, and a set of
//! `addresses`, the following are guaranteed:
//! - For all addresses `a` in `addresses`, `a` is in the range `base .. (base +
//! size)` (note that this requires `a < base + size`, not `a <= base + size`)
@ -122,11 +124,11 @@
//! - `size <= isize::MAX`
//!
//! As a consequence of these guarantees, given any address `a` within the set
//! of addresses of an allocated object:
//! of addresses of an allocation:
//! - It is guaranteed that `a - base` does not overflow `isize`
//! - It is guaranteed that `a - base` is non-negative
//! - It is guaranteed that, given `o = a - base` (i.e., the offset of `a` within
//! the allocated object), `base + o` will not wrap around the address space (in
//! the allocation), `base + o` will not wrap around the address space (in
//! other words, will not overflow `usize`)
//!
//! [`null()`]: null
@ -138,8 +140,8 @@
//! and the freed memory gets reallocated before your read/write (in fact this is the
//! worst-case scenario, UAFs would be much less concerning if this didn't happen!).
//! As another example, consider that [`wrapping_offset`] is documented to "remember"
//! the allocated object that the original pointer points to, even if it is offset far
//! outside the memory range occupied by that allocated object.
//! the allocation that the original pointer points to, even if it is offset far
//! outside the memory range occupied by that allocation.
//! To rationalize claims like this, pointers need to somehow be *more* than just their addresses:
//! they must have **provenance**.
//!
@ -159,12 +161,12 @@
//! writes. Note that this can interact with the other components, e.g. a pointer might permit
//! mutation only for a subset of addresses, or only for a subset of its maximal timespan.
//!
//! When an [allocated object] is created, it has a unique Original Pointer. For alloc
//! When an [allocation] is created, it has a unique Original Pointer. For alloc
//! APIs this is literally the pointer the call returns, and for local variables and statics,
//! this is the name of the variable/static. (This is mildly overloading the term "pointer"
//! for the sake of brevity/exposition.)
//!
//! The Original Pointer for an allocated object has provenance that constrains the *spatial*
//! The Original Pointer for an allocation has provenance that constrains the *spatial*
//! permissions of this pointer to the memory range of the allocation, and the *temporal*
//! permissions to the lifetime of the allocation. Provenance is implicitly inherited by all
//! pointers transitively derived from the Original Pointer through operations like [`offset`],
@ -192,10 +194,10 @@
//! provenance since they access an empty range of memory.
//!
//! * It is undefined behavior to [`offset`] a pointer across a memory range that is not contained
//! in the allocated object it is derived from, or to [`offset_from`] two pointers not derived
//! from the same allocated object. Provenance is used to say what exactly "derived from" even
//! in the allocation it is derived from, or to [`offset_from`] two pointers not derived
//! from the same allocation. Provenance is used to say what exactly "derived from" even
//! means: the lineage of a pointer is traced back to the Original Pointer it descends from, and
//! that identifies the relevant allocated object. In particular, it's always UB to offset a
//! that identifies the relevant allocation. In particular, it's always UB to offset a
//! pointer derived from something that is now deallocated, except if the offset is 0.
//!
//! But it *is* still sound to:
@ -216,7 +218,7 @@
//! * Compare arbitrary pointers by address. Pointer comparison ignores provenance and addresses
//! *are* just integers, so there is always a coherent answer, even if the pointers are dangling
//! or from different provenances. Note that if you get "lucky" and notice that a pointer at the
//! end of one allocated object is the "same" address as the start of another allocated object,
//! end of one allocation is the "same" address as the start of another allocation,
//! anything you do with that fact is *probably* going to be gibberish. The scope of that
//! gibberish is kept under control by the fact that the two pointers *still* aren't allowed to
//! access the other's allocation (bytes), because they still have different provenance.
@ -369,7 +371,7 @@
//! integer-to-pointer casts.
//!
//! [aliasing]: ../../nomicon/aliasing.html
//! [allocated object]: #allocated-object
//! [allocation]: #allocation
//! [provenance]: #provenance
//! [book]: ../../book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer
//! [ub]: ../../reference/behavior-considered-undefined.html
@ -1289,7 +1291,7 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
// SAFETY: the caller must guarantee that `x` and `y` are
// valid for writes and properly aligned. `tmp` cannot be
// overlapping either `x` or `y` because `tmp` was just allocated
// on the stack as a separate allocated object.
// on the stack as a separate allocation.
unsafe {
copy_nonoverlapping(x, tmp.as_mut_ptr(), 1);
copy(y, x, 1); // `x` and `y` may overlap
@ -1409,7 +1411,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
// Going though a slice here helps codegen know the size fits in `isize`
let slice = slice_from_raw_parts_mut(x, count);
// SAFETY: This is all readable from the pointer, meaning it's one
// allocated object, and thus cannot be more than isize::MAX bytes.
// allocation, and thus cannot be more than isize::MAX bytes.
let bytes = unsafe { mem::size_of_val_raw::<[T]>(slice) };
if let Some(bytes) = NonZero::new(bytes) {
// SAFETY: These are the same ranges, just expressed in a different
@ -1563,7 +1565,7 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
// SAFETY: the caller must guarantee that `dst` is valid to be
// cast to a mutable reference (valid for writes, aligned, initialized),
// and cannot overlap `src` since `dst` must point to a distinct
// allocated object.
// allocation.
unsafe {
ub_checks::assert_unsafe_precondition!(
check_language_ub,
@ -1810,7 +1812,7 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
let mut tmp = MaybeUninit::<T>::uninit();
// SAFETY: the caller must guarantee that `src` is valid for reads.
// `src` cannot overlap `tmp` because `tmp` was just allocated on
// the stack as a separate allocated object.
// the stack as a separate allocation.
//
// Also, since we just wrote a valid value into `tmp`, it is guaranteed
// to be properly initialized.

View file

@ -448,7 +448,7 @@ impl<T: ?Sized> *mut T {
// SAFETY: the caller must uphold the safety contract for `offset`.
// The obtained pointer is valid for writes since the caller must
// guarantee that it points to the same allocated object as `self`.
// guarantee that it points to the same allocation as `self`.
unsafe { intrinsics::offset(self, count) }
}
@ -481,17 +481,17 @@ impl<T: ?Sized> *mut T {
///
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// The resulting pointer "remembers" the [allocated object] that `self` points to
/// The resulting pointer "remembers" the [allocation] that `self` points to
/// (this is called "[Provenance](ptr/index.html#provenance)").
/// The pointer must not be used to read or write other allocated objects.
/// The pointer must not be used to read or write other allocations.
///
/// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
/// `x` and `y` point into the same allocation.
///
/// Compared to [`offset`], this method basically delays the requirement of staying within the
/// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
/// same allocation: [`offset`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
/// can be optimized better and is thus preferable in performance-sensitive code.
@ -499,10 +499,10 @@ impl<T: ?Sized> *mut T {
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other
/// words, leaving the allocated object and then re-entering it later is permitted.
/// words, leaving the allocation and then re-entering it later is permitted.
///
/// [`offset`]: #method.offset
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Examples
///
@ -791,7 +791,7 @@ impl<T: ?Sized> *mut T {
/// * `self` and `origin` must either
///
/// * point to the same address, or
/// * both be [derived from][crate::ptr#provenance] a pointer to the same [allocated object], and the memory range between
/// * both be [derived from][crate::ptr#provenance] a pointer to the same [allocation], and the memory range between
/// the two pointers must be in bounds of that object. (See below for an example.)
///
/// * The distance between the pointers, in bytes, must be an exact multiple
@ -799,10 +799,10 @@ impl<T: ?Sized> *mut T {
///
/// As a consequence, the absolute distance between the pointers, in bytes, computed on
/// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is
/// implied by the in-bounds requirement, and the fact that no allocated object can be larger
/// implied by the in-bounds requirement, and the fact that no allocation can be larger
/// than `isize::MAX` bytes.
///
/// The requirement for pointers to be derived from the same allocated object is primarily
/// The requirement for pointers to be derived from the same allocation is primarily
/// needed for `const`-compatibility: the distance between pointers into *different* allocated
/// objects is not known at compile-time. However, the requirement also exists at
/// runtime and may be exploited by optimizations. If you wish to compute the difference between
@ -811,7 +811,7 @@ impl<T: ?Sized> *mut T {
// FIXME: recommend `addr()` instead of `as usize` once that is stable.
///
/// [`add`]: #method.add
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Panics
///
@ -1061,12 +1061,12 @@ impl<T: ?Sized> *mut T {
/// "wrapping around"), must fit in an `isize`.
///
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// [allocation], and the entire memory range between `self` and the result must be in
/// bounds of that allocation. In particular, this range must not "wrap around" the edge
/// of the address space.
///
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// Allocations can never be larger than `isize::MAX` bytes, so if the computed offset
/// stays in bounds of the allocation, it is guaranteed to satisfy the first requirement.
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// safe.
///
@ -1075,7 +1075,7 @@ impl<T: ?Sized> *mut T {
/// enables more aggressive compiler optimizations.
///
/// [`wrapping_sub`]: #method.wrapping_sub
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Examples
///
@ -1165,16 +1165,16 @@ impl<T: ?Sized> *mut T {
///
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// The resulting pointer "remembers" the [allocated object] that `self` points to; it must not
/// be used to read or write other allocated objects.
/// The resulting pointer "remembers" the [allocation] that `self` points to; it must not
/// be used to read or write other allocations.
///
/// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
/// `x` and `y` point into the same allocation.
///
/// Compared to [`add`], this method basically delays the requirement of staying within the
/// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
/// same allocation: [`add`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
/// can be optimized better and is thus preferable in performance-sensitive code.
@ -1182,10 +1182,10 @@ impl<T: ?Sized> *mut T {
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
/// allocated object and then re-entering it later is permitted.
/// allocation and then re-entering it later is permitted.
///
/// [`add`]: #method.add
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Examples
///
@ -1241,16 +1241,16 @@ impl<T: ?Sized> *mut T {
///
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// The resulting pointer "remembers" the [allocated object] that `self` points to; it must not
/// be used to read or write other allocated objects.
/// The resulting pointer "remembers" the [allocation] that `self` points to; it must not
/// be used to read or write other allocations.
///
/// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
/// `x` and `y` point into the same allocation.
///
/// Compared to [`sub`], this method basically delays the requirement of staying within the
/// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
/// same allocation: [`sub`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
/// can be optimized better and is thus preferable in performance-sensitive code.
@ -1258,10 +1258,10 @@ impl<T: ?Sized> *mut T {
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
/// allocated object and then re-entering it later is permitted.
/// allocation and then re-entering it later is permitted.
///
/// [`sub`]: #method.sub
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Examples
///
@ -1770,7 +1770,7 @@ impl<T> *mut [T] {
///
/// # Safety
///
/// `mid` must be [in-bounds] of the underlying [allocated object].
/// `mid` must be [in-bounds] of the underlying [allocation].
/// Which means `self` must be dereferenceable and span a single allocation
/// that is at least `mid * size_of::<T>()` bytes long. Not upholding these
/// requirements is *[undefined behavior]* even if the resulting pointers are not used.
@ -1781,7 +1781,7 @@ impl<T> *mut [T] {
///
/// [`split_at_mut_unchecked`]: #method.split_at_mut_unchecked
/// [in-bounds]: #method.add
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
/// # Examples
@ -1816,13 +1816,14 @@ impl<T> *mut [T] {
///
/// # Safety
///
/// `mid` must be [in-bounds] of the underlying [allocated object].
/// `mid` must be [in-bounds] of the underlying [allocation].
/// Which means `self` must be dereferenceable and span a single allocation
/// that is at least `mid * size_of::<T>()` bytes long. Not upholding these
/// requirements is *[undefined behavior]* even if the resulting pointers are not used.
///
/// [in-bounds]: #method.add
/// [out-of-bounds index]: #method.add
/// [allocation]: crate::ptr#allocation
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
/// # Examples
@ -1922,8 +1923,8 @@ impl<T> *mut [T] {
/// * The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes,
/// and it must be properly aligned. This means in particular:
///
/// * The entire memory range of this slice must be contained within a single [allocated object]!
/// Slices can never span across multiple allocated objects.
/// * The entire memory range of this slice must be contained within a single [allocation]!
/// Slices can never span across multiple allocations.
///
/// * The pointer must be aligned even for zero-length slices. One
/// reason for this is that enum layout optimizations may rely on references
@ -1944,7 +1945,7 @@ impl<T> *mut [T] {
/// See also [`slice::from_raw_parts`][].
///
/// [valid]: crate::ptr#safety
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Panics during const evaluation
///
@ -1980,8 +1981,8 @@ impl<T> *mut [T] {
/// * The pointer must be [valid] for reads and writes for `ptr.len() * size_of::<T>()`
/// many bytes, and it must be properly aligned. This means in particular:
///
/// * The entire memory range of this slice must be contained within a single [allocated object]!
/// Slices can never span across multiple allocated objects.
/// * The entire memory range of this slice must be contained within a single [allocation]!
/// Slices can never span across multiple allocations.
///
/// * The pointer must be aligned even for zero-length slices. One
/// reason for this is that enum layout optimizations may rely on references
@ -2002,7 +2003,7 @@ impl<T> *mut [T] {
/// See also [`slice::from_raw_parts_mut`][].
///
/// [valid]: crate::ptr#safety
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Panics during const evaluation
///

View file

@ -530,16 +530,16 @@ impl<T: ?Sized> NonNull<T> {
/// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
///
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// [allocation], and the entire memory range between `self` and the result must be in
/// bounds of that allocation. In particular, this range must not "wrap around" the edge
/// of the address space.
///
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// Allocations can never be larger than `isize::MAX` bytes, so if the computed offset
/// stays in bounds of the allocation, it is guaranteed to satisfy the first requirement.
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// safe.
///
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Examples
///
@ -606,16 +606,16 @@ impl<T: ?Sized> NonNull<T> {
/// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
///
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// [allocation], and the entire memory range between `self` and the result must be in
/// bounds of that allocation. In particular, this range must not "wrap around" the edge
/// of the address space.
///
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// Allocations can never be larger than `isize::MAX` bytes, so if the computed offset
/// stays in bounds of the allocation, it is guaranteed to satisfy the first requirement.
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// safe.
///
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Examples
///
@ -683,16 +683,16 @@ impl<T: ?Sized> NonNull<T> {
/// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
///
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// [allocation], and the entire memory range between `self` and the result must be in
/// bounds of that allocation. In particular, this range must not "wrap around" the edge
/// of the address space.
///
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// Allocations can never be larger than `isize::MAX` bytes, so if the computed offset
/// stays in bounds of the allocation, it is guaranteed to satisfy the first requirement.
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// safe.
///
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Examples
///
@ -775,7 +775,7 @@ impl<T: ?Sized> NonNull<T> {
/// * `self` and `origin` must either
///
/// * point to the same address, or
/// * both be *derived from* a pointer to the same [allocated object], and the memory range between
/// * both be *derived from* a pointer to the same [allocation], and the memory range between
/// the two pointers must be in bounds of that object. (See below for an example.)
///
/// * The distance between the pointers, in bytes, must be an exact multiple
@ -783,10 +783,10 @@ impl<T: ?Sized> NonNull<T> {
///
/// As a consequence, the absolute distance between the pointers, in bytes, computed on
/// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is
/// implied by the in-bounds requirement, and the fact that no allocated object can be larger
/// implied by the in-bounds requirement, and the fact that no allocation can be larger
/// than `isize::MAX` bytes.
///
/// The requirement for pointers to be derived from the same allocated object is primarily
/// The requirement for pointers to be derived from the same allocation is primarily
/// needed for `const`-compatibility: the distance between pointers into *different* allocated
/// objects is not known at compile-time. However, the requirement also exists at
/// runtime and may be exploited by optimizations. If you wish to compute the difference between
@ -795,7 +795,7 @@ impl<T: ?Sized> NonNull<T> {
// FIXME: recommend `addr()` instead of `as usize` once that is stable.
///
/// [`add`]: #method.add
/// [allocated object]: crate::ptr#allocated-object
/// [allocation]: crate::ptr#allocation
///
/// # Panics
///
@ -1475,8 +1475,8 @@ impl<T> NonNull<[T]> {
/// * The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes,
/// and it must be properly aligned. This means in particular:
///
/// * The entire memory range of this slice must be contained within a single allocated object!
/// Slices can never span across multiple allocated objects.
/// * The entire memory range of this slice must be contained within a single allocation!
/// Slices can never span across multiple allocations.
///
/// * The pointer must be aligned even for zero-length slices. One
/// reason for this is that enum layout optimizations may rely on references
@ -1520,8 +1520,8 @@ impl<T> NonNull<[T]> {
/// * The pointer must be [valid] for reads and writes for `ptr.len() * size_of::<T>()`
/// many bytes, and it must be properly aligned. This means in particular:
///
/// * The entire memory range of this slice must be contained within a single allocated object!
/// Slices can never span across multiple allocated objects.
/// * The entire memory range of this slice must be contained within a single allocation!
/// Slices can never span across multiple allocations.
///
/// * The pointer must be aligned even for zero-length slices. One
/// reason for this is that enum layout optimizations may rely on references

View file

@ -14,8 +14,8 @@ use crate::{array, ptr, ub_checks};
/// * `data` must be non-null, [valid] for reads for `len * size_of::<T>()` many bytes,
/// and it must be properly aligned. This means in particular:
///
/// * The entire memory range of this slice must be contained within a single allocated object!
/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage)
/// * The entire memory range of this slice must be contained within a single allocation!
/// Slices can never span across multiple allocations. See [below](#incorrect-usage)
/// for an example incorrectly not taking this into account.
/// * `data` must be non-null and aligned even for zero-length slices or slices of ZSTs. One
/// reason for this is that enum layout optimizations may rely on references
@ -65,14 +65,14 @@ use crate::{array, ptr, ub_checks};
/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
/// unsafe {
/// // The assertion above ensures `fst` and `snd` are contiguous, but they might
/// // still be contained within _different allocated objects_, in which case
/// // still be contained within _different allocations_, in which case
/// // creating this slice is undefined behavior.
/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
/// }
/// }
///
/// fn main() {
/// // `a` and `b` are different allocated objects...
/// // `a` and `b` are different allocations...
/// let a = 42;
/// let b = 27;
/// // ... which may nevertheless be laid out contiguously in memory: | a | b |
@ -150,8 +150,8 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
/// * `data` must be non-null, [valid] for both reads and writes for `len * size_of::<T>()` many bytes,
/// and it must be properly aligned. This means in particular:
///
/// * The entire memory range of this slice must be contained within a single allocated object!
/// Slices can never span across multiple allocated objects.
/// * The entire memory range of this slice must be contained within a single allocation!
/// Slices can never span across multiple allocations.
/// * `data` must be non-null and aligned even for zero-length slices or slices of ZSTs. One
/// reason for this is that enum layout optimizations may rely on references
/// (including slices of any length) being aligned and non-null to distinguish
@ -228,8 +228,8 @@ pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
/// the last element, such that the offset from the end to the start pointer is
/// the length of the slice.
///
/// * The entire memory range of this slice must be contained within a single allocated object!
/// Slices can never span across multiple allocated objects.
/// * The entire memory range of this slice must be contained within a single allocation!
/// Slices can never span across multiple allocations.
///
/// * The range must contain `N` consecutive properly initialized values of type `T`.
///
@ -298,8 +298,8 @@ pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] {
/// the last element, such that the offset from the end to the start pointer is
/// the length of the slice.
///
/// * The entire memory range of this slice must be contained within a single allocated object!
/// Slices can never span across multiple allocated objects.
/// * The entire memory range of this slice must be contained within a single allocation!
/// Slices can never span across multiple allocations.
///
/// * The range must contain `N` consecutive properly initialized values of type `T`.
///

View file

@ -26,7 +26,7 @@ pub static S5: &[MaybeUninit<u8>] = unsafe { from_raw_parts((&D1) as *const _ as
// is valid as [bool; 4], so this is not UB (it's basically a transmute)
pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
// Structs are considered single allocated objects,
// Structs are considered single allocations,
// as long as you don't reinterpret padding as initialized
// data everything is ok.
pub static S7: &[u16] = unsafe {