|
10 | 10 | **Note**: a full aliasing model for Rust, defining when aliasing is allowed
|
11 | 11 | and when not, has not yet been defined. The purpose of this definition is to
|
12 | 12 | define when aliasing *happens*, not when it is *allowed*. The most developed
|
13 |
| -potential aliasing model so far is known as "Stacked Borrows", and can be found |
14 |
| -[here](https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md). |
| 13 | +potential aliasing model so far is [Stacked Borrows][stacked-borrows]. |
15 | 14 |
|
16 | 15 | Consider the following example:
|
17 | 16 |
|
@@ -56,6 +55,46 @@ somewhat differently from this definition. However, that's considered a low
|
56 | 55 | level detail of a particular Rust implementation. When programming Rust, the
|
57 | 56 | Abstract Rust Machine is intended to operate according to the definition here.
|
58 | 57 |
|
| 58 | +#### (Pointer) Provenance |
| 59 | + |
| 60 | +The *provenance* of a pointer is used to distinguish pointers that point to the same memory address (i.e., pointers that, when cast to `usize`, will compare equal). |
| 61 | +Provenance is extra state that only exists in the Rust Abstract Machine; it is needed to specify program behavior but not present any more when the program runs on real hardware. |
| 62 | +In other words, pointers that only differ in their provenance can *not* be distinguished any more in the final binary (but provenance can influence how the compiler translates the program). |
| 63 | + |
| 64 | +The exact form of provenance in Rust is unclear. |
| 65 | +It is also unclear whether provenance applies to more than just pointers, i.e., one could imagine integers having provenance as well (so that pointer provenance can be preserved when pointers are cast to an integer and back). |
| 66 | +In the following, we give some examples if what provenance *could* look like. |
| 67 | + |
| 68 | +**Using provenance to track originating allocation.** |
| 69 | +For example, we have to distinguish pointers to the same location if they originated from different allocations. |
| 70 | +Cross-allocation pointer arithmetic [does not lead to usable pointers](https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset), so the Rust Abstract Machine *somehow* has to remember the original allocation to which a pointer pointed. |
| 71 | +It uses provenance to achieve this: |
| 72 | + |
| 73 | +```rust |
| 74 | +// Let's assume the two allocations here have base addresses 0x100 and 0x200. |
| 75 | +// We write pointer provenance as `@N` where `N` is some kind of ID uniquely |
| 76 | +// identifying the allocation. |
| 77 | +let raw1 = Box::into_raw(Box::new(13u8)); |
| 78 | +let raw2 = Box::into_raw(Box::new(42u8)); |
| 79 | +let raw2_wrong = raw1.wrapping_add(raw2.wrapping_sub(raw1 as usize) as usize); |
| 80 | +// These pointers now have the following values: |
| 81 | +// raw1 points to address 0x100 and has provenance @1. |
| 82 | +// raw2 points to address 0x200 and has provenance @2. |
| 83 | +// raw2_wrong points to address 0x200 and has provenance @1. |
| 84 | +// In other words, raw2 and raw2_wrong have same *address*... |
| 85 | +assert_eq!(raw2 as usize, raw2_wrong as usize); |
| 86 | +// ...but it would be UB to dereference raw2_wrong, as it has the wrong *provenance*: |
| 87 | +// it points to address 0x200, which is in allocation @2, but the pointer |
| 88 | +// has provenance @1. |
| 89 | +``` |
| 90 | + |
| 91 | +This kind of provenance also exists in C/C++, but Rust is more permissive by (a) providing a [way to do pointer arithmetic across allocation boundaries without causing immediate UB](https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset) (though, as we have seen, the resulting pointer still cannot be used for locations outside the allocation it originates), and (b) by allowing pointers to always be compared safely, even if their provenance differs. |
| 92 | +For some more information, see [this document proposing a more precise definition of provenance for C](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2364.pdf). |
| 93 | + |
| 94 | +**Using provenance for Rust's aliasing rules.** |
| 95 | +Another example of pointer provenance is the "tag" from [Stacked Borrows][stacked-borrows]. |
| 96 | +For some more information, see [this blog post](https://www.ralfj.de/blog/2018/07/24/pointers-and-bytes.html). |
| 97 | + |
59 | 98 | #### Interior mutability
|
60 | 99 |
|
61 | 100 | *Interior Mutation* means mutating memory where there also exists a live shared reference pointing to the same memory; or mutating memory through a pointer derived from a shared reference.
|
@@ -140,7 +179,8 @@ requirement of 2.
|
140 | 179 |
|
141 | 180 | ### TODO
|
142 | 181 |
|
143 |
| -* *tag* |
144 | 182 | * *rvalue*
|
145 | 183 | * *lvalue*
|
146 | 184 | * *representation*
|
| 185 | + |
| 186 | +[stacked-borrows]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md |
0 commit comments