+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.
/* 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
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;
void *p;
} alternate_signal_stack;
-static void
-null_action (int signo __attribute__ ((unused)))
+static _GL_ASYNC_SAFE void
+null_action (int signo _GL_UNUSED)
{
}
/* 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
{
/* 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
{
}
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");
/* 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
# endif
int
-c_stack_action (void (*action) (int))
+c_stack_action (_GL_ASYNC_SAFE void (*action) (int))
{
int r;
stack_t st;
&& 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;
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));
/* The signal handler. It gets called asynchronously. */
-static void
+static _GL_ASYNC_SAFE void
cleanup_action (int sig _GL_UNUSED)
{
size_t i;
/* ========================================================================= */
-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(),
/* Uninstall the handlers. */
-static void
+static _GL_ASYNC_SAFE void
uninstall_handlers (void)
{
size_t i;
/* The signal handler. It gets called asynchronously. */
-static void
+static _GL_ASYNC_SAFE void
fatal_signal_handler (int sig)
{
for (;;)
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
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
/* Handle SIGCONT. */
-static void
+static _GL_ASYNC_SAFE void
sighandler (int sig)
{
suspended = 1;
#endif
/* The cleanup action. It gets called asynchronously. */
-static void
+static _GL_ASYNC_SAFE void
cleanup_slaves (void)
{
for (;;)
/* 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 ();
-# 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,
#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