[GHC] #12750: hGetContents leads to late/silent failures

#12750: hGetContents leads to late/silent failures -------------------------------------+------------------------------------- Reporter: | Owner: massimo.zaniboni | Type: bug | Status: new Priority: normal | Milestone: Component: Core | Version: 8.0.1 Libraries | Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: Incorrect result Unknown/Multiple | at runtime Test Case: | Blocked By: https://github.com/massimo- | zaniboni/ghc_lazy_file_content_error| Blocking: | Related Tickets: #9236 Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- I have the same problem described in the closed ticket #9236 This is a test-case https://github.com/massimo- zaniboni/ghc_lazy_file_content_error I tried with ghc 7.10.3 and 8.0.1 -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12750 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12750: hGetContents leads to late/silent failures -------------------------------------+------------------------------------- Reporter: massimo.zaniboni | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Core Libraries | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: Incorrect result | Test Case: at runtime | https://github.com/massimo- | zaniboni/ghc_lazy_file_content_error Blocked By: | Blocking: Related Tickets: #9236 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by massimo.zaniboni): Probably it is better if (when I have time) I insert the test-case inside the testsuites of GHC, and not as an external repo. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12750#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

`hGetContents` closes automatically the handle when the end of the file is reached. But in case of actions with exceptions, the end of the file could be not reached and the handle can be left temporally open, before
#12750: hGetContents leads to late/silent failures -------------------------------------+------------------------------------- Reporter: massimo.zaniboni | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Core Libraries | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: Incorrect result | Test Case: at runtime | https://github.com/massimo- | zaniboni/ghc_lazy_file_content_error Blocked By: | Blocking: Related Tickets: #9236 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by rwbarton): the garbage collector reclaim it. That's right. It's normally no big deal to leave a file handle open for a little while. If this is a problem for you, then don't use `hGetContents`.
So the suggested pattern is managing file handles inside `bracket` resource management functions. But this can introduce problems in case of lazy evaluations, because the code processing the file content can be called after the handle is closed.
Indeed, mixing `hGetContents` and `bracket` isn't recommended. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12750#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12750: hGetContents leads to late/silent failures -------------------------------------+------------------------------------- Reporter: massimo.zaniboni | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Core Libraries | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: Incorrect result | Test Case: at runtime | https://github.com/massimo- | zaniboni/ghc_lazy_file_content_error Blocked By: | Blocking: Related Tickets: #9236 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by massimo.zaniboni): Replying to [comment:2 rwbarton]:
Indeed, mixing `hGetContents` and `bracket` isn't recommended.
I like lazy functions like `Data.Text.Lazy.hGetContents` because I can process file content chunk by chunk using a constant amount of RAM, and the code is very elegant. In any case the problem is related to any type of lazy evaluation using a resource managed by `bracket`, so not only `hGetContents`. More clearly there are two bugs: 1) when the code reads the content of a closed file handle, instead of returning a run-time exception, a normal EOF is returned, and the application code has a bad behavior, because normal code path is executed instead of processing the exception. 2) `bracket` does not work well with resources processed in a lazy way, because the thunk using the resource can be used after `bracket` has closed it, generating unexpected run-time errors. So the best semantic of `bracket` should be a strict evaluation of the result. It is a behavior more predictable and similar to Resource Acquisition Is Initialization (RAII) semantic of C++. But probably this is not the best place for signaling this. By the way I solved the problem executing with strict semantic all the file processing instructions inside `bracket`. File content is still processed chunk by chunk, but the handle is closed only at the end, when the result is returned. So my work-around rule is: use `bracket` only with strict semantic. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12750#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC