#1753: GHC's file locking mechanism not prepared for close() returning -1
-----------------------------+----------------------------------------------
Reporter: guest | Owner:
Type: bug | Status: new
Priority: normal | Milestone:
Component: libraries/base | Version: 6.6.1
Severity: normal | Keywords:
Difficulty: Easy (1 hr) | Os: Multiple
Testcase: | Architecture: Unknown
-----------------------------+----------------------------------------------
There is a bug in GHC file locking mechanism which manifests itself when
close() returns -1. The reasons for the problem, as I see it, are:
* asymmetry in the locking mechanism - creating the lock by device/inode,
but
releasing by fd
* not handling exceptions properly in hClose
* trying to do the job of the operating system and/or trying to correct
the
behavior of the operating system - but this one is a criticism of
Haskell
Report, not of GHC
I will demonstrate the scenario on an example program:
{{{
main = do
try $ do
h <- openFile "A" AppendMode
-- As part of opening A, GHC adds a lock to the writeLock table
-- (libraries/base/cbits/lockFile.c).
hClose h
-- Assume that close() returned -1 when performing hClose, but
released
-- the file descriptor anyway (this happened for us).
-- In hClose_help (libraries/base/GHC/Handle.hs) an exception is
-- raised by (throwErrnoIfMinus1Retry_ "hClose" ...).
-- As a result, (unlockFile fd) is not performed, which leaves
-- a lock on A's device and inode. Further attempts to open A
-- will fail, of course, but let's look at a more interesting
scenario.
-- Remember that h's underlying file descriptor was released and
is
-- available.
do
h1 <- openFile "B" AppendMode
-- Assume that "B" is opened under the same file descriptor that
was earlier
-- assigned to "A".
-- OpenFile locks "B", and the lock for it is put at the end of
writeLock
-- table.
hClose h1
-- What happens here is that unlockFile removes the first lock
matching h1's
-- file descriptor. But this is the lock for A!
-- The lock for B is left intact.
do
h1 <- openFile "B" AppendMode
-- openFile fails because of the stray lock for B.
hClose h1
}}}
A can see the following solutions to this problem:
* handle the exception properly. I think this should be straightforward,
but there may
be some hidden dangers - after all, when close() fails you already have
a strange situation.
Perhaps we should check if the file descriptor is still in use with
fstat()? On the other
hand, it shouldn't make much difference as long as the Handle is marked
as closed.
* remove all locks with matching fd - this would only fix the A/B
problem, and it would be
a bit awkward - after all, we probably don't want to have duplicated
fds in the lock tables
If we can agree on the acceptable solution, I could try fixing it myself.
This would be a good exercise in working with GHC's darcs repository.
BTW, functions lockFile and unlockFile seem to be quite expensive:
* they use linear search on the lock tables
* when deleting an entry unlockFile moves all subsequent entries up
Perhaps it would be a good idea to get rid of locking requirements from
haskell-prime?
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/1753>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs