2828//!   undefined behavior to perform two concurrent accesses to the same location from different 
2929//!   threads unless both accesses only read from memory. Notice that this explicitly 
3030//!   includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot 
31- //!   be used for inter-thread synchronization. 
31+ //!   be used for inter-thread synchronization, regardless of whether they are acting on 
32+ //!   Rust memory or not. 
3233//! * The result of casting a reference to a pointer is valid for as long as the 
3334//!   underlying allocation is live and no reference (just raw pointers) is used to 
3435//!   access the same memory. That is, reference and pointer accesses cannot be 
114115//! fully contiguous (i.e., has no "holes"), there is no guarantee that this 
115116//! will not change in the future. 
116117//! 
118+ //! Allocations must behave like "normal" memory: in particular, reads must not have 
119+ //! side-effects, and writes must become visible to other threads using the usual synchronization 
120+ //! primitives. 
121+ //! 
117122//! For any allocation with `base` address, `size`, and a set of 
118123//! `addresses`, the following are guaranteed: 
119124//! - For all addresses `a` in `addresses`, `a` is in the range `base .. (base + 
@@ -2021,54 +2026,61 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
20212026    } 
20222027} 
20232028
2024- /// Performs a volatile read of the value from `src` without moving it. This 
2025- /// leaves the memory in `src` unchanged. 
2026- /// 
2027- /// Volatile operations are intended to act on I/O memory, and are guaranteed 
2028- /// to not be elided or reordered by the compiler across other volatile 
2029- /// operations. 
2030- /// 
2031- /// # Notes 
2032- /// 
2033- /// Rust does not currently have a rigorously and formally defined memory model, 
2034- /// so the precise semantics of what "volatile" means here is subject to change 
2035- /// over time. That being said, the semantics will almost always end up pretty 
2036- /// similar to [C11's definition of volatile][c11]. 
2037- /// 
2038- /// The compiler shouldn't change the relative order or number of volatile 
2039- /// memory operations. However, volatile memory operations on zero-sized types 
2040- /// (e.g., if a zero-sized type is passed to `read_volatile`) are noops 
2041- /// and may be ignored. 
2042- /// 
2043- /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 
2029+ /// Performs a volatile read of the value from `src` without moving it. 
2030+ /// 
2031+ /// Volatile operations are intended to act on I/O memory. As such, they are considered externally 
2032+ /// observable events (just like syscalls, but less opaque), and are guaranteed to not be elided or 
2033+ /// reordered by the compiler across other externally observable events. With this in mind, there 
2034+ /// are two cases of usage that need to be distinguished: 
2035+ /// 
2036+ /// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like 
2037+ ///   [`read`], except for the additional guarantee that it won't be elided or reordered (see 
2038+ ///   above). This implies that the operation will actually access memory and not e.g. be lowered to 
2039+ ///   reusing data from a previous read. Other than that, all the usual rules for memory accesses 
2040+ ///   apply (including provenance).  In particular, just like in C, whether an operation is volatile 
2041+ ///   has no bearing whatsoever on questions involving concurrent accesses from multiple threads. 
2042+ ///   Volatile accesses behave exactly like non-atomic accesses in that regard. 
2043+ /// 
2044+ /// - Volatile operations, however, may also be used to access memory that is _outside_ of any Rust 
2045+ ///   allocation. In this use-case, the pointer does *not* have to be [valid] for reads. This is 
2046+ ///   typically used for CPU and peripheral registers that must be accessed via an I/O memory 
2047+ ///   mapping, most commonly at fixed addresses reserved by the hardware. These often have special 
2048+ ///   semantics associated to their manipulation, and cannot be used as general purpose memory. 
2049+ ///   Here, any address value is possible, including 0 and [`usize::MAX`], so long as the semantics 
2050+ ///   of such a read are well-defined by the target hardware. The provenance of the pointer is 
2051+ ///   irrelevant, and it can be created with [`without_provenance`]. The access must not trap. It 
2052+ ///   can cause side-effects, but those must not affect Rust-allocated memory in any way. This 
2053+ ///   access is still not considered [atomic], and as such it cannot be used for inter-thread 
2054+ ///   synchronization. 
2055+ /// 
2056+ /// Note that volatile memory operations where T is a zero-sized type are noops and may be ignored. 
2057+ /// 
2058+ /// [allocation]: crate::ptr#allocated-object 
2059+ /// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses 
20442060/// 
20452061/// # Safety 
20462062/// 
2063+ /// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of whether `T` is 
2064+ /// [`Copy`]. If `T` is not [`Copy`], using both the returned value and the value at `*src` can 
2065+ /// [violate memory safety][read-ownership]. However, storing non-[`Copy`] types in volatile memory 
2066+ /// is almost certainly incorrect. 
2067+ /// 
20472068/// Behavior is undefined if any of the following conditions are violated: 
20482069/// 
2049- /// * `src` must be [valid] for reads. 
2070+ /// * `src` must be either [valid] for reads, or it must point to memory outside of all Rust 
2071+ ///   allocations and reading from that memory must: 
2072+ ///   - not trap, and 
2073+ ///   - not cause any memory inside a Rust allocation to be modified. 
20502074/// 
20512075/// * `src` must be properly aligned. 
20522076/// 
2053- /// * `src` must point to a properly initialized value of type `T`. 
2054- /// 
2055- /// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of 
2056- /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned 
2057- /// value and the value at `*src` can [violate memory safety][read-ownership]. 
2058- /// However, storing non-[`Copy`] types in volatile memory is almost certainly 
2059- /// incorrect. 
2077+ /// * Reading from `src` must produce a properly initialized value of type `T`. 
20602078/// 
20612079/// Note that even if `T` has size `0`, the pointer must be properly aligned. 
20622080/// 
20632081/// [valid]: self#safety 
20642082/// [read-ownership]: read#ownership-of-the-returned-value 
20652083/// 
2066- /// Just like in C, whether an operation is volatile has no bearing whatsoever 
2067- /// on questions involving concurrent access from multiple threads. Volatile 
2068- /// accesses behave exactly like non-atomic accesses in that regard. In particular, 
2069- /// a race between a `read_volatile` and any write operation to the same location 
2070- /// is undefined behavior. 
2071- /// 
20722084/// # Examples 
20732085/// 
20742086/// Basic usage: 
@@ -2090,63 +2102,70 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
20902102    unsafe  { 
20912103        ub_checks:: assert_unsafe_precondition!( 
20922104            check_language_ub, 
2093-             "ptr::read_volatile requires that the pointer argument is aligned and non-null " , 
2105+             "ptr::read_volatile requires that the pointer argument is aligned" , 
20942106            ( 
20952107                addr:  * const  ( )  = src as  * const  ( ) , 
20962108                align:  usize  = align_of:: <T >( ) , 
2097-                 is_zst:  bool  = T :: IS_ZST , 
2098-             )  => ub_checks:: maybe_is_aligned_and_not_null( addr,  align,  is_zst) 
2109+             )  => ub_checks:: maybe_is_aligned( addr,  align) 
20992110        ) ; 
21002111        intrinsics:: volatile_load ( src) 
21012112    } 
21022113} 
21032114
2104- /// Performs a volatile write of a memory location with the given value without 
2105- /// reading or dropping the old value. 
2106- /// 
2107- /// Volatile operations are intended to act on I/O memory, and are guaranteed 
2108- /// to not be elided or reordered by the compiler across other volatile 
2109- /// operations. 
2110- /// 
2111- /// `write_volatile` does not drop the contents of `dst`. This is safe, but it 
2112- /// could leak allocations or resources, so care should be taken not to overwrite 
2113- /// an object that should be dropped. 
2114- /// 
2115- /// Additionally, it does not drop `src`. Semantically, `src` is moved into the 
2116- /// location pointed to by `dst`. 
2117- /// 
2118- /// # Notes 
2119- /// 
2120- /// Rust does not currently have a rigorously and formally defined memory model, 
2121- /// so the precise semantics of what "volatile" means here is subject to change 
2122- /// over time. That being said, the semantics will almost always end up pretty 
2123- /// similar to [C11's definition of volatile][c11]. 
2124- /// 
2125- /// The compiler shouldn't change the relative order or number of volatile 
2126- /// memory operations. However, volatile memory operations on zero-sized types 
2127- /// (e.g., if a zero-sized type is passed to `write_volatile`) are noops 
2128- /// and may be ignored. 
2129- /// 
2130- /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 
2115+ /// Performs a volatile write of a memory location with the given value without reading or dropping 
2116+ /// the old value. 
2117+ /// 
2118+ /// Volatile operations are intended to act on I/O memory. As such, they are considered externally 
2119+ /// observable events (just like syscalls), and are guaranteed to not be elided or reordered by the 
2120+ /// compiler across other externally observable events. With this in mind, there are two cases of 
2121+ /// usage that need to be distinguished: 
2122+ /// 
2123+ /// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like 
2124+ ///   [`write`][write()], except for the additional guarantee that it won't be elided or reordered 
2125+ ///   (see above). This implies that the operation will actually access memory and not e.g. be 
2126+ ///   lowered to a register access. Other than that, all the usual rules for memory accesses apply 
2127+ ///   (including provenance). In particular, just like in C, whether an operation is volatile has no 
2128+ ///   bearing whatsoever on questions involving concurrent access from multiple threads. Volatile 
2129+ ///   accesses behave exactly like non-atomic accesses in that regard. 
2130+ /// 
2131+ /// - Volatile operations, however, may also be used to access memory that is _outside_ of any Rust 
2132+ ///   allocation. In this use-case, the pointer does *not* have to be [valid] for writes. This is 
2133+ ///   typically used for CPU and peripheral registers that must be accessed via an I/O memory 
2134+ ///   mapping, most commonly at fixed addresses reserved by the hardware. These often have special 
2135+ ///   semantics associated to their manipulation, and cannot be used as general purpose memory. 
2136+ ///   Here, any address value is possible, including 0 and [`usize::MAX`], so long as the semantics 
2137+ ///   of such a write are well-defined by the target hardware. The provenance of the pointer is 
2138+ ///   irrelevant, and it can be created with [`without_provenance`]. The access must not trap. It 
2139+ ///   can cause side-effects, but those must not affect Rust-allocated memory in any way. This 
2140+ ///   access is still not considered [atomic], and as such it cannot be used for inter-thread 
2141+ ///   synchronization. 
2142+ /// 
2143+ /// Note that volatile memory operations on zero-sized types (e.g., if a zero-sized type is passed 
2144+ /// to `write_volatile`) are noops and may be ignored. 
2145+ /// 
2146+ /// `write_volatile` does not drop the contents of `dst`. This is safe, but it could leak 
2147+ /// allocations or resources, so care should be taken not to overwrite an object that should be 
2148+ /// dropped when operating on Rust memory. Additionally, it does not drop `src`. Semantically, `src` 
2149+ /// is moved into the location pointed to by `dst`. 
2150+ /// 
2151+ /// [allocation]: crate::ptr#allocated-object 
2152+ /// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses 
21312153/// 
21322154/// # Safety 
21332155/// 
21342156/// Behavior is undefined if any of the following conditions are violated: 
21352157/// 
2136- /// * `dst` must be [valid] for writes. 
2158+ /// * `dst` must be either [valid] for writes, or it must point to memory outside of all Rust 
2159+ ///   allocations and writing to that memory must: 
2160+ ///   - not trap, and 
2161+ ///   - not cause any memory inside a Rust allocation to be modified. 
21372162/// 
21382163/// * `dst` must be properly aligned. 
21392164/// 
21402165/// Note that even if `T` has size `0`, the pointer must be properly aligned. 
21412166/// 
21422167/// [valid]: self#safety 
21432168/// 
2144- /// Just like in C, whether an operation is volatile has no bearing whatsoever 
2145- /// on questions involving concurrent access from multiple threads. Volatile 
2146- /// accesses behave exactly like non-atomic accesses in that regard. In particular, 
2147- /// a race between a `write_volatile` and any other operation (reading or writing) 
2148- /// on the same location is undefined behavior. 
2149- /// 
21502169/// # Examples 
21512170/// 
21522171/// Basic usage: 
@@ -2170,12 +2189,11 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
21702189    unsafe  { 
21712190        ub_checks:: assert_unsafe_precondition!( 
21722191            check_language_ub, 
2173-             "ptr::write_volatile requires that the pointer argument is aligned and non-null " , 
2192+             "ptr::write_volatile requires that the pointer argument is aligned" , 
21742193            ( 
21752194                addr:  * mut  ( )  = dst as  * mut  ( ) , 
21762195                align:  usize  = align_of:: <T >( ) , 
2177-                 is_zst:  bool  = T :: IS_ZST , 
2178-             )  => ub_checks:: maybe_is_aligned_and_not_null( addr,  align,  is_zst) 
2196+             )  => ub_checks:: maybe_is_aligned( addr,  align) 
21792197        ) ; 
21802198        intrinsics:: volatile_store ( dst,  src) ; 
21812199    } 
0 commit comments