Using the fork function in signal handlers

Updated -

The GNU C Library (shipped as part of Red Hat Enterprise Linux in the glibc) package provides a function called fork, which creates a new process as a copy of the current process image.

POSIX specifies that fork can be called safely from signal handlers; it is required to be an async-signal-safe function. However, the implementation in glibc does not match this requirement. The main reason is that existing application usage requires that memory allocation functions such as malloc and free must work in the new subprocess created by fork, even in the case where the original process was multi-threaded. Therefore, fork must bring the original process into a consistent state as far as malloc is concerned, and in general, this is not possible when fork is executed from a signal handler. The current implementation may self-deadlock under such circumstances and the process invoking fork will hang indefinitely.

There is an upstream bug which tracks this POSIX compliance issue:

The downstream bug for Red Hat Enterprise Linux is:

As of February 2017, this issue has only been addressed partially upstream (for single-threaded programs in glibc 2.25).

Even though POSIX permits calls to fork from signal handlers, it is unclear what happens if a function which is not async-signal-safe is called from a fork handler (registered using pthread_atfork). The general interpretation is that if fork is called from a signal handler, all registered signal handlers must only call async-signal-safe functions. Furthermore, the consensus interpretation is that after a fork from a signal handler, the new subprocess essentially remains in a signal handler context and must call async-signal-safe functions only.

Future versions of POSIX may drop the requirement for fork to be async-signal-safe, so it is recommended to adjust applications not to call fork from signal handlers. In particular, applications should use system crash handlers such as abrt instead of installing signal handlers which use fork as part of an attempt to write a coredump. An out-of-process crash handler preserves more process information (such as register and stack contents at the time of the crash) compared to an in-process crash handler because the crash handler itself overwrites information.

Historically, there have been other reasons why the fork function can deadlock and hang indefinitely. These issues may be addressed as part of the regular maintenance of the glibc package in Red Hat Enterprise Linux.

Comments