Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Error in Internal.hsc Non-exhaustive patterns in case, aborts server #32

Open
jcberentsen opened this Issue · 6 comments

4 participants

Christian Berentsen Eric Mertens Michael Snoyman Holger Reinhardt
Christian Berentsen

I have a Yesod webserver running that reliably aborts (after running a while) on an error in Network.hsc:

Last output:

HostIPv4
NimbusYesod: Network/Socket/Internal.hsc:(292,3)-(308,61): Non-exhaustive patterns in case

This is on Mac OSX 10.6.8
ghc is version 7.0.3
Network is version 2.3.0.11

Eric Mertens

Yesod is crashing in the middle of "peekSockAddr". As written, peekSockAddr only allows the address family to be Unix, INET, or INET6. Any other values will result in pattern match failure. My guess is that someone is trying to peek something that is not a sockaddr or not checking a return code before treating some zeroed memory as a sockaddr. The user experiencing this issue should add a default case and print the family before throwing an exception to shed some light on the particular issue.

Michael Snoyman

I just checked over the Yesod codebase (including Warp) and we're not calling peekSockAddr at all. Looking through the network codebase briefly, I'm guessing the most likely candidate for the call site is accept.

@jcberentsen Can you try adding the default case the @glguy mentioned, and possible some tracing information to accept? cAlso, Can you check if the issue arises in the context of Warp itself:

{-# LANGUAGE OverloadedStrings #-}
import Network.Wai
import Network.Wai.Handler.Warp
import Network.HTTP.Types

main = run 3000 $ const $ return $ responseLBS status200 [] ""
Christian Berentsen

Ok, trying Warp only.

Christian Berentsen

How do I go ahead and change the 'accept' source? Changing existing packages at source level is new to me. I took a look at 'accept' in Socket.hsc and it is a bit hard for me to read, preprocessor noise... Also I don't quite understand the pattern:

allocaBytes sz $ \ sockaddr -> do

followed later by:
addr <- peekSockAddr sockaddr

How is sockaddr filled with the relevant data? Is it the c_accept* that does this? Is the return code checked, I am unable to see if it is.

Christian Berentsen

So far the Warp only server has been running fine.

Holger Reinhardt

How is sockaddr filled with the relevant data? Is it the c_accept* that does this?

Yes, a pointer is passed to c_accept.

Is the return code checked

Yes, by the 'throwSocketErrorIfMinus1RetryMayBlock' function.

I think the first thing you should do is what glguy suggested. Replace the peekSockAddr function with:

-- | Read a 'SockAddr' from the given memory location.
peekSockAddr :: Ptr SockAddr -> IO SockAddr
peekSockAddr p = do
  family <- (#peek struct sockaddr, sa_family) p
  case family :: CSaFamily of
#if defined(DOMAIN_SOCKET_SUPPORT)
    (#const AF_UNIX) -> do
        str <- peekCString ((#ptr struct sockaddr_un, sun_path) p)
        return (SockAddrUnix str)
#endif
    (#const AF_INET) -> do
        addr <- (#peek struct sockaddr_in, sin_addr) p
        port <- (#peek struct sockaddr_in, sin_port) p
        return (SockAddrInet (PortNum port) addr)
#if defined(IPV6_SOCKET_SUPPORT)
    (#const AF_INET6) -> do
        port <- (#peek struct sockaddr_in6, sin6_port) p
        flow <- (#peek struct sockaddr_in6, sin6_flowinfo) p
        addr <- (#peek struct sockaddr_in6, sin6_addr) p
        scope <- (#peek struct sockaddr_in6, sin6_scope_id) p
        return (SockAddrInet6 (PortNum port) flow addr scope)
#endif
    x -> error $ "peekSockAddr error: "++show x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.