Repository navigation
hGetContents does not close handle on exception #712
Description
Activity
There is no promise that the handle will be closed promptly, only that it will be closed eventually (namely, when the garbage collector will trigger finalisers).
But I agree that
Data.Text.IO.readFileshould usewithFileinstead ofopenFile. Patches are welcome.Ah, I guess
System.IO.hGetContents'also does not close the handle promptly. Is there a reason why bothSystem.IO.hGetContents'andData.Text.IO.hGetContentsshould not do so, given that they aim for non-lazy IO semantics? From what I can tell, this is whatData.ByteString.hGetContentsdoes, but it is difficult to test since there is no easy way to provoke failure. I feel like the immediate closing behavior would be less surprising, but maybe there is a good reason for the way things are.I guess this also means that the comment on
System.IO.readFile'is not quite accurate. UsingwithFileis not overkill, as it ensures prompt closure of the handle which the underlyinghGetContents'by itself does not guarantee.I think I might have misled you above, I was not aware that
hGetContentssets semi-closed mode.I'm not an expert in this area:
hGetContentsalmost immediately goes intowithHandleand code there gets too dense to skim through. Perhaps the precise semantics in the presence of exceptions a good question for GHC issue tracker.
Anyway,
Data.Text.IO.readFileshould be modelled afterSystem.IO.readFile'(usingwithFile) and notSystem.IO.readFile(which leaves it tohGetContentsto close the handle). The current implementation is most likely a copy-paste without much analysis. Fancy to fire a PR?- linked a pull request that will close this issueImplement `readFile` in Terms of `withFile` for Prompt Closing of Handle #714
on Oct 6, 2026 We've fixed
readFilebut I think the behavior ofhGetContentsandhGetContents'here is a bug, or at the very least undesirable.Looking at
System.IOfor comparison:-
hGetContentscloses the handle on decoding exception, which is technically anIOException, so this arguably respects its spec:A semi-closed handle becomes closed:
- if
hCloseis applied to it; - if an I/O error occurs when reading an item from the handle;
- or once the entire contents of the handle has been read.
- if
-
hGetContents'does not close the handle on error. I believe this is a bug. I've opened a GHC ticket to get another opinion https://gitlab.haskell.org/ghc/ghc/-/work_items/27905
Reacted by julmb-
The documentation for
Data.Text.IO.hGetContentspromisesHowever, this seems to not be the case:
On my system (
ghc-9.12.2,text-2.1.4), this yieldsAs far as I can tell, this also affects
Data.Text.IO.readFile, which usesopenFileinstead ofwithFileand so the handle is not closed there either.System.IO.readFile'useswithFileand has a comment acknowledging that this should not be necessary:I cannot say with 100% certainty, but I believe this to be the root cause of a "resource exhausted (Too many open files)" exception in my application.