-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Lint for types where cleanup before drop is desirable #32677
Comments
Seems to be related to #32255, i.e the same concern of closing (or cancelling) & handling errors before drop. Due to the terrible events that unfold if you panic in unwinding (= abort), panic in a destructor implementation is not a good idea. |
Interesting -- if no panic, then there are two possibilities on drop when unwritten bytes remain:
The discussion came up on rust-protobuf because its output stream abstraction ( Perhaps a good solution here is just to add a |
I expect the libs team will be helping us in this discussion. Some I/O resources are not well modelled with RAII at the moment, and should rather be linear types == you have to call a consuming operation on them (maybe in rust it does not need to be consuming, just disabling). File, BufWriter, etc, need to first have “eager” error handling available to call, such as .close(), .flush(), or .cancel(). To not have any breaking changes, instead introduce lints that sternly guide the user towards ensuring the final methods are called on linear resources before they go out of scope. To make this complete, maybe the lint must even suggest that something that contains a File or BufWriter is also adding a final method. Ensuring this up front is more in line with Rust's philosophies than using drop and panic. |
See also rust-lang/rfcs#1568.
I do not see a problem here personally. One can always manually run the I would rather it not ignore the errors which happen on flush and panic, but maybe there’s a reason for that (double-panics is not a good-enough one).
That’s a no-go breakage for non-major release in my eyes. |
I think the motivation behind this issue sounds good to me, but I think that the conclusions it reaches are untenable unfortunately. Rust is generally pretty good about helping you not ignore errors, and the buffered writer does indeed make it easy to ignore the error of the last write. In cases like this we need to be sure to add some method of seeing the error, and as pointed out by @nagisa in this case it's the Some thoughts on the proposal:
We can perhaps investigate lints or some other method of helping programs call |
We could add something similar to the This way there's no breaking change, but everyone starts getting a warning + an easy fix. |
In In POSIX, the only portable way to observe a final write error is by observing the result of |
The flush that was referred to was Using
This is exposed as the |
How about offering the end user maximum flexibility? The writer types could have a "DropPolicy" parameter (in the sense of c++ policy-based design), with maybe some default, but still allowing the end user to choose behaviour. |
@oli-obk an alternative might be to mark types as "require explicit drop" and allow those types to provide a That is, a user would then be required to explicitly call drop on the object, drop would then consume the object and could return an enum that its either empty (success), or contains a (self, error_code) with the consumed object and the error, such that the user can retry the drop operation. |
…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.
BufWriter.drop
is broken.BufWriter
flushes data ondrop
and ignores the result. It is incorrect for two reasons:drop
may indefinitly hang, for example, ifBufWrtiter
underlying stream is socket, and nobody reads on the other sideGenerally, 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 toWrite
trait):cancel
. User ofBufWriter
must explicitly call eitherflush
orcancel
prior to drop.struct BufWriter
getsunfinished
flag instead ofpanicked
.BufWriter.write
unconditionally setsunfinished = true
.BufWriter.flush
orBufWriter.cancel
unconditionally setunfinished = false
.And finally,
BufWriter.drop
becomes an assertion: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.The text was updated successfully, but these errors were encountered: