diff --git a/src/doc/unstable-book/src/library-features/read-initializer.md b/src/doc/unstable-book/src/library-features/read-initializer.md new file mode 100644 index 00000000000..898fe58eeee --- /dev/null +++ b/src/doc/unstable-book/src/library-features/read-initializer.md @@ -0,0 +1,7 @@ +# `read_initializer` + +The tracking issue for this feature is: [#42788] + +[#0]: https://github.com/rust-lang/rust/issues/42788 + +------------------------ diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 69843199348..5b8c0c33990 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -19,7 +19,7 @@ use fmt; use ffi::OsString; -use io::{self, SeekFrom, Seek, Read, Write}; +use io::{self, SeekFrom, Seek, Read, Initializer, Write}; use path::{Path, PathBuf}; use sys::fs as fs_imp; use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner}; @@ -446,8 +446,10 @@ impl Read for File { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.inner.read_to_end(buf) + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() } } #[stable(feature = "rust1", since = "1.0.0")] @@ -468,8 +470,10 @@ impl<'a> Read for &'a File { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.inner.read_to_end(buf) + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 3b82412716e..296ee78aadb 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -15,7 +15,7 @@ use cmp; use error; use fmt; -use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom}; +use io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom}; use memchr; /// The `BufReader` struct adds buffering to any reader. @@ -92,11 +92,16 @@ pub fn new(inner: R) -> BufReader { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: R) -> BufReader { - BufReader { - inner: inner, - buf: vec![0; cap].into_boxed_slice(), - pos: 0, - cap: 0, + unsafe { + let mut buffer = Vec::with_capacity(cap); + buffer.set_len(cap); + inner.initializer().initialize(&mut buffer); + BufReader { + inner: inner, + buf: buffer.into_boxed_slice(), + pos: 0, + cap: 0, + } } } @@ -180,6 +185,11 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { self.consume(nread); Ok(nread) } + + // we can't skip unconditionally because of the large buffer case in read. + unsafe fn initializer(&self) -> Initializer { + self.inner.initializer() + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 53347eb14db..616b4f47ed3 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -12,7 +12,7 @@ use core::convert::TryInto; use cmp; -use io::{self, SeekFrom, Error, ErrorKind}; +use io::{self, Initializer, SeekFrom, Error, ErrorKind}; /// A `Cursor` wraps another type and provides it with a /// [`Seek`] implementation. @@ -229,6 +229,11 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { self.pos += n as u64; Ok(n) } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs index f691289811b..d6b41ceda43 100644 --- a/src/libstd/io/impls.rs +++ b/src/libstd/io/impls.rs @@ -9,7 +9,7 @@ // except according to those terms. use cmp; -use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind}; +use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind}; use fmt; use mem; @@ -23,6 +23,11 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } + #[inline] + unsafe fn initializer(&self) -> Initializer { + (**self).initializer() + } + #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { (**self).read_to_end(buf) @@ -87,6 +92,11 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } + #[inline] + unsafe fn initializer(&self) -> Initializer { + (**self).initializer() + } + #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { (**self).read_to_end(buf) @@ -171,6 +181,11 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { Ok(amt) } + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } + #[inline] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { if buf.len() > self.len() { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 3f859c45c28..680a5f32ae2 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -275,6 +275,7 @@ use result; use str; use memchr; +use ptr; #[stable(feature = "rust1", since = "1.0.0")] pub use self::buffered::{BufReader, BufWriter, LineWriter}; @@ -292,7 +293,7 @@ pub use self::stdio::{StdoutLock, StderrLock, StdinLock}; #[unstable(feature = "print_internals", issue = "0")] pub use self::stdio::{_print, _eprint}; -#[unstable(feature = "libstd_io_internals", issue = "0")] +#[unstable(feature = "libstd_io_internals", issue = "42788")] #[doc(no_inline, hidden)] pub use self::stdio::{set_panic, set_print}; @@ -307,6 +308,14 @@ const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; +struct Guard<'a> { buf: &'a mut Vec, len: usize } + +impl<'a> Drop for Guard<'a> { + fn drop(&mut self) { + unsafe { self.buf.set_len(self.len); } + } +} + // A few methods below (read_to_string, read_line) will append data into a // `String` buffer, but we need to be pretty careful when doing this. The // implementation will just call `.as_mut_vec()` and then delegate to a @@ -328,23 +337,16 @@ fn append_to_string(buf: &mut String, f: F) -> Result where F: FnOnce(&mut Vec) -> Result { - struct Guard<'a> { s: &'a mut Vec, len: usize } - impl<'a> Drop for Guard<'a> { - fn drop(&mut self) { - unsafe { self.s.set_len(self.len); } - } - } - unsafe { - let mut g = Guard { len: buf.len(), s: buf.as_mut_vec() }; - let ret = f(g.s); - if str::from_utf8(&g.s[g.len..]).is_err() { + let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() }; + let ret = f(g.buf); + if str::from_utf8(&g.buf[g.len..]).is_err() { ret.and_then(|_| { Err(Error::new(ErrorKind::InvalidData, "stream did not contain valid UTF-8")) }) } else { - g.len = g.s.len(); + g.len = g.buf.len(); ret } } @@ -356,25 +358,32 @@ fn drop(&mut self) { // of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every // time is 4,500 times (!) slower than this if the reader has a very small // amount of data to return. +// +// Because we're extending the buffer with uninitialized data for trusted +// readers, we need to make sure to truncate that if any of this panics. fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { let start_len = buf.len(); - let mut len = start_len; + let mut g = Guard { len: buf.len(), buf: buf }; let mut new_write_size = 16; let ret; loop { - if len == buf.len() { + if g.len == g.buf.len() { if new_write_size < DEFAULT_BUF_SIZE { new_write_size *= 2; } - buf.resize(len + new_write_size, 0); + unsafe { + g.buf.reserve(new_write_size); + g.buf.set_len(g.len + new_write_size); + r.initializer().initialize(&mut g.buf[g.len..]); + } } - match r.read(&mut buf[len..]) { + match r.read(&mut g.buf[g.len..]) { Ok(0) => { - ret = Ok(len - start_len); + ret = Ok(g.len - start_len); break; } - Ok(n) => len += n, + Ok(n) => g.len += n, Err(ref e) if e.kind() == ErrorKind::Interrupted => {} Err(e) => { ret = Err(e); @@ -383,7 +392,6 @@ fn read_to_end(r: &mut R, buf: &mut Vec) -> Result } } - buf.truncate(len); ret } @@ -494,6 +502,31 @@ pub trait Read { #[stable(feature = "rust1", since = "1.0.0")] fn read(&mut self, buf: &mut [u8]) -> Result; + /// Determines if this `Read`er can work with buffers of uninitialized + /// memory. + /// + /// The default implementation returns an initializer which will zero + /// buffers. + /// + /// If a `Read`er guarantees that it can work properly with uninitialized + /// memory, it should call `Initializer::nop()`. See the documentation for + /// `Initializer` for details. + /// + /// The behavior of this method must be independent of the state of the + /// `Read`er - the method only takes `&self` so that it can be used through + /// trait objects. + /// + /// # Unsafety + /// + /// This method is unsafe because a `Read`er could otherwise return a + /// non-zeroing `Initializer` from another `Read` type without an `unsafe` + /// block. + #[unstable(feature = "read_initializer", issue = "42788")] + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::zeroing() + } + /// Read all bytes until EOF in this source, placing them into `buf`. /// /// All bytes read from this source will be appended to the specified buffer @@ -829,6 +862,50 @@ fn take(self, limit: u64) -> Take where Self: Sized { } } +/// A type used to conditionally initialize buffers passed to `Read` methods. +#[unstable(feature = "read_initializer", issue = "42788")] +#[derive(Debug)] +pub struct Initializer(bool); + +impl Initializer { + /// Returns a new `Initializer` which will zero out buffers. + #[unstable(feature = "read_initializer", issue = "42788")] + #[inline] + pub fn zeroing() -> Initializer { + Initializer(true) + } + + /// Returns a new `Initializer` which will not zero out buffers. + /// + /// # Unsafety + /// + /// This may only be called by `Read`ers which guarantee that they will not + /// read from buffers passed to `Read` methods, and that the return value of + /// the method accurately reflects the number of bytes that have been + /// written to the head of the buffer. + #[unstable(feature = "read_initializer", issue = "42788")] + #[inline] + pub unsafe fn nop() -> Initializer { + Initializer(false) + } + + /// Indicates if a buffer should be initialized. + #[unstable(feature = "read_initializer", issue = "42788")] + #[inline] + pub fn should_initialize(&self) -> bool { + self.0 + } + + /// Initializes a buffer if necessary. + #[unstable(feature = "read_initializer", issue = "42788")] + #[inline] + pub fn initialize(&self, buf: &mut [u8]) { + if self.should_initialize() { + unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) } + } + } +} + /// A trait for objects which are byte-oriented sinks. /// /// Implementors of the `Write` trait are sometimes called 'writers'. @@ -1608,6 +1685,15 @@ fn read(&mut self, buf: &mut [u8]) -> Result { } self.second.read(buf) } + + unsafe fn initializer(&self) -> Initializer { + let initializer = self.first.initializer(); + if initializer.should_initialize() { + initializer + } else { + self.second.initializer() + } + } } #[stable(feature = "chain_bufread", since = "1.9.0")] @@ -1772,6 +1858,10 @@ fn read(&mut self, buf: &mut [u8]) -> Result { self.limit -= n as u64; Ok(n) } + + unsafe fn initializer(&self) -> Initializer { + self.inner.initializer() + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index a8b0bf0071a..fb489bf487b 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -13,7 +13,7 @@ use cell::RefCell; use fmt; use io::lazy::Lazy; -use io::{self, BufReader, LineWriter}; +use io::{self, Initializer, BufReader, LineWriter}; use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; @@ -75,8 +75,10 @@ fn stderr_raw() -> io::Result { stdio::Stderr::new().map(StderrRaw) } impl Read for StdinRaw { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() } } impl Write for StdoutRaw { @@ -116,12 +118,6 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { Maybe::Fake => Ok(0) } } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - match *self { - Maybe::Real(ref mut r) => handle_ebadf(r.read_to_end(buf), 0), - Maybe::Fake => Ok(0) - } - } } fn handle_ebadf(r: io::Result, default: T) -> io::Result { @@ -294,6 +290,10 @@ impl Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.lock().read(buf) } + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { self.lock().read_to_end(buf) } @@ -310,8 +310,9 @@ impl<'a> Read for StdinLock<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.inner.read_to_end(buf) + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() } } diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 078f1ad3f6c..88f4214296d 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -11,7 +11,8 @@ #![allow(missing_copy_implementations)] use fmt; -use io::{self, Read, Write, ErrorKind, BufRead}; +use io::{self, Read, Initializer, Write, ErrorKind, BufRead}; +use mem; /// Copies the entire contents of a reader into a writer. /// @@ -47,7 +48,12 @@ pub fn copy(reader: &mut R, writer: &mut W) -> io::Result where R: Read, W: Write { - let mut buf = [0; super::DEFAULT_BUF_SIZE]; + let mut buf = unsafe { + let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized(); + reader.initializer().initialize(&mut buf); + buf + }; + let mut written = 0; loop { let len = match reader.read(&mut buf) { @@ -90,11 +96,19 @@ pub fn empty() -> Empty { Empty { _priv: () } } #[stable(feature = "rust1", since = "1.0.0")] impl Read for Empty { + #[inline] fn read(&mut self, _buf: &mut [u8]) -> io::Result { Ok(0) } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } } #[stable(feature = "rust1", since = "1.0.0")] impl BufRead for Empty { + #[inline] fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) } + #[inline] fn consume(&mut self, _n: usize) {} } @@ -133,12 +147,18 @@ pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } } #[stable(feature = "rust1", since = "1.0.0")] impl Read for Repeat { + #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { for slot in &mut *buf { *slot = self.byte; } Ok(buf.len()) } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } } #[stable(feature = "std_debug", since = "1.16.0")] @@ -176,7 +196,9 @@ pub fn sink() -> Sink { Sink { _priv: () } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for Sink { + #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { Ok(buf.len()) } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index c1493c9c6f4..7be1fc9cd8c 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -11,7 +11,7 @@ use io::prelude::*; use fmt; -use io; +use io::{self, Initializer}; use net::{ToSocketAddrs, SocketAddr, Shutdown}; use sys_common::net as net_imp; use sys_common::{AsInner, FromInner, IntoInner}; @@ -481,8 +481,10 @@ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { #[stable(feature = "rust1", since = "1.0.0")] impl Read for TcpStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() } } #[stable(feature = "rust1", since = "1.0.0")] @@ -493,8 +495,10 @@ fn flush(&mut self) -> io::Result<()> { Ok(()) } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Read for &'a TcpStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 4c6d88c0ae8..4632c8a918e 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -60,7 +60,7 @@ use ffi::OsStr; use fmt; use fs; -use io; +use io::{self, Initializer}; use path::Path; use str; use sys::pipe::{read2, AnonPipe}; @@ -208,8 +208,9 @@ impl Read for ChildStdout { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.inner.read_to_end(buf) + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() } } @@ -250,8 +251,9 @@ impl Read for ChildStderr { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.inner.read_to_end(buf) + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() } } diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs index b6de68a9dc1..1b37aafef56 100644 --- a/src/libstd/sys/redox/fd.rs +++ b/src/libstd/sys/redox/fd.rs @@ -14,7 +14,6 @@ use mem; use sys::{cvt, syscall}; use sys_common::AsInner; -use sys_common::io::read_to_end_uninitialized; pub struct FileDesc { fd: usize, @@ -78,10 +77,6 @@ impl<'a> Read for &'a FileDesc { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } - - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - unsafe { read_to_end_uninitialized(self, buf) } - } } impl AsInner for FileDesc { diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index a8391d2b898..48d9cdcb2c9 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -285,10 +285,6 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) - } - pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs index 936097d7fb2..ac3fd2ad6b9 100644 --- a/src/libstd/sys/redox/net/tcp.rs +++ b/src/libstd/sys/redox/net/tcp.rs @@ -41,10 +41,6 @@ pub fn read(&self, buf: &mut [u8]) -> Result { self.0.read(buf) } - pub fn read_to_end(&self, buf: &mut Vec) -> Result { - self.0.read_to_end(buf) - } - pub fn write(&self, buf: &[u8]) -> Result { self.0.write(buf) } diff --git a/src/libstd/sys/redox/pipe.rs b/src/libstd/sys/redox/pipe.rs index e7240fbe7bf..05863adf108 100644 --- a/src/libstd/sys/redox/pipe.rs +++ b/src/libstd/sys/redox/pipe.rs @@ -34,10 +34,6 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) - } - pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs index 607eef051d6..c839531cc26 100644 --- a/src/libstd/sys/redox/stdio.rs +++ b/src/libstd/sys/redox/stdio.rs @@ -25,13 +25,6 @@ pub fn read(&self, data: &mut [u8]) -> io::Result { fd.into_raw(); ret } - - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - let fd = FileDesc::new(0); - let ret = fd.read_to_end(buf); - fd.into_raw(); - ret - } } impl Stdout { diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index d688f2fa504..94b87a6bff4 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -17,7 +17,7 @@ use ascii; use ffi::OsStr; use fmt; -use io; +use io::{self, Initializer}; use mem; use net::Shutdown; use os::unix::ffi::OsStrExt; @@ -516,8 +516,9 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { io::Read::read(&mut &*self, buf) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - io::Read::read_to_end(&mut &*self, buf) + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() } } @@ -527,8 +528,9 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() } } diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 405fac2b9d7..138087f1651 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -17,7 +17,6 @@ use sync::atomic::{AtomicBool, Ordering}; use sys::cvt; use sys_common::AsInner; -use sys_common::io::read_to_end_uninitialized; #[derive(Debug)] pub struct FileDesc { @@ -232,10 +231,6 @@ impl<'a> Read for &'a FileDesc { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } - - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - unsafe { read_to_end_uninitialized(self, buf) } - } } impl AsInner for FileDesc { diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index e893a139094..59dceba8953 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -491,10 +491,6 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) - } - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { self.0.read_at(buf, offset) } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 5efddca110f..8fb361a78e2 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -198,10 +198,6 @@ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { self.recv_from_with_flags(buf, MSG_PEEK) } - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) - } - pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index ca5ef4bcfc5..ec9b6f17dca 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -71,10 +71,6 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) - } - pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index 6d38b00b39e..7a8fe25d98e 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -25,13 +25,6 @@ pub fn read(&self, data: &mut [u8]) -> io::Result { fd.into_raw(); ret } - - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - let fd = FileDesc::new(libc::STDIN_FILENO); - let ret = fd.read_to_end(buf); - fd.into_raw(); - ret - } } impl Stdout { diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 4efc68afdc4..7f3291cf304 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -324,10 +324,6 @@ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { self.handle.read_at(buf, offset) } - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - self.handle.read_to_end(buf) - } - pub fn write(&self, buf: &[u8]) -> io::Result { self.handle.write(buf) } diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index fdb9483fe1c..3729d6d6534 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -18,7 +18,6 @@ use ptr; use sys::c; use sys::cvt; -use sys_common::io::read_to_end_uninitialized; /// An owned container for `HANDLE` object, closing them on Drop. /// @@ -216,8 +215,4 @@ impl<'a> Read for &'a RawHandle { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } - - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - unsafe { read_to_end_uninitialized(self, buf) } - } } diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index adf6210d82e..f2a2793425d 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -20,7 +20,6 @@ use sys::c; use sys; use sys_common::{self, AsInner, FromInner, IntoInner}; -use sys_common::io::read_to_end_uninitialized; use sys_common::net; use time::Duration; @@ -200,11 +199,6 @@ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { self.recv_from_with_flags(buf, c::MSG_PEEK) } - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - let mut me = self; - (&mut me).read_to_end(buf) - } - pub fn set_timeout(&self, dur: Option, kind: c_int) -> io::Result<()> { let timeout = match dur { @@ -283,10 +277,6 @@ impl<'a> Read for &'a Socket { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } - - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - unsafe { read_to_end_uninitialized(self, buf) } - } } impl Drop for Socket { diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index 8073473f7ff..be7482c4bb1 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -164,10 +164,6 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - self.inner.read_to_end(buf) - } - pub fn write(&self, buf: &[u8]) -> io::Result { self.inner.write(buf) } diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index d72e4b4438b..b5e5b5760f2 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -20,7 +20,6 @@ use sys::c; use sys::cvt; use sys::handle::Handle; -use sys_common::io::read_to_end_uninitialized; pub enum Output { Console(c::HANDLE), @@ -151,10 +150,6 @@ impl<'a> Read for &'a Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } - - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - unsafe { read_to_end_uninitialized(self, buf) } - } } impl Stdout { diff --git a/src/libstd/sys_common/io.rs b/src/libstd/sys_common/io.rs index 23daeeb5187..ab23936358e 100644 --- a/src/libstd/sys_common/io.rs +++ b/src/libstd/sys_common/io.rs @@ -7,51 +7,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use io; -use io::ErrorKind; -use io::Read; -use slice::from_raw_parts_mut; - pub const DEFAULT_BUF_SIZE: usize = 8 * 1024; -// Provides read_to_end functionality over an uninitialized buffer. -// This function is unsafe because it calls the underlying -// read function with a slice into uninitialized memory. The default -// implementation of read_to_end for readers will zero out new memory in -// the buf before passing it to read, but avoiding this zero can often -// lead to a fairly significant performance win. -// -// Implementations using this method have to adhere to two guarantees: -// * The implementation of read never reads the buffer provided. -// * The implementation of read correctly reports how many bytes were written. -pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec) -> io::Result { - - let start_len = buf.len(); - buf.reserve(16); - - // Always try to read into the empty space of the vector (from the length to the capacity). - // If the vector ever fills up then we reserve an extra byte which should trigger the normal - // reallocation routines for the vector, which will likely double the size. - // - // This function is similar to the read_to_end function in std::io, but the logic about - // reservations and slicing is different enough that this is duplicated here. - loop { - if buf.len() == buf.capacity() { - buf.reserve(1); - } - - let buf_slice = from_raw_parts_mut(buf.as_mut_ptr().offset(buf.len() as isize), - buf.capacity() - buf.len()); - - match r.read(buf_slice) { - Ok(0) => { return Ok(buf.len() - start_len); } - Ok(n) => { let len = buf.len() + n; buf.set_len(len); }, - Err(ref e) if e.kind() == ErrorKind::Interrupted => { } - Err(e) => { return Err(e); } - } - } -} - #[cfg(test)] #[allow(dead_code)] // not used on emscripten pub mod test { @@ -91,89 +48,3 @@ pub fn tmpdir() -> TempDir { TempDir(ret) } } - -#[cfg(test)] -mod tests { - use io::prelude::*; - use super::*; - use io; - use io::{ErrorKind, Take, Repeat, repeat}; - use slice::from_raw_parts; - - struct ErrorRepeat { - lr: Take - } - - fn error_repeat(byte: u8, limit: u64) -> ErrorRepeat { - ErrorRepeat { lr: repeat(byte).take(limit) } - } - - impl Read for ErrorRepeat { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let ret = self.lr.read(buf); - if let Ok(0) = ret { - return Err(io::Error::new(ErrorKind::Other, "")) - } - ret - } - } - - fn init_vec_data() -> Vec { - let mut vec = vec![10u8; 200]; - unsafe { vec.set_len(0); } - vec - } - - fn assert_all_eq(buf: &[u8], value: u8) { - for n in buf { - assert_eq!(*n, value); - } - } - - fn validate(buf: &Vec, good_read_len: usize) { - assert_all_eq(buf, 1u8); - let cap = buf.capacity(); - let end_slice = unsafe { from_raw_parts(buf.as_ptr().offset(good_read_len as isize), - cap - good_read_len) }; - assert_all_eq(end_slice, 10u8); - } - - #[test] - fn read_to_end_uninit_error() { - let mut er = error_repeat(1,100); - let mut vec = init_vec_data(); - if let Err(_) = unsafe { read_to_end_uninitialized(&mut er, &mut vec) } { - validate(&vec, 100); - } else { - assert!(false); - } - } - - #[test] - fn read_to_end_uninit_zero_len_vec() { - let mut er = repeat(1).take(100); - let mut vec = Vec::new(); - let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() }; - assert_all_eq(&vec, 1u8); - assert_eq!(vec.len(), n); - } - - #[test] - fn read_to_end_uninit_good() { - let mut er = repeat(1).take(100); - let mut vec = init_vec_data(); - let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() }; - validate(&vec, 100); - assert_eq!(vec.len(), n); - } - - #[bench] - #[cfg_attr(target_os = "emscripten", ignore)] - fn bench_uninitialized(b: &mut ::test::Bencher) { - b.iter(|| { - let mut lr = repeat(1).take(10000000); - let mut vec = Vec::with_capacity(1024); - unsafe { read_to_end_uninitialized(&mut lr, &mut vec) } - }); - } -} diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index a1897c8bd67..809b728379d 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -243,10 +243,6 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - self.inner.read_to_end(buf) - } - pub fn write(&self, buf: &[u8]) -> io::Result { let len = cmp::min(buf.len(), ::max_value() as usize) as wrlen_t; let ret = cvt(unsafe {