|
| 1 | +// ignore-tidy-undocumented-unsafe |
| 2 | + |
| 3 | +use crate::cmp; |
| 4 | +use crate::fmt; |
| 5 | +use crate::mem; |
| 6 | +use crate::num::NonZeroUsize; |
| 7 | +use crate::ptr::NonNull; |
| 8 | + |
| 9 | +const fn size_align<T>() -> (usize, usize) { |
| 10 | + (mem::size_of::<T>(), mem::align_of::<T>()) |
| 11 | +} |
| 12 | + |
| 13 | +/// Layout of a block of memory. |
| 14 | +/// |
| 15 | +/// An instance of `Layout` describes a particular layout of memory. |
| 16 | +/// You build a `Layout` up as an input to give to an allocator. |
| 17 | +/// |
| 18 | +/// All layouts have an associated size and a power-of-two alignment. |
| 19 | +/// |
| 20 | +/// (Note that layouts are *not* required to have non-zero size, |
| 21 | +/// even though `GlobalAlloc` requires that all memory requests |
| 22 | +/// be non-zero in size. A caller must either ensure that conditions |
| 23 | +/// like this are met, use specific allocators with looser |
| 24 | +/// requirements, or use the more lenient `AllocRef` interface.) |
| 25 | +#[stable(feature = "alloc_layout", since = "1.28.0")] |
| 26 | +#[derive(Copy, Clone, Debug, PartialEq, Eq)] |
| 27 | +#[lang = "alloc_layout"] |
| 28 | +pub struct Layout { |
| 29 | + // size of the requested block of memory, measured in bytes. |
| 30 | + size_: usize, |
| 31 | + |
| 32 | + // alignment of the requested block of memory, measured in bytes. |
| 33 | + // we ensure that this is always a power-of-two, because API's |
| 34 | + // like `posix_memalign` require it and it is a reasonable |
| 35 | + // constraint to impose on Layout constructors. |
| 36 | + // |
| 37 | + // (However, we do not analogously require `align >= sizeof(void*)`, |
| 38 | + // even though that is *also* a requirement of `posix_memalign`.) |
| 39 | + align_: NonZeroUsize, |
| 40 | +} |
| 41 | + |
| 42 | +impl Layout { |
| 43 | + /// Constructs a `Layout` from a given `size` and `align`, |
| 44 | + /// or returns `LayoutErr` if any of the following conditions |
| 45 | + /// are not met: |
| 46 | + /// |
| 47 | + /// * `align` must not be zero, |
| 48 | + /// |
| 49 | + /// * `align` must be a power of two, |
| 50 | + /// |
| 51 | + /// * `size`, when rounded up to the nearest multiple of `align`, |
| 52 | + /// must not overflow (i.e., the rounded value must be less than |
| 53 | + /// or equal to `usize::MAX`). |
| 54 | + #[stable(feature = "alloc_layout", since = "1.28.0")] |
| 55 | + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] |
| 56 | + #[inline] |
| 57 | + pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> { |
| 58 | + if !align.is_power_of_two() { |
| 59 | + return Err(LayoutErr { private: () }); |
| 60 | + } |
| 61 | + |
| 62 | + // (power-of-two implies align != 0.) |
| 63 | + |
| 64 | + // Rounded up size is: |
| 65 | + // size_rounded_up = (size + align - 1) & !(align - 1); |
| 66 | + // |
| 67 | + // We know from above that align != 0. If adding (align - 1) |
| 68 | + // does not overflow, then rounding up will be fine. |
| 69 | + // |
| 70 | + // Conversely, &-masking with !(align - 1) will subtract off |
| 71 | + // only low-order-bits. Thus if overflow occurs with the sum, |
| 72 | + // the &-mask cannot subtract enough to undo that overflow. |
| 73 | + // |
| 74 | + // Above implies that checking for summation overflow is both |
| 75 | + // necessary and sufficient. |
| 76 | + if size > usize::MAX - (align - 1) { |
| 77 | + return Err(LayoutErr { private: () }); |
| 78 | + } |
| 79 | + |
| 80 | + unsafe { Ok(Layout::from_size_align_unchecked(size, align)) } |
| 81 | + } |
| 82 | + |
| 83 | + /// Creates a layout, bypassing all checks. |
| 84 | + /// |
| 85 | + /// # Safety |
| 86 | + /// |
| 87 | + /// This function is unsafe as it does not verify the preconditions from |
| 88 | + /// [`Layout::from_size_align`](#method.from_size_align). |
| 89 | + #[stable(feature = "alloc_layout", since = "1.28.0")] |
| 90 | + #[rustc_const_stable(feature = "alloc_layout", since = "1.28.0")] |
| 91 | + #[inline] |
| 92 | + pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { |
| 93 | + Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) } |
| 94 | + } |
| 95 | + |
| 96 | + /// The minimum size in bytes for a memory block of this layout. |
| 97 | + #[stable(feature = "alloc_layout", since = "1.28.0")] |
| 98 | + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] |
| 99 | + #[inline] |
| 100 | + pub const fn size(&self) -> usize { |
| 101 | + self.size_ |
| 102 | + } |
| 103 | + |
| 104 | + /// The minimum byte alignment for a memory block of this layout. |
| 105 | + #[stable(feature = "alloc_layout", since = "1.28.0")] |
| 106 | + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] |
| 107 | + #[inline] |
| 108 | + pub const fn align(&self) -> usize { |
| 109 | + self.align_.get() |
| 110 | + } |
| 111 | + |
| 112 | + /// Constructs a `Layout` suitable for holding a value of type `T`. |
| 113 | + #[stable(feature = "alloc_layout", since = "1.28.0")] |
| 114 | + #[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")] |
| 115 | + #[inline] |
| 116 | + pub const fn new<T>() -> Self { |
| 117 | + let (size, align) = size_align::<T>(); |
| 118 | + // Note that the align is guaranteed by rustc to be a power of two and |
| 119 | + // the size+align combo is guaranteed to fit in our address space. As a |
| 120 | + // result use the unchecked constructor here to avoid inserting code |
| 121 | + // that panics if it isn't optimized well enough. |
| 122 | + unsafe { Layout::from_size_align_unchecked(size, align) } |
| 123 | + } |
| 124 | + |
| 125 | + /// Produces layout describing a record that could be used to |
| 126 | + /// allocate backing structure for `T` (which could be a trait |
| 127 | + /// or other unsized type like a slice). |
| 128 | + #[stable(feature = "alloc_layout", since = "1.28.0")] |
| 129 | + #[inline] |
| 130 | + pub fn for_value<T: ?Sized>(t: &T) -> Self { |
| 131 | + let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); |
| 132 | + // See rationale in `new` for why this is using an unsafe variant below |
| 133 | + debug_assert!(Layout::from_size_align(size, align).is_ok()); |
| 134 | + unsafe { Layout::from_size_align_unchecked(size, align) } |
| 135 | + } |
| 136 | + |
| 137 | + /// Creates a `NonNull` that is dangling, but well-aligned for this Layout. |
| 138 | + /// |
| 139 | + /// Note that the pointer value may potentially represent a valid pointer, |
| 140 | + /// which means this must not be used as a "not yet initialized" |
| 141 | + /// sentinel value. Types that lazily allocate must track initialization by |
| 142 | + /// some other means. |
| 143 | + #[unstable(feature = "alloc_layout_extra", issue = "55724")] |
| 144 | + pub const fn dangling(&self) -> NonNull<u8> { |
| 145 | + // align is non-zero and a power of two |
| 146 | + unsafe { NonNull::new_unchecked(self.align() as *mut u8) } |
| 147 | + } |
| 148 | + |
| 149 | + /// Creates a layout describing the record that can hold a value |
| 150 | + /// of the same layout as `self`, but that also is aligned to |
| 151 | + /// alignment `align` (measured in bytes). |
| 152 | + /// |
| 153 | + /// If `self` already meets the prescribed alignment, then returns |
| 154 | + /// `self`. |
| 155 | + /// |
| 156 | + /// Note that this method does not add any padding to the overall |
| 157 | + /// size, regardless of whether the returned layout has a different |
| 158 | + /// alignment. In other words, if `K` has size 16, `K.align_to(32)` |
| 159 | + /// will *still* have size 16. |
| 160 | + /// |
| 161 | + /// Returns an error if the combination of `self.size()` and the given |
| 162 | + /// `align` violates the conditions listed in |
| 163 | + /// [`Layout::from_size_align`](#method.from_size_align). |
| 164 | + #[unstable(feature = "alloc_layout_extra", issue = "55724")] |
| 165 | + #[inline] |
| 166 | + pub fn align_to(&self, align: usize) -> Result<Self, LayoutErr> { |
| 167 | + Layout::from_size_align(self.size(), cmp::max(self.align(), align)) |
| 168 | + } |
| 169 | + |
| 170 | + /// Returns the amount of padding we must insert after `self` |
| 171 | + /// to ensure that the following address will satisfy `align` |
| 172 | + /// (measured in bytes). |
| 173 | + /// |
| 174 | + /// e.g., if `self.size()` is 9, then `self.padding_needed_for(4)` |
| 175 | + /// returns 3, because that is the minimum number of bytes of |
| 176 | + /// padding required to get a 4-aligned address (assuming that the |
| 177 | + /// corresponding memory block starts at a 4-aligned address). |
| 178 | + /// |
| 179 | + /// The return value of this function has no meaning if `align` is |
| 180 | + /// not a power-of-two. |
| 181 | + /// |
| 182 | + /// Note that the utility of the returned value requires `align` |
| 183 | + /// to be less than or equal to the alignment of the starting |
| 184 | + /// address for the whole allocated block of memory. One way to |
| 185 | + /// satisfy this constraint is to ensure `align <= self.align()`. |
| 186 | + #[unstable(feature = "alloc_layout_extra", issue = "55724")] |
| 187 | + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] |
| 188 | + #[inline] |
| 189 | + pub const fn padding_needed_for(&self, align: usize) -> usize { |
| 190 | + let len = self.size(); |
| 191 | + |
| 192 | + // Rounded up value is: |
| 193 | + // len_rounded_up = (len + align - 1) & !(align - 1); |
| 194 | + // and then we return the padding difference: `len_rounded_up - len`. |
| 195 | + // |
| 196 | + // We use modular arithmetic throughout: |
| 197 | + // |
| 198 | + // 1. align is guaranteed to be > 0, so align - 1 is always |
| 199 | + // valid. |
| 200 | + // |
| 201 | + // 2. `len + align - 1` can overflow by at most `align - 1`, |
| 202 | + // so the &-mask with `!(align - 1)` will ensure that in the |
| 203 | + // case of overflow, `len_rounded_up` will itself be 0. |
| 204 | + // Thus the returned padding, when added to `len`, yields 0, |
| 205 | + // which trivially satisfies the alignment `align`. |
| 206 | + // |
| 207 | + // (Of course, attempts to allocate blocks of memory whose |
| 208 | + // size and padding overflow in the above manner should cause |
| 209 | + // the allocator to yield an error anyway.) |
| 210 | + |
| 211 | + let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); |
| 212 | + len_rounded_up.wrapping_sub(len) |
| 213 | + } |
| 214 | + |
| 215 | + /// Creates a layout by rounding the size of this layout up to a multiple |
| 216 | + /// of the layout's alignment. |
| 217 | + /// |
| 218 | + /// This is equivalent to adding the result of `padding_needed_for` |
| 219 | + /// to the layout's current size. |
| 220 | + #[unstable(feature = "alloc_layout_extra", issue = "55724")] |
| 221 | + #[inline] |
| 222 | + pub fn pad_to_align(&self) -> Layout { |
| 223 | + let pad = self.padding_needed_for(self.align()); |
| 224 | + // This cannot overflow. Quoting from the invariant of Layout: |
| 225 | + // > `size`, when rounded up to the nearest multiple of `align`, |
| 226 | + // > must not overflow (i.e., the rounded value must be less than |
| 227 | + // > `usize::MAX`) |
| 228 | + let new_size = self.size() + pad; |
| 229 | + |
| 230 | + Layout::from_size_align(new_size, self.align()).unwrap() |
| 231 | + } |
| 232 | + |
| 233 | + /// Creates a layout describing the record for `n` instances of |
| 234 | + /// `self`, with a suitable amount of padding between each to |
| 235 | + /// ensure that each instance is given its requested size and |
| 236 | + /// alignment. On success, returns `(k, offs)` where `k` is the |
| 237 | + /// layout of the array and `offs` is the distance between the start |
| 238 | + /// of each element in the array. |
| 239 | + /// |
| 240 | + /// On arithmetic overflow, returns `LayoutErr`. |
| 241 | + #[unstable(feature = "alloc_layout_extra", issue = "55724")] |
| 242 | + #[inline] |
| 243 | + pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> { |
| 244 | + // This cannot overflow. Quoting from the invariant of Layout: |
| 245 | + // > `size`, when rounded up to the nearest multiple of `align`, |
| 246 | + // > must not overflow (i.e., the rounded value must be less than |
| 247 | + // > `usize::MAX`) |
| 248 | + let padded_size = self.size() + self.padding_needed_for(self.align()); |
| 249 | + let alloc_size = padded_size.checked_mul(n).ok_or(LayoutErr { private: () })?; |
| 250 | + |
| 251 | + unsafe { |
| 252 | + // self.align is already known to be valid and alloc_size has been |
| 253 | + // padded already. |
| 254 | + Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size)) |
| 255 | + } |
| 256 | + } |
| 257 | + |
| 258 | + /// Creates a layout describing the record for `self` followed by |
| 259 | + /// `next`, including any necessary padding to ensure that `next` |
| 260 | + /// will be properly aligned. Note that the resulting layout will |
| 261 | + /// satisfy the alignment properties of both `self` and `next`. |
| 262 | + /// |
| 263 | + /// The resulting layout will be the same as that of a C struct containing |
| 264 | + /// two fields with the layouts of `self` and `next`, in that order. |
| 265 | + /// |
| 266 | + /// Returns `Some((k, offset))`, where `k` is layout of the concatenated |
| 267 | + /// record and `offset` is the relative location, in bytes, of the |
| 268 | + /// start of the `next` embedded within the concatenated record |
| 269 | + /// (assuming that the record itself starts at offset 0). |
| 270 | + /// |
| 271 | + /// On arithmetic overflow, returns `LayoutErr`. |
| 272 | + #[unstable(feature = "alloc_layout_extra", issue = "55724")] |
| 273 | + #[inline] |
| 274 | + pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> { |
| 275 | + let new_align = cmp::max(self.align(), next.align()); |
| 276 | + let pad = self.padding_needed_for(next.align()); |
| 277 | + |
| 278 | + let offset = self.size().checked_add(pad).ok_or(LayoutErr { private: () })?; |
| 279 | + let new_size = offset.checked_add(next.size()).ok_or(LayoutErr { private: () })?; |
| 280 | + |
| 281 | + let layout = Layout::from_size_align(new_size, new_align)?; |
| 282 | + Ok((layout, offset)) |
| 283 | + } |
| 284 | + |
| 285 | + /// Creates a layout describing the record for `n` instances of |
| 286 | + /// `self`, with no padding between each instance. |
| 287 | + /// |
| 288 | + /// Note that, unlike `repeat`, `repeat_packed` does not guarantee |
| 289 | + /// that the repeated instances of `self` will be properly |
| 290 | + /// aligned, even if a given instance of `self` is properly |
| 291 | + /// aligned. In other words, if the layout returned by |
| 292 | + /// `repeat_packed` is used to allocate an array, it is not |
| 293 | + /// guaranteed that all elements in the array will be properly |
| 294 | + /// aligned. |
| 295 | + /// |
| 296 | + /// On arithmetic overflow, returns `LayoutErr`. |
| 297 | + #[unstable(feature = "alloc_layout_extra", issue = "55724")] |
| 298 | + #[inline] |
| 299 | + pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> { |
| 300 | + let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?; |
| 301 | + Layout::from_size_align(size, self.align()) |
| 302 | + } |
| 303 | + |
| 304 | + /// Creates a layout describing the record for `self` followed by |
| 305 | + /// `next` with no additional padding between the two. Since no |
| 306 | + /// padding is inserted, the alignment of `next` is irrelevant, |
| 307 | + /// and is not incorporated *at all* into the resulting layout. |
| 308 | + /// |
| 309 | + /// On arithmetic overflow, returns `LayoutErr`. |
| 310 | + #[unstable(feature = "alloc_layout_extra", issue = "55724")] |
| 311 | + #[inline] |
| 312 | + pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutErr> { |
| 313 | + let new_size = self.size().checked_add(next.size()).ok_or(LayoutErr { private: () })?; |
| 314 | + Layout::from_size_align(new_size, self.align()) |
| 315 | + } |
| 316 | + |
| 317 | + /// Creates a layout describing the record for a `[T; n]`. |
| 318 | + /// |
| 319 | + /// On arithmetic overflow, returns `LayoutErr`. |
| 320 | + #[unstable(feature = "alloc_layout_extra", issue = "55724")] |
| 321 | + #[inline] |
| 322 | + pub fn array<T>(n: usize) -> Result<Self, LayoutErr> { |
| 323 | + Layout::new::<T>().repeat(n).map(|(k, offs)| { |
| 324 | + debug_assert!(offs == mem::size_of::<T>()); |
| 325 | + k |
| 326 | + }) |
| 327 | + } |
| 328 | +} |
| 329 | + |
| 330 | +/// The parameters given to `Layout::from_size_align` |
| 331 | +/// or some other `Layout` constructor |
| 332 | +/// do not satisfy its documented constraints. |
| 333 | +#[stable(feature = "alloc_layout", since = "1.28.0")] |
| 334 | +#[derive(Clone, PartialEq, Eq, Debug)] |
| 335 | +pub struct LayoutErr { |
| 336 | + private: (), |
| 337 | +} |
| 338 | + |
| 339 | +// (we need this for downstream impl of trait Error) |
| 340 | +#[stable(feature = "alloc_layout", since = "1.28.0")] |
| 341 | +impl fmt::Display for LayoutErr { |
| 342 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 343 | + f.write_str("invalid parameters to Layout::from_size_align") |
| 344 | + } |
| 345 | +} |
0 commit comments