]> Savannah Git Hosting - gnulib.git/commitdiff
Help making signal handlers more reliable.
authorBruno Haible <bruno@clisp.org>
Tue, 19 Mar 2019 22:32:42 +0000 (23:32 +0100)
committerBruno Haible <bruno@clisp.org>
Tue, 19 Mar 2019 22:32:42 +0000 (23:32 +0100)
* m4/gnulib-common.m4 (gl_COMMON_BODY): Emit definition of
_GL_ASYNC_SAFE into config.h.
* lib/nanosleep.c (sighandler): Mark as _GL_ASYNC_SAFE.
* lib/fatal-signal.h (at_fatal_signal): Add _GL_ASYNC_SAFE marker to
argument.
* lib/fatal-signal.c (action_t, uninstall_handlers,
fatal_signal_handler): Mark as _GL_ASYNC_SAFE.
* lib/clean-temp.c (cleanup_action): Mark as _GL_ASYNC_SAFE.
* lib/wait-process.c (cleanup_slaves, cleanup_slaves_action): Mark as
_GL_ASYNC_SAFE.
* lib/c-stack.h (c_stack_action): Add _GL_ASYNC_SAFE marker to argument.
* lib/c-stack.c: Add _GL_ASYNC_SAFE markers.

ChangeLog
lib/c-stack.c
lib/c-stack.h
lib/clean-temp.c
lib/fatal-signal.c
lib/fatal-signal.h
lib/nanosleep.c
lib/wait-process.c
m4/gnulib-common.m4

index 02bed463abf189ceefcfe41f813e3f9dfcfa2647..9313fdc4884de61587da00d71789198231b591fd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2019-03-19  Bruno Haible  <bruno@clisp.org>
+
+       Help making signal handlers more reliable.
+       * m4/gnulib-common.m4 (gl_COMMON_BODY): Emit definition of
+       _GL_ASYNC_SAFE into config.h.
+       * lib/nanosleep.c (sighandler): Mark as _GL_ASYNC_SAFE.
+       * lib/fatal-signal.h (at_fatal_signal): Add _GL_ASYNC_SAFE marker to
+       argument.
+       * lib/fatal-signal.c (action_t, uninstall_handlers,
+       fatal_signal_handler): Mark as _GL_ASYNC_SAFE.
+       * lib/clean-temp.c (cleanup_action): Mark as _GL_ASYNC_SAFE.
+       * lib/wait-process.c (cleanup_slaves, cleanup_slaves_action): Mark as
+       _GL_ASYNC_SAFE.
+       * lib/c-stack.h (c_stack_action): Add _GL_ASYNC_SAFE marker to argument.
+       * lib/c-stack.c: Add _GL_ASYNC_SAFE markers.
+
 2019-03-18  Bruno Haible  <bruno@clisp.org>
 
        _Noreturn: clang and MSVC do support [[noreturn]] in C++11 mode.
index c62726b45da83f117268db16fa687a119bd0402e..929bb3a3156e93df6f8f19d07037f592323b1fe9 100644 (file)
@@ -91,7 +91,7 @@ typedef struct sigaltstack stack_t;
 
 /* The user-specified action to take when a SEGV-related program error
    or stack overflow occurs.  */
-static void (* volatile segv_action) (int);
+static _GL_ASYNC_SAFE void (* volatile segv_action) (int);
 
 /* Translated messages for program errors and stack overflow.  Do not
    translate them in the signal handler, since gettext is not
@@ -107,7 +107,7 @@ static char const * volatile stack_overflow_message;
    appears to have been a stack overflow, or with a core dump
    otherwise.  This function is async-signal-safe.  */
 
-static _Noreturn void
+static _GL_ASYNC_SAFE _Noreturn void
 die (int signo)
 {
   char const *message;
@@ -146,8 +146,8 @@ static union
   void *p;
 } alternate_signal_stack;
 
-static void
-null_action (int signo __attribute__ ((unused)))
+static _GL_ASYNC_SAFE void
+null_action (int signo _GL_UNUSED)
 {
 }
 
@@ -164,8 +164,8 @@ static volatile int segv_handler_missing;
 /* Handle a segmentation violation and exit if it cannot be stack
    overflow.  This function is async-signal-safe.  */
 
