-
Notifications
You must be signed in to change notification settings - Fork 13.9k
Description
BufWriter.drop is broken.
BufWriter flushes data on drop and ignores the result. It is incorrect for two reasons:
- you must not ignore write errors. For example, when filesystem is full, write fails. Currently last write error is quietly ignored. This code demonstrates the problem: http://is.gd/ZdgbF9
dropmay indefinitly hang, for example, ifBufWrtiterunderlying stream is socket, and nobody reads on the other side
Generally, I think any drop must only release resources, do not do anything blocking or failing.
The similar issue was only partially fixed in #30888.
We (together with @cfallin) propose a solution:
Proposed solution
Add another function to BufWriter (and probably to Write trait): cancel. User of BufWriter must explicitly call either flush or cancel prior to drop.
struct BufWriter gets unfinished flag instead of panicked.
BufWriter.write unconditionally sets unfinished = true.
BufWriter.flush or BufWriter.cancel unconditionally set unfinished = false.
And finally, BufWriter.drop becomes an assertion:
impl Drop for BufWriter {
fn drop(&mut self) {
// check `flush` or `cancel` is explicitly called
// but it is OK to discard buffer on panic
assert!(!self.unfinished || std::thread::panicking());
}
}
That change is backward incompatible, however, it is not that bad: developer will likely get panic on first program run, and can quickly fix the code.
Change could be transitional: no-op cancel function could be added in rust version current+1 and assertion added in rust version current+2.