@@ -2113,14 +2113,15 @@ pub unsafe trait FromZeros: TryFromBytes {
2113
2113
/// Note that `Box<Self>` can be converted to `Arc<Self>` and other
2114
2114
/// container types without reallocation.
2115
2115
///
2116
- /// # Panics
2116
+ /// # Errors
2117
2117
///
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.
2119
2120
#[ must_use = "has no side effects (other than allocation)" ]
2120
2121
#[ cfg( any( feature = "alloc" , test) ) ]
2121
2122
#[ cfg_attr( doc_cfg, doc( cfg( feature = "alloc" ) ) ) ]
2122
2123
#[ inline]
2123
- fn new_box_zeroed ( ) -> Box < Self >
2124
+ fn new_box_zeroed ( ) -> Result < Box < Self > , AllocError >
2124
2125
where
2125
2126
Self : Sized ,
2126
2127
{
@@ -2146,22 +2147,18 @@ pub unsafe trait FromZeros: TryFromBytes {
2146
2147
// [2] Per https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.dangling:
2147
2148
//
2148
2149
// 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 ( ) ) } ) ;
2152
2151
}
2153
2152
2154
2153
// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
2155
2154
#[ allow( clippy:: undocumented_unsafe_blocks) ]
2156
2155
let ptr = unsafe { alloc:: alloc:: alloc_zeroed ( layout) . cast :: < Self > ( ) } ;
2157
2156
if ptr. is_null ( ) {
2158
- alloc :: alloc :: handle_alloc_error ( layout ) ;
2157
+ return Err ( AllocError ) ;
2159
2158
}
2160
2159
// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
2161
2160
#[ allow( clippy:: undocumented_unsafe_blocks) ]
2162
- unsafe {
2163
- Box :: from_raw ( ptr)
2164
- }
2161
+ Ok ( unsafe { Box :: from_raw ( ptr) } )
2165
2162
}
2166
2163
2167
2164
/// Creates a `Box<[Self]>` (a boxed slice) from zeroed bytes.
@@ -2181,22 +2178,24 @@ pub unsafe trait FromZeros: TryFromBytes {
2181
2178
/// actual information, but its `len()` property will report the correct
2182
2179
/// value.
2183
2180
///
2184
- /// # Panics
2181
+ /// # Errors
2185
2182
///
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 .
2188
2185
#[ must_use = "has no side effects (other than allocation)" ]
2189
2186
#[ cfg( feature = "alloc" ) ]
2190
2187
#[ cfg_attr( doc_cfg, doc( cfg( feature = "alloc" ) ) ) ]
2191
2188
#[ inline]
2192
- fn new_box_slice_zeroed ( len : usize ) -> Box < [ Self ] >
2189
+ fn new_box_zeroed_with_elems ( count : usize ) -> Result < Box < Self > , AllocError >
2193
2190
where
2194
- Self : Sized ,
2191
+ Self : KnownLayout < PointerMetadata = usize > ,
2195
2192
{
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 ( ) ;
2200
2199
// On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a
2201
2200
// bug in which sufficiently-large allocations (those which, when
2202
2201
// rounded up to the alignment, overflow `isize`) are not rejected,
@@ -2205,32 +2204,47 @@ pub unsafe trait FromZeros: TryFromBytes {
2205
2204
// TODO(#67): Once our MSRV is > 1.64.0, remove this assertion.
2206
2205
#[ allow( clippy:: as_conversions) ]
2207
2206
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
+
2209
2211
// TODO(https://github.com/rust-lang/rust/issues/55724): Use
2210
2212
// `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 ) ) ?;
2213
2214
2214
2215
let ptr = if layout. size ( ) != 0 {
2215
2216
// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
2216
2217
#[ 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 ) ,
2220
2222
}
2221
- ptr
2222
2223
} else {
2223
2224
// `Box<[T]>` does not allocate when `T` is zero-sized or when `len`
2224
2225
// is zero, but it does require a non-null dangling pointer for its
2225
2226
// allocation.
2226
- NonNull :: < Self > :: dangling ( ) . as_ptr ( )
2227
+ NonNull :: < u8 > :: dangling ( )
2227
2228
} ;
2228
2229
2230
+ let ptr = Self :: raw_from_ptr_len ( ptr, count) ;
2231
+
2229
2232
// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
2230
2233
#[ allow( clippy:: undocumented_unsafe_blocks) ]
2231
- unsafe {
2232
- Box :: from_raw ( slice:: from_raw_parts_mut ( ptr, len) )
2233
- }
2234
+ Ok ( unsafe { Box :: from_raw ( ptr. as_ptr ( ) ) } )
2235
+ }
2236
+
2237
+ #[ deprecated( since = "0.8.0" , note = "renamed to `FromZeros::new_box_zeroed_with_elems`" ) ]
2238
+ #[ doc( hidden) ]
2239
+ #[ cfg( feature = "alloc" ) ]
2240
+ #[ cfg_attr( doc_cfg, doc( cfg( feature = "alloc" ) ) ) ]
2241
+ #[ must_use = "has no side effects (other than allocation)" ]
2242
+ #[ inline( always) ]
2243
+ fn new_box_slice_zeroed ( len : usize ) -> Result < Box < [ Self ] > , AllocError >
2244
+ where
2245
+ Self : Sized ,
2246
+ {
2247
+ <[ Self ] >:: new_box_zeroed_with_elems ( len)
2234
2248
}
2235
2249
2236
2250
/// Creates a `Vec<Self>` from zeroed bytes.
@@ -2249,19 +2263,19 @@ pub unsafe trait FromZeros: TryFromBytes {
2249
2263
/// actual information, but its `len()` property will report the correct
2250
2264
/// value.
2251
2265
///
2252
- /// # Panics
2266
+ /// # Errors
2253
2267
///
2254
- /// * Panics if `size_of::<Self>() * len` overflows.
2255
- /// * Panics if allocation of `size_of::<Self>() * len` bytes fails .
2268
+ /// Returns an error on allocation failure. Allocation failure is
2269
+ /// guaranteed never to cause a panic or an abort .
2256
2270
#[ must_use = "has no side effects (other than allocation)" ]
2257
2271
#[ cfg( feature = "alloc" ) ]
2258
2272
#[ cfg_attr( doc_cfg, doc( cfg( feature = "alloc" ) ) ) ]
2259
2273
#[ inline( always) ]
2260
- fn new_vec_zeroed ( len : usize ) -> Vec < Self >
2274
+ fn new_vec_zeroed ( len : usize ) -> Result < Vec < Self > , AllocError >
2261
2275
where
2262
2276
Self : Sized ,
2263
2277
{
2264
- Self :: new_box_slice_zeroed ( len) . into ( )
2278
+ < [ Self ] > :: new_box_zeroed_with_elems ( len) . map ( Into :: into )
2265
2279
}
2266
2280
}
2267
2281
@@ -4972,7 +4986,7 @@ mod alloc_support {
4972
4986
4973
4987
#[ test]
4974
4988
fn test_new_box_zeroed ( ) {
4975
- assert_eq ! ( * u64 :: new_box_zeroed( ) , 0 ) ;
4989
+ assert_eq ! ( u64 :: new_box_zeroed( ) , Ok ( Box :: new ( 0 ) ) ) ;
4976
4990
}
4977
4991
4978
4992
#[ test]
@@ -4986,13 +5000,13 @@ mod alloc_support {
4986
5000
// when running under Miri.
4987
5001
#[ allow( clippy:: unit_cmp) ]
4988
5002
{
4989
- assert_eq ! ( * <( ) >:: new_box_zeroed( ) , ( ) ) ;
5003
+ assert_eq ! ( <( ) >:: new_box_zeroed( ) , Ok ( Box :: new ( ( ) ) ) ) ;
4990
5004
}
4991
5005
}
4992
5006
4993
5007
#[ test]
4994
5008
fn test_new_box_slice_zeroed ( ) {
4995
- let mut s: Box < [ u64 ] > = u64:: new_box_slice_zeroed ( 3 ) ;
5009
+ let mut s: Box < [ u64 ] > = < [ u64 ] > :: new_box_zeroed_with_elems ( 3 ) . unwrap ( ) ;
4996
5010
assert_eq ! ( s. len( ) , 3 ) ;
4997
5011
assert_eq ! ( & * s, & [ 0 , 0 , 0 ] ) ;
4998
5012
s[ 1 ] = 3 ;
@@ -5001,13 +5015,13 @@ mod alloc_support {
5001
5015
5002
5016
#[ test]
5003
5017
fn test_new_box_slice_zeroed_empty ( ) {
5004
- let s: Box < [ u64 ] > = u64:: new_box_slice_zeroed ( 0 ) ;
5018
+ let s: Box < [ u64 ] > = < [ u64 ] > :: new_box_zeroed_with_elems ( 0 ) . unwrap ( ) ;
5005
5019
assert_eq ! ( s. len( ) , 0 ) ;
5006
5020
}
5007
5021
5008
5022
#[ test]
5009
5023
fn test_new_box_slice_zeroed_zst ( ) {
5010
- let mut s: Box < [ ( ) ] > = <( ) >:: new_box_slice_zeroed ( 3 ) ;
5024
+ let mut s: Box < [ ( ) ] > = <[ ( ) ] >:: new_box_zeroed_with_elems ( 3 ) . unwrap ( ) ;
5011
5025
assert_eq ! ( s. len( ) , 3 ) ;
5012
5026
assert ! ( s. get( 10 ) . is_none( ) ) ;
5013
5027
// This test exists in order to exercise unsafe code, especially
@@ -5021,21 +5035,19 @@ mod alloc_support {
5021
5035
5022
5036
#[ test]
5023
5037
fn test_new_box_slice_zeroed_zst_empty ( ) {
5024
- let s: Box < [ ( ) ] > = <( ) >:: new_box_slice_zeroed ( 0 ) ;
5038
+ let s: Box < [ ( ) ] > = <[ ( ) ] >:: new_box_zeroed_with_elems ( 0 ) . unwrap ( ) ;
5025
5039
assert_eq ! ( s. len( ) , 0 ) ;
5026
5040
}
5027
5041
5028
5042
#[ 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
- }
5043
+ fn test_new_box_slice_zeroed_errors ( ) {
5044
+ assert_eq ! ( <[ u16 ] >:: new_box_zeroed_with_elems( usize :: MAX ) , Err ( AllocError ) ) ;
5033
5045
5034
- #[ test]
5035
- #[ should_panic( expected = "assertion failed: size <= max_alloc" ) ]
5036
- fn test_new_box_slice_zeroed_panics_isize_overflow ( ) {
5037
5046
let max = usize:: try_from ( isize:: MAX ) . unwrap ( ) ;
5038
- let _ = u16:: new_box_slice_zeroed ( ( max / mem:: size_of :: < u16 > ( ) ) + 1 ) ;
5047
+ assert_eq ! (
5048
+ <[ u16 ] >:: new_box_zeroed_with_elems( ( max / mem:: size_of:: <u16 >( ) ) + 1 ) ,
5049
+ Err ( AllocError )
5050
+ ) ;
5039
5051
}
5040
5052
}
5041
5053
}
@@ -5525,14 +5537,20 @@ mod tests {
5525
5537
5526
5538
#[ cfg( feature = "alloc" ) ]
5527
5539
{
5528
- assert_eq ! ( bool :: new_box_zeroed( ) , Box :: new( false ) ) ;
5529
- assert_eq ! ( char :: new_box_zeroed( ) , Box :: new( '\0' ) ) ;
5540
+ assert_eq ! ( bool :: new_box_zeroed( ) , Ok ( Box :: new( false ) ) ) ;
5541
+ assert_eq ! ( char :: new_box_zeroed( ) , Ok ( Box :: new( '\0' ) ) ) ;
5530
5542
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' ] ) ;
5543
+ assert_eq ! (
5544
+ <[ bool ] >:: new_box_zeroed_with_elems( 3 ) . unwrap( ) . as_ref( ) ,
5545
+ [ false , false , false ]
5546
+ ) ;
5547
+ assert_eq ! (
5548
+ <[ char ] >:: new_box_zeroed_with_elems( 3 ) . unwrap( ) . as_ref( ) ,
5549
+ [ '\0' , '\0' , '\0' ]
5550
+ ) ;
5533
5551
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' ] ) ;
5552
+ assert_eq ! ( bool :: new_vec_zeroed( 3 ) . unwrap ( ) . as_ref( ) , [ false , false , false ] ) ;
5553
+ assert_eq ! ( char :: new_vec_zeroed( 3 ) . unwrap ( ) . as_ref( ) , [ '\0' , '\0' , '\0' ] ) ;
5536
5554
}
5537
5555
5538
5556
let mut string = "hello" . to_string ( ) ;
0 commit comments