1 /* POSIX compatible signal blocking. 2 Copyright (C) 2008-2021 Free Software Foundation, Inc. 3 Written by Eric Blake <ebb9@byu.net>, 2008. 4 5 This file is free software: you can redistribute it and/or modify 6 it under the terms of the GNU Lesser General Public License as 7 published by the Free Software Foundation; either version 2.1 of the 8 License, or (at your option) any later version. 9 10 This file is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public License 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 17 18 #include <config.h> 19 20 /* Specification. */ 21 #include <signal.h> 22 23 #include <errno.h> 24 #include <stdint.h> 25 #include <stdlib.h> 26 27 /* This implementation of sigaction is tailored to native Windows behavior: 28 signal() has SysV semantics (ie. the handler is uninstalled before 29 it is invoked). This is an inherent data race if an asynchronous 30 signal is sent twice in a row before we can reinstall our handler, 31 but there's nothing we can do about it. Meanwhile, sigprocmask() 32 is not present, and while we can use the gnulib replacement to 33 provide critical sections, it too suffers from potential data races 34 in the face of an ill-timed asynchronous signal. And we compound 35 the situation by reading static storage in a signal handler, which 36 POSIX warns is not generically async-signal-safe. Oh well. 37 38 Additionally: 39 - We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD 40 is not defined. 41 - We don't implement SA_ONSTACK, because sigaltstack() is not present. 42 - We ignore SA_RESTART, because blocking native Windows API calls are 43 not interrupted anyway when an asynchronous signal occurs, and the 44 MSVCRT runtime never sets errno to EINTR. 45 - We don't implement SA_SIGINFO because it is impossible to do so 46 portably. 47 48 POSIX states that an application should not mix signal() and 49 sigaction(). We support the use of signal() within the gnulib 50 sigprocmask() substitute, but all other application code linked 51 with this module should stick with only sigaction(). */ 52 53 /* Check some of our assumptions. */ 54 #if defined SIGCHLD || defined HAVE_SIGALTSTACK || defined HAVE_SIGINTERRUPT 55 # error "Revisit the assumptions made in the sigaction module" 56 #endif 57 58 /* Out-of-range substitutes make a good fallback for uncatchable 59 signals. */ 60 #ifndef SIGKILL 61 # define SIGKILL (-1) 62 #endif 63 #ifndef SIGSTOP 64 # define SIGSTOP (-1) 65 #endif 66 67 /* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias 68 for the signal SIGABRT. Only one signal handler is stored for both 69 SIGABRT and SIGABRT_COMPAT. SIGABRT_COMPAT is not a signal of its own. */ 70 #if defined _WIN32 && ! defined __CYGWIN__ 71 # undef SIGABRT_COMPAT 72 # define SIGABRT_COMPAT 6 73 #endif 74 75 /* A signal handler. */ 76 typedef void (*handler_t) (int signal); 77 78 /* Set of current actions. If sa_handler for an entry is NULL, then 79 that signal is not currently handled by the sigaction handler. */ 80 static struct sigaction volatile action_array[NSIG] /* = 0 */; 81 82 /* Signal handler that is installed for signals. */ 83 static void 84 sigaction_handler (int sig) /* */ 85 { 86 handler_t handler; 87 sigset_t mask; 88 sigset_t oldmask; 89 int saved_errno = errno; 90 if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler) 91 { 92 /* Unexpected situation; be careful to avoid recursive abort. */ 93 if (sig == SIGABRT) 94 signal (SIGABRT, SIG_DFL); 95 abort (); 96 } 97 98 /* Reinstall the signal handler when required; otherwise update the 99 bookkeeping so that the user's handler may call sigaction and get 100 accurate results. We know the signal isn't currently blocked, or 101 we wouldn't be in its handler, therefore we know that we are not 102 interrupting a sigaction() call. There is a race where any 103 asynchronous instance of the same signal occurring before we 104 reinstall the handler will trigger the default handler; oh 105 well. */ 106 handler = action_array[sig].sa_handler; 107 if ((action_array[sig].sa_flags & SA_RESETHAND) == 0) 108 signal (sig, sigaction_handler); 109 else 110 action_array[sig].sa_handler = NULL; 111 112 /* Block appropriate signals. */ 113 mask = action_array[sig].sa_mask; 114 if ((action_array[sig].sa_flags & SA_NODEFER) == 0) 115 sigaddset (&mask, sig); 116 sigprocmask (SIG_BLOCK, &mask, &oldmask); 117 118 /* Invoke the user's handler, then restore prior mask. */ 119 errno = saved_errno; 120 handler (sig); 121 saved_errno = errno; 122 sigprocmask (SIG_SETMASK, &oldmask, NULL); 123 errno = saved_errno; 124 } 125 126 /* Change and/or query the action that will be taken on delivery of 127 signal SIG. If not NULL, ACT describes the new behavior. If not 128 NULL, OACT is set to the prior behavior. Return 0 on success, or 129 set errno and return -1 on failure. */ 130 int 131 sigaction (int sig, const struct sigaction *restrict act, /* */ 132 struct sigaction *restrict oact) 133 { 134 sigset_t mask; 135 sigset_t oldmask; 136 int saved_errno; 137 138 if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP 139 || (act && act->sa_handler == SIG_ERR)) 140 { 141 errno = EINVAL; 142 return -1; 143 } 144 145 #ifdef SIGABRT_COMPAT 146 if (sig == SIGABRT_COMPAT) 147 sig = SIGABRT; 148 #endif 149 150 /* POSIX requires sigaction() to be async-signal-safe. In other 151 words, if an asynchronous signal can occur while we are anywhere 152 inside this function, the user's handler could then call 153 sigaction() recursively and expect consistent results. We meet 154 this rule by using sigprocmask to block all signals before 155 modifying any data structure that could be read from a signal 156 handler; this works since we know that the gnulib sigprocmask 157 replacement does not try to use sigaction() from its handler. */ 158 if (!act && !oact) 159 return 0; 160 sigfillset (&mask); 161 sigprocmask (SIG_BLOCK, &mask, &oldmask); 162 if (oact) 163 { 164 if (action_array[sig].sa_handler) 165 *oact = action_array[sig]; 166 else 167 { 168 /* Safe to change the handler at will here, since all 169 signals are currently blocked. */ 170 oact->sa_handler = signal (sig, SIG_DFL); 171 if (oact->sa_handler == SIG_ERR) 172 goto failure; 173 signal (sig, oact->sa_handler); 174 oact->sa_flags = SA_RESETHAND | SA_NODEFER; 175 sigemptyset (&oact->sa_mask); 176 } 177 } 178 179 if (act) 180 { 181 /* Safe to install the handler before updating action_array, 182 since all signals are currently blocked. */ 183 if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN) 184 { 185 if (signal (sig, act->sa_handler) == SIG_ERR) 186 goto failure; 187 action_array[sig].sa_handler = NULL; 188 } 189 else 190 { 191 if (signal (sig, sigaction_handler) == SIG_ERR) 192 goto failure; 193 action_array[sig] = *act; 194 } 195 } 196 sigprocmask (SIG_SETMASK, &oldmask, NULL); 197 return 0; 198 199 failure: 200 saved_errno = errno; 201 sigprocmask (SIG_SETMASK, &oldmask, NULL); 202 errno = saved_errno; 203 return -1; 204 }