diff options
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/alloc.rs | 190 | ||||
| -rw-r--r-- | library/std/src/keyword_docs.rs | 2 | ||||
| -rw-r--r-- | library/std/src/lib.rs | 3 | ||||
| -rw-r--r-- | library/std/src/sync/once.rs | 2 | ||||
| -rw-r--r-- | library/std/src/sys/unix/fd.rs | 40 | ||||
| -rw-r--r-- | library/std/src/sys/wasi/fs.rs | 1 |
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; |
