@@ -2071,11 +2071,16 @@ impl<F: FnPtr> fmt::Debug for F {
2071
2071
/// as all other references. This macro can create a raw pointer *without* creating
2072
2072
/// a reference first.
2073
2073
///
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.
2079
2084
///
2080
2085
/// Note that `Deref`/`Index` coercions (and their mutable counterparts) are applied inside
2081
2086
/// `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 {
2086
2091
///
2087
2092
/// # Example
2088
2093
///
2094
+ /// **Correct usage: Creating a pointer to unaligned data**
2095
+ ///
2089
2096
/// ```
2090
2097
/// use std::ptr;
2091
2098
///
@@ -2101,9 +2108,27 @@ impl<F: FnPtr> fmt::Debug for F {
2101
2108
/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2);
2102
2109
/// ```
2103
2110
///
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.)
2107
2132
#[ stable( feature = "raw_ref_macros" , since = "1.51.0" ) ]
2108
2133
#[ rustc_macro_transparency = "semitransparent" ]
2109
2134
#[ allow_internal_unstable( raw_ref_op) ]
@@ -2120,11 +2145,12 @@ pub macro addr_of($place:expr) {
2120
2145
/// as all other references. This macro can create a raw pointer *without* creating
2121
2146
/// a reference first.
2122
2147
///
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.
2128
2154
///
2129
2155
/// Note that `Deref`/`Index` coercions (and their mutable counterparts) are applied inside
2130
2156
/// `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) {
2135
2161
///
2136
2162
/// # Examples
2137
2163
///
2138
- /// **Creating a pointer to unaligned data: **
2164
+ /// **Correct usage: Creating a pointer to unaligned data**
2139
2165
///
2140
2166
/// ```
2141
2167
/// use std::ptr;
@@ -2153,7 +2179,7 @@ pub macro addr_of($place:expr) {
2153
2179
/// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference.
2154
2180
/// ```
2155
2181
///
2156
- /// **Creating a pointer to uninitialized data: **
2182
+ /// **Correct usage: Creating a pointer to uninitialized data**
2157
2183
///
2158
2184
/// ```rust
2159
2185
/// use std::{ptr, mem::MaybeUninit};
@@ -2169,6 +2195,28 @@ pub macro addr_of($place:expr) {
2169
2195
/// unsafe { f1_ptr.write(true); }
2170
2196
/// let init = unsafe { uninit.assume_init() };
2171
2197
/// ```
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.)
2172
2220
#[ stable( feature = "raw_ref_macros" , since = "1.51.0" ) ]
2173
2221
#[ rustc_macro_transparency = "semitransparent" ]
2174
2222
#[ allow_internal_unstable( raw_ref_op) ]
0 commit comments