summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2019-10-29 09:46:10 -0400
committerBen Gamari <ben@smart-cactus.org>2019-11-03 12:56:20 -0500
commit176367f85d4f518372f78cf853a6d6b84d77a529 (patch)
treefa57f4d18d0d34e05d5ca6fd9280e0f58789f922
parent061f7f9b06f0faec23a1c5128967d509d6944e00 (diff)
downloadhaskell-176367f85d4f518372f78cf853a6d6b84d77a529.tar.gz
base: Clamp IO operation size to 2GB on Darwin
As reported in #17414, Darwin throws EINVAL in response to large writes. (cherry picked from commit 08810f123eb3b49bcfb3dd1d46284ec9d53d2612)
-rw-r--r--libraries/base/GHC/IO/FD.hs21
1 files changed, 17 insertions, 4 deletions
diff --git a/libraries/base/GHC/IO/FD.hs b/libraries/base/GHC/IO/FD.hs
index 2d3736a9dc..a889601be9 100644
--- a/libraries/base/GHC/IO/FD.hs
+++ b/libraries/base/GHC/IO/FD.hs
@@ -67,6 +67,17 @@ import System.Posix.Types
c_DEBUG_DUMP :: Bool
c_DEBUG_DUMP = False
+-- Darwin limits the length of writes to 2GB. See
+-- #17414.
+clampWriteSize, clampReadSize :: Int -> Int
+#if defined(darwin_HOST_OS)
+clampWriteSize = min 0x7fffffff
+clampReadSize = min 0x7fffffff
+#else
+clampWriteSize = id
+clampReadSize = id
+#endif
+
-- -----------------------------------------------------------------------------
-- The file-descriptor IO device
@@ -430,13 +441,14 @@ setRaw fd raw = System.Posix.Internals.setCooked (fdFD fd) (not raw)
fdRead :: FD -> Ptr Word8 -> Int -> IO Int
fdRead fd ptr bytes
- = do { r <- readRawBufferPtr "GHC.IO.FD.fdRead" fd ptr 0 (fromIntegral bytes)
+ = do { r <- readRawBufferPtr "GHC.IO.FD.fdRead" fd ptr 0
+ (fromIntegral $ clampReadSize bytes)
; return (fromIntegral r) }
fdReadNonBlocking :: FD -> Ptr Word8 -> Int -> IO (Maybe Int)
fdReadNonBlocking fd ptr bytes = do
r <- readRawBufferPtrNoBlock "GHC.IO.FD.fdReadNonBlocking" fd ptr
- 0 (fromIntegral bytes)
+ 0 (fromIntegral $ clampReadSize bytes)
case fromIntegral r of
(-1) -> return (Nothing)
n -> return (Just n)
@@ -444,7 +456,8 @@ fdReadNonBlocking fd ptr bytes = do
fdWrite :: FD -> Ptr Word8 -> Int -> IO ()
fdWrite fd ptr bytes = do
- res <- writeRawBufferPtr "GHC.IO.FD.fdWrite" fd ptr 0 (fromIntegral bytes)
+ res <- writeRawBufferPtr "GHC.IO.FD.fdWrite" fd ptr 0
+ (fromIntegral $ clampWriteSize bytes)
let res' = fromIntegral res
if res' < bytes
then fdWrite fd (ptr `plusPtr` res') (bytes - res')
@@ -454,7 +467,7 @@ fdWrite fd ptr bytes = do
fdWriteNonBlocking :: FD -> Ptr Word8 -> Int -> IO Int
fdWriteNonBlocking fd ptr bytes = do
res <- writeRawBufferPtrNoBlock "GHC.IO.FD.fdWriteNonBlocking" fd ptr 0
- (fromIntegral bytes)
+ (fromIntegral $ clampWriteSize bytes)
return (fromIntegral res)
-- -----------------------------------------------------------------------------