Skip to content

Commit c1fb50f

Browse files
committed
Auto merge of #32107 - Stebalien:partial-write, r=alexcrichton
Never return an error after a partial write If LineWriter fails to flush, return the number of bytes written instead of an error. Fixes #32085
2 parents 4b87655 + c516335 commit c1fb50f

File tree

1 file changed

+32
-2
lines changed

1 file changed

+32
-2
lines changed

src/libstd/io/buffered.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -762,8 +762,10 @@ impl<W: Write> Write for LineWriter<W> {
762762
match memchr::memrchr(b'\n', buf) {
763763
Some(i) => {
764764
let n = try!(self.inner.write(&buf[..i + 1]));
765-
if n != i + 1 { return Ok(n) }
766-
try!(self.inner.flush());
765+
if n != i + 1 || self.inner.flush().is_err() {
766+
// Do not return errors on partial writes.
767+
return Ok(n);
768+
}
767769
self.inner.write(&buf[i + 1..]).map(|i| n + i)
768770
}
769771
None => self.inner.write(buf),
@@ -982,6 +984,34 @@ mod tests {
982984
assert_eq!(v, []);
983985
}
984986

987+
#[test]
988+
fn test_line_buffer_fail_flush() {
989+
// Issue #32085
990+
struct FailFlushWriter<'a>(&'a mut Vec<u8>);
991+
992+
impl<'a> Write for FailFlushWriter<'a> {
993+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
994+
self.0.extend_from_slice(buf);
995+
Ok(buf.len())
996+
}
997+
fn flush(&mut self) -> io::Result<()> {
998+
Err(io::Error::new(io::ErrorKind::Other, "flush failed"))
999+
}
1000+
}
1001+
1002+
let mut buf = Vec::new();
1003+
{
1004+
let mut writer = LineWriter::new(FailFlushWriter(&mut buf));
1005+
let to_write = b"abc\ndef";
1006+
if let Ok(written) = writer.write(to_write) {
1007+
assert!(written < to_write.len(), "didn't flush on new line");
1008+
// PASS
1009+
return;
1010+
}
1011+
}
1012+
assert!(buf.is_empty(), "write returned an error but wrote data");
1013+
}
1014+
9851015
#[test]
9861016
fn test_line_buffer() {
9871017
let mut writer = LineWriter::new(Vec::new());

0 commit comments

Comments
 (0)