33#![ stable( feature = "alloc_module" , since = "1.28.0" ) ]
44
55use core:: intrinsics:: { self , min_align_of_val, size_of_val} ;
6- use core:: ptr:: { NonNull , Unique } ;
6+ use core:: ptr:: { self , NonNull , Unique } ;
77
88#[ stable( feature = "alloc_module" , since = "1.28.0" ) ]
99#[ doc( inline) ]
@@ -180,36 +180,45 @@ impl Global {
180180 unsafe fn grow_impl (
181181 & mut self ,
182182 ptr : NonNull < u8 > ,
183- layout : Layout ,
184- new_size : usize ,
183+ old_layout : Layout ,
184+ new_layout : Layout ,
185185 zeroed : bool ,
186186 ) -> Result < NonNull < [ u8 ] > , AllocErr > {
187187 debug_assert ! (
188- new_size >= layout . size( ) ,
189- "`new_size ` must be greater than or equal to `layout .size()`"
188+ new_layout . size ( ) >= old_layout . size( ) ,
189+ "`new_layout.size() ` must be greater than or equal to `old_layout .size()`"
190190 ) ;
191191
192- match layout. size ( ) {
193- // SAFETY: the caller must ensure that the `new_size` does not overflow.
194- // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout.
195- 0 => unsafe {
196- let new_layout = Layout :: from_size_align_unchecked ( new_size, layout. align ( ) ) ;
197- self . alloc_impl ( new_layout, zeroed)
198- } ,
192+ match old_layout. size ( ) {
193+ 0 => self . alloc_impl ( new_layout, zeroed) ,
199194
200195 // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
201196 // as required by safety conditions. Other conditions must be upheld by the caller
202- old_size => unsafe {
203- // `realloc` probably checks for `new_size >= size` or something similar.
204- intrinsics:: assume ( new_size >= layout. size ( ) ) ;
197+ old_size if old_layout. align ( ) == new_layout. align ( ) => unsafe {
198+ let new_size = new_layout. size ( ) ;
199+
200+ // `realloc` probably checks for `new_size >= old_layout.size()` or something similar.
201+ intrinsics:: assume ( new_size >= old_layout. size ( ) ) ;
205202
206- let raw_ptr = realloc ( ptr. as_ptr ( ) , layout , new_size) ;
203+ let raw_ptr = realloc ( ptr. as_ptr ( ) , old_layout , new_size) ;
207204 let ptr = NonNull :: new ( raw_ptr) . ok_or ( AllocErr ) ?;
208205 if zeroed {
209206 raw_ptr. add ( old_size) . write_bytes ( 0 , new_size - old_size) ;
210207 }
211208 Ok ( NonNull :: slice_from_raw_parts ( ptr, new_size) )
212209 } ,
210+
211+ // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`,
212+ // both the old and new memory allocation are valid for reads and writes for `old_size`
213+ // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
214+ // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
215+ // for `dealloc` must be upheld by the caller.
216+ old_size => unsafe {
217+ let new_ptr = self . alloc_impl ( new_layout, zeroed) ?;
218+ ptr:: copy_nonoverlapping ( ptr. as_ptr ( ) , new_ptr. as_mut_ptr ( ) , old_size) ;
219+ self . dealloc ( ptr, old_layout) ;
220+ Ok ( new_ptr)
221+ } ,
213222 }
214223 }
215224}
@@ -239,52 +248,64 @@ unsafe impl AllocRef for Global {
239248 unsafe fn grow (
240249 & mut self ,
241250 ptr : NonNull < u8 > ,
242- layout : Layout ,
243- new_size : usize ,
251+ old_layout : Layout ,
252+ new_layout : Layout ,
244253 ) -> Result < NonNull < [ u8 ] > , AllocErr > {
245254 // SAFETY: all conditions must be upheld by the caller
246- unsafe { self . grow_impl ( ptr, layout , new_size , false ) }
255+ unsafe { self . grow_impl ( ptr, old_layout , new_layout , false ) }
247256 }
248257
249258 #[ inline]
250259 unsafe fn grow_zeroed (
251260 & mut self ,
252261 ptr : NonNull < u8 > ,
253- layout : Layout ,
254- new_size : usize ,
262+ old_layout : Layout ,
263+ new_layout : Layout ,
255264 ) -> Result < NonNull < [ u8 ] > , AllocErr > {
256265 // SAFETY: all conditions must be upheld by the caller
257- unsafe { self . grow_impl ( ptr, layout , new_size , true ) }
266+ unsafe { self . grow_impl ( ptr, old_layout , new_layout , true ) }
258267 }
259268
260269 #[ inline]
261270 unsafe fn shrink (
262271 & mut self ,
263272 ptr : NonNull < u8 > ,
264- layout : Layout ,
265- new_size : usize ,
273+ old_layout : Layout ,
274+ new_layout : Layout ,
266275 ) -> Result < NonNull < [ u8 ] > , AllocErr > {
267276 debug_assert ! (
268- new_size <= layout . size( ) ,
269- "`new_size ` must be smaller than or equal to `layout .size()`"
277+ new_layout . size ( ) <= old_layout . size( ) ,
278+ "`new_layout.size() ` must be smaller than or equal to `old_layout .size()`"
270279 ) ;
271280
272- match new_size {
281+ match new_layout . size ( ) {
273282 // SAFETY: conditions must be upheld by the caller
274283 0 => unsafe {
275- self . dealloc ( ptr, layout ) ;
276- Ok ( NonNull :: slice_from_raw_parts ( layout . dangling ( ) , 0 ) )
284+ self . dealloc ( ptr, old_layout ) ;
285+ Ok ( NonNull :: slice_from_raw_parts ( new_layout . dangling ( ) , 0 ) )
277286 } ,
278287
279288 // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
280- new_size => unsafe {
281- // `realloc` probably checks for `new_size <= size` or something similar.
282- intrinsics:: assume ( new_size <= layout . size ( ) ) ;
289+ new_size if old_layout . align ( ) == new_layout . align ( ) => unsafe {
290+ // `realloc` probably checks for `new_size <= old_layout. size() ` or something similar.
291+ intrinsics:: assume ( new_size <= old_layout . size ( ) ) ;
283292
284- let raw_ptr = realloc ( ptr. as_ptr ( ) , layout , new_size) ;
293+ let raw_ptr = realloc ( ptr. as_ptr ( ) , old_layout , new_size) ;
285294 let ptr = NonNull :: new ( raw_ptr) . ok_or ( AllocErr ) ?;
286295 Ok ( NonNull :: slice_from_raw_parts ( ptr, new_size) )
287296 } ,
297+
298+ // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`,
299+ // both the old and new memory allocation are valid for reads and writes for `new_size`
300+ // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
301+ // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
302+ // for `dealloc` must be upheld by the caller.
303+ new_size => unsafe {
304+ let new_ptr = self . alloc ( new_layout) ?;
305+ ptr:: copy_nonoverlapping ( ptr. as_ptr ( ) , new_ptr. as_mut_ptr ( ) , new_size) ;
306+ self . dealloc ( ptr, old_layout) ;
307+ Ok ( new_ptr)
308+ } ,
288309 }
289310 }
290311}
@@ -297,7 +318,7 @@ unsafe impl AllocRef for Global {
297318unsafe fn exchange_malloc ( size : usize , align : usize ) -> * mut u8 {
298319 let layout = unsafe { Layout :: from_size_align_unchecked ( size, align) } ;
299320 match Global . alloc ( layout) {
300- Ok ( ptr) => ptr. as_non_null_ptr ( ) . as_ptr ( ) ,
321+ Ok ( ptr) => ptr. as_mut_ptr ( ) ,
301322 Err ( _) => handle_alloc_error ( layout) ,
302323 }
303324}
0 commit comments