Fixup stout/stderr on Windows
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.
This commit is contained in:
parent
4b87655e69
commit
8427efaab3
2 changed files with 26 additions and 21 deletions
|
|
@ -12,7 +12,6 @@ use prelude::v1::*;
|
|||
use io::prelude::*;
|
||||
|
||||
use cell::{RefCell, BorrowState};
|
||||
use cmp;
|
||||
use fmt;
|
||||
use io::lazy::Lazy;
|
||||
use io::{self, BufReader, LineWriter};
|
||||
|
|
@ -312,22 +311,6 @@ impl<'a> BufRead for StdinLock<'a> {
|
|||
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 @@ impl Write for Stdout {
|
|||
#[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 @@ impl Write for Stderr {
|
|||
#[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()
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue