LineWriter can return an error after a partial write if flushing the inner BufWriter fails (
|
try!(self.inner.flush()); |
). It should instead return
Ok(bytes_written), ignoring the error.
OLD REPORT:
I originally thought this problem was systematic so I audited stdlib. Apparently it isn't... See below.
The write trait guarantees:
If an error is returned then no bytes in the buffer were written to this writer.
However, this is violated all over stdlib. For example, if "abc\nde" is written to a LineWriter, the LineWriter could write "abc", try to flush, and then return an error due to a failed flush. However, "abc" has been written violating the spec.
IMO, the solution is to return Ok(amount_written) for partial writes and drop the error (if any). This should be safe because of write's write-xor-error guarantee. If the error was transient, the caller never needs to know. Otherwise, they will will learn of it on the next write.
Here's everything in the stdlib that implements write (and should be audited):
LineWritercan return an error after a partial write if flushing the innerBufWriterfails (rust/src/libstd/io/buffered.rs
Line 766 in cb343c3
Ok(bytes_written), ignoring the error.OLD REPORT:
I originally thought this problem was systematic so I audited stdlib. Apparently it isn't... See below.
The write trait guarantees:
However, this is violated all over stdlib. For example, if
"abc\nde"is written to aLineWriter, theLineWritercould write"abc", try to flush, and then return an error due to a failed flush. However,"abc"has been written violating the spec.IMO, the solution is to return
Ok(amount_written)for partial writes and drop the error (if any). This should be safe because of write's write-xor-error guarantee. If the error was transient, the caller never needs to know. Otherwise, they will will learn of it on the next write.Here's everything in the stdlib that implements write (and should be audited):
Sinkinlibrustdoc/test.rsSinkinlibstd/io/util.rs&'a mut Winlibstd/io/impls.rsBox<W>inlibstd/io/impls.rs&'a mut [u8]inlibstd/io/impls.rsVec<u8>inlibstd/io/impls.rsCursor<&'a mut [u8]>inlibstd/io/cursor.rsCursor<Vec<u8>>inlibstd/io/cursor.rsCursor<Box<[u8]>>inlibstd/io/cursor.rsStdoutRawinlibstd/io/stdio.rsStderrRawinlibstd/io/stdio.rsMaybe<W>inlibstd/io/stdio.rsStdoutinlibstd/io/stdio.rsStdoutLock<'a>inlibstd/io/stdio.rsStderrinlibstd/io/stdio.rsStderrLock<'a>inlibstd/io/stdio.rsBufWriter<W>inlibstd/io/buffered.rsLineWriter<W>inlibstd/io/buffered.rs(buggy)Broadcast<T, U>inlibstd/io/mod.rs(buggy but unfixable and deprecated).TcpStreaminlibstd/net/tcp.rs&'a TcpStreaminlibstd/net/tcp.rsStderrinlibstd/sys/unix/stdio.rsStderrinlibstd/sys/windows/stdio.rs(panics on partial write)ChildStdininlibstd/process.rsFileinlibstd/fs.rs&'a Fileinlibstd/fs.rs