From 1b11ba87ae96deea5d71729ad389f46e101a1991 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Oct 2024 11:29:30 +0200 Subject: [PATCH] zero-sized accesses are fine on null pointers --- library/core/src/intrinsics.rs | 6 +++--- library/core/src/primitive_docs.rs | 9 ++++++--- library/core/src/ptr/mod.rs | 14 +++++++------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 69ad4f415196c..38e858626b94b 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -3138,7 +3138,7 @@ pub const fn ptr_metadata + ?Sized, M>(_ptr: *cons /// [violate memory safety][read-ownership]. /// /// Note that even if the effectively copied size (`count * size_of::()`) is -/// `0`, the pointers must be non-null and properly aligned. +/// `0`, the pointers must be properly aligned. /// /// [`read`]: crate::ptr::read /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value @@ -3261,7 +3261,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us /// [violate memory safety][read-ownership]. /// /// Note that even if the effectively copied size (`count * size_of::()`) is -/// `0`, the pointers must be non-null and properly aligned. +/// `0`, the pointers must be properly aligned. /// /// [`read`]: crate::ptr::read /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value @@ -3342,7 +3342,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// * `dst` must be properly aligned. /// /// Note that even if the effectively copied size (`count * size_of::()`) is -/// `0`, the pointer must be non-null and properly aligned. +/// `0`, the pointer must be properly aligned. /// /// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB) /// later if the written bytes are not a valid representation of some `T`. For instance, the diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 89936dc12ac36..22fd47b05962b 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -505,9 +505,11 @@ impl () {} /// /// *[See also the `std::ptr` module](ptr).* /// -/// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. -/// Raw pointers can be unaligned or [`null`]. However, when a raw pointer is -/// dereferenced (using the `*` operator), it must be non-null and aligned. +/// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. Raw pointers +/// can be out-of-bounds, unaligned, or [`null`]. However, when loading from or storing to a raw +/// pointer, it must be [valid] for the given access and aligned. When using a field expression, +/// tuple index expression, or array/slice index expression on a raw pointer, it follows the rules +/// of [in-bounds pointer arithmetic][`offset`]. /// /// Storing through a raw pointer using `*ptr = data` calls `drop` on the old value, so /// [`write`] must be used if the type has drop glue and memory is not already @@ -613,6 +615,7 @@ impl () {} /// [`offset`]: pointer::offset /// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw /// [`write`]: ptr::write +/// [valid]: ptr#safety #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer {} diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 09ff7f8cab173..f7036f30a99ec 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1024,7 +1024,7 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// /// * Both `x` and `y` must be properly aligned. /// -/// Note that even if `T` has size `0`, the pointers must be non-null and properly aligned. +/// Note that even if `T` has size `0`, the pointers must be properly aligned. /// /// [valid]: self#safety /// @@ -1110,7 +1110,7 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { /// beginning at `y` with the same size. /// /// Note that even if the effectively copied size (`count * size_of::()`) is `0`, -/// the pointers must be non-null and properly aligned. +/// the pointers must be properly aligned. /// /// [valid]: self#safety /// @@ -1243,7 +1243,7 @@ const unsafe fn swap_nonoverlapping_simple_untyped(x: *mut T, y: *mut T, coun /// /// * `dst` must point to a properly initialized value of type `T`. /// -/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned. +/// Note that even if `T` has size `0`, the pointer must be properly aligned. /// /// [valid]: self#safety /// @@ -1300,7 +1300,7 @@ pub const unsafe fn replace(dst: *mut T, src: T) -> T { /// /// * `src` must point to a properly initialized value of type `T`. /// -/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned. +/// Note that even if `T` has size `0`, the pointer must be properly aligned. /// /// # Examples /// @@ -1555,7 +1555,7 @@ pub const unsafe fn read_unaligned(src: *const T) -> T { /// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the /// case. /// -/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned. +/// Note that even if `T` has size `0`, the pointer must be properly aligned. /// /// [valid]: self#safety /// @@ -1774,7 +1774,7 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { /// However, storing non-[`Copy`] types in volatile memory is almost certainly /// incorrect. /// -/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned. +/// Note that even if `T` has size `0`, the pointer must be properly aligned. /// /// [valid]: self#safety /// [read-ownership]: read#ownership-of-the-returned-value @@ -1853,7 +1853,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// * `dst` must be properly aligned. /// -/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned. +/// Note that even if `T` has size `0`, the pointer must be properly aligned. /// /// [valid]: self#safety ///