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) ]
@@ -162,36 +162,45 @@ impl Global {
162
162
unsafe fn grow_impl (
163
163
& mut self ,
164
164
ptr : NonNull < u8 > ,
165
- layout : Layout ,
166
- new_size : usize ,
165
+ old_layout : Layout ,
166
+ new_layout : Layout ,
167
167
zeroed : bool ,
168
168
) -> Result < NonNull < [ u8 ] > , AllocErr > {
169
169
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()`"
172
172
) ;
173
173
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) ,
181
176
182
177
// SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
183
178
// 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 ( ) ) ;
187
184
188
- let raw_ptr = realloc ( ptr. as_ptr ( ) , layout , new_size) ;
185
+ let raw_ptr = realloc ( ptr. as_ptr ( ) , old_layout , new_size) ;
189
186
let ptr = NonNull :: new ( raw_ptr) . ok_or ( AllocErr ) ?;
190
187
if zeroed {
191
188
raw_ptr. add ( old_size) . write_bytes ( 0 , new_size - old_size) ;
192
189
}
193
190
Ok ( NonNull :: slice_from_raw_parts ( ptr, new_size) )
194
191
} ,
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
+ } ,
195
204
}
196
205
}
197
206
}
@@ -221,52 +230,64 @@ unsafe impl AllocRef for Global {
221
230
unsafe fn grow (
222
231
& mut self ,
223
232
ptr : NonNull < u8 > ,
224
- layout : Layout ,
225
- new_size : usize ,
233
+ old_layout : Layout ,
234
+ new_layout : Layout ,
226
235
) -> Result < NonNull < [ u8 ] > , AllocErr > {
227
236
// 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 ) }
229
238
}
230
239
231
240
#[ inline]
232
241
unsafe fn grow_zeroed (
233
242
& mut self ,
234
243
ptr : NonNull < u8 > ,
235
- layout : Layout ,
236
- new_size : usize ,
244
+ old_layout : Layout ,
245
+ new_layout : Layout ,
237
246
) -> Result < NonNull < [ u8 ] > , AllocErr > {
238
247
// 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 ) }
240
249
}
241
250
242
251
#[ inline]
243
252
unsafe fn shrink (
244
253
& mut self ,
245
254
ptr : NonNull < u8 > ,
246
- layout : Layout ,
247
- new_size : usize ,
255
+ old_layout : Layout ,
256
+ new_layout : Layout ,
248
257
) -> Result < NonNull < [ u8 ] > , AllocErr > {
249
258
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()`"
252
261
) ;
253
262
254
- match new_size {
263
+ match new_layout . size ( ) {
255
264
// SAFETY: conditions must be upheld by the caller
256
265
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 ) )
259
268
} ,
260
269
261
270
// 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 ( ) ) ;
265
274
266
- let raw_ptr = realloc ( ptr. as_ptr ( ) , layout , new_size) ;
275
+ let raw_ptr = realloc ( ptr. as_ptr ( ) , old_layout , new_size) ;
267
276
let ptr = NonNull :: new ( raw_ptr) . ok_or ( AllocErr ) ?;
268
277
Ok ( NonNull :: slice_from_raw_parts ( ptr, new_size) )
269
278
} ,
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
+ } ,
270
291
}
271
292
}
272
293
}
@@ -279,7 +300,7 @@ unsafe impl AllocRef for Global {
279
300
unsafe fn exchange_malloc ( size : usize , align : usize ) -> * mut u8 {
280
301
let layout = unsafe { Layout :: from_size_align_unchecked ( size, align) } ;
281
302
match Global . alloc ( layout) {
282
- Ok ( ptr) => ptr. as_non_null_ptr ( ) . as_ptr ( ) ,
303
+ Ok ( ptr) => ptr. as_mut_ptr ( ) ,
283
304
Err ( _) => handle_alloc_error ( layout) ,
284
305
}
285
306
}
0 commit comments