about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/alloc.rs190
-rw-r--r--library/std/src/keyword_docs.rs2
-rw-r--r--library/std/src/lib.rs3
-rw-r--r--library/std/src/sync/once.rs2
-rw-r--r--library/std/src/sys/unix/fd.rs40
-rw-r--r--library/std/src/sys/wasi/fs.rs1
6 files changed, 140 insertions, 98 deletions
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index ecfaaeace51..4712cc95b4a 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -140,28 +140,35 @@ pub struct System;
 #[unstable(feature = "allocator_api", issue = "32838")]
 unsafe impl AllocRef for System {
     #[inline]
-    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
-        unsafe {
-            let size = layout.size();
-            if size == 0 {
-                Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
-            } else {
-                let raw_ptr = match init {
-                    AllocInit::Uninitialized => GlobalAlloc::alloc(self, layout),
-                    AllocInit::Zeroed => GlobalAlloc::alloc_zeroed(self, layout),
-                };
-                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
-                Ok(MemoryBlock { ptr, size })
-            }
-        }
+    fn alloc(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+        let size = layout.size();
+        let ptr = if size == 0 {
+            layout.dangling()
+        } else {
+            // SAFETY: `layout` is non-zero in size,
+            unsafe { NonNull::new(GlobalAlloc::alloc(&System, layout)).ok_or(AllocErr)? }
+        };
+        Ok(NonNull::slice_from_raw_parts(ptr, size))
+    }
+
+    #[inline]
+    fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+        let size = layout.size();
+        let ptr = if size == 0 {
+            layout.dangling()
+        } else {
+            // SAFETY: `layout` is non-zero in size,
+            unsafe { NonNull::new(GlobalAlloc::alloc_zeroed(&System, layout)).ok_or(AllocErr)? }
+        };
+        Ok(NonNull::slice_from_raw_parts(ptr, size))
     }
 
     #[inline]
     unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
         if layout.size() != 0 {
-            // SAFETY: The safety guarantees are explained in the documentation
-            // for the `GlobalAlloc` trait and its `dealloc` method.
-            unsafe { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) }
+            // SAFETY: `layout` is non-zero in size,
+            // other conditions must be upheld by the caller
+            unsafe { GlobalAlloc::dealloc(&System, ptr.as_ptr(), layout) }
         }
     }
 
@@ -171,53 +178,59 @@ unsafe impl AllocRef for System {
         ptr: NonNull<u8>,
         layout: Layout,
         new_size: usize,
-        placement: ReallocPlacement,
-        init: AllocInit,
-    ) -> Result<MemoryBlock, AllocErr> {
-        let size = layout.size();
+    ) -> Result<NonNull<[u8]>, AllocErr> {
         debug_assert!(
-            new_size >= size,
-            "`new_size` must be greater than or equal to `memory.size()`"
+            new_size >= layout.size(),
+            "`new_size` must be greater than or equal to `layout.size()`"
         );
 
-        if size == new_size {
-            return Ok(MemoryBlock { ptr, size });
+        // SAFETY: `new_size` must be non-zero, which is checked in the match expression.
+        // Other conditions must be upheld by the caller
+        unsafe {
+            match layout.size() {
+                old_size if old_size == new_size => {
+                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
+                }
+                0 => self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())),
+                old_size => {
+                    // `realloc` probably checks for `new_size > size` or something similar.
+                    intrinsics::assume(new_size > old_size);
+                    let raw_ptr = GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size);
+                    let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
+                }
+            }
         }
+    }
 
