Skip to content

Commit 4a0b05a

Browse files
robxmergify-bot
authored and
mergify-bot
committed
Use async-safe bracket for withTempFileName
If `withTempFileName` receives an asynchronous exception (e.g. a canceled async), the bracket cleanup handler will attempt to remove the temporary file. This can fail with an IO exception. Regular bracket then throws that IO exception, swallowing the asynchronous exception. To calling code, this appears no different from an IO exception thrown from the body, and it won't be able to tell that it should be exiting promptly. This manifests concretely during temporary file clean-up of `asyncFetchPackages` on Windows (seen during unit testing in CI), where temporary file removal fails (on GHC 8.4), which leads to `concurrently` failing to cancel the outstanding download because it's handled like a regular download failure.
1 parent deca6e7 commit 4a0b05a

File tree

1 file changed

+4
-2
lines changed
  • cabal-install/src/Distribution/Client

1 file changed

+4
-2
lines changed

cabal-install/src/Distribution/Client/Utils.hs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ import Data.List
4949
( groupBy )
5050
import Foreign.C.Types ( CInt(..) )
5151
import qualified Control.Exception as Exception
52-
( finally, bracket )
52+
( finally )
53+
import qualified Control.Exception.Safe as Safe
54+
( bracket )
5355
import System.Directory
5456
( canonicalizePath, doesFileExist, findExecutable, getCurrentDirectory
5557
, removeFile, setCurrentDirectory, getDirectoryContents, doesDirectoryExist )
@@ -118,7 +120,7 @@ withTempFileName :: FilePath
118120
-> String
119121
-> (FilePath -> IO a) -> IO a
120122
withTempFileName tmpDir template action =
121-
Exception.bracket
123+
Safe.bracket
122124
(openTempFile tmpDir template)
123125
(\(name, _) -> removeExistingFile name)
124126
(\(name, h) -> hClose h >> action name)

0 commit comments

Comments
 (0)