Opened 5 years ago

Closed 5 years ago

#9817 closed bug (fixed)

signal handlers in unix are passed garbage when using the signle threaded rts

Reported by: redneb Owned by: simonmar
Priority: normal Milestone: 7.8.4
Component: Runtime System Version: 7.8.3
Keywords: Cc: simonmar
Operating System: POSIX Architecture: Unknown/Multiple
Type of failure: Incorrect result at runtime Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s): Phab:D515
Wiki Page:

Description

When a signal handler (registered with GHC.Conc.Signal.setHandler) is called upon the receipt of the relevant signal, it is passed a memory buffer in the form of a ForeignPtr Word8. This buffer contains a copy of the siginfo_t struct that was originally passed to the underlying os signal handler. Unfortunately, this only seems to work correctly in the threaded rts. In the single-threaded rts, the buffer contains garbage. This can be demonstrated by the following program:

import Control.Concurrent
import System.Posix.Signals

main :: IO ()
main = do
    wait <- newEmptyMVar
    _ <- flip (installHandler sig) Nothing $ CatchInfo $ \info -> do
        putStrLn $ "Received a signal " ++ show (siginfoSignal info)
        putMVar wait ()
    raiseSignal sig
    putStrLn $ "Sending myself a signal " ++ show sig
    takeMVar wait
  where
    sig = sigUSR2

If you compile the program with the -threaded flag then everything works just fine:

Sending myself a signal 12
Received a signal 12

but without it, the signal handler will print a totaly random signal number:

Sending myself a signal 12
Received a signal 138644296

I was able to track this down to the function startSignalHandlers in rts/posix/Signals.c. This function (which is only used by the single threaded rts) allocates a buffer and copies the siginfo_t struct to it and then schedules GHC.Conc.Signal.runHandlers to be run in a new thread. The problem is that while GHC.Conc.Signal.runHandlers expects a ForeignPtr Word8, here it is given a Ptr Word8. This has two implications: the signal handler is given invalid data, and nobody is deallocating the buffer so we are leaking memory every time a signal is received that has a custom handler.

Change History (5)

comment:1 Changed 5 years ago by redneb

Differential Rev(s): Phab:D515

comment:2 Changed 5 years ago by redneb

Status: newpatch

comment:3 Changed 5 years ago by redneb

Since there is going to be a 7.8.4 release, I think it makes sense to include my patch for that release as well. It is small, non-intrusive and solves a real issue with 7.8.3.

comment:4 Changed 5 years ago by Austin Seipp <austin@…>

In 7ca5bb090ff78141fbe275b058a9e35ee496bd58/ghc:

compiler: fix trac issue #9817

Summary:
When we call runHandlers, we must pass it a ForeignPtr. To ensure that
this happens, we introduce a wrapper that receives a plain Ptr and
converts it into a ForeignPtr. Then we adjust startSignalHandlers in
rts/posix/Signals.c to call the wrapper instead of calling runHandlers
directly.

Reviewers: hvr, austin, rwbarton, simonmar

Reviewed By: austin, simonmar

Subscribers: simonmar, thomie, carter

Differential Revision: https://phabricator.haskell.org/D515

GHC Trac Issues: #9817

comment:5 Changed 5 years ago by thoughtpolice

Milestone: 7.8.4
Resolution: fixed
Status: patchclosed

Merged to 7.8.4.

Note: See TracTickets for help on using tickets.