@@ -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