|
103 | 103 | //! they must have provenance. |
104 | 104 | //! |
105 | 105 | //! When an allocation is created, that allocation has a unique Original Pointer. For alloc |
106 | | -//! APIs this is literally the pointer the call returns, and for variables declarations this |
107 | | -//! is the name of the variable. This is mildly overloading the term "pointer" for the sake |
108 | | -//! of brevity/exposition. |
| 106 | +//! APIs this is literally the pointer the call returns, and for local variables and statics, |
| 107 | +//! this is the name of the variable/static. This is mildly overloading the term "pointer" |
| 108 | +//! for the sake of brevity/exposition. |
109 | 109 | //! |
110 | 110 | //! The Original Pointer for an allocation is guaranteed to have unique access to the entire |
111 | 111 | //! allocation and *only* that allocation. In this sense, an allocation can be thought of |
112 | 112 | //! as a "sandbox" that cannot be broken into or out of. *Provenance* is the permission |
113 | 113 | //! to access an allocation's sandbox and has both a *spatial* and *temporal* component: |
114 | 114 | //! |
115 | | -//! * Spatial: A range of bytes in the allocation that the pointer is allowed to access. |
116 | | -//! * Temporal: Some kind of globally unique identifier tied to the allocation itself. |
| 115 | +//! * Spatial: A range of bytes that the pointer is allowed to access. |
| 116 | +//! * Temporal: The allocation that access to these bytes is tied to. |
117 | 117 | //! |
118 | 118 | //! Spatial provenance makes sure you don't go beyond your sandbox, while temporal provenance |
119 | 119 | //! makes sure that you can't "get lucky" after your permission to access some memory |
|
139 | 139 | //! formal [Stacked Borrows][] research project, which is what tools like [miri][] are based on. |
140 | 140 | //! In particular, Stacked Borrows is necessary to properly describe what borrows are allowed |
141 | 141 | //! to do and when they become invalidated. This necessarily involves much more complex |
142 | | -//! *temporal* reasoning than simply identifying allocations. |
| 142 | +//! *temporal* reasoning than simply identifying allocations. Adjusting APIs and code |
| 143 | +//! for the strict provenance experiment will also greatly help Stacked Borrows. |
143 | 144 | //! |
144 | 145 | //! |
145 | 146 | //! ## Pointer Vs Addresses |
|
152 | 153 | //! to very complex and unreliable heuristics. But of course, converting between pointers and |
153 | 154 | //! integers is very useful, so what can we do? |
154 | 155 | //! |
155 | | -//! Strict Provenance attempts to square this circle by decoupling Rust's traditional conflation |
| 156 | +//! Also did you know WASM is actually a "Harvard Architecture"? As in function pointers are |
| 157 | +//! handled completely differently from data pointers? And we kind of just shipped Rust on WASM |
| 158 | +//! without really addressing the fact that we let you freely convert between function pointers |
| 159 | +//! and data pointers, because it mostly Just Works? Let's just put that on the "pointer casts |
| 160 | +//! are dubious" pile. |
| 161 | +//! |
| 162 | +//! Strict Provenance attempts to square these circles by decoupling Rust's traditional conflation |
156 | 163 | //! of pointers and `usize` (and `isize`), and defining a pointer to semantically contain the |
157 | 164 | //! following information: |
158 | 165 | //! |
|
246 | 253 | //! Situations where a valid pointer *must* be created from just an address, such as baremetal code |
247 | 254 | //! accessing a memory-mapped interface at a fixed address, are an open question on how to support. |
248 | 255 | //! These situations *will* still be allowed, but we might require some kind of "I know what I'm |
249 | | -//! doing" annotation to explain the situation to the compiler. Because those situations require |
250 | | -//! `volatile` accesses anyway, it should be possible to carve out exceptions for them. |
| 256 | +//! doing" annotation to explain the situation to the compiler. It's also possible they need no |
| 257 | +//! special attention at all, because they're generally accessing memory outside the scope of |
| 258 | +//! "the abstract machine", or already using "I know what I'm doing" annotations like "volatile". |
251 | 259 | //! |
252 | 260 | //! Under [Strict Provenance] is is Undefined Behaviour to: |
253 | 261 | //! |
254 | 262 | //! * Access memory through a pointer that does not have provenance over that memory. |
255 | 263 | //! |
256 | | -//! * [`offset`] a pointer to an address it doesn't have provenance over. |
| 264 | +//! * [`offset`] a pointer to or from an address it doesn't have provenance over. |
257 | 265 | //! This means it's always UB to offset a pointer derived from something deallocated, |
258 | 266 | //! even if the offset is 0. Note that a pointer "one past the end" of its provenance |
259 | 267 | //! is not actually outside its provenance, it just has 0 bytes it can load/store. |
|
295 | 303 | //! |
296 | 304 | //! * Perform pointer tagging tricks. This falls out of [`wrapping_offset`] but is worth |
297 | 305 | //! mentioning in more detail because of the limitations of [CHERI][]. Low-bit tagging |
298 | | -//! is very robust, and often doesn't even go out of bounds because types have a |
| 306 | +//! is very robust, and often doesn't even go out of bounds because types ensure |
299 | 307 | //! size >= align (and over-aligning actually gives CHERI more flexibility). Anything |
300 | 308 | //! more complex than this rapidly enters "extremely platform-specific" territory as |
301 | 309 | //! certain things may or may not be allowed based on specific supported operations. |
|
0 commit comments