Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BufWriter documentation should warn about ignored errors on drop #37045

Closed
jgallag88 opened this issue Oct 8, 2016 · 3 comments
Closed

BufWriter documentation should warn about ignored errors on drop #37045

jgallag88 opened this issue Oct 8, 2016 · 3 comments

Comments

@jgallag88
Copy link
Contributor

BufWriter calls flush_buf() in its destructor, which writes out the contents of its internal buffer to the underlying writer. The destructor ignores any errors that happen when flushing the buffer. This makes it easy to accidentally forget to handle such errors:

use std::io::BufWriter;
use std::io::Result;
use std::io::Write;
use std::process::{ChildStdin, Command, Stdio};
use std::time::Duration;
use std::thread;

fn mk_broken_pipe() -> ChildStdin {
    let child = Command::new("true").stdin(Stdio::piped()).spawn().unwrap();
    // Wait for child to exit and close it's end of the pipe
    thread::sleep(Duration::from_secs(1));
    child.stdin.unwrap() // All writes to this pipe should now fail
}

fn f1() -> Result<()> {
    let mut child_stdin = mk_broken_pipe();
    child_stdin.write_all(b"Some bytes")
}

fn f2() -> Result<()> {
    let mut child_stdin = BufWriter::new(mk_broken_pipe());
    child_stdin.write_all(b"Some bytes")
    // Oops, forgot to call flush()
}

fn f3() -> Result<()> {
    let mut child_stdin = BufWriter::new(mk_broken_pipe());
    try!(child_stdin.write_all(b"Some bytes"));
    child_stdin.flush()
}

fn main() {
    println!("Without BufWriter: {:?}", f1());
    println!("With BufWriter, but forgot to call flush: {:?}", f2());
    println!("With BufWriter, with call to flush: {:?}", f3());
}

The code above outputs

Without BufWriter: Err(Error { repr: Os { code: 32, message: "Broken pipe" } })
With BufWriter, but forgot to call flush: Ok(())
With BufWriter, with call to flush: Err(Error { repr: Os { code: 32, message: "Broken pipe" } })

It's tempting (at least to me) to think of BufWriter as preserving the semantics of the underlying writer, while offering possible performance improvements. It doesn't quite though, and it's unfortunately easy to forget to call flush(), and to ignore errors when using BufWriter, as in function f2() above.

It seems like a warning in the BufWriter documentation could be helpful here. Right now it says

The buffer will be written out when the writer is dropped.

Perhaps it could be changed to something like

When the writer is dropped, the BufWriter will be flushed and the contents of its buffer will be written out. However, any errors that happen when the writer is dropped will be ignored. Code that wishes to handle such errors must manually call flush() before the writer is dropped.

If a change along these lines is of interest, I'll make a pull request.

@nagisa
Copy link
Member

nagisa commented Oct 8, 2016

Duplicate of #32677

@jgallag88
Copy link
Contributor Author

Ah, didn't notice that one. Well, if you want a documentation change until that one gets sorted out, let me know.

@Mark-Simulacrum
Copy link
Member

I'm going to close this in favor of #32677.

Mark-Simulacrum added a commit to Mark-Simulacrum/rust that referenced this issue Jul 12, 2017
…bnik

Add warning to BufWriter documentation

When using `BufWriter`, it is very easy to unintentionally ignore errors, because errors which occur when flushing buffered data when the `BufWriter` is dropped are ignored. This has been noted in a couple places:  rust-lang#32677, rust-lang#37045.

There has been some discussion about how to fix this problem in rust-lang#32677, but no solution seems likely to land in the near future. For now, anyone who wishes to have robust error handling must remember to manually call `flush()` on a `BufWriter` before it is dropped.  Until a permanent fix is in place, it seems worthwhile to add a warning to that effect to the documentation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants