|
19 | 19 | //! pointer. The following points are only concerned with non-zero-sized accesses.
|
20 | 20 | //! * A [null] pointer is *never* valid.
|
21 | 21 | //! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer be
|
22 |
| -//! *dereferenceable*. The [provenance] of the pointer is used to determine which [allocation] |
23 |
| -//! it is derived from; a pointer is dereferenceable if the memory range of the given size |
24 |
| -//! starting at the pointer is entirely contained within the bounds of that allocation. Note |
25 |
| -//! that in Rust, every (stack-allocated) variable is considered a separate allocation. |
| 22 | +//! *dereferenceable*. The [provenance] of the pointer is used to determine which [allocated |
| 23 | +//! object] it is derived from; a pointer is dereferenceable if the memory range of the given size |
| 24 | +//! starting at the pointer is entirely contained within the bounds of that allocated object. Note |
| 25 | +//! that in Rust, every (stack-allocated) variable is considered a separate allocated object. |
26 | 26 | //! * All accesses performed by functions in this module are *non-atomic* in the sense
|
27 | 27 | //! of [atomic operations] used to synchronize between threads. This means it is
|
28 | 28 | //! undefined behavior to perform two concurrent accesses to the same location from different
|
|
31 | 31 | //! be used for inter-thread synchronization, regardless of whether it is acting on
|
32 | 32 | //! Rust memory or not.
|
33 | 33 | //! * The result of casting a reference to a pointer is valid for as long as the
|
34 |
| -//! underlying allocation is live and no reference (just raw pointers) is used to |
| 34 | +//! underlying object is live and no reference (just raw pointers) is used to |
35 | 35 | //! access the same memory. That is, reference and pointer accesses cannot be
|
36 | 36 | //! interleaved.
|
37 | 37 | //!
|
|
96 | 96 | //!
|
97 | 97 | //! [valid value]: ../../reference/behavior-considered-undefined.html#invalid-values
|
98 | 98 | //!
|
99 |
| -//! ## Allocation |
| 99 | +//! ## Allocated object |
100 | 100 | //!
|
101 |
| -//! <a id="allocated-object"></a> <!-- keep old URLs working --> |
102 |
| -//! |
103 |
| -//! An *allocation* is a subset of program memory which is addressable |
| 101 | +//! An *allocated object* is a subset of program memory which is addressable |
104 | 102 | //! from Rust, and within which pointer arithmetic is possible. Examples of
|
105 |
| -//! allocations include heap allocations, stack-allocated variables, |
| 103 | +//! allocated objects include heap allocations, stack-allocated variables, |
106 | 104 | //! statics, and consts. The safety preconditions of some Rust operations -
|
107 | 105 | //! such as `offset` and field projections (`expr.field`) - are defined in
|
108 |
| -//! terms of the allocations on which they operate. |
| 106 | +//! terms of the allocated objects on which they operate. |
109 | 107 | //!
|
110 |
| -//! An allocation has a base address, a size, and a set of memory |
111 |
| -//! addresses. It is possible for an allocation to have zero size, but |
112 |
| -//! such an allocation will still have a base address. The base address |
113 |
| -//! of an allocation is not necessarily unique. While it is currently the |
114 |
| -//! case that an allocation always has a set of memory addresses which is |
| 108 | +//! An allocated object has a base address, a size, and a set of memory |
| 109 | +//! addresses. It is possible for an allocated object to have zero size, but |
| 110 | +//! such an allocated object will still have a base address. The base address |
| 111 | +//! of an allocated object is not necessarily unique. While it is currently the |
| 112 | +//! case that an allocated object always has a set of memory addresses which is |
115 | 113 | //! fully contiguous (i.e., has no "holes"), there is no guarantee that this
|
116 | 114 | //! will not change in the future.
|
117 | 115 | //!
|
118 |
| -//! Allocations must behave like "normal" memory: in particular, reads must not |
119 |
| -//! have side-effects, and writes must become visible to other threads using the |
120 |
| -//! usual synchronization primitives. |
| 116 | +//! Allocations must behave like "normal" memory: in particular, reads must not have |
| 117 | +//! side-effects, and writes must become visible to other threads using the usual synchronization |
| 118 | +//! primitives. |
121 | 119 | //!
|
122 |
| -//! For any allocation with `base` address, `size`, and a set of |
| 120 | +//! For any allocated object with `base` address, `size`, and a set of |
123 | 121 | //! `addresses`, the following are guaranteed:
|
124 | 122 | //! - For all addresses `a` in `addresses`, `a` is in the range `base .. (base +
|
125 | 123 | //! size)` (note that this requires `a < base + size`, not `a <= base + size`)
|
|
129 | 127 | //! - `size <= isize::MAX`
|
130 | 128 | //!
|
131 | 129 | //! As a consequence of these guarantees, given any address `a` within the set
|
132 |
| -//! of addresses of an allocation: |
| 130 | +//! of addresses of an allocated object: |
133 | 131 | //! - It is guaranteed that `a - base` does not overflow `isize`
|
134 | 132 | //! - It is guaranteed that `a - base` is non-negative
|
135 | 133 | //! - It is guaranteed that, given `o = a - base` (i.e., the offset of `a` within
|
136 |
| -//! the allocation), `base + o` will not wrap around the address space (in |
| 134 | +//! the allocated object), `base + o` will not wrap around the address space (in |
137 | 135 | //! other words, will not overflow `usize`)
|
138 | 136 | //!
|
139 | 137 | //! [`null()`]: null
|
|
145 | 143 | //! and the freed memory gets reallocated before your read/write (in fact this is the
|
146 | 144 | //! worst-case scenario, UAFs would be much less concerning if this didn't happen!).
|
147 | 145 | //! As another example, consider that [`wrapping_offset`] is documented to "remember"
|
148 |
| -//! the allocation that the original pointer points to, even if it is offset far |
149 |
| -//! outside the memory range occupied by that allocation. |
| 146 | +//! the allocated object that the original pointer points to, even if it is offset far |
| 147 | +//! outside the memory range occupied by that allocated object. |
150 | 148 | //! To rationalize claims like this, pointers need to somehow be *more* than just their addresses:
|
151 | 149 | //! they must have **provenance**.
|
152 | 150 | //!
|
|
166 | 164 | //! writes. Note that this can interact with the other components, e.g. a pointer might permit
|
167 | 165 | //! mutation only for a subset of addresses, or only for a subset of its maximal timespan.
|
168 | 166 | //!
|
169 |
| -//! When an [allocation] is created, it has a unique Original Pointer. For alloc |
| 167 | +//! When an [allocated object] is created, it has a unique Original Pointer. For alloc |
170 | 168 | //! APIs this is literally the pointer the call returns, and for local variables and statics,
|
171 | 169 | //! this is the name of the variable/static. (This is mildly overloading the term "pointer"
|
172 | 170 | //! for the sake of brevity/exposition.)
|
173 | 171 | //!
|
174 |
| -//! The Original Pointer for an allocation has provenance that constrains the *spatial* |
| 172 | +//! The Original Pointer for an allocated object has provenance that constrains the *spatial* |
175 | 173 | //! permissions of this pointer to the memory range of the allocation, and the *temporal*
|
176 | 174 | //! permissions to the lifetime of the allocation. Provenance is implicitly inherited by all
|
177 | 175 | //! pointers transitively derived from the Original Pointer through operations like [`offset`],
|
|
199 | 197 | //! provenance since they access an empty range of memory.
|
200 | 198 | //!
|
201 | 199 | //! * It is undefined behavior to [`offset`] a pointer across a memory range that is not contained
|
202 |
| -//! in the allocation it is derived from, or to [`offset_from`] two pointers not derived |
203 |
| -//! from the same allocation. Provenance is used to say what exactly "derived from" even |
| 200 | +//! in the allocated object it is derived from, or to [`offset_from`] two pointers not derived |
| 201 | +//! from the same allocated object. Provenance is used to say what exactly "derived from" even |
204 | 202 | //! means: the lineage of a pointer is traced back to the Original Pointer it descends from, and
|
205 |
| -//! that identifies the relevant allocation. In particular, it's always UB to offset a |
| 203 | +//! that identifies the relevant allocated object. In particular, it's always UB to offset a |
206 | 204 | //! pointer derived from something that is now deallocated, except if the offset is 0.
|
207 | 205 | //!
|
208 | 206 | //! But it *is* still sound to:
|
|
223 | 221 | //! * Compare arbitrary pointers by address. Pointer comparison ignores provenance and addresses
|
224 | 222 | //! *are* just integers, so there is always a coherent answer, even if the pointers are dangling
|
225 | 223 | //! or from different provenances. Note that if you get "lucky" and notice that a pointer at the
|
226 |
| -//! end of one allocation is the "same" address as the start of another allocation, |
| 224 | +//! end of one allocated object is the "same" address as the start of another allocated object, |
227 | 225 | //! anything you do with that fact is *probably* going to be gibberish. The scope of that
|
228 | 226 | //! gibberish is kept under control by the fact that the two pointers *still* aren't allowed to
|
229 | 227 | //! access the other's allocation (bytes), because they still have different provenance.
|
|
376 | 374 | //! integer-to-pointer casts.
|
377 | 375 | //!
|
378 | 376 | //! [aliasing]: ../../nomicon/aliasing.html
|
379 |
| -//! [allocation]: #allocation |
| 377 | +//! [allocated object]: #allocated-object |
380 | 378 | //! [provenance]: #provenance
|
381 | 379 | //! [book]: ../../book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer
|
382 | 380 | //! [ub]: ../../reference/behavior-considered-undefined.html
|
@@ -1023,7 +1021,7 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
|
1023 | 1021 | // SAFETY: the caller must guarantee that `x` and `y` are
|
1024 | 1022 | // valid for writes and properly aligned. `tmp` cannot be
|
1025 | 1023 | // overlapping either `x` or `y` because `tmp` was just allocated
|
1026 |
| - // on the stack as a separate allocation. |
| 1024 | + // on the stack as a separate allocated object. |
1027 | 1025 | unsafe {
|
1028 | 1026 | copy_nonoverlapping(x, tmp.as_mut_ptr(), 1);
|
1029 | 1027 | copy(y, x, 1); // `x` and `y` may overlap
|
@@ -1142,7 +1140,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
|
1142 | 1140 | // Going though a slice here helps codegen know the size fits in `isize`
|
1143 | 1141 | let slice = slice_from_raw_parts_mut(x, count);
|
1144 | 1142 | // SAFETY: This is all readable from the pointer, meaning it's one
|
1145 |
| - // allocation, and thus cannot be more than isize::MAX bytes. |
| 1143 | + // allocated object, and thus cannot be more than isize::MAX bytes. |
1146 | 1144 | let bytes = unsafe { mem::size_of_val_raw::<[T]>(slice) };
|
1147 | 1145 | if let Some(bytes) = NonZero::new(bytes) {
|
1148 | 1146 | // SAFETY: These are the same ranges, just expressed in a different
|
@@ -1295,7 +1293,7 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
|
1295 | 1293 | // SAFETY: the caller must guarantee that `dst` is valid to be
|
1296 | 1294 | // cast to a mutable reference (valid for writes, aligned, initialized),
|
1297 | 1295 | // and cannot overlap `src` since `dst` must point to a distinct
|
1298 |
| - // allocation. |
| 1296 | + // allocated object. |
1299 | 1297 | unsafe {
|
1300 | 1298 | ub_checks::assert_unsafe_precondition!(
|
1301 | 1299 | check_language_ub,
|
@@ -1542,7 +1540,7 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
|
1542 | 1540 | let mut tmp = MaybeUninit::<T>::uninit();
|
1543 | 1541 | // SAFETY: the caller must guarantee that `src` is valid for reads.
|
1544 | 1542 | // `src` cannot overlap `tmp` because `tmp` was just allocated on
|
1545 |
| - // the stack as a separate allocation. |
| 1543 | + // the stack as a separate allocated object. |
1546 | 1544 | //
|
1547 | 1545 | // Also, since we just wrote a valid value into `tmp`, it is guaranteed
|
1548 | 1546 | // to be properly initialized.
|
|
0 commit comments