1 // SPDX-License-Identifier: GPL-2.0 2 3 // Copyright (C) 2024 Google LLC. 4 5 //! Helpers for implementing list traits safely. 6 7 /// Declares that this type has a `ListLinks<ID>` field at a fixed offset. 8 /// 9 /// This trait is only used to help implement `ListItem` safely. If `ListItem` is implemented 10 /// manually, then this trait is not needed. Use the [`impl_has_list_links!`] macro to implement 11 /// this trait. 12 /// 13 /// # Safety 14 /// 15 /// All values of this type must have a `ListLinks<ID>` field at the given offset. 16 /// 17 /// The behavior of `raw_get_list_links` must not be changed. 18 pub unsafe trait HasListLinks<const ID: u64 = 0> { 19 /// The offset of the `ListLinks` field. 20 const OFFSET: usize; 21 22 /// Returns a pointer to the [`ListLinks<T, ID>`] field. 23 /// 24 /// # Safety 25 /// 26 /// The provided pointer must point at a valid struct of type `Self`. 27 /// 28 /// [`ListLinks<T, ID>`]: crate::list::ListLinks 29 // We don't really need this method, but it's necessary for the implementation of 30 // `impl_has_list_links!` to be correct. 31 #[inline] 32 unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut crate::list::ListLinks<ID> { 33 // SAFETY: The caller promises that the pointer is valid. The implementer promises that the 34 // `OFFSET` constant is correct. 35 unsafe { ptr.cast::<u8>().add(Self::OFFSET).cast() } 36 } 37 } 38 39 /// Implements the [`HasListLinks`] trait for the given type. 40 #[macro_export] 41 macro_rules! impl_has_list_links { 42 ($(impl$({$($generics:tt)*})? 43 HasListLinks$(<$id:tt>)? 44 for $self:ty 45 { self$(.$field:ident)* } 46 )*) => {$( 47 // SAFETY: The implementation of `raw_get_list_links` only compiles if the field has the 48 // right type. 49 // 50 // The behavior of `raw_get_list_links` is not changed since the `addr_of_mut!` macro is 51 // equivalent to the pointer offset operation in the trait definition. 52 unsafe impl$(<$($generics)*>)? $crate::list::HasListLinks$(<$id>)? for $self { 53 const OFFSET: usize = ::core::mem::offset_of!(Self, $($field).*) as usize; 54 55 #[inline] 56 unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut $crate::list::ListLinks$(<$id>)? { 57 // SAFETY: The caller promises that the pointer is not dangling. We know that this 58 // expression doesn't follow any pointers, as the `offset_of!` invocation above 59 // would otherwise not compile. 60 unsafe { ::core::ptr::addr_of_mut!((*ptr)$(.$field)*) } 61 } 62 } 63 )*}; 64 } 65 pub use impl_has_list_links; 66 67 /// Declares that the `ListLinks<ID>` field in this struct is inside a `ListLinksSelfPtr<T, ID>`. 68 /// 69 /// # Safety 70 /// 71 /// The `ListLinks<ID>` field of this struct at the offset `HasListLinks<ID>::OFFSET` must be 72 /// inside a `ListLinksSelfPtr<T, ID>`. 73 pub unsafe trait HasSelfPtr<T: ?Sized, const ID: u64 = 0> 74 where 75 Self: HasListLinks<ID>, 76 { 77 } 78 79 /// Implements the [`HasListLinks`] and [`HasSelfPtr`] traits for the given type. 80 #[macro_export] 81 macro_rules! impl_has_list_links_self_ptr { 82 ($(impl$({$($generics:tt)*})? 83 HasSelfPtr<$item_type:ty $(, $id:tt)?> 84 for $self:ty 85 { self.$field:ident } 86 )*) => {$( 87 // SAFETY: The implementation of `raw_get_list_links` only compiles if the field has the 88 // right type. 89 unsafe impl$(<$($generics)*>)? $crate::list::HasSelfPtr<$item_type $(, $id)?> for $self {} 90 91 unsafe impl$(<$($generics)*>)? $crate::list::HasListLinks$(<$id>)? for $self { 92 const OFFSET: usize = ::core::mem::offset_of!(Self, $field) as usize; 93 94 #[inline] 95 unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut $crate::list::ListLinks$(<$id>)? { 96 // SAFETY: The caller promises that the pointer is not dangling. 97 let ptr: *mut $crate::list::ListLinksSelfPtr<$item_type $(, $id)?> = 98 unsafe { ::core::ptr::addr_of_mut!((*ptr).$field) }; 99 ptr.cast() 100 } 101 } 102 )*}; 103 } 104 pub use impl_has_list_links_self_ptr; 105 106 /// Implements the [`ListItem`] trait for the given type. 107 /// 108 /// Requires that the type implements [`HasListLinks`]. Use the [`impl_has_list_links!`] macro to 109 /// implement that trait. 110 /// 111 /// [`ListItem`]: crate::list::ListItem 112 #[macro_export] 113 macro_rules! impl_list_item { 114 ( 115 $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $self:ty { 116 using ListLinks; 117 })* 118 ) => {$( 119 // SAFETY: See GUARANTEES comment on each method. 120 unsafe impl$(<$($generics)*>)? $crate::list::ListItem<$num> for $self { 121 // GUARANTEES: 122 // * This returns the same pointer as `prepare_to_insert` because `prepare_to_insert` 123 // is implemented in terms of `view_links`. 124 // * By the type invariants of `ListLinks`, the `ListLinks` has two null pointers when 125 // this value is not in a list. 126 unsafe fn view_links(me: *const Self) -> *mut $crate::list::ListLinks<$num> { 127 // SAFETY: The caller guarantees that `me` points at a valid value of type `Self`. 128 unsafe { 129 <Self as $crate::list::HasListLinks<$num>>::raw_get_list_links(me.cast_mut()) 130 } 131 } 132 133 // GUARANTEES: 134 // * `me` originates from the most recent call to `prepare_to_insert`, which just added 135 // `offset` to the pointer passed to `prepare_to_insert`. This method subtracts 136 // `offset` from `me` so it returns the pointer originally passed to 137 // `prepare_to_insert`. 138 // * The pointer remains valid until the next call to `post_remove` because the caller 139 // of the most recent call to `prepare_to_insert` promised to retain ownership of the 140 // `ListArc` containing `Self` until the next call to `post_remove`. The value cannot 141 // be destroyed while a `ListArc` reference exists. 142 unsafe fn view_value(me: *mut $crate::list::ListLinks<$num>) -> *const Self { 143 let offset = <Self as $crate::list::HasListLinks<$num>>::OFFSET; 144 // SAFETY: `me` originates from the most recent call to `prepare_to_insert`, so it 145 // points at the field at offset `offset` in a value of type `Self`. Thus, 146 // subtracting `offset` from `me` is still in-bounds of the allocation. 147 unsafe { (me as *const u8).sub(offset) as *const Self } 148 } 149 150 // GUARANTEES: 151 // This implementation of `ListItem` will not give out exclusive access to the same 152 // `ListLinks` several times because calls to `prepare_to_insert` and `post_remove` 153 // must alternate and exclusive access is given up when `post_remove` is called. 154 // 155 // Other invocations of `impl_list_item!` also cannot give out exclusive access to the 156 // same `ListLinks` because you can only implement `ListItem` once for each value of 157 // `ID`, and the `ListLinks` fields only work with the specified `ID`. 158 unsafe fn prepare_to_insert(me: *const Self) -> *mut $crate::list::ListLinks<$num> { 159 // SAFETY: The caller promises that `me` points at a valid value. 160 unsafe { <Self as $crate::list::ListItem<$num>>::view_links(me) } 161 } 162 163 // GUARANTEES: 164 // * `me` originates from the most recent call to `prepare_to_insert`, which just added 165 // `offset` to the pointer passed to `prepare_to_insert`. This method subtracts 166 // `offset` from `me` so it returns the pointer originally passed to 167 // `prepare_to_insert`. 168 unsafe fn post_remove(me: *mut $crate::list::ListLinks<$num>) -> *const Self { 169 let offset = <Self as $crate::list::HasListLinks<$num>>::OFFSET; 170 // SAFETY: `me` originates from the most recent call to `prepare_to_insert`, so it 171 // points at the field at offset `offset` in a value of type `Self`. Thus, 172 // subtracting `offset` from `me` is still in-bounds of the allocation. 173 unsafe { (me as *const u8).sub(offset) as *const Self } 174 } 175 } 176 )*}; 177 178 ( 179 $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $self:ty { 180 using ListLinksSelfPtr; 181 })* 182 ) => {$( 183 // SAFETY: See GUARANTEES comment on each method. 184 unsafe impl$(<$($generics)*>)? $crate::list::ListItem<$num> for $self { 185 // GUARANTEES: 186 // This implementation of `ListItem` will not give out exclusive access to the same 187 // `ListLinks` several times because calls to `prepare_to_insert` and `post_remove` 188 // must alternate and exclusive access is given up when `post_remove` is called. 189 // 190 // Other invocations of `impl_list_item!` also cannot give out exclusive access to the 191 // same `ListLinks` because you can only implement `ListItem` once for each value of 192 // `ID`, and the `ListLinks` fields only work with the specified `ID`. 193 unsafe fn prepare_to_insert(me: *const Self) -> *mut $crate::list::ListLinks<$num> { 194 // SAFETY: The caller promises that `me` points at a valid value of type `Self`. 195 let links_field = unsafe { <Self as $crate::list::ListItem<$num>>::view_links(me) }; 196 197 let spoff = $crate::list::ListLinksSelfPtr::<Self, $num>::LIST_LINKS_SELF_PTR_OFFSET; 198 // Goes via the offset as the field is private. 199 // 200 // SAFETY: The constant is equal to `offset_of!(ListLinksSelfPtr, self_ptr)`, so 201 // the pointer stays in bounds of the allocation. 202 let self_ptr = unsafe { (links_field as *const u8).add(spoff) } 203 as *const $crate::types::Opaque<*const Self>; 204 let cell_inner = $crate::types::Opaque::cast_into(self_ptr); 205 206 // SAFETY: This value is not accessed in any other places than `prepare_to_insert`, 207 // `post_remove`, or `view_value`. By the safety requirements of those methods, 208 // none of these three methods may be called in parallel with this call to 209 // `prepare_to_insert`, so this write will not race with any other access to the 210 // value. 211 unsafe { ::core::ptr::write(cell_inner, me) }; 212 213 links_field 214 } 215 216 // GUARANTEES: 217 // * This returns the same pointer as `prepare_to_insert` because `prepare_to_insert` 218 // returns the return value of `view_links`. 219 // * By the type invariants of `ListLinks`, the `ListLinks` has two null pointers when 220 // this value is not in a list. 221 unsafe fn view_links(me: *const Self) -> *mut $crate::list::ListLinks<$num> { 222 // SAFETY: The caller promises that `me` points at a valid value of type `Self`. 223 unsafe { 224 <Self as $crate::list::HasListLinks<$num>>::raw_get_list_links(me.cast_mut()) 225 } 226 } 227 228 // This function is also used as the implementation of `post_remove`, so the caller 229 // may choose to satisfy the safety requirements of `post_remove` instead of the safety 230 // requirements for `view_value`. 231 // 232 // GUARANTEES: (always) 233 // * This returns the same pointer as the one passed to the most recent call to 234 // `prepare_to_insert` since that call wrote that pointer to this location. The value 235 // is only modified in `prepare_to_insert`, so it has not been modified since the 236 // most recent call. 237 // 238 // GUARANTEES: (only when using the `view_value` safety requirements) 239 // * The pointer remains valid until the next call to `post_remove` because the caller 240 // of the most recent call to `prepare_to_insert` promised to retain ownership of the 241 // `ListArc` containing `Self` until the next call to `post_remove`. The value cannot 242 // be destroyed while a `ListArc` reference exists. 243 unsafe fn view_value(links_field: *mut $crate::list::ListLinks<$num>) -> *const Self { 244 let spoff = $crate::list::ListLinksSelfPtr::<Self, $num>::LIST_LINKS_SELF_PTR_OFFSET; 245 // SAFETY: The constant is equal to `offset_of!(ListLinksSelfPtr, self_ptr)`, so 246 // the pointer stays in bounds of the allocation. 247 let self_ptr = unsafe { (links_field as *const u8).add(spoff) } 248 as *const ::core::cell::UnsafeCell<*const Self>; 249 let cell_inner = ::core::cell::UnsafeCell::raw_get(self_ptr); 250 // SAFETY: This is not a data race, because the only function that writes to this 251 // value is `prepare_to_insert`, but by the safety requirements the 252 // `prepare_to_insert` method may not be called in parallel with `view_value` or 253 // `post_remove`. 254 unsafe { ::core::ptr::read(cell_inner) } 255 } 256 257 // GUARANTEES: 258 // The first guarantee of `view_value` is exactly what `post_remove` guarantees. 259 unsafe fn post_remove(me: *mut $crate::list::ListLinks<$num>) -> *const Self { 260 // SAFETY: This specific implementation of `view_value` allows the caller to 261 // promise the safety requirements of `post_remove` instead of the safety 262 // requirements for `view_value`. 263 unsafe { <Self as $crate::list::ListItem<$num>>::view_value(me) } 264 } 265 } 266 )*}; 267 } 268 pub use impl_list_item; 269