Skip to content

Commit ce943eb

Browse files
committed
Auto merge of #32184 - ollie27:win_stdout, r=alexcrichton
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.
2 parents 1c8b245 + bd80a53 commit ce943eb

File tree

2 files changed

+21
-23
lines changed

2 files changed

+21
-23
lines changed

src/libstd/io/stdio.rs

+2-19
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use prelude::v1::*;
1212
use io::prelude::*;
1313

1414
use cell::{RefCell, BorrowState};
15-
use cmp;
1615
use fmt;
1716
use io::lazy::Lazy;
1817
use io::{self, BufReader, LineWriter};
@@ -312,22 +311,6 @@ impl<'a> BufRead for StdinLock<'a> {
312311
fn consume(&mut self, n: usize) { self.inner.consume(n) }
313312
}
314313

315-
// As with stdin on windows, stdout often can't handle writes of large
316-
// sizes. For an example, see #14940. For this reason, don't try to
317-
// write the entire output buffer on windows. On unix we can just
318-
// write the whole buffer all at once.
319-
//
320-
// For some other references, it appears that this problem has been
321-
// encountered by others [1] [2]. We choose the number 8KB just because
322-
// libuv does the same.
323-
//
324-
// [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232
325-
// [2]: http://www.mail-archive.com/[email protected]/msg00661.html
326-
#[cfg(windows)]
327-
const OUT_MAX: usize = 8192;
328-
#[cfg(unix)]
329-
const OUT_MAX: usize = ::usize::MAX;
330-
331314
/// A handle to the global standard output stream of the current process.
332315
///
333316
/// Each handle shares a global buffer of data to be written to the standard
@@ -440,7 +423,7 @@ impl Write for Stdout {
440423
#[stable(feature = "rust1", since = "1.0.0")]
441424
impl<'a> Write for StdoutLock<'a> {
442425
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
443-
self.inner.borrow_mut().write(&buf[..cmp::min(buf.len(), OUT_MAX)])
426+
self.inner.borrow_mut().write(buf)
444427
}
445428
fn flush(&mut self) -> io::Result<()> {
446429
self.inner.borrow_mut().flush()
@@ -546,7 +529,7 @@ impl Write for Stderr {
546529
#[stable(feature = "rust1", since = "1.0.0")]
547530
impl<'a> Write for StderrLock<'a> {
548531
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
549-
self.inner.borrow_mut().write(&buf[..cmp::min(buf.len(), OUT_MAX)])
532+
self.inner.borrow_mut().write(buf)
550533
}
551534
fn flush(&mut self) -> io::Result<()> {
552535
self.inner.borrow_mut().flush()

src/libstd/sys/windows/stdio.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use prelude::v1::*;
1414
use io::prelude::*;
1515

16+
use cmp;
1617
use io::{self, Cursor};
1718
use ptr;
1819
use str;
@@ -58,10 +59,24 @@ fn write(out: &Output, data: &[u8]) -> io::Result<usize> {
5859
Output::Console(ref c) => c.get().raw(),
5960
Output::Pipe(ref p) => return p.get().write(data),
6061
};
61-
let utf16 = match str::from_utf8(data).ok() {
62-
Some(utf8) => utf8.encode_utf16().collect::<Vec<u16>>(),
63-
None => return Err(invalid_encoding()),
62+
// As with stdin on windows, stdout often can't handle writes of large
63+
// sizes. For an example, see #14940. For this reason, don't try to
64+
// write the entire output buffer on windows.
65+
//
66+
// For some other references, it appears that this problem has been
67+
// encountered by others [1] [2]. We choose the number 8K just because
68+
// libuv does the same.
69+
//
70+
// [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232
71+
// [2]: http://www.mail-archive.com/[email protected]/msg00661.html
72+
const OUT_MAX: usize = 8192;
73+
let len = cmp::min(data.len(), OUT_MAX);
74+
let utf8 = match str::from_utf8(&data[..len]) {
75+
Ok(s) => s,
76+
Err(ref e) if e.valid_up_to() == 0 => return Err(invalid_encoding()),
77+
Err(e) => str::from_utf8(&data[..e.valid_up_to()]).unwrap(),
6478
};
79+
let utf16 = utf8.encode_utf16().collect::<Vec<u16>>();
6580
let mut written = 0;
6681
try!(cvt(unsafe {
6782
c::WriteConsoleW(handle,
@@ -74,7 +89,7 @@ fn write(out: &Output, data: &[u8]) -> io::Result<usize> {
7489
// FIXME if this only partially writes the utf16 buffer then we need to
7590
// figure out how many bytes of `data` were actually written
7691
assert_eq!(written as usize, utf16.len());
77-
Ok(data.len())
92+
Ok(utf8.len())
7893
}
7994

8095
impl Stdin {

0 commit comments

Comments
 (0)