@@ -49,21 +49,28 @@ impl fmt::Display for AllocError {
4949/// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of
5050/// data described via [`Layout`][].
5151///
52- /// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers.
53- /// An allocator for `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
54- /// allocated memory.
52+ /// `Allocator` is mostly designed to be implemented on ZSTs, references, or smart pointers,
53+ /// but can also be implemented directly on the underlying memory-owning type so long as it
54+ /// upholds the necessary guarantees. In general, an allocator of the type `MyAlloc([u8; N])`
55+ /// cannot be soundly created without being pinned or otherwise immovable in order to be
56+ /// correct.
5557///
5658/// In contrast to [`GlobalAlloc`][], `Allocator` allows zero-sized allocations. If an underlying
5759/// allocator does not support this (like jemalloc) or responds by returning a null pointer
5860/// (such as `libc::malloc`), this must be caught by the implementation.
5961///
62+ /// In order to be usable in a flexible manner while still being sound, implementors of the trait
63+ /// must uphold very detailed semantics as explained below; the following terms are thus provided
64+ /// as vocabulary for allocator safety and implementation requirements:
65+ ///
6066/// ### Equivalent allocators
6167///
6268/// Multiple allocator values can sometimes be interchangeable with each other.
6369/// When this is the case, we refer to those allocators as being *equivalent* to
6470/// each other.
6571///
66- /// The following conditions are sufficient conditions for allocators to be equivalent.
72+ /// Users of allocators may assume the following are true of equivalent allocators,
73+ /// and implementors must ensure these rules are upheld:
6774/// * An allocator is equivalent to itself. (Equivalence is reflexive.)
6875/// * If an allocator is equivalent to a second allocator, then
6976/// the second allocator is also equivalent to the first. (Equivalence is symmetric.)
@@ -73,9 +80,8 @@ impl fmt::Display for AllocError {
7380/// (Equivalence is transitive.)
7481/// * Moving, subtyping, unsize-coercing, or trait-upcasting an allocator does not change
7582/// what the allocator is equivalent to.
76- /// * Copying or cloning allocator results in an allocator that's
77- /// equivalent to the initial allocator, should the [`AllocatorClone`] trait
78- /// be implemented.
83+ /// * Copying or cloning an allocator creates an equivalent one, should the
84+ /// [`AllocatorClone`] trait be implemented.
7985///
8086/// Additionally, implementors of `Allocator` may specify additional equivalences
8187/// between allocators. It is the responsibility of such implementors to make sure
@@ -104,14 +110,14 @@ impl fmt::Display for AllocError {
104110/// * The memory block is deallocated. This occurs when the memory block
105111/// is passed as an argument to a [`deallocate`] call, or when it is passed
106112/// as an argument to a [`grow`], [`grow_zeroed`] or [`shrink`] call that returns `Ok`.
107- /// * All (equivalent) allocators that this memory block is allocated with,
108- /// each has one of the following happen to them :
113+ /// * For all (equivalent) allocators that this memory block is currently allocated by, at
114+ /// least one of the following has occurred :
109115/// * The allocator's destructor runs.
110- /// * The allocator is mutated through public API taking `&mut` access.
116+ /// * The allocator is mutated through a public or otherwise untrusted API taking `&mut` access.
111117/// * One of the borrow-checker lifetimes in the allocator's type expires.
112118///
113119/// Note that these conditions imply that a collection may ensure that
114- /// any specific currently allocated memory block won't be invalidated, by:
120+ /// any specific currently allocated memory block won't be invalidated by:
115121/// * not deallocating that memory block,
116122/// * owning an allocator that memory block is allocated with, and
117123/// * not publicly exposing `&mut` access to that allocator.
@@ -120,11 +126,11 @@ impl fmt::Display for AllocError {
120126/// allowed to invalidate its memory blocks. Furthermore, unsafe public API
121127/// of an allocator with `&` access must document that they invalidate
122128/// memory blocks (e.g., by calling `deallocate`) if they do. Therefore,
123- /// collections may safely expose `&` access to its allocator.
129+ /// a collection may safely expose `&` access to its allocator.
124130///
125- /// Also note that, even in cases where are other "alive" allocators known to be
126- /// equivalent to a given collection's allocator, most collections still should
127- /// not publicly expose `&mut` access to its allocator . The fact that there are
131+ /// Also note that, even in cases where there are other "alive" allocators known
132+ /// to be equivalent to a given collection's allocator, most collections still should
133+ /// not publicly expose `&mut` access to their allocators . The fact that there are
128134/// other "alive" allocators would prevent this `&mut` access from invalidating
129135/// the collection's memory block, but public `&mut` access is still likely to
130136/// be unsound, since a user could replace the collection's allocator with
@@ -140,8 +146,8 @@ impl fmt::Display for AllocError {
140146///
141147/// ### Memory fitting
142148///
143- /// Some of the methods require that a `layout` *fit * a memory block or vice versa. This means that the
144- /// following conditions must hold:
149+ /// Some of the methods require that a `layout` *fits * a memory block or vice versa. This means
150+ /// that the following conditions must hold:
145151/// * the memory block must be *currently allocated* with alignment of [`layout.align()`], and
146152/// * [`layout.size()`] must fall in the range `min ..= max`, where:
147153/// - `min` is the size of the layout used to allocate the block, and
@@ -154,28 +160,32 @@ impl fmt::Display for AllocError {
154160/// # Safety
155161///
156162/// Implementors of `Allocator` must ensure that a memory block that
157- /// is [*currently allocated*] by the allocator points to valid memory,
163+ /// is [*currently allocated*] by the allocator points to valid memory
158164/// until that memory block is [*invalidated*]. The implementor must also
159165/// not violate this invariant of `Allocator` via allocator equivalences
160- /// that are in the implementor's control (e.g., via an incorrect `unsafe
161- /// impl AllocatorClone for MyAllocator`).
166+ /// that are in the implementor's control.
162167///
163168/// Additionally, any memory block returned by the allocator must
164169/// satisfy the allocation invariants described in `core::ptr`.
165170/// In particular, if a block has base address `p` and size `n`,
166- /// then `p as usize + n <= usize::MAX` must hold.
171+ /// then `p as usize + n <= usize::MAX` must hold. These blocks must also
172+ /// be wholly disjoint.
167173///
168174/// This ensures that pointer arithmetic within the allocation
169- /// (for example, `ptr.add(len)`) cannot overflow the address space.
175+ /// (for example, `ptr.add(len)`) cannot overflow the address space, and
176+ /// that it is possible to perform nonoverlapping copies between allocations.
170177///
171178/// None of the allocating or deallocating methods may unwind. This restriction
172179/// may be lifted in the future by ensuring unwinding out of an allocating function always
173180/// aborts. If an implementor of `Allocator` also has drop glue or directly implements `Drop`,
174181/// dropping the allocator must not result in an unwind.
175182///
176- /// Lastly, the methods on this trait must be *correct*; i.e. the layout requested
183+ /// It is undefined behavior for the allocator to read, write, or deallocate any memory that
184+ /// is currently allocated. This memory is owned by the user; the allocator must not touch it.
185+ ///
186+ /// Lastly, the methods on this trait must be *correct*; in particular, the layout requested
177187/// must be respected, calls must zero out memory if the documentation so requires,
178- /// and returning an `AllocError` from a reallocating method must indeed ensure that
188+ /// returning an `AllocError` from a reallocating method must indeed ensure that
179189/// the old pointer was not invalidated, and de/reallocating calls must accept layouts
180190/// in the ranges defined by their documentation.
181191///
@@ -203,7 +213,7 @@ pub const unsafe trait Allocator {
203213 /// Note that the returned block of memory is considered [*currently allocated*]
204214 /// with this allocator (and equivalent allocators).
205215 /// Therefore, it is the responsibility of implementors of `Allocator` to make sure that
206- /// this block of memory points to valid memory until the block is [*invalidated*]
216+ /// this block of memory remains valid until it is [*invalidated*].
207217 ///
208218 /// [*currently allocated*]: #currently-allocated-memory
209219 /// [*invalidated*]: #invalidating-memory-blocks
@@ -539,14 +549,15 @@ pub unsafe trait AllocatorClone: Allocator + Clone {}
539549///
540550/// # Safety
541551///
542- /// Implementors must ensure that memory cannot be freed except via a call to
543- /// `Allocator::deallocate`, and that subtype coercion preserves this invariant.
552+ /// Implementors must ensure that memory blocks are *only, ever* invalidated by a
553+ /// call to a de/reallocating method on `Allocator`, and that this holds true for all
554+ /// possible instances of all subtypes of the implementor as well.
544555///
545556/// These requirements trivially apply to allocators that always maintain global state, such as
546557/// `System` or `Global`. However, due to subtype coercion, it is *not* sound to implement
547- /// for an arbitrary `Allocator + 'static` due to [edge-case interactions][unsound] with
548- /// `Pin::clone`. Namely, an impl of `StaticAllocator for MyAllocator + 'long` guarantees that an
549- /// impl of `StaticAllocator for MyAllocator + 'short` would be sound to write .
558+ /// for an arbitrary `Allocator + 'static` due to [edge-case interactions][unsound] with e.g.
559+ /// `Pin::clone`. Namely, an impl of `StaticAllocator for MyAllocator + 'long` guarantees that any
560+ /// value of `MyAllocator + 'short` also fulfills the requirements of `StaticAllocator` .
550561///
551562/// The following must thus be guaranteed:
552563/// - the `Drop` impl of the allocator does not invalidate any allocations;
@@ -617,9 +628,10 @@ where
617628}
618629
619630#[ unstable( feature = "allocator_api" , issue = "32838" ) ]
620- unsafe impl < A > Allocator for & mut A
631+ #[ rustc_const_unstable( feature = "const_heap" , issue = "79597" ) ]
632+ const unsafe impl < A > Allocator for & mut A
621633where
622- A : Allocator + ?Sized ,
634+ A : [ const ] Allocator + ?Sized ,
623635{
624636 #[ inline]
625637 fn allocate ( & self , layout : Layout ) -> Result < NonNull < [ u8 ] > , AllocError > {
@@ -678,3 +690,6 @@ unsafe impl<A: Allocator + ?Sized> AllocatorClone for &A {}
678690// its semantics, and references are equivalent to the allocator they reference.
679691#[ unstable( feature = "allocator_api" , issue = "32838" ) ]
680692unsafe impl < A : StaticAllocator + ?Sized > StaticAllocator for & A { }
693+
694+ #[ unstable( feature = "allocator_api" , issue = "32838" ) ]
695+ unsafe impl < A : StaticAllocator + ?Sized > StaticAllocator for & mut A { }
0 commit comments