File descriptor reuse causes Handle to point to a different stream
Short: A handle h has been closed with hClose, while the file descriptor underneath h has been reused, then hPutStrLn h might succeed with the content written to the reconnected file descriptor.
**Long: ** A popular server design -- also in Haskell -- is to have one thread for each connected network client. The thread usually is blocking on read for new packets of the connected client, while other threads write to the socket of the connected client.
If a client drops its connection, the read thread terminates, and hCloses the handle. However, in the example attached, we do not bother to notify the other threads that the handle became invalid. We expect any write to the closed handle to fail, so that those threads can lazily clean up their handle lists and drop clients when they see a failing write.
However, the approach above does not work, as hPutStrLn will not fail for closed handles, as the base library seems to rely on closed file descriptors to signal errors on obsolete handles. When the file descriptor is reused however, hPutStrLn will not signal any error, but happily write content destined for an obsolete Handle to a file descriptor of a new unrelated Handle.
In the example attached, just use netcat to connect and reconnect to port 1243, multiple times. The server will echo the list of connected handles. If you just connect/reconnect that should not grow, but it does, as old handles are not clean up because of non-failing writes.
You will also see the number of status message to multiply on connect.
This code is a minimal version of http://sequence.complete.org/node/258
Trac metadata
Trac field | Value |
---|---|
Version | 7.0.1 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | libraries/base |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |