|
149 | 149 | //! * The **provenance** it has, defining the memory it has permission to access. Provenance can be |
150 | 150 | //! absent, in which case the pointer does not have permission to access any memory. |
151 | 151 | //! |
| 152 | +//! The exact structure of provenance is not yet specified, but the permission defined by a |
| 153 | +//! pointer's provenance have both a *spatial* and *temporal* component: |
| 154 | +//! |
| 155 | +//! * Spatial: The set of memory addresses that the pointer is allowed to access. |
| 156 | +//! * Temporal: The timespan during which the pointer is allowed to access those memory addresses. |
| 157 | +//! |
152 | 158 | //! When an [allocated object] is created, it has a unique Original Pointer. For alloc |
153 | 159 | //! APIs this is literally the pointer the call returns, and for local variables and statics, |
154 | 160 | //! this is the name of the variable/static. (This is mildly overloading the term "pointer" |
155 | 161 | //! for the sake of brevity/exposition.) |
156 | 162 | //! |
157 | | -//! The Original Pointer for an allocated object is guaranteed to have unique access to the entire |
158 | | -//! allocation and *only* that allocation. In this sense, an allocation can be thought of as a |
159 | | -//! "sandbox" that the pointer must not leave (at penalty of undefined behavior). *Provenance* is |
160 | | -//! about tracking each pointer's lineage back to the Original Pointer that it got derived from. |
161 | | -//! This controls which permission the pointer has to access (part of) an allocation's sandbox. This |
162 | | -//! permission has both a *spatial* and *temporal* component: |
163 | | -//! |
164 | | -//! * Spatial: A range of bytes that the pointer is allowed to access. |
165 | | -//! * Temporal: The timespan during which the pointer is allowed to access these bytes. |
166 | | -//! |
167 | | -//! Spatial provenance requires that you don't go beyond your sandbox, while temporal provenance |
168 | | -//! requires that you can't "get lucky" after your permission to access some memory |
169 | | -//! has been revoked (either through deallocations or borrows expiring). |
170 | | -//! |
171 | | -//! Provenance is implicitly shared with all pointers transitively derived from |
172 | | -//! the Original Pointer through operations like [`offset`], borrowing, and pointer casts. |
173 | | -//! Some operations may *shrink* the derived provenance, limiting how much memory it can |
174 | | -//! access or how long it's valid for (i.e. borrowing a subfield and subslicing can shrink the |
175 | | -//! spatial component of provenance, and all borrowing can shrink the temporal component of |
176 | | -//! provenance). |
177 | | -//! |
178 | | -//! Shrinking provenance cannot be undone: even if you "know" there is a larger allocation, you |
179 | | -//! can't derive a pointer with a larger provenance. Similarly, you cannot "recombine" |
180 | | -//! two contiguous provenances back into one (i.e. with a `fn merge(&[T], &[T]) -> &[T]`). |
| 163 | +//! The Original Pointer for an allocated object has provenance that constraints the *spatial* |
| 164 | +//! permissions of this pointer to the memory range of the allocation, and the *temporal* |
| 165 | +//! permissions to the lifetime of the allocation. Provenance is implicitly inherited by all |
| 166 | +//! pointers transitively derived from the Original Pointer through operations like [`offset`], |
| 167 | +//! borrowing, and pointer casts. Some operations may *shrink* the permissions of the derived |
| 168 | +//! provenance, limiting how much memory it can access or how long it's valid for (i.e. borrowing a |
| 169 | +//! subfield and subslicing can shrink the spatial component of provenance, and all borrowing can |
| 170 | +//! shrink the temporal component of provenance). However, no operation can ever *grow* the |
| 171 | +//! permissions of the derived provenance: even if you "know" there is a larger allocation, you |
| 172 | +//! can't derive a pointer with a larger provenance. Similarly, you cannot "recombine" two |
| 173 | +//! contiguous provenances back into one (i.e. with a `fn merge(&[T], &[T]) -> &[T]`). |
181 | 174 | //! |
182 | 175 | //! A reference to a place always has provenance over at least the memory that place occupies. |
183 | 176 | //! A reference to a slice always has provenance over at least the range that slice describes. |
184 | 177 | //! Whether and when exactly the provenance of a reference gets "shrunk" to *exactly* fit |
185 | 178 | //! the memory it points to is not yet determined. |
186 | 179 | //! |
187 | | -//! If an allocation is deallocated, all pointers with provenance to that allocation become |
188 | | -//! invalidated, and effectively lose their provenance. |
189 | | -//! |
190 | 180 | //! Provenance can affect whether a program has undefined behavior: |
191 | 181 | //! |
192 | 182 | //! * It is undefined behavior to access memory through a pointer that does not have provenance over |
|
0 commit comments