about summary refs log tree commit diff
path: root/src/liballoc/alloc.rs
diff options
context:
space:
mode:
authorTim Diekmann <tim.diekmann@3dvision.de>2020-03-26 17:11:47 +0100
committerTim Diekmann <tim.diekmann@3dvision.de>2020-03-26 17:11:47 +0100
commit2526accdd35c564eee80b6453a0b4965e6a76afd (patch)
tree76705d1a424dc9682b2e1c2599db6a0985d25335 /src/liballoc/alloc.rs
parent56cbf2f22aeb6448acd7eb49e9b2554c80bdbf79 (diff)
downloadrust-2526accdd35c564eee80b6453a0b4965e6a76afd.tar.gz
rust-2526accdd35c564eee80b6453a0b4965e6a76afd.zip
Fix issues from review and unsoundness of `RawVec::into_box`
Diffstat (limited to 'src/liballoc/alloc.rs')
-rw-r--r--src/liballoc/alloc.rs96
1 files changed, 45 insertions, 51 deletions
diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs
index 26524f62962..7eb9e0d5ea3 100644
--- a/src/liballoc/alloc.rs
+++ b/src/liballoc/alloc.rs
@@ -4,7 +4,7 @@
 
 use core::intrinsics::{self, min_align_of_val, size_of_val};
 use core::ptr::{NonNull, Unique};
-use core::usize;
+use core::{mem, usize};
 
 #[stable(feature = "alloc_module", since = "1.28.0")]
 #[doc(inline)]
@@ -165,102 +165,96 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
 #[unstable(feature = "allocator_api", issue = "32838")]
 unsafe impl AllocRef for Global {
     #[inline]
-    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<(NonNull<u8>, usize), AllocErr> {
-        let new_size = layout.size();
-        if new_size == 0 {
-            Ok((layout.dangling(), 0))
-        } else {
-            unsafe {
+    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
+        unsafe {
+            if layout.size() == 0 {
+                Ok(MemoryBlock::new(layout.dangling(), layout))
+            } else {
                 let raw_ptr = match init {
                     AllocInit::Uninitialized => alloc(layout),
                     AllocInit::Zeroed => alloc_zeroed(layout),
                 };
                 let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
-                Ok((ptr, new_size))
+                Ok(MemoryBlock::new(ptr, layout))
             }
         }
     }
 
     #[inline]
-    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
-        if layout.size() != 0 {
-            dealloc(ptr.as_ptr(), layout)
+    unsafe fn dealloc(&mut self, memory: MemoryBlock) {
+        if memory.size() != 0 {
+            dealloc(memory.ptr().as_ptr(), memory.layout())
         }
     }
 
     #[inline]
     unsafe fn grow(
         &mut self,
-        ptr: NonNull<u8>,
-        layout: Layout,
+        memory: &mut MemoryBlock,
         new_size: usize,
         placement: ReallocPlacement,
         init: AllocInit,
-    ) -> Result<(NonNull<u8>, usize), AllocErr> {
-        let old_size = layout.size();
+    ) -> Result<(), AllocErr> {
+        let old_size = memory.size();
         debug_assert!(
             new_size >= old_size,
-            "`new_size` must be greater than or equal to `layout.size()`"
+            "`new_size` must be greater than or equal to `memory.size()`"
         );
 
         if old_size == new_size {
-            return Ok((ptr, new_size));
+            return Ok(());
         }
 
+        let new_layout = Layout::from_size_align_unchecked(new_size, memory.align());
         match placement {
+            ReallocPlacement::InPlace => return Err(AllocErr),
+            ReallocPlacement::MayMove if memory.size() == 0 => {
+                *memory = self.alloc(new_layout, init)?
+            }
             ReallocPlacement::MayMove => {
-                if old_size == 0 {
-                    self.alloc(Layout::from_size_align_unchecked(new_size, layout.align()), init)
-                } else {
-                    // `realloc` probably checks for `new_size > old_size` or something similar.
-                    // `new_size` must be greater than or equal to `old_size` due to the safety constraint,
-                    // and `new_size` == `old_size` was caught before
-                    intrinsics::assume(new_size > old_size);
-                    let ptr =
-                        NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)?;
-                    let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
-                    init.initialize_offset(ptr, new_layout, old_size);
-                    Ok((ptr, new_size))
-                }
+                // `realloc` probably checks for `new_size > old_size` or something similar.
+                intrinsics::assume(new_size > old_size);
+                let ptr = realloc(memory.ptr().as_ptr(), memory.layout(), new_size);
+                *memory = MemoryBlock::new(NonNull::new(ptr).ok_or(AllocErr)?, new_layout);
+                memory.init_offset(init, old_size);
             }
-            ReallocPlacement::InPlace => Err(AllocErr),
         }
+        Ok(())
     }
 
     #[inline]
     unsafe fn shrink(
         &mut self,
-        ptr: NonNull<u8>,
-        layout: Layout,
+        memory: &mut MemoryBlock,
         new_size: usize,
         placement: ReallocPlacement,
-    ) -> Result<(NonNull<u8>, usize), AllocErr> {
-        let old_size = layout.size();
+    ) -> Result<(), AllocErr> {
+        let old_size = memory.size();
         debug_assert!(
             new_size <= old_size,
-            "`new_size` must be smaller than or equal to `layout.size()`"
+            "`new_size` must be smaller than or equal to `memory.size()`"
         );
 
         if old_size == new_size {
-            return Ok((ptr, new_size));
+            return Ok(());
         }
 
+        let new_layout = Layout::from_size_align_unchecked(new_size, memory.align());
         match placement {
+            ReallocPlacement::InPlace => return Err(AllocErr),
+            ReallocPlacement::MayMove if new_size == 0 => {
+                let new_memory = MemoryBlock::new(new_layout.dangling(), new_layout);
+                let old_memory = mem::replace(memory, new_memory);
+                self.dealloc(old_memory)
+            }
             ReallocPlacement::MayMove => {
-                let ptr = if new_size == 0 {
-                    self.dealloc(ptr, layout);
-                    layout.dangling()
-                } else {
-                    // `realloc` probably checks for `new_size > old_size` or something similar.
-                    // `new_size` must be smaller than or equal to `old_size` due to the safety constraint,
-                    // and `new_size` == `old_size` was caught before
-                    intrinsics::assume(new_size < old_size);
-                    NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)?
-                };
-                Ok((ptr, new_size))
+                // `realloc` probably checks for `new_size < old_size` or something similar.
+                intrinsics::assume(new_size < old_size);
+                let ptr = realloc(memory.ptr().as_ptr(), memory.layout(), new_size);
+                *memory = MemoryBlock::new(NonNull::new(ptr).ok_or(AllocErr)?, new_layout);
             }
-            ReallocPlacement::InPlace => Err(AllocErr),
         }
+        Ok(())
     }
 }
 
@@ -272,7 +266,7 @@ unsafe impl AllocRef for Global {
 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
     let layout = Layout::from_size_align_unchecked(size, align);
     match Global.alloc(layout, AllocInit::Uninitialized) {
-        Ok((ptr, _)) => ptr.as_ptr(),
+        Ok(memory) => memory.ptr().as_ptr(),
         Err(_) => handle_alloc_error(layout),
     }
 }
@@ -288,7 +282,7 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
     let size = size_of_val(ptr.as_ref());
     let align = min_align_of_val(ptr.as_ref());
     let layout = Layout::from_size_align_unchecked(size, align);
-    Global.dealloc(ptr.cast().into(), layout)
+    Global.dealloc(MemoryBlock::new(ptr.cast().into(), layout))
 }
 
 /// Abort on memory allocation error or failure.