-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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: race between os.(*File).Close() and os.(*File).Read() #10001
Comments
As I understand it, POSIX does not guarantee the result of calling |
Changing Close() to not write to file.fd yet still only close once per the comment is pretty straightforward (see below). However, setting file.fd to -1 has the positive side affect that file operations after Close() will not be using a stale fd at the syscall level, so we should keep the -1 assignment unless we want to take the file.closedMutex every operation which defeats the purpose.
|
Imagine the following three events happening one after the other:
In that case, the call to f1.Read() would actually be reading from an invalid file descriptor. Setting the internal .fd property to -1 prevents that situation. |
I am not disputing that there is a race. What I am suggesting is fixing On Thu, Feb 26, 2015 at 7:41 AM, Alvaro Lopez Ortega <
|
@davecheney FYI my first reply was not meant as a reply to your first comment. Looking into it more I agree with you. From the linux man page:
I will fix this at a higher level in the serial library. Closing. |
The problem here is not with file.fd, but with the actual file. Whenever you call Close concurrently with Read/Write you are risking of corrupting arbitrary file or leaking sensitive data to an arbitrary socket. |
Here's is a simple reproduction case operating on a regular file (in this case "race.go"). This is with go 1.4.2
In this case, this would obviously be a silly thing to do because there is also a larger race condition in terms of how much data is actually read from the Read() call. The real case this came up was with a serial port device (https://github.com/tarm/goserial) where the Read() and Close() might happen in different goroutines because the Read() can take a long time (serial ports can be configured to block forever until the next character). A syscall.Close() will allow the Read() to return, which is why os.(*File).Close() and Read() are useful to be able to run in different goroutines.
The problematic line in file_unix.go:close() is
Conceptually, does it make sense that Close() and Read() should be allowed to run at the same time? The cost of a mutex in Close() is not important, but putting a mutex in Read() might have a performance impact. Would a fix be appropriate for the std library? Should I try to work around this in the goserial library by not using os.File?
The text was updated successfully, but these errors were encountered: