-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
os: File implicitly closed when garbage-collected due to runtime finalizer but this behavior is not documented #41505
Comments
Thank you for filing this issue @PureWhiteWu! Unfortunately we can’t remove this behavior, but perhaps we can document it. I worry thought that documenting that files have finalizers might encourage callous behavior in which folks just rely on garbage collection to sort out for them file close problems which will cause undeterministic leaks and bugs. I understand that in between invoking syscall.Write(fd, payload) and the end, a garbage collection cycle might run, but unfortunately that program has a leak that then depends on undefined behavior. How often have you seen such code? |
@odeke-em Thanks for your reply! This is a bug we encountered in our real-world program, in which we are doing something like this(simplified version):
And we got -9 (bad fd) after some time. This bug is hard to debug, so I think something should be changed to prevent this. |
Gotcha, I understand and thank you for the citation. For some remedies: Some docs updates to state that a file might be garbage collected perhaps could have helped you in this case then, if we stated the need to keep the file alive for the course of usage or to ensure it is closed, but the finalizer is an implementation/system specific detail. It is definitely inconvenient to try to go down many rabbit holes trying to figure out why a bad fd error occurred. |
/cc @ianlancetaylor |
It is documented. The os.File.Fd documentation says, in part,
It sounds like you already understand the problem and the workarounds from your original description.
Perhaps, though the crash seems fairly hard to miss. In any case, if you're using direct syscalls to write files rather than the usual mechanisms, you should be prepared for some amount of tricky debugging. |
@cespare Thanks very much, I missed this part.
In some cases, the for loop may quit before gc, so this may occur occasionally. I think this is really hard to debug for users, because users are not expected to understand how gc works and when will gc execute. @odeke-em Thanks for your reply, I think But maybe we can make things more clearly, such as adding an extra line:
|
Related issue: #34810 |
The problem here is the call of the I do not think we should add any documentation to |
Perhaps |
I think that the File.Fd method should be deprecated in favor of RawConn.Control and perhaps a new RawConn.MultiControl. We cannot remove File.Fd due to the Go 1 promise, but it is very hard to use correctly. It is what I would call a "foot gun". |
@ianlancetaylor Why this is a |
Perhaps. Should probably be separate issue though.
It's here to stay so might as well minimize damage by documenting it.
Apparently it wasn't if user still made mistake after reading it. And took their time to write up issue in bug tracker (how many more users have done this mistake? how many fixed it for themselves and didn't make an issue?).
Yes. But documentation doesn't suggest using |
Hmm. I think people who made such a mistake, solved, and stay silent thought it was their mistake other than an issue of the document, meaning the doc is clear on documenting its behavior. A meta issue regarding the misuse of a (potential) problematic APIs (such as
I don't see a reason the document needs explicitly suggest using f, err := os.Open("foo")
if err != nil { ... }
defer f.Close() |
Why spend time arguing against documentation enhancement? Amending the docs is no more costly :-) |
I believe that issue is that some people consider They probably miss "or f is garbage collected" because frankly it's short and looks insignificant since var won't even go out of scope. If at least one more sentence were to be added it probably would bring a bit more attention to possible mistake (they would at least check if they do We could also add suggestion to prefer using Is there reason to not do anything? I don't think adding a bit more info to known footgun method would hurt anyone.
Indeed. Maybe I should just try making PR at this point. |
@changkun I marked this as needs-fix because I think the documentation can be improved. I think the docs should explicitly point at |
First, thank you all for involving in this issue! I usually use Goland for coding, so when I was writing this code, I just saw the Fd method through the code hint and used it directly, without reading the Fd comment carefully, and assumed that if I didn't close it, Fd would always be alive, based on my C experience. Thank you for reading this. |
Change https://golang.org/cl/256899 mentions this issue: |
actual comment has |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (
go env
)?Linux and macOS.
What did you do?
Code: https://play.golang.org/p/YmHIIc7sha4
Note: This does not reproduce in go playground, but can reproduce on my mac/linux.
What did you expect to see?
No panic.
What did you see instead?
panic: bad file descriptor
Reason
I found that this is because there's an implicitly close call when the
file
object is garbage-collected.In os/file_unix.go:
What do I expect
I know there's thousands of method to avoid being garbage-collected such as runtime.KeepAlive, but I think this is unreasonable, either this behaviour should be removed or the
file
object should not be garbage-collected.If a user forgets to call file.Close, the memory should be leaking.
Also, this behaviour isn't documented anywhere.
The text was updated successfully, but these errors were encountered: