From c837fdeb0df1652dcadcf712c565e30f79726091 Mon Sep 17 00:00:00 2001 From: Julian Brunner Date: Sun, 27 Sep 2026 16:35:25 +0200 Subject: [PATCH 1/2] implement `readFile` in terms of `withFile` for prompt closing of handle --- src/Data/Text/IO.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Data/Text/IO.hs b/src/Data/Text/IO.hs index aa0e7faa..f4093e96 100644 --- a/src/Data/Text/IO.hs +++ b/src/Data/Text/IO.hs @@ -45,8 +45,7 @@ module Data.Text.IO import Data.Text (Text) import Prelude hiding (appendFile, getContents, getLine, interact, putStr, putStrLn, readFile, writeFile) -import System.IO (Handle, IOMode(..), openFile, stdin, stdout, - withFile) +import System.IO (Handle, IOMode(..), stdin, stdout, withFile) import qualified Control.Exception as E import Control.Monad (liftM2, when) import Data.IORef (readIORef) @@ -73,7 +72,7 @@ import System.IO.Error (isEOFError) -- using 'Data.Text.Encoding.decodeUtf8' '.' 'Data.ByteString.readFile' -- is a much faster and safer alternative. readFile :: FilePath -> IO Text -readFile name = openFile name ReadMode >>= hGetContents +readFile name = withFile name ReadMode hGetContents -- | Write a string to a file. The file is truncated to zero length -- before writing begins. From 0ef79eeb4771acb57f342e889ac7b8aedb741f37 Mon Sep 17 00:00:00 2001 From: Li-yao Xia Date: Wed, 7 Oct 2026 00:34:24 +0200 Subject: [PATCH 2/2] Add regression test: readFile must close the handle on exception --- tests/Tests/Regressions.hs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Tests/Regressions.hs b/tests/Tests/Regressions.hs index 892d635d..64a31fe6 100644 --- a/tests/Tests/Regressions.hs +++ b/tests/Tests/Regressions.hs @@ -13,6 +13,7 @@ module Tests.Regressions import Control.Exception (ErrorCall, SomeException, handle, evaluate, displayException, try) import Data.Char (isLetter, chr) import GHC.Exts (Int(..), sizeofByteArray#) +import Control.Exception (IOException) import System.IO import System.IO.Temp (withSystemTempFile) import Test.Tasty.HUnit (assertBool, assertEqual, assertFailure, (@?=)) @@ -36,6 +37,8 @@ import qualified Test.Tasty as F import qualified Test.Tasty.HUnit as F import Tests.Utils (withTempFile) import System.IO.Error (isFullError) +import Control.Monad (when) +import Data.Either (isRight) -- Reported by Michael Snoyman: UTF-8 encoding a large lazy bytestring -- caused either a segfault or attempt to allocate a negative number @@ -213,6 +216,17 @@ t648 = withTempFile $ \_ h -> do line' <- T.hGetLine h T.append line "\r" @?= line' +t714 :: IO () +t714 = withTempFile $ \name h -> do + hSetBinaryMode h True + hPutChar h '\xFF' + hClose h + e :: Either IOException T.Text <- try (T.readFile name) + when (isRight e) (assertFailure "should fail") + -- readFile must close the handle even in the case of an exception, + -- in which case the next line should succeed. + openFile name WriteMode >>= hClose + tests :: F.TestTree tests = F.testGroup "Regressions" [ F.testCase "hGetContents_crash" hGetContents_crash @@ -233,4 +247,5 @@ tests = F.testGroup "Regressions" , F.testCase "t559" t559 , F.testCase "t633" t633 , F.testCase "t648" t648 + , F.testCase "t714" t714 ]