3
3
#![ stable( feature = "alloc_module" , since = "1.28.0" ) ]
4
4
5
5
use core:: intrinsics:: { self , min_align_of_val, size_of_val} ;
6
- use core:: ptr:: { NonNull , Unique } ;
6
+ use core:: ptr:: { self , NonNull , Unique } ;
7
7
8
8
#[ stable( feature = "alloc_module" , since = "1.28.0" ) ]
9
9
#[ doc( inline) ]
@@ -180,36 +180,45 @@ impl Global {
180
180
unsafe fn grow_impl (
181
181
& mut self ,
182
182
ptr : NonNull < u8 > ,
183
- layout : Layout ,
184
- new_size : usize ,
183
+ old_layout : Layout ,
184
+ new_layout : Layout ,
185
185
zeroed : bool ,
186
186
) -> Result < NonNull < [ u8 ] > , AllocErr > {
187
187
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()`"
190
190
) ;
191
191
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) ,
199
194
200
195
// SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
201
196
// 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 ( ) ) ;
205
202
206
- let raw_ptr = realloc ( ptr. as_ptr ( ) , layout , new_size) ;
203
+ let raw_ptr = realloc ( ptr. as_ptr ( ) , old_layout , new_size) ;
207
204
let ptr = NonNull :: new ( raw_ptr) . ok_or ( AllocErr ) ?;
208
205
if zeroed {
209
206
raw_ptr. add ( old_size) . write_bytes ( 0 , new_size - old_size) ;
210
207
}
211
208
Ok ( NonNull :: slice_from_raw_parts ( ptr, new_size) )
212
209
} ,
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
+ } ,
213
222
}
214
223
}
215
224
}
@@ -239,52 +248,64 @@ unsafe impl AllocRef for Global {
239
248
unsafe fn grow (
240
249
& mut self ,
241
250
ptr : NonNull < u8 > ,
242
- layout : Layout ,
243
- new_size : usize ,
251
+ old_layout : Layout ,
252
+ new_layout : Layout ,
244
253
) -> Result < NonNull < [ u8 ] > , AllocErr > {
245
254
// 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 ) }
247
256
}
248
257
249
258
#[ inline]
250
259
unsafe fn grow_zeroed (
251
260
& mut self ,
252
261
ptr : NonNull < u8 > ,
253
- layout : Layout ,
254
- new_size : usize ,
262
+ old_layout : Layout ,
263
+ new_layout : Layout ,
255
264
) -> Result < NonNull < [ u8 ] > , AllocErr > {
256
265
// 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 ) }
258
267
}
259
268
260
269
#[ inline]
261
270
unsafe fn shrink (
262
271
& mut self ,
263
272
ptr : NonNull < u8 > ,
264
- layout : Layout ,
265
- new_size : usize ,
273
+ old_layout : Layout ,
274
+ new_layout : Layout ,
266
275
) -> Result < NonNull < [ u8 ] > , AllocErr > {
267
276
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()`"
270
279
) ;
271
280
272
- match new_size {
281
+ match new_layout . size ( ) {
273
282
// SAFETY: conditions must be upheld by the caller
274
283
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 ) )
277
286
} ,
278
287
279
288
// 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 ( ) ) ;
283
292
284
- let raw_ptr = realloc ( ptr. as_ptr ( ) , layout , new_size) ;
293
+ let raw_ptr = realloc ( ptr. as_ptr ( ) , old_layout , new_size) ;
285
294
let ptr = NonNull :: new ( raw_ptr) . ok_or ( AllocErr ) ?;
286
295
Ok ( NonNull :: slice_from_raw_parts ( ptr, new_size) )
287
296
} ,
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
+ } ,
288
309
}
289
310
}
290
311
}
@@ -297,7 +318,7 @@ unsafe impl AllocRef for Global {
297
318
unsafe fn exchange_malloc ( size : usize , align : usize ) -> * mut u8 {
298
319
let layout = unsafe { Layout :: from_size_align_unchecked ( size, align) } ;
299
320
match Global . alloc ( layout) {
300
- Ok ( ptr) => ptr. as_non_null_ptr ( ) . as_ptr ( ) ,
321
+ Ok ( ptr) => ptr. as_mut_ptr ( ) ,
301
322
Err ( _) => handle_alloc_error ( layout) ,
302
323
}
303
324
}
0 commit comments