diff options
| author | Fenrir <[email protected]> | 2018-08-19 17:48:00 -0600 |
|---|---|---|
| committer | Fenrir <[email protected]> | 2018-08-19 17:56:18 -0600 |
| commit | 5d28bfcfd6086c3328837de9695099ea39048d0d (patch) | |
| tree | a514fde042ff2a504a03305bfe0894ff8cd8d47e /ctr-std/src/io | |
| parent | Update for latest nightly 2018-06-09 (#70) (diff) | |
| download | ctru-rs-5d28bfcfd6086c3328837de9695099ea39048d0d.tar.xz ctru-rs-5d28bfcfd6086c3328837de9695099ea39048d0d.zip | |
Update for nightly-2018-08-18
Diffstat (limited to 'ctr-std/src/io')
| -rw-r--r-- | ctr-std/src/io/buffered.rs | 85 | ||||
| -rw-r--r-- | ctr-std/src/io/cursor.rs | 57 | ||||
| -rw-r--r-- | ctr-std/src/io/error.rs | 25 | ||||
| -rw-r--r-- | ctr-std/src/io/lazy.rs | 30 | ||||
| -rw-r--r-- | ctr-std/src/io/mod.rs | 171 | ||||
| -rw-r--r-- | ctr-std/src/io/stdio.rs | 40 | ||||
| -rw-r--r-- | ctr-std/src/io/util.rs | 2 |
7 files changed, 117 insertions, 293 deletions
diff --git a/ctr-std/src/io/buffered.rs b/ctr-std/src/io/buffered.rs index ee297d3..03c97de 100644 --- a/ctr-std/src/io/buffered.rs +++ b/ctr-std/src/io/buffered.rs @@ -61,7 +61,8 @@ pub struct BufReader<R> { } impl<R: Read> BufReader<R> { - /// Creates a new `BufReader` with a default buffer capacity. + /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB, + /// but may change in the future. /// /// # Examples /// @@ -153,33 +154,6 @@ impl<R: Read> BufReader<R> { #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut R { &mut self.inner } - /// Returns `true` if there are no bytes in the internal buffer. - /// - /// # Examples - // - /// ```no_run - /// # #![feature(bufreader_is_empty)] - /// use std::io::BufReader; - /// use std::io::BufRead; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let mut reader = BufReader::new(f1); - /// assert!(reader.is_empty()); - /// - /// if reader.fill_buf()?.len() > 0 { - /// assert!(!reader.is_empty()); - /// } - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "bufreader_is_empty", issue = "45323", reason = "recently added")] - #[rustc_deprecated(since = "1.26.0", reason = "use .buffer().is_empty() instead")] - pub fn is_empty(&self) -> bool { - self.buffer().is_empty() - } - /// Returns a reference to the internally buffered data. /// /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty. @@ -454,7 +428,8 @@ pub struct BufWriter<W: Write> { pub struct IntoInnerError<W>(W, Error); impl<W: Write> BufWriter<W> { - /// Creates a new `BufWriter` with a default buffer capacity. + /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, + /// but may change in the future. /// /// # Examples /// @@ -738,7 +713,7 @@ impl<W> fmt::Display for IntoInnerError<W> { /// reducing the number of actual writes to the file. /// /// ```no_run -/// use std::fs::File; +/// use std::fs::{self, File}; /// use std::io::prelude::*; /// use std::io::LineWriter; /// @@ -752,17 +727,30 @@ impl<W> fmt::Display for IntoInnerError<W> { /// let file = File::create("poem.txt")?; /// let mut file = LineWriter::new(file); /// -/// for &byte in road_not_taken.iter() { -/// file.write(&[byte]).unwrap(); -/// } +/// file.write_all(b"I shall be telling this with a sigh")?; /// -/// // let's check we did the right thing. -/// let mut file = File::open("poem.txt")?; -/// let mut contents = String::new(); +/// // No bytes are written until a newline is encountered (or +/// // the internal buffer is filled). +/// assert_eq!(fs::read_to_string("poem.txt")?, ""); +/// file.write_all(b"\n")?; +/// assert_eq!( +/// fs::read_to_string("poem.txt")?, +/// "I shall be telling this with a sigh\n", +/// ); /// -/// file.read_to_string(&mut contents)?; +/// // Write the rest of the poem. +/// file.write_all(b"Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference.")?; /// -/// assert_eq!(contents.as_bytes(), &road_not_taken[..]); +/// // The last line of the poem doesn't end in a newline, so +/// // we have to flush or drop the `LineWriter` to finish +/// // writing. +/// file.flush()?; +/// +/// // Confirm the whole poem was written. +/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]); /// Ok(()) /// } /// ``` @@ -862,7 +850,7 @@ impl<W: Write> LineWriter<W> { /// /// The internal buffer is written out before returning the writer. /// - // # Errors + /// # Errors /// /// An `Err` will be returned if an error occurs while flushing the buffer. /// @@ -1251,25 +1239,6 @@ mod tests { } #[test] - #[allow(deprecated)] - fn read_char_buffered() { - let buf = [195, 159]; - let reader = BufReader::with_capacity(1, &buf[..]); - assert_eq!(reader.chars().next().unwrap().unwrap(), 'ß'); - } - - #[test] - #[allow(deprecated)] - fn test_chars() { - let buf = [195, 159, b'a']; - let reader = BufReader::with_capacity(1, &buf[..]); - let mut it = reader.chars(); - assert_eq!(it.next().unwrap().unwrap(), 'ß'); - assert_eq!(it.next().unwrap().unwrap(), 'a'); - assert!(it.next().is_none()); - } - - #[test] #[should_panic] fn dont_panic_in_drop_on_panicked_flush() { struct FailFlushWriter; diff --git a/ctr-std/src/io/cursor.rs b/ctr-std/src/io/cursor.rs index 8ac5257..14f2015 100644 --- a/ctr-std/src/io/cursor.rs +++ b/ctr-std/src/io/cursor.rs @@ -10,15 +10,17 @@ use io::prelude::*; +use core::convert::TryInto; use cmp; use io::{self, Initializer, SeekFrom, Error, ErrorKind}; -/// A `Cursor` wraps another type and provides it with a +/// A `Cursor` wraps an in-memory buffer and provides it with a /// [`Seek`] implementation. /// -/// `Cursor`s are typically used with in-memory buffers to allow them to -/// implement [`Read`] and/or [`Write`], allowing these buffers to be used -/// anywhere you might use a reader or writer that does actual I/O. +/// `Cursor`s are used with in-memory buffers, anything implementing +/// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`], +/// allowing these buffers to be used anywhere you might use a reader or writer +/// that does actual I/O. /// /// The standard library implements some I/O traits on various types which /// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and @@ -86,11 +88,11 @@ pub struct Cursor<T> { } impl<T> Cursor<T> { - /// Creates a new cursor wrapping the provided underlying I/O object. + /// Creates a new cursor wrapping the provided underlying in-memory buffer. /// - /// Cursor initial position is `0` even if underlying object (e. - /// g. `Vec`) is not empty. So writing to cursor starts with - /// overwriting `Vec` content, not with appending to it. + /// Cursor initial position is `0` even if underlying buffer (e.g. `Vec`) + /// is not empty. So writing to cursor starts with overwriting `Vec` + /// content, not with appending to it. /// /// # Examples /// @@ -259,26 +261,9 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<us Ok(amt) } -/// Compensate removal of some impls per -/// https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243 -#[cfg(any(target_pointer_width = "16", - target_pointer_width = "32"))] -fn try_into(n: u64) -> Result<usize, ()> { - if n <= (<usize>::max_value() as u64) { - Ok(n as usize) - } else { - Err(()) - } -} - -#[cfg(any(target_pointer_width = "64"))] -fn try_into(n: u64) -> Result<usize, ()> { - Ok(n as usize) -} - // Resizing write implementation fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> { - let pos: usize = try_into(*pos_mut).map_err(|_| { + let pos: usize = (*pos_mut).try_into().map_err(|_| { Error::new(ErrorKind::InvalidInput, "cursor position exceeds maximum possible vector length") })?; @@ -566,26 +551,6 @@ mod tests { } #[test] - #[allow(deprecated)] - fn test_read_char() { - let b = &b"Vi\xE1\xBB\x87t"[..]; - let mut c = Cursor::new(b).chars(); - assert_eq!(c.next().unwrap().unwrap(), 'V'); - assert_eq!(c.next().unwrap().unwrap(), 'i'); - assert_eq!(c.next().unwrap().unwrap(), 'ệ'); - assert_eq!(c.next().unwrap().unwrap(), 't'); - assert!(c.next().is_none()); - } - - #[test] - #[allow(deprecated)] - fn test_read_bad_char() { - let b = &b"\x80"[..]; - let mut c = Cursor::new(b).chars(); - assert!(c.next().unwrap().is_err()); - } - - #[test] fn seek_past_end() { let buf = [0xff]; let mut r = Cursor::new(&buf[..]); diff --git a/ctr-std/src/io/error.rs b/ctr-std/src/io/error.rs index bdd675e..3e50988 100644 --- a/ctr-std/src/io/error.rs +++ b/ctr-std/src/io/error.rs @@ -83,7 +83,7 @@ enum Repr { #[derive(Debug)] struct Custom { kind: ErrorKind, - error: Box<error::Error+Send+Sync>, + error: Box<dyn error::Error+Send+Sync>, } /// A list specifying general categories of I/O error. @@ -97,6 +97,7 @@ struct Custom { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] +#[non_exhaustive] pub enum ErrorKind { /// An entity was not found, often a file. #[stable(feature = "rust1", since = "1.0.0")] @@ -180,15 +181,6 @@ pub enum ErrorKind { /// read. #[stable(feature = "read_exact", since = "1.6.0")] UnexpectedEof, - - /// A marker variant that tells the compiler that users of this enum cannot - /// match it exhaustively. - #[unstable(feature = "io_error_internals", - reason = "better expressed through extensible enums that this \ - enum cannot be exhaustively matched against", - issue = "0")] - #[doc(hidden)] - __Nonexhaustive, } impl ErrorKind { @@ -212,7 +204,6 @@ impl ErrorKind { ErrorKind::Interrupted => "operation interrupted", ErrorKind::Other => "other os error", ErrorKind::UnexpectedEof => "unexpected end of file", - ErrorKind::__Nonexhaustive => unreachable!() } } } @@ -250,12 +241,12 @@ impl Error { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new<E>(kind: ErrorKind, error: E) -> Error - where E: Into<Box<error::Error+Send+Sync>> + where E: Into<Box<dyn error::Error+Send+Sync>> { Self::_new(kind, error.into()) } - fn _new(kind: ErrorKind, error: Box<error::Error+Send+Sync>) -> Error { + fn _new(kind: ErrorKind, error: Box<dyn error::Error+Send+Sync>) -> Error { Error { repr: Repr::Custom(Box::new(Custom { kind, @@ -373,7 +364,7 @@ impl Error { /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { + pub fn get_ref(&self) -> Option<&(dyn error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, @@ -444,7 +435,7 @@ impl Error { /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> { + pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, @@ -478,7 +469,7 @@ impl Error { /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> { + pub fn into_inner(self) -> Option<Box<dyn error::Error+Send+Sync>> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, @@ -551,7 +542,7 @@ impl error::Error for Error { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, diff --git a/ctr-std/src/io/lazy.rs b/ctr-std/src/io/lazy.rs index 9cef4e3..4fb367f 100644 --- a/ctr-std/src/io/lazy.rs +++ b/ctr-std/src/io/lazy.rs @@ -15,15 +15,21 @@ use sys_common; use sys_common::mutex::Mutex; pub struct Lazy<T> { + // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly! lock: Mutex, ptr: Cell<*mut Arc<T>>, init: fn() -> Arc<T>, } +#[inline] +const fn done<T>() -> *mut Arc<T> { 1_usize as *mut _ } + unsafe impl<T> Sync for Lazy<T> {} impl<T: Send + Sync + 'static> Lazy<T> { - pub const fn new(init: fn() -> Arc<T>) -> Lazy<T> { + /// Safety: `init` must not call `get` on the variable that is being + /// initialized. + pub const unsafe fn new(init: fn() -> Arc<T>) -> Lazy<T> { Lazy { lock: Mutex::new(), ptr: Cell::new(ptr::null_mut()), @@ -33,32 +39,34 @@ impl<T: Send + Sync + 'static> Lazy<T> { pub fn get(&'static self) -> Option<Arc<T>> { unsafe { - self.lock.lock(); + let _guard = self.lock.lock(); let ptr = self.ptr.get(); - let ret = if ptr.is_null() { + if ptr.is_null() { Some(self.init()) - } else if ptr as usize == 1 { + } else if ptr == done() { None } else { Some((*ptr).clone()) - }; - self.lock.unlock(); - return ret + } } } + // Must only be called with `lock` held unsafe fn init(&'static self) -> Arc<T> { // If we successfully register an at exit handler, then we cache the // `Arc` allocation in our own internal box (it will get deallocated by // the at exit handler). Otherwise we just return the freshly allocated // `Arc`. let registered = sys_common::at_exit(move || { - self.lock.lock(); - let ptr = self.ptr.get(); - self.ptr.set(1 as *mut _); - self.lock.unlock(); + let ptr = { + let _guard = self.lock.lock(); + self.ptr.replace(done()) + }; drop(Box::from_raw(ptr)) }); + // This could reentrantly call `init` again, which is a problem + // because our `lock` allows reentrancy! + // That's why `new` is unsafe and requires the caller to ensure no reentrancy happens. let ret = (self.init)(); if registered.is_ok() { self.ptr.set(Box::into_raw(Box::new(ret.clone()))); diff --git a/ctr-std/src/io/mod.rs b/ctr-std/src/io/mod.rs index eba4e9f..b83f3fb 100644 --- a/ctr-std/src/io/mod.rs +++ b/ctr-std/src/io/mod.rs @@ -147,7 +147,7 @@ //! ``` //! //! Note that you cannot use the [`?` operator] in functions that do not return -//! a [`Result<T, E>`][`Result`] (e.g. `main`). Instead, you can call [`.unwrap()`] +//! a [`Result<T, E>`][`Result`]. Instead, you can call [`.unwrap()`] //! or `match` on the return value to catch any possible errors: //! //! ```no_run @@ -270,10 +270,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use cmp; -use core::str as core_str; -use error as std_error; use fmt; -use result; use str; use memchr; use ptr; @@ -357,19 +354,26 @@ fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize> // avoid paying to allocate and zero a huge chunk of memory if the reader only // has 4 bytes while still making large reads if the reader does have a ton // 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. +// time is 4,500 times (!) slower than a default reservation size of 32 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: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> { + read_to_end_with_reservation(r, buf, 32) +} + +fn read_to_end_with_reservation<R: Read + ?Sized>(r: &mut R, + buf: &mut Vec<u8>, + reservation_size: usize) -> Result<usize> +{ let start_len = buf.len(); let mut g = Guard { len: buf.len(), buf: buf }; let ret; loop { if g.len == g.buf.len() { unsafe { - g.buf.reserve(32); + g.buf.reserve(reservation_size); let capacity = g.buf.capacity(); g.buf.set_len(capacity); r.initializer().initialize(&mut g.buf[g.len..]); @@ -800,53 +804,6 @@ pub trait Read { Bytes { inner: self } } - /// Transforms this `Read` instance to an [`Iterator`] over [`char`]s. - /// - /// This adaptor will attempt to interpret this reader as a UTF-8 encoded - /// sequence of characters. The returned iterator will return [`None`] once - /// EOF is reached for this reader. Otherwise each element yielded will be a - /// [`Result`]`<`[`char`]`, E>` where `E` may contain information about what I/O error - /// occurred or where decoding failed. - /// - /// Currently this adaptor will discard intermediate data read, and should - /// be avoided if this is not desired. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`File`]: ../fs/struct.File.html - /// [`Iterator`]: ../../std/iter/trait.Iterator.html - /// [`Result`]: ../../std/result/enum.Result.html - /// [`char`]: ../../std/primitive.char.html - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// ```no_run - /// #![feature(io)] - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// - /// for c in f.chars() { - /// println!("{}", c.unwrap()); - /// } - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "io", reason = "the semantics of a partial read/write \ - of where errors happen is currently \ - unclear and may change", - issue = "27802")] - #[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: - https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] - #[allow(deprecated)] - fn chars(self) -> Chars<Self> where Self: Sized { - Chars { inner: self } - } - /// Creates an adaptor which will chain this stream with another. /// /// The returned `Read` instance will first read all bytes from this object @@ -1949,6 +1906,12 @@ impl<T: Read> Read for Take<T> { unsafe fn initializer(&self) -> Initializer { self.inner.initializer() } + + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> { + let reservation_size = cmp::min(self.limit, 32) as usize; + + read_to_end_with_reservation(self, buf, reservation_size) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1972,7 +1935,7 @@ impl<T: BufRead> BufRead for Take<T> { } } -fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> { +fn read_one_byte(reader: &mut dyn Read) -> Option<Result<u8>> { let mut buf = [0]; loop { return match reader.read(&mut buf) { @@ -2005,104 +1968,6 @@ impl<R: Read> Iterator for Bytes<R> { } } -/// An iterator over the `char`s of a reader. -/// -/// This struct is generally created by calling [`chars`][chars] on a reader. -/// Please see the documentation of `chars()` for more details. -/// -/// [chars]: trait.Read.html#method.chars -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: - https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] -#[derive(Debug)] -#[allow(deprecated)] -pub struct Chars<R> { - inner: R, -} - -/// An enumeration of possible errors that can be generated from the `Chars` -/// adapter. -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: - https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] -#[derive(Debug)] -#[allow(deprecated)] -pub enum CharsError { - /// Variant representing that the underlying stream was read successfully - /// but it did not contain valid utf8 data. - NotUtf8, - - /// Variant representing that an I/O error occurred. - Other(Error), -} - -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -#[allow(deprecated)] -impl<R: Read> Iterator for Chars<R> { - type Item = result::Result<char, CharsError>; - - fn next(&mut self) -> Option<result::Result<char, CharsError>> { - let first_byte = match read_one_byte(&mut self.inner)? { - Ok(b) => b, - Err(e) => return Some(Err(CharsError::Other(e))), - }; - let width = core_str::utf8_char_width(first_byte); - if width == 1 { return Some(Ok(first_byte as char)) } - if width == 0 { return Some(Err(CharsError::NotUtf8)) } - let mut buf = [first_byte, 0, 0, 0]; - { - let mut start = 1; - while start < width { - match self.inner.read(&mut buf[start..width]) { - Ok(0) => return Some(Err(CharsError::NotUtf8)), - Ok(n) => start += n, - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => return Some(Err(CharsError::Other(e))), - } - } - } - Some(match str::from_utf8(&buf[..width]).ok() { - Some(s) => Ok(s.chars().next().unwrap()), - None => Err(CharsError::NotUtf8), - }) - } -} - -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -#[allow(deprecated)] -impl std_error::Error for CharsError { - fn description(&self) -> &str { - match *self { - CharsError::NotUtf8 => "invalid utf8 encoding", - CharsError::Other(ref e) => std_error::Error::description(e), - } - } - fn cause(&self) -> Option<&std_error::Error> { - match *self { - CharsError::NotUtf8 => None, - CharsError::Other(ref e) => e.cause(), - } - } -} - -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -#[allow(deprecated)] -impl fmt::Display for CharsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - CharsError::NotUtf8 => { - "byte stream did not contain valid utf8".fmt(f) - } - CharsError::Other(ref e) => e.fmt(f), - } - } -} - /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// diff --git a/ctr-std/src/io/stdio.rs b/ctr-std/src/io/stdio.rs index 2472bed..1f256f5 100644 --- a/ctr-std/src/io/stdio.rs +++ b/ctr-std/src/io/stdio.rs @@ -21,7 +21,7 @@ use thread::LocalKey; /// Stdout used by print! and println! macros thread_local! { - static LOCAL_STDOUT: RefCell<Option<Box<Write + Send>>> = { + static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = { RefCell::new(None) } } @@ -197,12 +197,13 @@ pub struct StdinLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new(stdin_init); + static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = unsafe { Lazy::new(stdin_init) }; return Stdin { inner: INSTANCE.get().expect("cannot access stdin during shutdown"), }; fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> { + // This must not reentrantly access `INSTANCE` let stdin = match stdin_raw() { Ok(stdin) => Maybe::Real(stdin), _ => Maybe::Fake @@ -396,12 +397,13 @@ pub struct StdoutLock<'a> { #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> - = Lazy::new(stdout_init); + = unsafe { Lazy::new(stdout_init) }; return Stdout { inner: INSTANCE.get().expect("cannot access stdout during shutdown"), }; fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> { + // This must not reentrantly access `INSTANCE` let stdout = match stdout_raw() { Ok(stdout) => Maybe::Real(stdout), _ => Maybe::Fake, @@ -531,12 +533,14 @@ pub struct StderrLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { - static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new(stderr_init); + static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = + unsafe { Lazy::new(stderr_init) }; return Stderr { inner: INSTANCE.get().expect("cannot access stderr during shutdown"), }; fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> { + // This must not reentrantly access `INSTANCE` let stderr = match stderr_raw() { Ok(stderr) => Maybe::Real(stderr), _ => Maybe::Fake, @@ -624,7 +628,7 @@ impl<'a> fmt::Debug for StderrLock<'a> { with a more general mechanism", issue = "0")] #[doc(hidden)] -pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> { +pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> { use panicking::LOCAL_STDERR; use mem; LOCAL_STDERR.with(move |slot| { @@ -648,7 +652,7 @@ pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> { with a more general mechanism", issue = "0")] #[doc(hidden)] -pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> { +pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> { use mem; LOCAL_STDOUT.with(move |slot| { mem::replace(&mut *slot.borrow_mut(), sink) @@ -670,7 +674,7 @@ pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> { /// However, if the actual I/O causes an error, this function does panic. fn print_to<T>( args: fmt::Arguments, - local_s: &'static LocalKey<RefCell<Option<Box<Write+Send>>>>, + local_s: &'static LocalKey<RefCell<Option<Box<dyn Write+Send>>>>, global_s: fn() -> T, label: &str, ) @@ -712,10 +716,32 @@ pub fn _eprint(args: fmt::Arguments) { #[cfg(test)] mod tests { + use panic::{UnwindSafe, RefUnwindSafe}; use thread; use super::*; #[test] + fn stdout_unwind_safe() { + assert_unwind_safe::<Stdout>(); + } + #[test] + fn stdoutlock_unwind_safe() { + assert_unwind_safe::<StdoutLock>(); + assert_unwind_safe::<StdoutLock<'static>>(); + } + #[test] + fn stderr_unwind_safe() { + assert_unwind_safe::<Stderr>(); + } + #[test] + fn stderrlock_unwind_safe() { + assert_unwind_safe::<StderrLock>(); + assert_unwind_safe::<StderrLock<'static>>(); + } + + fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {} + + #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn panic_doesnt_poison() { thread::spawn(|| { diff --git a/ctr-std/src/io/util.rs b/ctr-std/src/io/util.rs index 195310a..33f741d 100644 --- a/ctr-std/src/io/util.rs +++ b/ctr-std/src/io/util.rs @@ -223,7 +223,7 @@ mod tests { assert_eq!(copy(&mut r, &mut w).unwrap(), 4); let mut r = repeat(0).take(1 << 17); - assert_eq!(copy(&mut r as &mut Read, &mut w as &mut Write).unwrap(), 1 << 17); + assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); } #[test] |