-        match placement {
-            ReallocPlacement::InPlace => Err(AllocErr),
-            ReallocPlacement::MayMove if layout.size() == 0 => {
-                let new_layout =
-                    // SAFETY: The new size and layout alignement guarantees
-                    // are transfered to the caller (they come from parameters).
-                    //
-                    // See the preconditions for `Layout::from_size_align` to
-                    // see what must be checked.
-                    unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
-                self.alloc(new_layout, init)
-            }
-            ReallocPlacement::MayMove => {
-                // SAFETY:
-                //
-                // The safety guarantees are explained in the documentation
-                // for the `GlobalAlloc` trait and its `dealloc` method.
-                //
-                // `realloc` probably checks for `new_size > size` or something
-                // similar.
-                //
-                // For the guarantees about `init_offset`, see its documentation:
-                // `ptr` is assumed valid (and checked for non-NUL) and
-                // `memory.size` is set to `new_size` so the offset being `size`
-                // is valid.
-                let memory = unsafe {
-                    intrinsics::assume(new_size > size);
-                    let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
-                    let memory =
-                        MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size };
-                    init.init_offset(memory, size);
-                    memory
-                };
-                Ok(memory)
+    #[inline]
+    unsafe fn grow_zeroed(
+        &mut self,
+        ptr: NonNull<u8>,
+        layout: Layout,
+        new_size: usize,
+    ) -> Result<NonNull<[u8]>, AllocErr> {
+        debug_assert!(
+            new_size >= layout.size(),
+            "`new_size` must be greater than or equal to `layout.size()`"
+        );
+
+        // SAFETY: `new_size` must be non-zero, which is checked in the match expression.
+        // Other conditions must be upheld by the caller
+        unsafe {
+            match layout.size() {
+                old_size if old_size == new_size => {
+                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
+                }
+                0 => self.alloc_zeroed(Layout::from_size_align_unchecked(new_size, layout.align())),
+                old_size => {
+                    // `realloc` probably checks for `new_size > size` or something similar.
+                    intrinsics::assume(new_size > old_size);
+                    let raw_ptr = GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size);
+                    raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
+                    let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
+                }
             }
         }
     }
@@ -228,45 +241,34 @@ unsafe impl AllocRef for System {
         ptr: NonNull<u8>,
         layout: Layout,
         new_size: usize,
-        placement: ReallocPlacement,
-    ) -> Result<MemoryBlock, AllocErr> {
-        let size = layout.size();
+    ) -> Result<NonNull<[u8]>, AllocErr> {
+        let old_size = layout.size();
         debug_assert!(
-            new_size <= size,
-            "`new_size` must be smaller than or equal to `memory.size()`"
+            new_size <= old_size,
+            "`new_size` must be smaller than or equal to `layout.size()`"
         );
 
-        if size == new_size {
-            return Ok(MemoryBlock { ptr, size });
-        }
-
-        match placement {
-            ReallocPlacement::InPlace => Err(AllocErr),
-            ReallocPlacement::MayMove if new_size == 0 => {
-                // SAFETY: see `GlobalAlloc::dealloc` for the guarantees that
-                // must be respected. `ptr` and `layout` are parameters and so
-                // those guarantees must be checked by the caller.
-                unsafe { self.dealloc(ptr, layout) };
-                Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
+        let ptr = if new_size == old_size {
+            ptr
+        } else if new_size == 0 {
+            // SAFETY: `layout` is non-zero in size as `old_size` != `new_size`
+            // Other conditions must be upheld by the caller
+            unsafe {
+                self.dealloc(ptr, layout);
             }
-            ReallocPlacement::MayMove => {
-                // SAFETY:
-                //
-                // See `GlobalAlloc::realloc` for more informations about the
-                // guarantees expected by this method. `ptr`, `layout` and
-                // `new_size` are parameters and the responsability for their
-                // correctness is left to the caller.
-                //
-                // `realloc` probably checks for `new_size < size` or something
-                // similar.
-                let memory = unsafe {
-                    intrinsics::assume(new_size < size);
-                    let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
-                    MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size }
-                };
-                Ok(memory)
-            }
-        }
+            layout.dangling()
+        } else {
+            // SAFETY: new_size is not zero,
+            // Other conditions must be upheld by the caller
+            let raw_ptr = unsafe {
+                // `realloc` probably checks for `new_size < old_size` or something similar.
+                intrinsics::assume(new_size < old_size);
+                GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size)
+            };
+            NonNull::new(raw_ptr).ok_or(AllocErr)?
+        };
+
+        Ok(NonNull::slice_from_raw_parts(ptr, new_size))
     }
 }
 static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 1fa438747c1..c98008688ab 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -1363,7 +1363,7 @@ mod self_upper_keyword {}
 ///
 /// let r1 = &FOO as *const _;
 /// let r2 = &FOO as *const _;
