about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorMatt Brubeck <mbrubeck@limpet.net>2017-03-09 17:53:01 -0800
committerMatt Brubeck <mbrubeck@limpet.net>2017-04-15 09:01:56 -0700
commit675475c4d3e3b1ebff5b761570f4a3f9a0ca23df (patch)
tree49cfa5b4d6edca5205909e9b0729e9744507940c /src/liballoc
parent5637ed756632ded9e458b82a23cc1dddbb57c51f (diff)
downloadrust-675475c4d3e3b1ebff5b761570f4a3f9a0ca23df.tar.gz
rust-675475c4d3e3b1ebff5b761570f4a3f9a0ca23df.zip
Specialize Vec::from_elem<u8> to use calloc or memset
Fixes #38723.
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/heap.rs34
-rw-r--r--src/liballoc/raw_vec.rs17
2 files changed, 50 insertions, 1 deletions
diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs
index 51e6f2f8bd7..08a0b2a6d00 100644
--- a/src/liballoc/heap.rs
+++ b/src/liballoc/heap.rs
@@ -23,6 +23,7 @@ use core::intrinsics::{min_align_of_val, size_of_val};
 extern "C" {
     #[allocator]
     fn __rust_allocate(size: usize, align: usize) -> *mut u8;
+    fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8;
     fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize);
     fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8;
     fn __rust_reallocate_inplace(ptr: *mut u8,
@@ -59,6 +60,20 @@ pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
     __rust_allocate(size, align)
 }
 
+/// Return a pointer to `size` bytes of memory aligned to `align` and
+/// initialized to zeroes.
+///
+/// On failure, return a null pointer.
+///
+/// Behavior is undefined if the requested size is 0 or the alignment is not a
+/// power of 2. The alignment must be no larger than the largest supported page
+/// size on the platform.
+#[inline]
+pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
+    check_size_and_alignment(size, align);
+    __rust_allocate_zeroed(size, align)
+}
+
 /// Resize the allocation referenced by `ptr` to `size` bytes.
 ///
 /// On failure, return a null pointer and leave the original allocation intact.
@@ -163,6 +178,25 @@ mod tests {
     use heap;
 
     #[test]
+    fn allocate_zeroed() {
+        unsafe {
+            let size = 1024;
+            let ptr = heap::allocate_zeroed(size, 1);
+            if ptr.is_null() {
+                ::oom()
+            }
+
+            let end = ptr.offset(size as isize);
+            let mut i = ptr;
+            while i < end {
+                assert_eq!(*i, 0);
+                i = i.offset(1);
+            }
+            heap::deallocate(ptr, size, 1);
+        }
+    }
+
+    #[test]
     fn basic_reallocate_inplace_noop() {
         unsafe {
             let size = 4000;
diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs
index 357a2724e00..6a53d3a9ca5 100644
--- a/src/liballoc/raw_vec.rs
+++ b/src/liballoc/raw_vec.rs
@@ -81,7 +81,18 @@ impl<T> RawVec<T> {
     /// # Aborts
     ///
     /// Aborts on OOM
+    #[inline]
     pub fn with_capacity(cap: usize) -> Self {
+        RawVec::allocate(cap, false)
+    }
+
+    /// Like `with_capacity` but guarantees the buffer is zeroed.
+    #[inline]
+    pub fn with_capacity_zeroed(cap: usize) -> Self {
+        RawVec::allocate(cap, true)
+    }
+
+    fn allocate(cap: usize, zeroed: bool) -> Self {
         unsafe {
             let elem_size = mem::size_of::<T>();
 
@@ -93,7 +104,11 @@ impl<T> RawVec<T> {
                 heap::EMPTY as *mut u8
             } else {
                 let align = mem::align_of::<T>();
-                let ptr = heap::allocate(alloc_size, align);
+                let ptr = if zeroed {
+                    heap::allocate_zeroed(alloc_size, align)
+                } else {
+                    heap::allocate(alloc_size, align)
+                };
                 if ptr.is_null() {
                     oom()
                 }