summaryrefslogtreecommitdiff
path: root/libraries/base/GHC/Event
diff options
context:
space:
mode:
authorMerijn Verstraaten <merijn@inconsistent.nl>2013-07-24 14:37:25 +0100
committerAustin Seipp <aseipp@pobox.com>2013-11-07 04:11:09 -0600
commit00e04e81fb127d716719a85d9387a98b664b7176 (patch)
treedb191e0c4edf8f3029c98eaf3dc033460ef5b645 /libraries/base/GHC/Event
parent2e7383763b22b1855360254ee514e9d7632cc037 (diff)
downloadhaskell-00e04e81fb127d716719a85d9387a98b664b7176.tar.gz
Fix OSX RTS crash due to bad coercion.
The code coerces Int to CInt, which causes an overflow if Int is bigger than CInt (for example, Int 64bit, CInt 32 bit). This results in a negative value being passed to c_poll. On Linux all negative values are treated as infinite timeouts, which gives subtly wrong semantics, but is unlikely to produce actual bugs. OSX insists that only -1 is a valid value for infinite timeout, any other negative timeout is treated as an invalid argument. This patch replaces the c_poll call with a loop that handles the overflow gracefully by chaining multiple calls to poll to obtain the proper semantics. Signed-off-by: Austin Seipp <aseipp@pobox.com>
Diffstat (limited to 'libraries/base/GHC/Event')
-rw-r--r--libraries/base/GHC/Event/Poll.hsc24
1 files changed, 23 insertions, 1 deletions
diff --git a/libraries/base/GHC/Event/Poll.hsc b/libraries/base/GHC/Event/Poll.hsc
index 665949b786..6d089fb387 100644
--- a/libraries/base/GHC/Event/Poll.hsc
+++ b/libraries/base/GHC/Event/Poll.hsc
@@ -35,6 +35,7 @@ import Foreign.Ptr (Ptr)
import Foreign.Storable (Storable(..))
import GHC.Base
import GHC.Conc.Sync (withMVar)
+import GHC.Enum (maxBound)
import GHC.Num (Num(..))
import GHC.Real (ceiling, fromIntegral)
import GHC.Show (Show)
@@ -90,7 +91,7 @@ poll p mtout f = do
E.throwErrnoIfMinus1NoRetry "c_poll" $
case mtout of
Just tout ->
- c_poll ptr (fromIntegral len) (fromIntegral (fromTimeout tout))
+ c_pollLoop ptr (fromIntegral len) (fromTimeout tout)
Nothing ->
c_poll_unsafe ptr (fromIntegral len) 0
unless (n == 0) $ do
@@ -102,6 +103,27 @@ poll p mtout f = do
return (i', i' == n)
else return (i, True)
return (fromIntegral n)
+ where
+ -- The poll timeout is specified as an Int, but c_poll takes a CInt. These
+ -- can't be safely coerced as on many systems (e.g. x86_64) CInt has a a
+ -- maxBound of (2^32 - 1), even though Int may have a significantly higher
+ -- bound.
+ --
+ -- This function deals with timeouts greater than maxBound :: CInt, by
+ -- looping until c_poll returns a non-zero value (0 indicates timeout
+ -- expired) OR the full timeout has passed.
+ c_pollLoop :: Ptr PollFd -> (#type nfds_t) -> Int -> IO CInt
+ c_pollLoop ptr len tout
+ | tout <= maxPollTimeout = c_poll ptr len (fromIntegral tout)
+ | otherwise = do
+ result <- c_poll ptr len (fromIntegral maxPollTimeout)
+ if result == 0
+ then c_pollLoop ptr len (fromIntegral (tout - maxPollTimeout))
+ else return result
+
+ -- Timeout of c_poll is limited by max value of CInt
+ maxPollTimeout :: Int
+ maxPollTimeout = fromIntegral (maxBound :: CInt)
fromTimeout :: E.Timeout -> Int
fromTimeout E.Forever = -1