From 8427efaab377346c0c4be73664422897a4072330 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Thu, 10 Mar 2016 19:09:02 +0000 Subject: 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. --- src/libstd/sys/windows/stdio.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'src/libstd/sys/windows') diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index 5883904c21d..190c2571628 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -58,8 +58,30 @@ fn write(out: &Output, data: &[u8]) -> io::Result { 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::>(), + 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::>() + } None => return Err(invalid_encoding()), }; let mut written = 0; @@ -74,7 +96,7 @@ fn write(out: &Output, data: &[u8]) -> io::Result { // 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 { -- cgit 1.4.1-3-g733a5 From 69939392425f160055378f190a65094a96c5cdbc Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Thu, 10 Mar 2016 23:59:28 +0000 Subject: Simplify Windows stdout/stderr --- src/libstd/sys/windows/stdio.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/libstd/sys/windows') diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index 190c2571628..a7110044d7f 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -69,8 +69,7 @@ fn write(out: &Output, data: &[u8]) -> io::Result { // [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() { + let (utf16, data_len) = match str::from_utf8(data).ok() { Some(mut utf8) => { if utf8.len() > OUT_MAX { let mut new_len = OUT_MAX; @@ -79,8 +78,7 @@ fn write(out: &Output, data: &[u8]) -> io::Result { } utf8 = &utf8[..new_len]; } - data_len = utf8.len(); - utf8.encode_utf16().collect::>() + (utf8.encode_utf16().collect::>(), utf8.len()) } None => return Err(invalid_encoding()), }; -- cgit 1.4.1-3-g733a5 From bd80a53407e15f13ce50a07642491680010fa090 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sat, 12 Mar 2016 04:18:17 +0000 Subject: Further simplify Windows stdout/stderr This makes it output as much valid UTF-8 as it can then return failure. --- src/libstd/sys/windows/stdio.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'src/libstd/sys/windows') diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index a7110044d7f..0a0851ffac3 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -13,6 +13,7 @@ use prelude::v1::*; use io::prelude::*; +use cmp; use io::{self, Cursor}; use ptr; use str; @@ -69,19 +70,13 @@ fn write(out: &Output, data: &[u8]) -> io::Result { // [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 (utf16, data_len) = match str::from_utf8(data).ok() { - 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]; - } - (utf8.encode_utf16().collect::>(), utf8.len()) - } - None => return Err(invalid_encoding()), + let len = cmp::min(data.len(), OUT_MAX); + let utf8 = match str::from_utf8(&data[..len]) { + Ok(s) => s, + Err(ref e) if e.valid_up_to() == 0 => return Err(invalid_encoding()), + Err(e) => str::from_utf8(&data[..e.valid_up_to()]).unwrap(), }; + let utf16 = utf8.encode_utf16().collect::>(); let mut written = 0; try!(cvt(unsafe { c::WriteConsoleW(handle, @@ -94,7 +89,7 @@ fn write(out: &Output, data: &[u8]) -> io::Result { // 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(utf8.len()) } impl Stdin { -- cgit 1.4.1-3-g733a5