|
15 | 15 | //! The precise rules for validity are not determined yet. The guarantees that are |
16 | 16 | //! provided at this point are very minimal: |
17 | 17 | //! |
18 | | -//! * For memory accesses of [size zero][zst], *every* pointer is valid, including the [null] |
19 | | -//! pointer. The following points are only concerned with non-zero-sized accesses. |
20 | | -//! * A [null] pointer is *never* valid. |
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 |
| 18 | +//! * A [null] pointer is *never* valid for reads/writes. |
| 19 | +//! * For memory accesses of [size zero][zst], *every* non-null pointer is valid for reads/writes. |
| 20 | +//! The following points are only concerned with non-zero-sized accesses. |
| 21 | +//! * For a pointer to be valid for reads/writes, it is necessary, but not always sufficient, that |
| 22 | +//! the pointer be *dereferenceable*. The [provenance] of the pointer is used to determine which |
| 23 | +//! [allocation] it is derived from; a pointer is dereferenceable if the memory range of the given |
| 24 | +//! size starting at the pointer is entirely contained within the bounds of that allocation. Note |
25 | 25 | //! that in Rust, every (stack-allocated) variable is considered a separate allocation. |
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 |
29 | | -//! threads unless both accesses only read from memory. Notice that this explicitly |
30 | | -//! includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot |
31 | | -//! be used for inter-thread synchronization, regardless of whether they are acting on |
32 | | -//! Rust memory or not. |
33 | | -//! * The result of casting a reference to a pointer is valid for as long as the |
| 29 | +//! threads unless both accesses only read from memory. |
| 30 | +//! * The result of casting a reference to a pointer is valid for reads/writes for as long as the |
34 | 31 | //! underlying allocation is live and no reference (just raw pointers) is used to |
35 | 32 | //! access the same memory. That is, reference and pointer accesses cannot be |
36 | 33 | //! interleaved. |
|
41 | 38 | //! information, see the [book] as well as the section in the reference devoted |
42 | 39 | //! to [undefined behavior][ub]. |
43 | 40 | //! |
| 41 | +//! Note that some operations such as [`read`] and [`write`] do allow null pointers if the total |
| 42 | +//! size of the access is zero. However, other operations internally convert pointers into |
| 43 | +//! references. Therefore, the general notion of "valid for reads/writes" excludes null pointers, |
| 44 | +//! and the specific operations that permit null pointers mention that as an exception. |
| 45 | +//! Furthermore, [`read_volatile`] and [`write_volatile`] can be used in even more situations; |
| 46 | +//! see their documentation for details. |
| 47 | +//! |
44 | 48 | //! We say that a pointer is "dangling" if it is not valid for any non-zero-sized accesses. This |
45 | 49 | //! means out-of-bounds pointers, pointers to freed memory, null pointers, and pointers created with |
46 | 50 | //! [`NonNull::dangling`] are all dangling. |
@@ -450,9 +454,9 @@ mod mut_ptr; |
450 | 454 | /// |
451 | 455 | /// Behavior is undefined if any of the following conditions are violated: |
452 | 456 | /// |
453 | | -/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes. |
| 457 | +/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes or that number must be 0. |
454 | 458 | /// |
455 | | -/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes. |
| 459 | +/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes or that number must be 0. |
456 | 460 | /// |
457 | 461 | /// * Both `src` and `dst` must be properly aligned. |
458 | 462 | /// |
@@ -568,11 +572,11 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us |
568 | 572 | /// |
569 | 573 | /// Behavior is undefined if any of the following conditions are violated: |
570 | 574 | /// |
571 | | -/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes. |
| 575 | +/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes or that number must be 0. |
572 | 576 | /// |
573 | | -/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes, and must remain valid even |
574 | | -/// when `src` is read for `count * size_of::<T>()` bytes. (This means if the memory ranges |
575 | | -/// overlap, the `dst` pointer must not be invalidated by `src` reads.) |
| 577 | +/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes or that number must be 0, |
| 578 | +/// and `dst` must remain valid even when `src` is read for `count * size_of::<T>()` bytes. (This |
| 579 | +/// means if the memory ranges overlap, the `dst` pointer must not be invalidated by `src` reads.) |
576 | 580 | /// |
577 | 581 | /// * Both `src` and `dst` must be properly aligned. |
578 | 582 | /// |
@@ -1565,7 +1569,7 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T { |
1565 | 1569 | /// |
1566 | 1570 | /// Behavior is undefined if any of the following conditions are violated: |
1567 | 1571 | /// |
1568 | | -/// * `src` must be [valid] for reads. |
| 1572 | +/// * `src` must be [valid] for reads or `T` must be a ZST. |
1569 | 1573 | /// |
1570 | 1574 | /// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the |
1571 | 1575 | /// case. |
@@ -1817,7 +1821,7 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T { |
1817 | 1821 | /// |
1818 | 1822 | /// Behavior is undefined if any of the following conditions are violated: |
1819 | 1823 | /// |
1820 | | -/// * `dst` must be [valid] for writes. |
| 1824 | +/// * `dst` must be [valid] for writes or `T` must be a ZST. |
1821 | 1825 | /// |
1822 | 1826 | /// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the |
1823 | 1827 | /// case. |
@@ -2040,8 +2044,8 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) { |
2040 | 2044 | /// |
2041 | 2045 | /// Behavior is undefined if any of the following conditions are violated: |
2042 | 2046 | /// |
2043 | | -/// * `src` must be either [valid] for reads, or it must point to memory outside of all Rust |
2044 | | -/// allocations and reading from that memory must: |
| 2047 | +/// * `src` must be either [valid] for reads, or `T` must be a ZST, or `src` must point to memory |
| 2048 | +/// outside of all Rust allocations and reading from that memory must: |
2045 | 2049 | /// - not trap, and |
2046 | 2050 | /// - not cause any memory inside a Rust allocation to be modified. |
2047 | 2051 | /// |
@@ -2128,8 +2132,8 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T { |
2128 | 2132 | /// |
2129 | 2133 | /// Behavior is undefined if any of the following conditions are violated: |
2130 | 2134 | /// |
2131 | | -/// * `dst` must be either [valid] for writes, or it must point to memory outside of all Rust |
2132 | | -/// allocations and writing to that memory must: |
| 2135 | +/// * `dst` must be either [valid] for writes, or `T` must be a ZST, or `dst` must point to memory |
| 2136 | +/// outside of all Rust allocations and writing to that memory must: |
2133 | 2137 | /// - not trap, and |
2134 | 2138 | /// - not cause any memory inside a Rust allocation to be modified. |
2135 | 2139 | /// |
|
0 commit comments