fatal-signal.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /* Emergency actions in case of a fatal signal.
  2. Copyright (C) 2003-2004, 2006-2013 Free Software Foundation, Inc.
  3. Written by Bruno Haible <bruno@clisp.org>, 2003.
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. #include <config.h>
  15. /* Specification. */
  16. #include "fatal-signal.h"
  17. #include <stdbool.h>
  18. #include <stdlib.h>
  19. #include <signal.h>
  20. #include <unistd.h>
  21. #include "sig-handler.h"
  22. #include "xalloc.h"
  23. #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
  24. /* ========================================================================= */
  25. /* The list of fatal signals.
  26. These are those signals whose default action is to terminate the process
  27. without a core dump, except
  28. SIGKILL - because it cannot be caught,
  29. SIGALRM SIGUSR1 SIGUSR2 SIGPOLL SIGIO SIGLOST - because applications
  30. often use them for their own purpose,
  31. SIGPROF SIGVTALRM - because they are used for profiling,
  32. SIGSTKFLT - because it is more similar to SIGFPE, SIGSEGV, SIGBUS,
  33. SIGSYS - because it is more similar to SIGABRT, SIGSEGV,
  34. SIGPWR - because it of too special use,
  35. SIGRTMIN...SIGRTMAX - because they are reserved for application use.
  36. plus
  37. SIGXCPU, SIGXFSZ - because they are quite similar to SIGTERM. */
  38. static int fatal_signals[] =
  39. {
  40. /* ISO C 99 signals. */
  41. #ifdef SIGINT
  42. SIGINT,
  43. #endif
  44. #ifdef SIGTERM
  45. SIGTERM,
  46. #endif
  47. /* POSIX:2001 signals. */
  48. #ifdef SIGHUP
  49. SIGHUP,
  50. #endif
  51. #ifdef SIGPIPE
  52. SIGPIPE,
  53. #endif
  54. /* BSD signals. */
  55. #ifdef SIGXCPU
  56. SIGXCPU,
  57. #endif
  58. #ifdef SIGXFSZ
  59. SIGXFSZ,
  60. #endif
  61. /* Native Windows signals. */
  62. #ifdef SIGBREAK
  63. SIGBREAK,
  64. #endif
  65. 0
  66. };
  67. #define num_fatal_signals (SIZEOF (fatal_signals) - 1)
  68. /* Eliminate signals whose signal handler is SIG_IGN. */
  69. static void
  70. init_fatal_signals (void)
  71. {
  72. static bool fatal_signals_initialized = false;
  73. if (!fatal_signals_initialized)
  74. {
  75. size_t i;
  76. for (i = 0; i < num_fatal_signals; i++)
  77. {
  78. struct sigaction action;
  79. if (sigaction (fatal_signals[i], NULL, &action) >= 0
  80. && get_handler (&action) == SIG_IGN)
  81. fatal_signals[i] = -1;
  82. }
  83. fatal_signals_initialized = true;
  84. }
  85. }
  86. /* ========================================================================= */
  87. typedef void (*action_t) (void);
  88. /* Type of an entry in the actions array.
  89. The 'action' field is accessed from within the fatal_signal_handler(),
  90. therefore we mark it as 'volatile'. */
  91. typedef struct
  92. {
  93. volatile action_t action;
  94. }
  95. actions_entry_t;
  96. /* The registered cleanup actions. */
  97. static actions_entry_t static_actions[32];
  98. static actions_entry_t * volatile actions = static_actions;
  99. static sig_atomic_t volatile actions_count = 0;
  100. static size_t actions_allocated = SIZEOF (static_actions);
  101. /* The saved signal handlers.
  102. Size 32 would not be sufficient: On HP-UX, SIGXCPU = 33, SIGXFSZ = 34. */
  103. static struct sigaction saved_sigactions[64];
  104. /* Uninstall the handlers. */
  105. static void
  106. uninstall_handlers (void)
  107. {
  108. size_t i;
  109. for (i = 0; i < num_fatal_signals; i++)
  110. if (fatal_signals[i] >= 0)
  111. {
  112. int sig = fatal_signals[i];
  113. if (saved_sigactions[sig].sa_handler == SIG_IGN)
  114. saved_sigactions[sig].sa_handler = SIG_DFL;
  115. sigaction (sig, &saved_sigactions[sig], NULL);
  116. }
  117. }
  118. /* The signal handler. It gets called asynchronously. */
  119. static void
  120. fatal_signal_handler (int sig)
  121. {
  122. for (;;)
  123. {
  124. /* Get the last registered cleanup action, in a reentrant way. */
  125. action_t action;
  126. size_t n = actions_count;
  127. if (n == 0)
  128. break;
  129. n--;
  130. actions_count = n;
  131. action = actions[n].action;
  132. /* Execute the action. */
  133. action ();
  134. }
  135. /* Now execute the signal's default action.
  136. If the signal being delivered was blocked, the re-raised signal would be
  137. delivered when this handler returns. But the way we install this handler,
  138. no signal is blocked, and the re-raised signal is delivered already
  139. during raise(). */
  140. uninstall_handlers ();
  141. raise (sig);
  142. }
  143. /* Install the handlers. */
  144. static void
  145. install_handlers (void)
  146. {
  147. size_t i;
  148. struct sigaction action;
  149. action.sa_handler = &fatal_signal_handler;
  150. /* If we get a fatal signal while executing fatal_signal_handler, enter
  151. fatal_signal_handler recursively, since it is reentrant. Hence no
  152. SA_RESETHAND. */
  153. action.sa_flags = SA_NODEFER;
  154. sigemptyset (&action.sa_mask);
  155. for (i = 0; i < num_fatal_signals; i++)
  156. if (fatal_signals[i] >= 0)
  157. {
  158. int sig = fatal_signals[i];
  159. if (!(sig < sizeof (saved_sigactions) / sizeof (saved_sigactions[0])))
  160. abort ();
  161. sigaction (sig, &action, &saved_sigactions[sig]);
  162. }
  163. }
  164. /* Register a cleanup function to be executed when a catchable fatal signal
  165. occurs. */
  166. void
  167. at_fatal_signal (action_t action)
  168. {
  169. static bool cleanup_initialized = false;
  170. if (!cleanup_initialized)
  171. {
  172. init_fatal_signals ();
  173. install_handlers ();
  174. cleanup_initialized = true;
  175. }
  176. if (actions_count == actions_allocated)
  177. {
  178. /* Extend the actions array. Note that we cannot use xrealloc(),
  179. because then the cleanup() function could access an already
  180. deallocated array. */
  181. actions_entry_t *old_actions = actions;
  182. size_t old_actions_allocated = actions_allocated;
  183. size_t new_actions_allocated = 2 * actions_allocated;
  184. actions_entry_t *new_actions =
  185. XNMALLOC (new_actions_allocated, actions_entry_t);
  186. size_t k;
  187. /* Don't use memcpy() here, because memcpy takes non-volatile arguments
  188. and is therefore not guaranteed to complete all memory stores before
  189. the next statement. */
  190. for (k = 0; k < old_actions_allocated; k++)
  191. new_actions[k] = old_actions[k];
  192. actions = new_actions;
  193. actions_allocated = new_actions_allocated;
  194. /* Now we can free the old actions array. */
  195. if (old_actions != static_actions)
  196. free (old_actions);
  197. }
  198. /* The two uses of 'volatile' in the types above (and ISO C 99 section
  199. 5.1.2.3.(5)) ensure that we increment the actions_count only after
  200. the new action has been written to the memory location
  201. actions[actions_count]. */
  202. actions[actions_count].action = action;
  203. actions_count++;
  204. }
  205. /* ========================================================================= */
  206. static sigset_t fatal_signal_set;
  207. static void
  208. init_fatal_signal_set (void)
  209. {
  210. static bool fatal_signal_set_initialized = false;
  211. if (!fatal_signal_set_initialized)
  212. {
  213. size_t i;
  214. init_fatal_signals ();
  215. sigemptyset (&fatal_signal_set);
  216. for (i = 0; i < num_fatal_signals; i++)
  217. if (fatal_signals[i] >= 0)
  218. sigaddset (&fatal_signal_set, fatal_signals[i]);
  219. fatal_signal_set_initialized = true;
  220. }
  221. }
  222. /* Temporarily delay the catchable fatal signals. */
  223. void
  224. block_fatal_signals (void)
  225. {
  226. init_fatal_signal_set ();
  227. sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
  228. }
  229. /* Stop delaying the catchable fatal signals. */
  230. void
  231. unblock_fatal_signals (void)
  232. {
  233. init_fatal_signal_set ();
  234. sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
  235. }