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) ]
@@ -162,36 +162,45 @@ impl Global {
162162 unsafe fn grow_impl (
163163 & mut self ,
164164 ptr : NonNull < u8 > ,
165- layout : Layout ,
166- new_size : usize ,
165+ old_layout : Layout ,
166+ new_layout : Layout ,
167167 zeroed : bool ,
168168 ) -> Result < NonNull < [ u8 ] > , AllocErr > {
169169 debug_assert ! (
170- new_size >= layout . size( ) ,
171- "`new_size ` must be greater than or equal to `layout .size()`"
170+ new_layout . size ( ) >= old_layout . size( ) ,
171+ "`new_layout.size() ` must be greater than or equal to `old_layout .size()`"
172172 ) ;
173173
174- match layout. size ( ) {
175- // SAFETY: the caller must ensure that the `new_size` does not overflow.
176- // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout.
177- 0 => unsafe {
178- let new_layout = Layout :: from_size_align_unchecked ( new_size, layout. align ( ) ) ;
179- self . alloc_impl ( new_layout, zeroed)
180- } ,
174+ match old_layout. size ( ) {
175+ 0 => self . alloc_impl ( new_layout, zeroed) ,
181176
182177 // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
183178 // as required by safety conditions. Other conditions must be upheld by the caller
184- old_size => unsafe {
185- // `realloc` probably checks for `new_size >= size` or something similar.
186- intrinsics:: assume ( new_size >= layout. size ( ) ) ;
179+ old_size if old_layout. align ( ) == new_layout. align ( ) => unsafe {
180+ let new_size = new_layout. size ( ) ;
181+
182+ // `realloc` probably checks for `new_size >= old_layout.size()` or something similar.
183+ intrinsics:: assume ( new_size >= old_layout. size ( ) ) ;
187184
188- let raw_ptr = realloc ( ptr. as_ptr ( ) , layout , new_size) ;
185+ let raw_ptr = realloc ( ptr. as_ptr ( ) , old_layout , new_size) ;
189186 let ptr = NonNull :: new ( raw_ptr) . ok_or ( AllocErr ) ?;
190187 if zeroed {
191188 raw_ptr. add ( old_size) . write_bytes ( 0 , new_size - old_size) ;
192189 }
193190 Ok ( NonNull :: slice_from_raw_parts ( ptr, new_size) )
194191 } ,
192+
193+ // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`,
194+ // both the old and new memory allocation are valid for reads and writes for `old_size`
195+ // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
196+ // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
197+ // for `dealloc` must be upheld by the caller.
198+ old_size => unsafe {
199+ let new_ptr = self . alloc_impl ( new_layout, zeroed) ?;
200+ ptr:: copy_nonoverlapping ( ptr. as_ptr ( ) , new_ptr. as_mut_ptr ( ) , old_size) ;
201+ self . dealloc ( ptr, old_layout) ;
202+ Ok ( new_ptr)
203+ } ,
195204 }
196205 }
197206}
@@ -221,52 +230,64 @@ unsafe impl AllocRef for Global {
221230 unsafe fn grow (
222231 & mut self ,
223232 ptr : NonNull < u8 > ,
224- layout : Layout ,
225- new_size : usize ,
233+ old_layout : Layout ,
234+ new_layout : Layout ,
226235 ) -> Result < NonNull < [ u8 ] > , AllocErr > {
227236 // SAFETY: all conditions must be upheld by the caller
228- unsafe { self . grow_impl ( ptr, layout , new_size , false ) }
237+ unsafe { self . grow_impl ( ptr, old_layout , new_layout , false ) }
229238 }
230239
231240 #[ inline]
232241 unsafe fn grow_zeroed (
233242 & mut self ,
234243 ptr : NonNull < u8 > ,
235- layout : Layout ,
236- new_size : usize ,
244+ old_layout : Layout ,
245+ new_layout : Layout ,
237246 ) -> Result < NonNull < [ u8 ] > , AllocErr > {
238247 // SAFETY: all conditions must be upheld by the caller
239- unsafe { self . grow_impl ( ptr, layout , new_size , true ) }
248+ unsafe { self . grow_impl ( ptr, old_layout , new_layout , true ) }
240249 }
241250
242251 #[ inline]
243252 unsafe fn shrink (
244253 & mut self ,
245254 ptr : NonNull < u8 > ,
246- layout : Layout ,
247- new_size : usize ,
255+ old_layout : Layout ,
256+ new_layout : Layout ,
248257 ) -> Result < NonNull < [ u8 ] > , AllocErr > {
249258 debug_assert ! (
250- new_size <= layout . size( ) ,
251- "`new_size ` must be smaller than or equal to `layout .size()`"
259+ new_layout . size ( ) <= old_layout . size( ) ,
260+ "`new_layout.size() ` must be smaller than or equal to `old_layout .size()`"
252261 ) ;
253262
254- match new_size {
263+ match new_layout . size ( ) {
255264 // SAFETY: conditions must be upheld by the caller
256265 0 => unsafe {
257- self . dealloc ( ptr, layout ) ;
258- Ok ( NonNull :: slice_from_raw_parts ( layout . dangling ( ) , 0 ) )
266+ self . dealloc ( ptr, old_layout ) ;
267+ Ok ( NonNull :: slice_from_raw_parts ( new_layout . dangling ( ) , 0 ) )
259268 } ,
260269
261270 // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
262- new_size => unsafe {
263- // `realloc` probably checks for `new_size <= size` or something similar.
264- intrinsics:: assume ( new_size <= layout . size ( ) ) ;
271+ new_size if old_layout . align ( ) == new_layout . align ( ) => unsafe {
272+ // `realloc` probably checks for `new_size <= old_layout. size() ` or something similar.
273+ intrinsics:: assume ( new_size <= old_layout . size ( ) ) ;
265274
266- let raw_ptr = realloc ( ptr. as_ptr ( ) , layout , new_size) ;
275+ let raw_ptr = realloc ( ptr. as_ptr ( ) , old_layout , new_size) ;
267276 let ptr = NonNull :: new ( raw_ptr) . ok_or ( AllocErr ) ?;
268277 Ok ( NonNull :: slice_from_raw_parts ( ptr, new_size) )
269278 } ,
279+
280+ // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`,
281+ // both the old and new memory allocation are valid for reads and writes for `new_size`
282+ // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
283+ // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
284+ // for `dealloc` must be upheld by the caller.
285+ new_size => unsafe {
286+ let new_ptr = self . alloc ( new_layout) ?;
287+ ptr:: copy_nonoverlapping ( ptr. as_ptr ( ) , new_ptr. as_mut_ptr ( ) , new_size) ;
288+ self . dealloc ( ptr, old_layout) ;
289+ Ok ( new_ptr)
290+ } ,
270291 }
271292 }
272293}
@@ -279,7 +300,7 @@ unsafe impl AllocRef for Global {
279300unsafe fn exchange_malloc ( size : usize , align : usize ) -> * mut u8 {
280301 let layout = unsafe { Layout :: from_size_align_unchecked ( size, align) } ;
281302 match Global . alloc ( layout) {
282- Ok ( ptr) => ptr. as_non_null_ptr ( ) . as_ptr ( ) ,
303+ Ok ( ptr) => ptr. as_mut_ptr ( ) ,
283304 Err ( _) => handle_alloc_error ( layout) ,
284305 }
285306}
0 commit comments