@@ -2113,14 +2113,15 @@ pub unsafe trait FromZeros: TryFromBytes {
21132113 /// Note that `Box<Self>` can be converted to `Arc<Self>` and other
21142114 /// container types without reallocation.
21152115 ///
2116- /// # Panics
2116+ /// # Errors
21172117 ///
2118- /// Panics if allocation of `size_of::<Self>()` bytes fails.
2118+ /// Returns an error on allocation failure. Allocation failure is guaranteed
2119+ /// never to cause a panic or an abort.
21192120 #[ must_use = "has no side effects (other than allocation)" ]
21202121 #[ cfg( any( feature = "alloc" , test) ) ]
21212122 #[ cfg_attr( doc_cfg, doc( cfg( feature = "alloc" ) ) ) ]
21222123 #[ inline]
2123- fn new_box_zeroed ( ) -> Box < Self >
2124+ fn new_box_zeroed ( ) -> Result < Box < Self > , AllocError >
21242125 where
21252126 Self : Sized ,
21262127 {
@@ -2146,22 +2147,18 @@ pub unsafe trait FromZeros: TryFromBytes {
21462147 // [2] Per https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.dangling:
21472148 //
21482149 // Creates a new `NonNull` that is dangling, but well-aligned.
2149- unsafe {
2150- return Box :: from_raw ( NonNull :: dangling ( ) . as_ptr ( ) ) ;
2151- }
2150+ return Ok ( unsafe { Box :: from_raw ( NonNull :: dangling ( ) . as_ptr ( ) ) } ) ;
21522151 }
21532152
21542153 // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
21552154 #[ allow( clippy:: undocumented_unsafe_blocks) ]
21562155 let ptr = unsafe { alloc:: alloc:: alloc_zeroed ( layout) . cast :: < Self > ( ) } ;
21572156 if ptr. is_null ( ) {
2158- alloc :: alloc :: handle_alloc_error ( layout ) ;
2157+ return Err ( AllocError ) ;
21592158 }
21602159 // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
21612160 #[ allow( clippy:: undocumented_unsafe_blocks) ]
2162- unsafe {
2163- Box :: from_raw ( ptr)
2164- }
2161+ Ok ( unsafe { Box :: from_raw ( ptr) } )
21652162 }
21662163
21672164 /// Creates a `Box<[Self]>` (a boxed slice) from zeroed bytes.
@@ -2181,22 +2178,24 @@ pub unsafe trait FromZeros: TryFromBytes {
21812178 /// actual information, but its `len()` property will report the correct
21822179 /// value.
21832180 ///
2184- /// # Panics
2181+ /// # Errors
21852182 ///
2186- /// * Panics if `size_of::<Self>() * len` overflows.
2187- /// * Panics if allocation of `size_of::<Self>() * len` bytes fails .
2183+ /// Returns an error on allocation failure. Allocation failure is
2184+ /// guaranteed never to cause a panic or an abort .
21882185 #[ must_use = "has no side effects (other than allocation)" ]
21892186 #[ cfg( feature = "alloc" ) ]
21902187 #[ cfg_attr( doc_cfg, doc( cfg( feature = "alloc" ) ) ) ]
21912188 #[ inline]
2192- fn new_box_slice_zeroed ( len : usize ) -> Box < [ Self ] >
2189+ fn new_box_zeroed_with_elems ( count : usize ) -> Result < Box < Self > , AllocError >
21932190 where
2194- Self : Sized ,
2191+ Self : KnownLayout < PointerMetadata = usize > ,
21952192 {
2196- let size = mem:: size_of :: < Self > ( )
2197- . checked_mul ( len)
2198- . expect ( "mem::size_of::<Self>() * len overflows `usize`" ) ;
2199- let align = mem:: align_of :: < Self > ( ) ;
2193+ let size = match count. size_for_metadata ( Self :: LAYOUT ) {
2194+ Some ( size) => size,
2195+ None => return Err ( AllocError ) ,
2196+ } ;
2197+
2198+ let align = Self :: LAYOUT . align . get ( ) ;
22002199 // On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a
22012200 // bug in which sufficiently-large allocations (those which, when
22022201 // rounded up to the alignment, overflow `isize`) are not rejected,
@@ -2205,32 +2204,58 @@ pub unsafe trait FromZeros: TryFromBytes {
22052204 // TODO(#67): Once our MSRV is > 1.64.0, remove this assertion.
22062205 #[ allow( clippy:: as_conversions) ]
22072206 let max_alloc = ( isize:: MAX as usize ) . saturating_sub ( align) ;
2208- assert ! ( size <= max_alloc) ;
2207+ if size > max_alloc {
2208+ return Err ( AllocError ) ;
2209+ }
2210+
22092211 // TODO(https://github.com/rust-lang/rust/issues/55724): Use
22102212 // `Layout::repeat` once it's stabilized.
2211- let layout =
2212- Layout :: from_size_align ( size, align) . expect ( "total allocation size overflows `isize`" ) ;
2213+ let layout = Layout :: from_size_align ( size, align) . or ( Err ( AllocError ) ) ?;
22132214
22142215 let ptr = if layout. size ( ) != 0 {
22152216 // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
22162217 #[ allow( clippy:: undocumented_unsafe_blocks) ]
2217- let ptr = unsafe { alloc:: alloc:: alloc_zeroed ( layout) . cast :: < Self > ( ) } ;
2218- if ptr. is_null ( ) {
2219- alloc:: alloc:: handle_alloc_error ( layout) ;
2218+ let ptr = unsafe { alloc:: alloc:: alloc_zeroed ( layout) } ;
2219+ match NonNull :: new ( ptr) {
2220+ Some ( ptr) => ptr,
2221+ None => return Err ( AllocError ) ,
22202222 }
2221- ptr
22222223 } else {
2224+ // SAFETY: `Self::LAYOUT.align` is a `NonZeroUsize`, which is
2225+ // guaranteed to be non-zero.
2226+ //
22232227 // `Box<[T]>` does not allocate when `T` is zero-sized or when `len`
22242228 // is zero, but it does require a non-null dangling pointer for its
22252229 // allocation.
2226- NonNull :: < Self > :: dangling ( ) . as_ptr ( )
2230+ //
2231+ // TODO(...): Use `without_provenance` once it's stable. That may
2232+ // optimize better. As written, Rust may assume that this consumes
2233+ // "exposed" provenance, and thus Rust may have to assume that this
2234+ // may consume provenance from any pointer whose provenance has been
2235+ // exposed.
2236+ unsafe { NonNull :: new_unchecked ( Self :: LAYOUT . align . get ( ) as * mut u8 ) }
22272237 } ;
22282238
2229- // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
2239+ let ptr = Self :: raw_from_ptr_len ( ptr, count) ;
2240+
2241+ // TODO(#429): Add a "SAFETY" comment and remove this `allow`. Make sure
2242+ // to include a justification that `ptr.as_ptr()` is validly-aligned in
2243+ // the ZST case (in which we manually construct a dangling pointer).
22302244 #[ allow( clippy:: undocumented_unsafe_blocks) ]
2231- unsafe {
2232- Box :: from_raw ( slice:: from_raw_parts_mut ( ptr, len) )
2233- }
2245+ Ok ( unsafe { Box :: from_raw ( ptr. as_ptr ( ) ) } )
2246+ }
2247+
2248+ #[ deprecated( since = "0.8.0" , note = "renamed to `FromZeros::new_box_zeroed_with_elems`" ) ]
2249+ #[ doc( hidden) ]
2250+ #[ cfg( feature = "alloc" ) ]
2251+ #[ cfg_attr( doc_cfg, doc( cfg( feature = "alloc" ) ) ) ]
2252+ #[ must_use = "has no side effects (other than allocation)" ]
2253+ #[ inline( always) ]
2254+ fn new_box_slice_zeroed ( len : usize ) -> Result < Box < [ Self ] > , AllocError >
2255+ where
2256+ Self : Sized ,
2257+ {
2258+ <[ Self ] >:: new_box_zeroed_with_elems ( len)
22342259 }
22352260
22362261 /// Creates a `Vec<Self>` from zeroed bytes.
@@ -2249,19 +2274,19 @@ pub unsafe trait FromZeros: TryFromBytes {
22492274 /// actual information, but its `len()` property will report the correct
22502275 /// value.
22512276 ///
2252- /// # Panics
2277+ /// # Errors
22532278 ///
2254- /// * Panics if `size_of::<Self>() * len` overflows.
2255- /// * Panics if allocation of `size_of::<Self>() * len` bytes fails .
2279+ /// Returns an error on allocation failure. Allocation failure is
2280+ /// guaranteed never to cause a panic or an abort .
22562281 #[ must_use = "has no side effects (other than allocation)" ]
22572282 #[ cfg( feature = "alloc" ) ]
22582283 #[ cfg_attr( doc_cfg, doc( cfg( feature = "alloc" ) ) ) ]
22592284 #[ inline( always) ]
2260- fn new_vec_zeroed ( len : usize ) -> Vec < Self >
2285+ fn new_vec_zeroed ( len : usize ) -> Result < Vec < Self > , AllocError >
22612286 where
22622287 Self : Sized ,
22632288 {
2264- Self :: new_box_slice_zeroed ( len) . into ( )
2289+ < [ Self ] > :: new_box_zeroed_with_elems ( len) . map ( Into :: into )
22652290 }
22662291}
22672292
@@ -4972,7 +4997,7 @@ mod alloc_support {
49724997
49734998 #[ test]
49744999 fn test_new_box_zeroed ( ) {
4975- assert_eq ! ( * u64 :: new_box_zeroed( ) , 0 ) ;
5000+ assert_eq ! ( u64 :: new_box_zeroed( ) , Ok ( Box :: new ( 0 ) ) ) ;
49765001 }
49775002
49785003 #[ test]
@@ -4986,13 +5011,13 @@ mod alloc_support {
49865011 // when running under Miri.
49875012 #[ allow( clippy:: unit_cmp) ]
49885013 {
4989- assert_eq ! ( * <( ) >:: new_box_zeroed( ) , ( ) ) ;
5014+ assert_eq ! ( <( ) >:: new_box_zeroed( ) , Ok ( Box :: new ( ( ) ) ) ) ;
49905015 }
49915016 }
49925017
49935018 #[ test]
49945019 fn test_new_box_slice_zeroed ( ) {
4995- let mut s: Box < [ u64 ] > = u64:: new_box_slice_zeroed ( 3 ) ;
5020+ let mut s: Box < [ u64 ] > = < [ u64 ] > :: new_box_zeroed_with_elems ( 3 ) . unwrap ( ) ;
49965021 assert_eq ! ( s. len( ) , 3 ) ;
49975022 assert_eq ! ( & * s, & [ 0 , 0 , 0 ] ) ;
49985023 s[ 1 ] = 3 ;
@@ -5001,13 +5026,13 @@ mod alloc_support {
50015026
50025027 #[ test]
50035028 fn test_new_box_slice_zeroed_empty ( ) {
5004- let s: Box < [ u64 ] > = u64:: new_box_slice_zeroed ( 0 ) ;
5029+ let s: Box < [ u64 ] > = < [ u64 ] > :: new_box_zeroed_with_elems ( 0 ) . unwrap ( ) ;
50055030 assert_eq ! ( s. len( ) , 0 ) ;
50065031 }
50075032
50085033 #[ test]
50095034 fn test_new_box_slice_zeroed_zst ( ) {
5010- let mut s: Box < [ ( ) ] > = <( ) >:: new_box_slice_zeroed ( 3 ) ;
5035+ let mut s: Box < [ ( ) ] > = <[ ( ) ] >:: new_box_zeroed_with_elems ( 3 ) . unwrap ( ) ;
50115036 assert_eq ! ( s. len( ) , 3 ) ;
50125037 assert ! ( s. get( 10 ) . is_none( ) ) ;
50135038 // This test exists in order to exercise unsafe code, especially
@@ -5021,21 +5046,19 @@ mod alloc_support {
50215046
50225047 #[ test]
50235048 fn test_new_box_slice_zeroed_zst_empty ( ) {
5024- let s: Box < [ ( ) ] > = <( ) >:: new_box_slice_zeroed ( 0 ) ;
5049+ let s: Box < [ ( ) ] > = <[ ( ) ] >:: new_box_zeroed_with_elems ( 0 ) . unwrap ( ) ;
50255050 assert_eq ! ( s. len( ) , 0 ) ;
50265051 }
50275052
50285053 #[ test]
5029- #[ should_panic( expected = "mem::size_of::<Self>() * len overflows `usize`" ) ]
5030- fn test_new_box_slice_zeroed_panics_mul_overflow ( ) {
5031- let _ = u16:: new_box_slice_zeroed ( usize:: MAX ) ;
5032- }
5054+ fn test_new_box_slice_zeroed_errors ( ) {
5055+ assert_eq ! ( <[ u16 ] >:: new_box_zeroed_with_elems( usize :: MAX ) , Err ( AllocError ) ) ;
50335056
5034- #[ test]
5035- #[ should_panic( expected = "assertion failed: size <= max_alloc" ) ]
5036- fn test_new_box_slice_zeroed_panics_isize_overflow ( ) {
50375057 let max = usize:: try_from ( isize:: MAX ) . unwrap ( ) ;
5038- let _ = u16:: new_box_slice_zeroed ( ( max / mem:: size_of :: < u16 > ( ) ) + 1 ) ;
5058+ assert_eq ! (
5059+ <[ u16 ] >:: new_box_zeroed_with_elems( ( max / mem:: size_of:: <u16 >( ) ) + 1 ) ,
5060+ Err ( AllocError )
5061+ ) ;
50395062 }
50405063 }
50415064}
@@ -5525,14 +5548,20 @@ mod tests {
55255548
55265549 #[ cfg( feature = "alloc" ) ]
55275550 {
5528- assert_eq ! ( bool :: new_box_zeroed( ) , Box :: new( false ) ) ;
5529- assert_eq ! ( char :: new_box_zeroed( ) , Box :: new( '\0' ) ) ;
5551+ assert_eq ! ( bool :: new_box_zeroed( ) , Ok ( Box :: new( false ) ) ) ;
5552+ assert_eq ! ( char :: new_box_zeroed( ) , Ok ( Box :: new( '\0' ) ) ) ;
55305553
5531- assert_eq ! ( bool :: new_box_slice_zeroed( 3 ) . as_ref( ) , [ false , false , false ] ) ;
5532- assert_eq ! ( char :: new_box_slice_zeroed( 3 ) . as_ref( ) , [ '\0' , '\0' , '\0' ] ) ;
5554+ assert_eq ! (
5555+ <[ bool ] >:: new_box_zeroed_with_elems( 3 ) . unwrap( ) . as_ref( ) ,
5556+ [ false , false , false ]
5557+ ) ;
5558+ assert_eq ! (
5559+ <[ char ] >:: new_box_zeroed_with_elems( 3 ) . unwrap( ) . as_ref( ) ,
5560+ [ '\0' , '\0' , '\0' ]
5561+ ) ;
55335562
5534- assert_eq ! ( bool :: new_vec_zeroed( 3 ) . as_ref( ) , [ false , false , false ] ) ;
5535- assert_eq ! ( char :: new_vec_zeroed( 3 ) . as_ref( ) , [ '\0' , '\0' , '\0' ] ) ;
5563+ assert_eq ! ( bool :: new_vec_zeroed( 3 ) . unwrap ( ) . as_ref( ) , [ false , false , false ] ) ;
5564+ assert_eq ! ( char :: new_vec_zeroed( 3 ) . unwrap ( ) . as_ref( ) , [ '\0' , '\0' , '\0' ] ) ;
55365565 }
55375566
55385567 let mut string = "hello" . to_string ( ) ;
0 commit comments