Skip to content

Commit a50ccd9

Browse files
authored
Rollup merge of #69027 - TimDiekmann:zeroed-alloc, r=Amanieu
Add missing `_zeroed` varants to `AllocRef` The majority of the allocator wg has decided to add the missing `_zeroed` variants to `AllocRef`: > these should be added since they can be efficiently implemented with the `mremap` system call on Linux. `mremap` allows you to move/grow/shrink a memory mapping, and any new pages added for growth are guaranteed to be zeroed. > > If `AllocRef` does not have these methods then the user will have to manually write zeroes to the added memory since the API makes no guarantees on their contents. For the full discussion please see rust-lang/wg-allocators#14. This PR provides default implementations for `realloc_zeroed`, `alloc_excess_zeroed`, `realloc_excess_zeroed`, and `grow_in_place_zeroed`. r? @Amanieu
2 parents 9bc003d + 97d1f8d commit a50ccd9

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

src/libcore/alloc.rs

+137
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,59 @@ pub unsafe trait AllocRef {
847847
result
848848
}
849849

850+
/// Behaves like `realloc`, but also ensures that the new contents
851+
/// are set to zero before being returned.
852+
///
853+
/// # Safety
854+
///
855+
/// This function is unsafe for the same reasons that `realloc` is.
856+
///
857+
/// # Errors
858+
///
859+
/// Returns `Err` only if the new layout
860+
/// does not meet the allocator's size
861+
/// and alignment constraints of the allocator, or if reallocation
862+
/// otherwise fails.
863+
///
864+
/// Implementations are encouraged to return `Err` on memory
865+
/// exhaustion rather than panicking or aborting, but this is not
866+
/// a strict requirement. (Specifically: it is *legal* to
867+
/// implement this trait atop an underlying native allocation
868+
/// library that aborts on memory exhaustion.)
869+
///
870+
/// Clients wishing to abort computation in response to a
871+
/// reallocation error are encouraged to call the [`handle_alloc_error`] function,
872+
/// rather than directly invoking `panic!` or similar.
873+
///
874+
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
875+
unsafe fn realloc_zeroed(
876+
&mut self,
877+
ptr: NonNull<u8>,
878+
layout: Layout,
879+
new_size: usize,
880+
) -> Result<NonNull<u8>, AllocErr> {
881+
let old_size = layout.size();
882+
883+
if new_size >= old_size {
884+
if let Ok(()) = self.grow_in_place_zeroed(ptr, layout, new_size) {
885+
return Ok(ptr);
886+
}
887+
} else if new_size < old_size {
888+
if let Ok(()) = self.shrink_in_place(ptr, layout, new_size) {
889+
return Ok(ptr);
890+
}
891+
}
892+
893+
// otherwise, fall back on alloc + copy + dealloc.
894+
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
895+
let result = self.alloc_zeroed(new_layout);
896+
if let Ok(new_ptr) = result {
897+
ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), cmp::min(old_size, new_size));
898+
self.dealloc(ptr, layout);
899+
}
900+
result
901+
}
902+
850903
/// Behaves like `alloc`, but also ensures that the contents
851904
/// are set to zero before being returned.
852905
///
@@ -898,6 +951,31 @@ pub unsafe trait AllocRef {
898951
self.alloc(layout).map(|p| Excess(p, usable_size.1))
899952
}
900953

