|
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