]> git.lizzy.rs Git - rust.git/commitdiff
Fixup stout/stderr on Windows
authorOliver Middleton <olliemail27@gmail.com>
Thu, 10 Mar 2016 19:09:02 +0000 (19:09 +0000)
committerOliver Middleton <olliemail27@gmail.com>
Thu, 10 Mar 2016 21:15:23 +0000 (21:15 +0000)
WriteConsoleW can fail if called with a large buffer so we need to slice
any stdout/stderr output.
However the current slicing has a few problems:
 1. It slices by byte but still expects valid UTF-8.
 2. The slicing happens even when not outputting to a console.
 3. panic! output is not sliced.

This fixes these issues by moving the slice to right before
WriteConsoleW and slicing on a char boundary.

src/libstd/io/stdio.rs
src/libstd/sys/windows/stdio.rs

index 25309a785c45a3e08b25ea25ac759db63ffa81d1..e1a388c38c45334272b1bbdfbfc61f422ef37af2 100644 (file)
@@ -12,7 +12,6 @@
 use io::prelude::*;
 
 use cell::{RefCell, BorrowState};
-use cmp;
 use fmt;
 use io::lazy::Lazy;
 use io::{self, BufReader, LineWriter};
@@ -312,22 +311,6 @@ fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() }
     fn consume(&mut self, n: usize) { self.inner.consume(n) }
 }
 
-// As with stdin on windows, stdout often can't handle writes of large
-// sizes. For an example, see #14940. For this reason, don't try to
-// write the entire output buffer on windows. On unix we can just
-// write the whole buffer all at once.
-//
-// For some other references, it appears that this problem has been
-// encountered by others [1] [2]. We choose the number 8KB just because
-// libuv does the same.
-//
-// [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232
-// [2]: http://www.mail-archive.com/log4net-dev@logging.apache.org/msg00661.html
-#[cfg(windows)]
-const OUT_MAX: usize = 8192;
-#[cfg(unix)]
-const OUT_MAX: usize = ::usize::MAX;
-
 /// A handle to the global standard output stream of the current process.
 ///
 /// Each handle shares a global buffer of data to be written to the standard
@@ -440,7 +423,7 @@ fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> Write for StdoutLock<'a> {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        self.inner.borrow_mut().write(&buf[..cmp::min(buf.len(), OUT_MAX)])
+        self.inner.borrow_mut().write(buf)
     }
     fn flush(&mut self) -> io::Result<()> {
         self.inner.borrow_mut().flush()
@@ -546,7 +529,7 @@ fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> Write for StderrLock<'a> {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        self.inner.borrow_mut().write(&buf[..cmp::min(buf.len(), OUT_MAX)])
+        self.inner.borrow_mut().write(buf)
     }
     fn flush(&mut self) -> io::Result<()> {
         self.inner.borrow_mut().flush()
index 5883904c21d729c92e14c786628424faed0ef4b8..190c257162822272f95cd4eb1e13db955644d5de 100644 (file)
@@ -58,8 +58,30 @@ fn write(out: &Output, data: &[u8]) -> io::Result<usize> {
         Output::Console(ref c) => c.get().raw(),
         Output::Pipe(ref p) => return p.get().write(data),
     };
+    // As with stdin on windows, stdout often can't handle writes of large
+    // sizes. For an example, see #14940. For this reason, don't try to
+    // write the entire output buffer on windows.
+    //
+    // For some other references, it appears that this problem has been
+    // encountered by others [1] [2]. We choose the number 8K just because
+    // libuv does the same.
+    //
+    // [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232
+    // [2]: http://www.mail-archive.com/log4net-dev@logging.apache.org/msg00661.html
+    const OUT_MAX: usize = 8192;
+    let data_len;
     let utf16 = match str::from_utf8(data).ok() {
-        Some(utf8) => utf8.encode_utf16().collect::<Vec<u16>>(),
+        Some(mut utf8) => {
+            if utf8.len() > OUT_MAX {
+                let mut new_len = OUT_MAX;
+                while !utf8.is_char_boundary(new_len) {
+                    new_len -= 1;
+                }
+                utf8 = &utf8[..new_len];
+            }
+            data_len = utf8.len();
+            utf8.encode_utf16().collect::<Vec<u16>>()
+        }
         None => return Err(invalid_encoding()),
     };
     let mut written = 0;
@@ -74,7 +96,7 @@ fn write(out: &Output, data: &[u8]) -> io::Result<usize> {
     // FIXME if this only partially writes the utf16 buffer then we need to
     //       figure out how many bytes of `data` were actually written
     assert_eq!(written as usize, utf16.len());
-    Ok(data.len())
+    Ok(data_len)
 }
 
 impl Stdin {