954+
/// Behaves like `alloc`, but also returns the whole size of
955+
/// the returned block. For some `layout` inputs, like arrays, this
956+
/// may include extra storage usable for additional data.
957+
/// Also it ensures that the contents are set to zero before being returned.
958+
///
959+
/// # Safety
960+
///
961+
/// This function is unsafe for the same reasons that `alloc` is.
962+
///
963+
/// # Errors
964+
///
965+
/// Returning `Err` indicates that either memory is exhausted or
966+
/// `layout` does not meet allocator's size or alignment
967+
/// constraints, just as in `alloc`.
968+
///
969+
/// Clients wishing to abort computation in response to an
970+
/// allocation error are encouraged to call the [`handle_alloc_error`] function,
971+
/// rather than directly invoking `panic!` or similar.
972+
///
973+
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
974+
unsafe fn alloc_excess_zeroed(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
975+
let usable_size = self.usable_size(&layout);
976+
self.alloc_zeroed(layout).map(|p| Excess(p, usable_size.1))
977+
}
978+
901979
/// Behaves like `realloc`, but also returns the whole size of
902980
/// the returned block. For some `layout` inputs, like arrays, this
903981
/// may include extra storage usable for additional data.
@@ -928,6 +1006,37 @@ pub unsafe trait AllocRef {
9281006
self.realloc(ptr, layout, new_size).map(|p| Excess(p, usable_size.1))
9291007
}
9301008

1009+
/// Behaves like `realloc`, but also returns the whole size of
1010+
/// the returned block. For some `layout` inputs, like arrays, this
1011+
/// may include extra storage usable for additional data.
1012+
/// Also it ensures that the contents are set to zero before being returned.
1013+
///
1014+
/// # Safety
1015+
///
1016+
/// This function is unsafe for the same reasons that `realloc` is.
1017+
///
1018+
/// # Errors
1019+
///
1020+
/// Returning `Err` indicates that either memory is exhausted or
1021+
/// `layout` does not meet allocator's size or alignment
1022+
/// constraints, just as in `realloc`.
1023+
///
1024+
/// Clients wishing to abort computation in response to a
1025+
/// reallocation error are encouraged to call the [`handle_alloc_error`] function,
1026+
/// rather than directly invoking `panic!` or similar.
1027+
///
1028+
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
1029+
unsafe fn realloc_excess_zeroed(
1030+
&mut self,
1031+
ptr: NonNull<u8>,
1032+
layout: Layout,
1033+
new_size: usize,
1034+
) -> Result<Excess, AllocErr> {
1035+
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
1036+
let usable_size = self.usable_size(&new_layout);
1037+
self.realloc_zeroed(ptr, layout, new_size).map(|p| Excess(p, usable_size.1))
1038+
}
1039+
9311040
/// Attempts to extend the allocation referenced by `ptr` to fit `new_size`.
9321041
///
9331042
/// If this returns `Ok`, then the allocator has asserted that the
@@ -977,6 +1086,34 @@ pub unsafe trait AllocRef {
9771086
if new_size <= u { Ok(()) } else { Err(CannotReallocInPlace) }
9781087
}
9791088

1089+
/// Behaves like `grow_in_place`, but also ensures that the new
1090+
/// contents are set to zero before being returned.
1091+
///
1092+
/// # Safety
1093+
///
1094+
/// This function is unsafe for the same reasons that `grow_in_place` is.
1095+
///
1096+
/// # Errors
1097+
///
1098+
/// Returns `Err(CannotReallocInPlace)` when the allocator is
1099+
/// unable to assert that the memory block referenced by `ptr`
1100+
/// could fit `layout`.
1101+
///
1102+
/// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error`
1103+
/// function; clients are expected either to be able to recover from
1104+
/// `grow_in_place` failures without aborting, or to fall back on
1105+
/// another reallocation method before resorting to an abort.
1106+
unsafe fn grow_in_place_zeroed(
1107+
&mut self,
1108+
ptr: NonNull<u8>,
1109+
layout: Layout,
1110+
new_size: usize,
1111+
) -> Result<(), CannotReallocInPlace> {
1112+
self.grow_in_place(ptr, layout, new_size)?;
1113+
ptr.as_ptr().add(layout.size()).write_bytes(0, new_size - layout.size());
1114+
Ok(())
1115+
}
1116+
9801117
/// Attempts to shrink the allocation referenced by `ptr` to fit `new_size`.
9811118
///
9821119
/// If this returns `Ok`, then the allocator has asserted that the

0 commit comments

Comments
 (0)