-/// // With a strictly read-only static, references will have the same adress
+/// // With a strictly read-only static, references will have the same address
 /// assert_eq!(r1, r2);
 /// // A static item can be used just like a variable in many cases
 /// println!("{:?}", FOO);
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index c81b949af65..0569e46241a 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -291,6 +291,7 @@
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(nll)]
+#![feature(nonnull_slice_from_raw_parts)]
 #![feature(once_cell)]
 #![feature(optin_builtin_traits)]
 #![feature(or_patterns)]
@@ -308,6 +309,8 @@
 #![feature(shrink_to)]
 #![feature(slice_concat_ext)]
 #![feature(slice_internals)]
+#![feature(slice_ptr_get)]
+#![feature(slice_ptr_len)]
 #![feature(slice_strip)]
 #![feature(staged_api)]
 #![feature(std_internals)]
diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs
index 64260990824..714ec3e8786 100644
--- a/library/std/src/sync/once.rs
+++ b/library/std/src/sync/once.rs
@@ -81,7 +81,7 @@
 //   see the changes to drop the `Waiter` struct correctly.
 // * There is one place where the two atomics `Once.state_and_queue` and
 //   `Waiter.signaled` come together, and might be reordered by the compiler or
-//   processor. Because both use Aquire ordering such a reordering is not
+//   processor. Because both use Acquire ordering such a reordering is not
 //   allowed, so no need for SeqCst.
 
 use crate::cell::Cell;
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 84c4d662161..e36a53084ba 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -3,6 +3,8 @@
 use crate::cmp;
 use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
 use crate::mem;
+#[cfg(not(any(target_os = "redox", target_env = "newlib")))]
+use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sys::cvt;
 use crate::sys_common::AsInner;
 
@@ -26,6 +28,27 @@ const READ_LIMIT: usize = c_int::MAX as usize - 1;
 #[cfg(not(target_os = "macos"))]
 const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
 
+#[cfg(not(any(target_os = "redox", target_env = "newlib")))]
+fn max_iov() -> usize {
+    static LIM: AtomicUsize = AtomicUsize::new(0);
+
+    let mut lim = LIM.load(Ordering::Relaxed);
+    if lim == 0 {
+        let ret = unsafe { libc::sysconf(libc::_SC_IOV_MAX) };
+
+        // 16 is the minimum value required by POSIX.
+        lim = if ret > 0 { ret as usize } else { 16 };
+        LIM.store(lim, Ordering::Relaxed);
+    }
+
+    lim
+}
+
+#[cfg(any(target_os = "redox", target_env = "newlib"))]
+fn max_iov() -> usize {
+    16 // The minimum value required by POSIX.
+}
+
 impl FileDesc {
     pub fn new(fd: c_int) -> FileDesc {
         FileDesc { fd }
@@ -54,7 +77,7 @@ impl FileDesc {
             libc::readv(
                 self.fd,
                 bufs.as_ptr() as *const libc::iovec,
-                cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
+                cmp::min(bufs.len(), max_iov()) as c_int,
             )
         })?;
         Ok(ret as usize)
@@ -111,7 +134,7 @@ impl FileDesc {
             libc::writev(
                 self.fd,
                 bufs.as_ptr() as *const libc::iovec,
-                cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
+                cmp::min(bufs.len(), max_iov()) as c_int,
             )
         })?;
         Ok(ret as usize)
@@ -256,3 +279,16 @@ impl Drop for FileDesc {
         let _ = unsafe { libc::close(self.fd) };
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::{FileDesc, IoSlice};
+
+    #[test]
+    fn limit_vector_count() {
+        let stdout = FileDesc { fd: 1 };
+        let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();
+
+        assert!(stdout.write_vectored(&bufs).is_ok());
+    }
+}
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index 2eed9e436a9..6782d845bb0 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -331,6 +331,7 @@ impl OpenOptions {
         // FIXME: some of these should probably be read-only or write-only...
         base |= wasi::RIGHTS_FD_ADVISE;
         base |= wasi::RIGHTS_FD_FDSTAT_SET_FLAGS;
+        base |= wasi::RIGHTS_FD_FILESTAT_GET;
         base |= wasi::RIGHTS_FD_FILESTAT_SET_TIMES;
         base |= wasi::RIGHTS_FD_SEEK;
         base |= wasi::RIGHTS_FD_SYNC;