@@ -72,9 +72,8 @@ impl Layout {
72
72
Layout::from_size_valid_align(size, unsafe { ValidAlign::new_unchecked(align) })
73
73
}
74
74
75
- /// Internal helper constructor to skip revalidating alignment validity.
76
- #[ inline]
77
- const fn from_size_valid_align ( size : usize , align : ValidAlign ) -> Result < Self , LayoutError > {
75
+ #[inline(always)]
76
+ const fn max_size_for_align(align: ValidAlign) -> usize {
78
77
// (power-of-two implies align != 0.)
79
78
80
79
// Rounded up size is:
@@ -89,7 +88,13 @@ impl Layout {
89
88
//
90
89
// Above implies that checking for summation overflow is both
91
90
// necessary and sufficient.
92
- if size > isize:: MAX as usize - ( align. as_nonzero ( ) . get ( ) - 1 ) {
91
+ isize::MAX as usize - (align.as_usize() - 1)
92
+ }
93
+
94
+ /// Internal helper constructor to skip revalidating alignment validity.
95
+ #[inline]
96
+ const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> {
97
+ if size > Self::max_size_for_align(align) {
93
98
return Err(LayoutError);
94
99
}
95
100
@@ -128,7 +133,7 @@ impl Layout {
128
133
without modifying the layout"]
129
134
#[inline]
130
135
pub const fn align(&self) -> usize {
131
- self . align . as_nonzero ( ) . get ( )
136
+ self.align.as_usize ()
132
137
}
133
138
134
139
/// Constructs a `Layout` suitable for holding a value of type `T`.
@@ -410,13 +415,33 @@ impl Layout {
410
415
411
416
/// Creates a layout describing the record for a `[T; n]`.
412
417
///
413
- /// On arithmetic overflow, returns `LayoutError`.
418
+ /// On arithmetic overflow or when the total size would exceed
419
+ /// `isize::MAX`, returns `LayoutError`.
414
420
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
415
421
#[inline]
416
422
pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
417
- let array_size = mem:: size_of :: < T > ( ) . checked_mul ( n) . ok_or ( LayoutError ) ?;
418
- // The safe constructor is called here to enforce the isize size limit.
419
- Layout :: from_size_valid_align ( array_size, ValidAlign :: of :: < T > ( ) )
423
+ // Reduce the amount of code we need to monomorphize per `T`.
424
+ return inner(mem::size_of::<T>(), ValidAlign::of::<T>(), n);
425
+
426
+ #[inline]
427
+ fn inner(element_size: usize, align: ValidAlign, n: usize) -> Result<Layout, LayoutError> {
428
+ // We need to check two things about the size:
429
+ // - That the total size won't overflow a `usize`, and
430
+ // - That the total size still fits in an `isize`.
431
+ // By using division we can check them both with a single threshold.
432
+ // That'd usually be a bad idea, but thankfully here the element size
433
+ // and alignment are constants, so the compiler will fold all of it.
434
+ if element_size != 0 && n > Layout::max_size_for_align(align) / element_size {
435
+ return Err(LayoutError);
436
+ }
437
+
438
+ let array_size = element_size * n;
439
+
440
+ // SAFETY: We just checked above that the `array_size` will not
441
+ // exceed `isize::MAX` even when rounded up to the alignment.
442
+ // And `ValidAlign` guarantees it's a power of two.
443
+ unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) }
444
+ }
420
445
}
421
446
}
422
447
0 commit comments