Skip to content

Commit

Permalink
Merge pull request #2610 from commercialhaskell/1979-fd-leak-sinkProc…
Browse files Browse the repository at this point in the history
…essStderrStdout

Fix FD leak in sinkProcessStderrStdout (fixes #1979)
  • Loading branch information
borsboom committed Sep 19, 2016
2 parents d6b4a15 + 3fd72d2 commit fed2863
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 3 deletions.
3 changes: 3 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ Bug fixes:
* Never treat `extra-dep` local packages as targets. This ensures
things like test suites are not run for these packages, and that
build output is not hidden due to their presence.
* Fix a resource leak in `sinkProcessStderrStdout` which could affect
much of the codebase, in particular copying precompiled
packages. [#1979](https://github.com/commercialhaskell/stack/issues/1979)

## 1.2.0

Expand Down
19 changes: 16 additions & 3 deletions src/System/Process/Read.hs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ import qualified System.Directory as D
import System.Environment (getEnvironment)
import System.Exit
import qualified System.FilePath as FP
import System.IO (Handle)
import System.IO (Handle, hClose)
import System.Process.Log
import Prelude () -- Hide post-AMP warnings

Expand Down Expand Up @@ -307,8 +307,21 @@ sinkProcessStderrStdout wd menv name args sinkStderr sinkStdout = do
(proc name' args) { env = envHelper menv, cwd = fmap toFilePath wd }
(\ClosedStream out err -> f err out)
where
f :: Source IO S.ByteString -> Source IO S.ByteString -> IO (e, o)
f err out = (err $$ sinkStderr) `concurrently` (out $$ sinkStdout)

-- There is a bug in streaming-commons or conduit-extra which
-- leads to a file descriptor leak. Ideally, we should be able to
-- simply use the following code. Instead, we're using the code
-- below it, which is explicit in closing Handles. When the
-- upstream bug is fixed, we can consider moving back to the
-- simpler code, though there's really no downside to the more
-- complex version used here.
--
-- f :: Source IO S.ByteString -> Source IO S.ByteString -> IO (e, o)
-- f err out = (err $$ sinkStderr) `concurrently` (out $$ sinkStdout)

f :: Handle -> Handle -> IO (e, o)
f err out = ((CB.sourceHandle err $$ sinkStderr) `concurrently` (CB.sourceHandle out $$ sinkStdout))
`finally` hClose err `finally` hClose out

-- | Like sinkProcessStderrStdout, but receives Handles for stderr and stdout instead of 'Sink's.
--
Expand Down

0 comments on commit fed2863

Please sign in to comment.