1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Infrastructure for handling projections. 4 5 use core::{ 6 mem::MaybeUninit, 7 ops::Deref, // 8 }; 9 10 use crate::prelude::*; 11 12 /// Error raised when a projection is attempted on an array or slice out of bounds. 13 pub struct OutOfBound; 14 15 impl From<OutOfBound> for Error { 16 #[inline(always)] 17 fn from(_: OutOfBound) -> Self { 18 ERANGE 19 } 20 } 21 22 /// A helper trait to perform index projection. 23 /// 24 /// This is similar to [`core::slice::SliceIndex`], but operates on raw pointers safely and 25 /// fallibly. 26 /// 27 /// # Safety 28 /// 29 /// For a given input pointer `slice` and return value `output`, the implementation of `index`, 30 /// `build_index` and `get` (if [`Some`] is returned) must ensure that: 31 /// - `output` has the same provenance as `slice`; 32 /// - `output.byte_offset_from(slice)` is between 0 to 33 /// `KnownSize::size(slice) - KnownSize::size(output)`. 34 /// 35 /// This means that if the input pointer is valid, then the pointer returned by `get`, `index` 36 /// or `build_index` is also valid. 37 #[diagnostic::on_unimplemented(message = "`{Self}` cannot be used to index `{T}`")] 38 #[doc(hidden)] 39 pub unsafe trait ProjectIndex<T: ?Sized>: Sized { 40 type Output: ?Sized; 41 42 /// Returns an index-projected pointer, if in bounds. 43 fn get(self, slice: *mut T) -> Option<*mut Self::Output>; 44 45 /// Returns an index-projected pointer; panic if out of bounds. 46 fn index(self, slice: *mut T) -> *mut Self::Output; 47 48 /// Returns an index-projected pointer; fail the build if it cannot be proved to be in bounds. 49 #[inline(always)] 50 fn build_index(self, slice: *mut T) -> *mut Self::Output { 51 match Self::get(self, slice) { 52 Some(v) => v, 53 None => build_error!(), 54 } 55 } 56 } 57 58 // Forward array impl to slice impl. 59 // 60 // SAFETY: Safety requirement guaranteed by the forwarded impl. 61 unsafe impl<T, I, const N: usize> ProjectIndex<[T; N]> for I 62 where 63 I: ProjectIndex<[T]>, 64 { 65 type Output = <I as ProjectIndex<[T]>>::Output; 66 67 #[inline(always)] 68 fn get(self, slice: *mut [T; N]) -> Option<*mut Self::Output> { 69 <I as ProjectIndex<[T]>>::get(self, slice) 70 } 71 72 #[inline(always)] 73 fn index(self, slice: *mut [T; N]) -> *mut Self::Output { 74 <I as ProjectIndex<[T]>>::index(self, slice) 75 } 76 77 #[inline(always)] 78 fn build_index(self, slice: *mut [T; N]) -> *mut Self::Output { 79 <I as ProjectIndex<[T]>>::build_index(self, slice) 80 } 81 } 82 83 // SAFETY: `get`-returned pointer has the same provenance as `slice` and the offset is checked to 84 // not exceed the required bound. 85 unsafe impl<T> ProjectIndex<[T]> for usize { 86 type Output = T; 87 88 #[inline(always)] 89 fn get(self, slice: *mut [T]) -> Option<*mut T> { 90 if self >= slice.len() { 91 None 92 } else { 93 Some(slice.cast::<T>().wrapping_add(self)) 94 } 95 } 96 97 #[inline(always)] 98 fn index(self, slice: *mut [T]) -> *mut T { 99 // Leverage Rust built-in operators for bounds checking. 100 // SAFETY: All non-null and aligned pointers are valid for ZST read. 101 let zst_slice = 102 unsafe { core::slice::from_raw_parts::<()>(core::ptr::dangling(), slice.len()) }; 103 let () = zst_slice[self]; 104 slice.cast::<T>().wrapping_add(self) 105 } 106 } 107 108 // SAFETY: `get`-returned pointer has the same provenance as `slice` and the offset is checked to 109 // not exceed the required bound. 110 unsafe impl<T> ProjectIndex<[T]> for core::ops::Range<usize> { 111 type Output = [T]; 112 113 #[inline(always)] 114 fn get(self, slice: *mut [T]) -> Option<*mut [T]> { 115 let new_len = self.end.checked_sub(self.start)?; 116 if self.end > slice.len() { 117 return None; 118 } 119 Some(core::ptr::slice_from_raw_parts_mut( 120 slice.cast::<T>().wrapping_add(self.start), 121 new_len, 122 )) 123 } 124 125 #[inline(always)] 126 fn index(self, slice: *mut [T]) -> *mut [T] { 127 // Leverage Rust built-in operators for bounds checking. 128 // SAFETY: All non-null and aligned pointers are valid for ZST read. 129 let zst_slice = 130 unsafe { core::slice::from_raw_parts::<()>(core::ptr::dangling(), slice.len()) }; 131 _ = zst_slice[self.clone()]; 132 133 // SAFETY: Bounds checked. 134 unsafe { self.get(slice).unwrap_unchecked() } 135 } 136 } 137 138 // SAFETY: Safety requirement guaranteed by the forwarded impl. 139 unsafe impl<T> ProjectIndex<[T]> for core::ops::RangeTo<usize> { 140 type Output = [T]; 141 142 #[inline(always)] 143 fn get(self, slice: *mut [T]) -> Option<*mut [T]> { 144 (0..self.end).get(slice) 145 } 146 147 #[inline(always)] 148 fn index(self, slice: *mut [T]) -> *mut [T] { 149 (0..self.end).index(slice) 150 } 151 } 152 153 // SAFETY: Safety requirement guaranteed by the forwarded impl. 154 unsafe impl<T> ProjectIndex<[T]> for core::ops::RangeFrom<usize> { 155 type Output = [T]; 156 157 #[inline(always)] 158 fn get(self, slice: *mut [T]) -> Option<*mut [T]> { 159 (self.start..slice.len()).get(slice) 160 } 161 162 #[inline(always)] 163 fn index(self, slice: *mut [T]) -> *mut [T] { 164 (self.start..slice.len()).index(slice) 165 } 166 } 167 168 // SAFETY: `get` returned the pointer as is, so it always has the same provenance and offset of 0. 169 unsafe impl<T> ProjectIndex<[T]> for core::ops::RangeFull { 170 type Output = [T]; 171 172 #[inline(always)] 173 fn get(self, slice: *mut [T]) -> Option<*mut [T]> { 174 Some(slice) 175 } 176 177 #[inline(always)] 178 fn index(self, slice: *mut [T]) -> *mut [T] { 179 slice 180 } 181 } 182 183 /// A helper trait to perform field projection. 184 /// 185 /// This trait has a `DEREF` generic parameter so it can be implemented twice for types that 186 /// implement [`Deref`]. This will cause an ambiguity error and thus block [`Deref`] types being 187 /// used as base of projection, as they can inject unsoundness. Users therefore must not specify 188 /// `DEREF` and should always leave it to be inferred. 189 /// 190 /// # Safety 191 /// 192 /// `proj` may only invoke `f` with a valid allocation, as the documentation of [`Self::proj`] 193 /// describes. 194 #[doc(hidden)] 195 pub unsafe trait ProjectField<const DEREF: bool> { 196 /// Project a pointer to a type to a pointer of a field. 197 /// 198 /// `f` may only be invoked with a valid allocation so it can safely obtain raw pointers to 199 /// fields using `&raw mut`. 200 /// 201 /// This is needed because `base` might not point to a valid allocation, while `&raw mut` 202 /// requires pointers to be in bounds of a valid allocation. 203 /// 204 /// # Safety 205 /// 206 /// `f` must return a pointer in bounds of the provided pointer. 207 unsafe fn proj<F>(base: *mut Self, f: impl FnOnce(*mut Self) -> *mut F) -> *mut F; 208 } 209 210 // NOTE: in theory, this API should work for `T: ?Sized` and `F: ?Sized`, too. However, we cannot 211 // currently support that as we need to obtain a valid allocation that `&raw const` can operate on. 212 // 213 // SAFETY: `proj` invokes `f` with valid allocation. 214 unsafe impl<T> ProjectField<false> for T { 215 #[inline(always)] 216 unsafe fn proj<F>(base: *mut Self, f: impl FnOnce(*mut Self) -> *mut F) -> *mut F { 217 // Create a valid allocation to start projection, as `base` is not necessarily so. The 218 // memory is never actually used so it will be optimized out, so it should work even for 219 // very large `T` (`memoffset` crate also relies on this). To be extra certain, we also 220 // annotate `f` closure with `#[inline(always)]` in the macro. 221 let mut place = MaybeUninit::uninit(); 222 let place_base = place.as_mut_ptr(); 223 let field = f(place_base); 224 // SAFETY: `field` is in bounds from `base` per safety requirement. 225 let offset = unsafe { field.byte_offset_from(place_base) }; 226 // Use `wrapping_byte_offset` as `base` does not need to be of valid allocation. 227 base.wrapping_byte_offset(offset).cast() 228 } 229 } 230 231 // SAFETY: Vacuously satisfied. 232 unsafe impl<T: Deref> ProjectField<true> for T { 233 #[inline(always)] 234 unsafe fn proj<F>(_: *mut Self, _: impl FnOnce(*mut Self) -> *mut F) -> *mut F { 235 build_error!("this function is a guard against `Deref` impl and is never invoked"); 236 } 237 } 238 239 /// Create a projection from a raw pointer. 240 /// 241 /// The projected pointer is within the memory region marked by the input pointer. There is no 242 /// requirement that the input raw pointer needs to be valid, so this macro may be used for 243 /// projecting pointers outside normal address space, e.g. I/O pointers. However, if the input 244 /// pointer is valid, the projected pointer is also valid. 245 /// 246 /// Supported projections include field projections and index projections. 247 /// It is not allowed to project into types that implement custom [`Deref`] or 248 /// [`Index`](core::ops::Index). 249 /// 250 /// The macro has basic syntax of `kernel::ptr::project!(ptr, projection)`, where `ptr` is an 251 /// expression that evaluates to a raw pointer which serves as the base of projection. `projection` 252 /// can be a projection expression of form `.field` (normally identifier, or numeral in case of 253 /// tuple structs) or of form `[index]`. 254 /// 255 /// If a mutable pointer is needed, the macro input can be prefixed with the `mut` keyword, i.e. 256 /// `kernel::ptr::project!(mut ptr, projection)`. By default, a const pointer is created. 257 /// 258 /// The `ptr::project!` macro can perform both fallible indexing and build-time checked indexing. 259 /// The syntax is of the form `[<flavor>: index]` where `flavor` indicates the way of handling 260 /// index out-of-bounds errors. 261 /// - `try` will raise an [`OutOfBound`] error (which is convertible to [`ERANGE`]). 262 /// - `build` will use the [`build_assert!`] mechanism to have the compiler validate the index is 263 /// in bounds. 264 /// - `panic` will cause a Rust [`panic!`] if the index goes out of bounds. 265 /// 266 /// # Examples 267 /// 268 /// Field projections are performed with `.field_name`: 269 /// 270 /// ``` 271 /// struct MyStruct { field: u32, } 272 /// let ptr: *const MyStruct = core::ptr::dangling(); 273 /// let field_ptr: *const u32 = kernel::ptr::project!(ptr, .field); 274 /// 275 /// struct MyTupleStruct(u32, u32); 276 /// 277 /// fn proj(ptr: *const MyTupleStruct) { 278 /// let field_ptr: *const u32 = kernel::ptr::project!(ptr, .1); 279 /// } 280 /// ``` 281 /// 282 /// Index projections are performed with `[<flavor>: index]`, where `flavor` is `try`, `build` or 283 /// `panic`: 284 /// 285 /// ``` 286 /// fn proj(ptr: *const [u8; 32]) -> Result { 287 /// let field_ptr: *const u8 = kernel::ptr::project!(ptr, [build: 1]); 288 /// // The following invocation, if uncommented, would fail the build. 289 /// // 290 /// // kernel::ptr::project!(ptr, [build: 128]); 291 /// 292 /// // This will raise an `OutOfBound` error (which is convertible to `ERANGE`). 293 /// kernel::ptr::project!(ptr, [try: 128]); 294 /// 295 /// // This will panic at runtime if executed. 296 /// kernel::ptr::project!(ptr, [panic: 128]); 297 /// Ok(()) 298 /// } 299 /// ``` 300 /// 301 /// If you need to match on the error instead of propagate, put the invocation inside a closure: 302 /// 303 /// ``` 304 /// let ptr: *const [u8; 32] = core::ptr::dangling(); 305 /// let field_ptr: Result<*const u8> = (|| -> Result<_> { 306 /// Ok(kernel::ptr::project!(ptr, [try: 128])) 307 /// })(); 308 /// assert!(field_ptr.is_err()); 309 /// ``` 310 /// 311 /// For mutable pointers, put `mut` as the first token in macro invocation. 312 /// 313 /// ``` 314 /// let ptr: *mut [(u8, u16); 32] = core::ptr::dangling_mut(); 315 /// let field_ptr: *mut u16 = kernel::ptr::project!(mut ptr, [build: 1].1); 316 /// ``` 317 #[macro_export] 318 macro_rules! project_pointer { 319 (@gen $ptr:ident, ) => {}; 320 // Field projection. `$field` needs to be `tt` to support tuple index like `.0`. 321 (@gen $ptr:ident, .$field:tt $($rest:tt)*) => { 322 // SAFETY: The provided closure always returns an in-bounds pointer. 323 let $ptr = unsafe { 324 $crate::ptr::projection::ProjectField::proj($ptr, #[inline(always)] |ptr| { 325 // Check unaligned field. Not all users (e.g. DMA) can handle unaligned 326 // projections. 327 if false { 328 let _ = &(*ptr).$field; 329 } 330 // SAFETY: `$field` is in bounds, and no implicit `Deref` is possible (if the 331 // type implements `Deref`, Rust cannot infer the generic parameter `DEREF`). 332 &raw mut (*ptr).$field 333 }) 334 }; 335 $crate::ptr::project!(@gen $ptr, $($rest)*) 336 }; 337 // Fallible index projection. 338 (@gen $ptr:ident, [try: $index:expr] $($rest:tt)*) => { 339 let $ptr = $crate::ptr::projection::ProjectIndex::get($index, $ptr) 340 .ok_or($crate::ptr::projection::OutOfBound)?; 341 $crate::ptr::project!(@gen $ptr, $($rest)*) 342 }; 343 // Panicking index projection. 344 (@gen $ptr:ident, [panic: $index:expr] $($rest:tt)*) => { 345 let $ptr = $crate::ptr::projection::ProjectIndex::index($index, $ptr); 346 $crate::ptr::project!(@gen $ptr, $($rest)*) 347 }; 348 // Build-time checked index projection. 349 (@gen $ptr:ident, [build: $index:expr] $($rest:tt)*) => { 350 let $ptr = $crate::ptr::projection::ProjectIndex::build_index($index, $ptr); 351 $crate::ptr::project!(@gen $ptr, $($rest)*) 352 }; 353 354 // For compatibility 355 (@gen $ptr:ident, [$index:expr]? $($rest:tt)*) => { 356 $crate::ptr::project!(@gen $ptr, [try: $index] $($rest)*) 357 }; 358 (@gen $ptr:ident, [$index:expr] $($rest:tt)*) => { 359 $crate::ptr::project!(@gen $ptr, [build: $index] $($rest)*) 360 }; 361 362 (mut $ptr:expr, $($proj:tt)*) => {{ 363 let ptr: *mut _ = $ptr; 364 $crate::ptr::project!(@gen ptr, $($proj)*); 365 ptr 366 }}; 367 ($ptr:expr, $($proj:tt)*) => {{ 368 let ptr = <*const _>::cast_mut($ptr); 369 // We currently always project using mutable pointer, as it is not decided whether `&raw 370 // const` allows the resulting pointer to be mutated (see documentation of `addr_of!`). 371 $crate::ptr::project!(@gen ptr, $($proj)*); 372 ptr.cast_const() 373 }}; 374 } 375