@@ -72,9 +72,8 @@ impl Layout {
7272 Layout :: from_size_valid_align ( size, unsafe { ValidAlign :: new_unchecked ( align) } )
7373 }
7474
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 {
7877 // (power-of-two implies align != 0.)
7978
8079 // Rounded up size is:
@@ -89,7 +88,13 @@ impl Layout {
8988 //
9089 // Above implies that checking for summation overflow is both
9190 // 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) {
9398 return Err ( LayoutError ) ;
9499 }
95100
@@ -128,7 +133,7 @@ impl Layout {
128133 without modifying the layout"]
129134 #[ inline]
130135 pub const fn align ( & self ) -> usize {
131- self . align . as_nonzero ( ) . get ( )
136+ self . align . as_usize ( )
132137 }
133138
134139 /// Constructs a `Layout` suitable for holding a value of type `T`.
@@ -410,13 +415,33 @@ impl Layout {
410415
411416 /// Creates a layout describing the record for a `[T; n]`.
412417 ///
413- /// On arithmetic overflow, returns `LayoutError`.
418+ /// On arithmetic overflow or when the total size would exceed
419+ /// `isize::MAX`, returns `LayoutError`.
414420 #[ stable( feature = "alloc_layout_manipulation" , since = "1.44.0" ) ]
415421 #[ inline]
416422 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+ }
420445 }
421446}
422447
0 commit comments