Skip to content

Commit 3e59b78

Browse files
authored
Rollup merge of #121759 - RalfJung:addr_of, r=the8472
attempt to further clarify addr_of docs
2 parents 2f72206 + ec5e2dc commit 3e59b78

File tree

1 file changed

+63
-15
lines changed

1 file changed

+63
-15
lines changed

library/core/src/ptr/mod.rs

+63-15
Original file line numberDiff line numberDiff line change
@@ -2071,11 +2071,16 @@ impl<F: FnPtr> fmt::Debug for F {
20712071
/// as all other references. This macro can create a raw pointer *without* creating
20722072
/// a reference first.
20732073
///
2074-
/// The `expr` in `addr_of!(expr)` is evaluated as a place expression, but never loads
2075-
/// from the place or requires the place to be dereferenceable. This means that
2076-
/// `addr_of!(*ptr)` is defined behavior even if `ptr` is null, dangling, or misaligned.
2077-
/// Note however that `addr_of!((*ptr).field)` still requires the projection to
2078-
/// `field` to be in-bounds, using the same rules as [`offset`].
2074+
/// See [`addr_of_mut`] for how to create a pointer to uninitialized data.
2075+
/// Doing that with `addr_of` would not make much sense since one could only
2076+
/// read the data, and that would be Undefined Behavior.
2077+
///
2078+
/// # Safety
2079+
///
2080+
/// The `expr` in `addr_of!(expr)` is evaluated as a place expression, but never loads from the
2081+
/// place or requires the place to be dereferenceable. This means that `addr_of!((*ptr).field)`
2082+
/// still requires the projection to `field` to be in-bounds, using the same rules as [`offset`].
2083+
/// However, `addr_of!(*ptr)` is defined behavior even if `ptr` is null, dangling, or misaligned.
20792084
///
20802085
/// Note that `Deref`/`Index` coercions (and their mutable counterparts) are applied inside
20812086
/// `addr_of!` like everywhere else, in which case a reference is created to call `Deref::deref` or
@@ -2086,6 +2091,8 @@ impl<F: FnPtr> fmt::Debug for F {
20862091
///
20872092
/// # Example
20882093
///
2094+
/// **Correct usage: Creating a pointer to unaligned data**
2095+
///
20892096
/// ```
20902097
/// use std::ptr;
20912098
///
@@ -2101,9 +2108,27 @@ impl<F: FnPtr> fmt::Debug for F {
21012108
/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2);
21022109
/// ```
21032110
///
2104-
/// See [`addr_of_mut`] for how to create a pointer to uninitialized data.
2105-
/// Doing that with `addr_of` would not make much sense since one could only
2106-
/// read the data, and that would be Undefined Behavior.
2111+
/// **Incorrect usage: Out-of-bounds fields projection**
2112+
///
2113+
/// ```rust,no_run
2114+
/// use std::ptr;
2115+
///
2116+
/// #[repr(C)]
2117+
/// struct MyStruct {
2118+
/// field1: i32,
2119+
/// field2: i32,
2120+
/// }
2121+
///
2122+
/// let ptr: *const MyStruct = ptr::null();
2123+
/// let fieldptr = unsafe { ptr::addr_of!((*ptr).field2) }; // Undefined Behavior ⚠️
2124+
/// ```
2125+
///
2126+
/// The field projection `.field2` would offset the pointer by 4 bytes,
2127+
/// but the pointer is not in-bounds of an allocation for 4 bytes,
2128+
/// so this offset is Undefined Behavior.
2129+
/// See the [`offset`] docs for a full list of requirements for inbounds pointer arithmetic; the
2130+
/// same requirements apply to field projections, even inside `addr_of!`. (In particular, it makes
2131+
/// no difference whether the pointer is null or dangling.)
21072132
#[stable(feature = "raw_ref_macros", since = "1.51.0")]
21082133
#[rustc_macro_transparency = "semitransparent"]
21092134
#[allow_internal_unstable(raw_ref_op)]
@@ -2120,11 +2145,12 @@ pub macro addr_of($place:expr) {
21202145
/// as all other references. This macro can create a raw pointer *without* creating
21212146
/// a reference first.
21222147
///
2123-
/// The `expr` in `addr_of_mut!(expr)` is evaluated as a place expression, but never loads
2124-
/// from the place or requires the place to be dereferenceable. This means that
2125-
/// `addr_of_mut!(*ptr)` is defined behavior even if `ptr` is null, dangling, or misaligned.
2126-
/// Note however that `addr_of_mut!((*ptr).field)` still requires the projection to
2127-
/// `field` to be in-bounds, using the same rules as [`offset`].
2148+
/// # Safety
2149+
///
2150+
/// The `expr` in `addr_of_mut!(expr)` is evaluated as a place expression, but never loads from the
2151+
/// place or requires the place to be dereferenceable. This means that `addr_of_mut!((*ptr).field)`
2152+
/// still requires the projection to `field` to be in-bounds, using the same rules as [`offset`].
2153+
/// However, `addr_of_mut!(*ptr)` is defined behavior even if `ptr` is null, dangling, or misaligned.
21282154
///
21292155
/// Note that `Deref`/`Index` coercions (and their mutable counterparts) are applied inside
21302156
/// `addr_of_mut!` like everywhere else, in which case a reference is created to call `Deref::deref`
@@ -2135,7 +2161,7 @@ pub macro addr_of($place:expr) {
21352161
///
21362162
/// # Examples
21372163
///
2138-
/// **Creating a pointer to unaligned data:**
2164+
/// **Correct usage: Creating a pointer to unaligned data**
21392165
///
21402166
/// ```
21412167
/// use std::ptr;
@@ -2153,7 +2179,7 @@ pub macro addr_of($place:expr) {
21532179
/// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference.
21542180
/// ```
21552181
///
2156-
/// **Creating a pointer to uninitialized data:**
2182+
/// **Correct usage: Creating a pointer to uninitialized data**
21572183
///
21582184
/// ```rust
21592185
/// use std::{ptr, mem::MaybeUninit};
@@ -2169,6 +2195,28 @@ pub macro addr_of($place:expr) {
21692195
/// unsafe { f1_ptr.write(true); }
21702196
/// let init = unsafe { uninit.assume_init() };
21712197
/// ```
2198+
///
2199+
/// **Incorrect usage: Out-of-bounds fields projection**
2200+
///
2201+
/// ```rust,no_run
2202+
/// use std::ptr;
2203+
///
2204+
/// #[repr(C)]
2205+
/// struct MyStruct {
2206+
/// field1: i32,
2207+
/// field2: i32,
2208+
/// }
2209+
///
2210+
/// let ptr: *mut MyStruct = ptr::null_mut();
2211+
/// let fieldptr = unsafe { ptr::addr_of_mut!((*ptr).field2) }; // Undefined Behavior ⚠️
2212+
/// ```
2213+
///
2214+
/// The field projection `.field2` would offset the pointer by 4 bytes,
2215+
/// but the pointer is not in-bounds of an allocation for 4 bytes,
2216+
/// so this offset is Undefined Behavior.
2217+
/// See the [`offset`] docs for a full list of requirements for inbounds pointer arithmetic; the
2218+
/// same requirements apply to field projections, even inside `addr_of_mut!`. (In particular, it
2219+
/// makes no difference whether the pointer is null or dangling.)
21722220
#[stable(feature = "raw_ref_macros", since = "1.51.0")]
21732221
#[rustc_macro_transparency = "semitransparent"]
21742222
#[allow_internal_unstable(raw_ref_op)]

0 commit comments

Comments
 (0)