[commit: packages/base] master: Fix OSX RTS crash due to bad coercion. (95a74f9)

git at git.haskell.org git at git.haskell.org
Thu Nov 7 13:57:10 UTC 2013


Repository : ssh://git@git.haskell.org/base

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/95a74f9b091a8b512828b6930ea46d7ac55be76b/base

>---------------------------------------------------------------

commit 95a74f9b091a8b512828b6930ea46d7ac55be76b
Author: Merijn Verstraaten <merijn at inconsistent.nl>
Date:   Wed Jul 24 14:37:25 2013 +0100

    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 at pobox.com>


>---------------------------------------------------------------

95a74f9b091a8b512828b6930ea46d7ac55be76b
 GHC/Event/Poll.hsc |   24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/GHC/Event/Poll.hsc b/GHC/Event/Poll.hsc
index 665949b..6d089fb 100644
--- a/GHC/Event/Poll.hsc
+++ b/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



More information about the ghc-commits mailing list