-static int segv_handler (void *address __attribute__ ((unused)),
-                         int serious)
+static _GL_ASYNC_SAFE int
+segv_handler (void *address _GL_UNUSED, int serious)
 {
 # if DEBUG
   {
@@ -185,9 +185,8 @@ static int segv_handler (void *address __attribute__ ((unused)),
 /* Handle a segmentation violation that is likely to be a stack
    overflow and exit.  This function is async-signal-safe.  */
 
-static _Noreturn void
-overflow_handler (int emergency,
-                  stackoverflow_context_t context __attribute__ ((unused)))
+static _GL_ASYNC_SAFE _Noreturn void
+overflow_handler (int emergency, stackoverflow_context_t context _GL_UNUSED)
 {
 # if DEBUG
   {
@@ -202,7 +201,7 @@ overflow_handler (int emergency,
 }
 
 int
-c_stack_action (void (*action) (int))
+c_stack_action (_GL_ASYNC_SAFE void (*action) (int))
 {
   segv_action = action ? action : null_action;
   program_error_message = _("program error");
@@ -229,9 +228,8 @@ c_stack_action (void (*action) (int))
 /* Handle a segmentation violation and exit.  This function is
    async-signal-safe.  */
 
-static _Noreturn void
-segv_handler (int signo, siginfo_t *info,
-              void *context __attribute__ ((unused)))
+static _GL_ASYNC_SAFE _Noreturn void
+segv_handler (int signo, siginfo_t *info, void *context _GL_UNUSED)
 {
   /* Clear SIGNO if it seems to have been a stack overflow.  */
 #  if ! HAVE_XSI_STACK_OVERFLOW_HEURISTIC
@@ -278,7 +276,7 @@ segv_handler (int signo, siginfo_t *info,
 # endif
 
 int
-c_stack_action (void (*action) (int))
+c_stack_action (_GL_ASYNC_SAFE void (*action) (int))
 {
   int r;
   stack_t st;
@@ -325,7 +323,7 @@ c_stack_action (void (*action) (int))
              && HAVE_STACK_OVERFLOW_HANDLING) || HAVE_LIBSIGSEGV) */
 
 int
-c_stack_action (void (*action) (int)  __attribute__ ((unused)))
+c_stack_action (_GL_ASYNC_SAFE void (*action) (int)  _GL_UNUSED)
 {
   errno = ENOTSUP;
   return -1;
index fcfe66f05efffdefc7be813f8739dc03a1b0d3ec..36dd4ec3ec55e3794354fcb9ce324e4cce226cdc 100644 (file)
@@ -41,4 +41,4 @@
    This function may install a handler for the SIGSEGV signal or for the SIGBUS
    signal or exercise other system dependent exception handling APIs.  */
 
-extern int c_stack_action (void (* /*action*/) (int));
+extern int c_stack_action (_GL_ASYNC_SAFE void (* /*action*/) (int));
index 0cb4a7e406c0b30944860f192b4b7bda861d6ac9..d333f56c090e65e21f817c62bf6bc8528e3c35bd 100644 (file)
@@ -180,7 +180,7 @@ string_hash (const void *x)
 
 
 /* The signal handler.  It gets called asynchronously.  */
-static void
+static _GL_ASYNC_SAFE void
 cleanup_action (int sig _GL_UNUSED)
 {
   size_t i;
index 7f12f12c164a94b12f7b0aad0cd20e56915f76d2..c9153f1e779763eb987c16bcf0a1172065190309 100644 (file)
@@ -107,7 +107,7 @@ init_fatal_signals (void)
 /* ========================================================================= */
 
 
-typedef void (*action_t) (int sig);
+typedef _GL_ASYNC_SAFE void (*action_t) (int sig);
 
 /* Type of an entry in the actions array.
    The 'action' field is accessed from within the fatal_signal_handler(),
@@ -131,7 +131,7 @@ static struct sigaction saved_sigactions[64];
 
 
 /* Uninstall the handlers.  */
-static void
+static _GL_ASYNC_SAFE void
 uninstall_handlers (void)
 {
   size_t i;
@@ -148,7 +148,7 @@ uninstall_handlers (void)
 
 
 /* The signal handler.  It gets called asynchronously.  */
-static void
+static _GL_ASYNC_SAFE void
 fatal_signal_handler (int sig)
 {
   for (;;)
index c7d8e35d62cf8263cc57ba5c70a6c259e3d48c85..8ac57cf55201168e22caa5f8de047e41a3b43c5f 100644 (file)
@@ -36,7 +36,8 @@ extern "C" {
    occurs.
 
    Restrictions for the cleanup function:
-     - The cleanup function can do all kinds of system calls.
+     - The cleanup function can do all kinds of system calls.  It may also
+       modify (clobber) errno.
      - It can also access application dependent memory locations and data
        structures provided they are in a consistent state. One way to ensure
        this is through block_fatal_signals()/unblock_fatal_signals(), see
@@ -51,7 +52,7 @@ extern "C" {
    The cleanup function is executed asynchronously.  It is unspecified
    whether during its execution the catchable fatal signals are blocked
    or not.  */
-extern void at_fatal_signal (void (*function) (int sig));
+extern void at_fatal_signal (_GL_ASYNC_SAFE void (*function) (int sig));
 
 
 /* Sometimes it is necessary to block the usually fatal signals while the
index 6f6cc89ea74d79d3b4ee53d08420151a16fda020..3150ff9b9de1e2578387cd04cbf4db0556bb367a 100644 (file)
@@ -194,7 +194,7 @@ static sig_atomic_t volatile suspended;
 
 /* Handle SIGCONT. */
 
-static void
+static _GL_ASYNC_SAFE void
 sighandler (int sig)
 {
   suspended = 1;
index b51e2447a09a2266f37cc07d996a9b44d2427064..7c6993317ef719515f69d2230cc009482b81a970 100644 (file)
@@ -80,7 +80,7 @@ static size_t slaves_allocated = SIZEOF (static_slaves);
 #endif
 
 /* The cleanup action.  It gets called asynchronously.  */
-static void
+static _GL_ASYNC_SAFE void
 cleanup_slaves (void)
 {
   for (;;)
@@ -104,7 +104,7 @@ cleanup_slaves (void)
 
 /* The cleanup action, taking a signal argument.
    It gets called asynchronously.  */
-static void
+static _GL_ASYNC_SAFE void
 cleanup_slaves_action (int sig _GL_UNUSED)
 {
   cleanup_slaves ();
index 20666a552a03015bdf4299169c34ea297f0b3579..8ad963e3557311a5fba6319dd1404994a9769638 100644 (file)
@@ -1,4 +1,4 @@
-# gnulib-common.m4 serial 43
+# gnulib-common.m4 serial 44
 dnl Copyright (C) 2007-2019 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -86,6 +86,33 @@ AC_DEFUN([gl_COMMON_BODY], [
 #else
 # define _GL_ATTRIBUTE_MALLOC /* empty */
 #endif
+])
+  AH_VERBATIM([async_safe],
+[/* The _GL_ASYNC_SAFE marker should be attached to functions that are
+   signal handlers (for signals other than SIGABRT, SIGPIPE) or can be
+   invoked from such signal handlers.  Such functions have some restrictions:
+     * All functions that it calls should be marked _GL_ASYNC_SAFE as well,
+       or should be listed as async-signal-safe in POSIX
+       <http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04>
+       section 2.4.3.  Note that malloc(), sprintf(), and fwrite(), in
+       particular, are NOT async-signal-safe.
+     * All memory locations (variables and struct fields) that these functions
+       access must be marked 'volatile'.  This holds for both read and write
+       accesses.  Otherwise the compiler might optimize away stores to and
+       reads from such locations that occur in the program, depending on its
+       data flow analysis.  For example, when the program contains a loop
+       that is intended to inspect a variable set from within a signal handler
+           while (!signal_occurred)
+             ;
+       the compiler is allowed to transform this into an endless loop if the
+       variable 'signal_occurred' is not declared 'volatile'.
+   Additionally, recall that:
+     * A signal handler should not modify errno (except if it is a handler
+       for a fatal signal and ends by raising the same signal again, thus
+       provoking the termination of the process).  If it invokes a function
+       that may clobber errno, it needs to save and restore the value of
+       errno.  */
+#define _GL_ASYNC_SAFE
 ])
   dnl Preparation for running test programs:
   dnl Tell glibc to write diagnostics from -D_FORTIFY_SOURCE=2 to stderr, not