snoyberg · GitHub

Hello!

I believe I found a bug in waitForProcess. When run in the MaskedInterruptible state, an async exception doesn't actually bring the thread down.

For example, the typed-process library exports withProcess which is similar to withCreateProcess, but ends up calling waitForProcess in the cleanup action of a bracket.

Even though waitForProcess is an interruptible foreign call, I think what's happening is:

  • Async exception enqueued for delivery to thread making waitForProcess call
  • GHC sees it's in an interruptible foreign call, sends SIGPIPE (GHC docs)
  • c_waitForProcess returns -1 with errno = EINTR
  • Upon returning to Haskell, the pending exception is not delivered, because the masking state is MaskedInterruptible
  • c_waitForProcess is retried because it's wrapped by throwErrnoIfMinus1Retry_

So our "interruptible" waitForProcess is only half-interrupted :)

My fix in this patch is to simply poll for any async exceptions before entering c_waitForProcess. Here is some related discussion I had with @snoyberg.

Thanks!

Read the original on github.com ↗