[GHC] #14621: GHC 8.2 GCed too early

GHC ghc-devs at haskell.org
Thu Dec 28 10:31:23 UTC 2017


#14621: GHC 8.2 GCed too early
-------------------------------------+-------------------------------------
           Reporter:  kazu-yamamoto  |             Owner:  (none)
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:
          Component:  Compiler       |           Version:  8.2.2
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  None/Unknown
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 The network package uses mkWeakVar so that unreachable Sockets can be
 GCed. See the master branch of https://github.com/haskell/network

 {{{
 mkSocket :: CInt
          -> Family
          -> SocketType
          -> ProtocolNumber
          -> SocketStatus
          -> IO Socket
 mkSocket fd fam sType pNum stat = do
    mStat <- newMVar stat
    withSocketsDo $ return ()
    let sock = Socket fd fam sType pNum mStat
 ##if MIN_VERSION_base(4,6,0)
    _ <- mkWeakMVar mStat $ close sock
 ##endif
    return sock
 }}}

 The following code cause "threadWait: invalid argument (Bad file
 descriptor)" in accept:

 {{{
 module Main where

 import Control.Concurrent (forkIO)
 import Control.Monad (void, forever)
 import Network.Socket hiding (recv)
 import Network.Socket.ByteString (recv, sendAll)

 main :: IO ()
 main = do
     let localhost = "localhost"
         listenPort = "9876"
         connectPort = "6789"
     proxy localhost listenPort connectPort

 proxy :: HostName -> ServiceName -> ServiceName -> IO ()
 proxy localhost listenPort connectPort = do
     fromClient <- serverSocket localhost listenPort
     toServer <- clientSocket localhost connectPort
     void $ forkIO $ relay toServer fromClient
     relay fromClient toServer

 relay :: Socket -> Socket -> IO ()
 relay s1 s2 = forever $ do
     payload <- recv s1 4096
     sendAll s2 payload

 serverSocket :: HostName -> ServiceName -> IO Socket
 serverSocket host port = do
     let hints = defaultHints {
                 addrFlags = [AI_PASSIVE]
               , addrSocketType = Stream
               }
     addr:_ <- getAddrInfo (Just hints) (Just host) (Just port)
     sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol
 addr)
     bind sock (addrAddress addr)
     listen sock 1
     fst <$> accept sock

 clientSocket :: HostName -> ServiceName -> IO Socket
 clientSocket host port = do
     let hints = defaultHints { addrSocketType = Stream }
     addr:_ <- getAddrInfo (Just hints) (Just host) (Just port)
     sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol
 addr)
     connect sock (addrAddress addr)
     return sock
 }}}

 GC frees sock while accepting. This occurs with GHC 8.2 or higher.

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14621>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list