fatal-signal.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /* Emergency actions in case of a fatal signal.
  2. Copyright (C) 2003-2004, 2006-2020 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 <https://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 "glthread/lock.h"
  22. #include "thread-optim.h"
  23. #include "sig-handler.h"
  24. #include "xalloc.h"
  25. #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
  26. /* ========================================================================= */
  27. /* The list of fatal signals.
  28. These are those signals whose default action is to terminate the process
  29. without a core dump, except
  30. SIGKILL - because it cannot be caught,
  31. SIGALRM SIGUSR1 SIGUSR2 SIGPOLL SIGIO SIGLOST - because applications
  32. often use them for their own purpose,
  33. SIGPROF SIGVTALRM - because they are used for profiling,
  34. SIGSTKFLT - because it is more similar to SIGFPE, SIGSEGV, SIGBUS,
  35. SIGSYS - because it is more similar to SIGABRT, SIGSEGV,
  36. SIGPWR - because it of too special use,
  37. SIGRTMIN...SIGRTMAX - because they are reserved for application use.
  38. plus
  39. SIGXCPU, SIGXFSZ - because they are quite similar to SIGTERM. */
  40. static int fatal_signals[] =
  41. {
  42. /* ISO C 99 signals. */
  43. #ifdef SIGINT
  44. SIGINT,
  45. #endif
  46. #ifdef SIGTERM
  47. SIGTERM,
  48. #endif
  49. /* POSIX:2001 signals. */
  50. #ifdef SIGHUP
  51. SIGHUP,
  52. #endif
  53. #ifdef SIGPIPE
  54. SIGPIPE,
  55. #endif
  56. /* BSD signals. */
  57. #ifdef SIGXCPU
  58. SIGXCPU,
  59. #endif
  60. #ifdef SIGXFSZ
  61. SIGXFSZ,
  62. #endif
  63. /* Native Windows signals. */
  64. #ifdef SIGBREAK
  65. SIGBREAK,
  66. #endif
  67. 0
  68. };
  69. #define num_fatal_signals (SIZEOF (fatal_signals) - 1)
  70. /* Eliminate signals whose signal handler is SIG_IGN. */
  71. static void
  72. init_fatal_signals (void)
  73. {
  74. /* This function is multithread-safe even without synchronization, because
  75. if two threads execute it simultaneously, the fatal_signals[] array will
  76. not change any more after the first of the threads has completed this
  77. function. */
  78. static bool fatal_signals_initialized = false;
  79. if (!fatal_signals_initialized)
  80. {
  81. size_t i;
  82. for (i = 0; i < num_fatal_signals; i++)
  83. {
  84. struct sigaction action;
  85. if (sigaction (fatal_signals[i], NULL, &action) >= 0
  86. && get_handler (&action) == SIG_IGN)
  87. fatal_signals[i] = -1;
  88. }
  89. fatal_signals_initialized = true;
  90. }
  91. }
  92. /* ========================================================================= */
  93. typedef _GL_ASYNC_SAFE void (*action_t) (int sig);
  94. /* Type of an entry in the actions array.
  95. The 'action' field is accessed from within the fatal_signal_handler(),
  96. therefore we mark it as 'volatile'. */
  97. typedef struct
  98. {
  99. volatile action_t action;
  100. }
  101. actions_entry_t;
  102. /* The registered cleanup actions. */
  103. static actions_entry_t static_actions[32];
  104. static actions_entry_t * volatile actions = static_actions;
  105. static sig_atomic_t volatile actions_count = 0;
  106. static size_t actions_allocated = SIZEOF (static_actions);
  107. /* The saved signal handlers.
  108. Size 32 would not be sufficient: On HP-UX, SIGXCPU = 33, SIGXFSZ = 34. */
  109. static struct sigaction saved_sigactions[64];
  110. /* Uninstall the handlers. */
  111. static _GL_ASYNC_SAFE void
  112. uninstall_handlers (void)
  113. {
  114. size_t i;
  115. for (i = 0; i < num_fatal_signals; i++)
  116. if (fatal_signals[i] >= 0)
  117. {
  118. int sig = fatal_signals[i];
  119. if (saved_sigactions[sig].sa_handler == SIG_IGN)
  120. saved_sigactions[sig].sa_handler = SIG_DFL;
  121. sigaction (sig, &saved_sigactions[sig], NULL);
  122. }
  123. }
  124. /* The signal handler. It gets called asynchronously. */
  125. static _GL_ASYNC_SAFE void
  126. fatal_signal_handler (int sig)
  127. {
  128. for (;;)
  129. {
  130. /* Get the last registered cleanup action, in a reentrant way. */
  131. action_t action;
  132. size_t n = actions_count;
  133. if (n == 0)
  134. break;
  135. n--;
  136. actions_count = n;
  137. action = actions[n].action;
  138. /* Execute the action. */
  139. action (sig);
  140. }
  141. /* Now execute the signal's default action.
  142. If the signal being delivered was blocked, the re-raised signal would be
  143. delivered when this handler returns. But the way we install this handler,
  144. no signal is blocked, and the re-raised signal is delivered already
  145. during raise(). */
  146. uninstall_handlers ();
  147. raise (sig);
  148. }
  149. /* Install the handlers. */
  150. static void
  151. install_handlers (void)
  152. {
  153. size_t i;
  154. struct sigaction action;
  155. action.sa_handler = &fatal_signal_handler;
  156. /* If we get a fatal signal while executing fatal_signal_handler, enter
  157. fatal_signal_handler recursively, since it is reentrant. Hence no
  158. SA_RESETHAND. */
  159. action.sa_flags = SA_NODEFER;
  160. sigemptyset (&action.sa_mask);
  161. for (i = 0; i < num_fatal_signals; i++)
  162. if (fatal_signals[i] >= 0)
  163. {
  164. int sig = fatal_signals[i];
  165. if (!(sig < sizeof (saved_sigactions) / sizeof (saved_sigactions[0])))
  166. abort ();
  167. sigaction (sig, &action, &saved_sigactions[sig]);
  168. }
  169. }
  170. /* Lock that makes at_fatal_signal multi-thread safe. */
  171. gl_lock_define_initialized (static, at_fatal_signal_lock)
  172. /* Register a cleanup function to be executed when a catchable fatal signal
  173. occurs. */
  174. void
  175. at_fatal_signal (action_t action)
  176. {
  177. bool mt = gl_multithreaded ();
  178. if (mt) gl_lock_lock (at_fatal_signal_lock);
  179. static bool cleanup_initialized = false;
  180. if (!cleanup_initialized)
  181. {
  182. init_fatal_signals ();
  183. install_handlers ();
  184. cleanup_initialized = true;
  185. }
  186. if (actions_count == actions_allocated)
  187. {
  188. /* Extend the actions array. Note that we cannot use xrealloc(),
  189. because then the cleanup() function could access an already
  190. deallocated array. */
  191. actions_entry_t *old_actions = actions;
  192. size_t old_actions_allocated = actions_allocated;
  193. size_t new_actions_allocated = 2 * actions_allocated;
  194. actions_entry_t *new_actions =
  195. XNMALLOC (new_actions_allocated, actions_entry_t);
  196. size_t k;
  197. /* Don't use memcpy() here, because memcpy takes non-volatile arguments
  198. and is therefore not guaranteed to complete all memory stores before
  199. the next statement. */
  200. for (k = 0; k < old_actions_allocated; k++)
  201. new_actions[k] = old_actions[k];
  202. actions = new_actions;
  203. actions_allocated = new_actions_allocated;
  204. /* Now we can free the old actions array. */
  205. /* No, we can't do that. If fatal_signal_handler is running in a
  206. different thread and has already fetched the actions pointer (getting
  207. old_actions) but not yet accessed its n-th element, that thread may
  208. crash when accessing an element of the already freed old_actions
  209. array. */
  210. #if 0
  211. if (old_actions != static_actions)
  212. free (old_actions);
  213. #endif
  214. }
  215. /* The two uses of 'volatile' in the types above (and ISO C 99 section
  216. 5.1.2.3.(5)) ensure that we increment the actions_count only after
  217. the new action has been written to the memory location
  218. actions[actions_count]. */
  219. actions[actions_count].action = action;
  220. actions_count++;
  221. if (mt) gl_lock_unlock (at_fatal_signal_lock);
  222. }
  223. /* ========================================================================= */
  224. static sigset_t fatal_signal_set;
  225. static void
  226. do_init_fatal_signal_set (void)
  227. {
  228. size_t i;
  229. init_fatal_signals ();
  230. sigemptyset (&fatal_signal_set);
  231. for (i = 0; i < num_fatal_signals; i++)
  232. if (fatal_signals[i] >= 0)
  233. sigaddset (&fatal_signal_set, fatal_signals[i]);
  234. }
  235. /* Ensure that do_init_fatal_signal_set is called once only. */
  236. gl_once_define(static, fatal_signal_set_once)
  237. static void
  238. init_fatal_signal_set (void)
  239. {
  240. gl_once (fatal_signal_set_once, do_init_fatal_signal_set);
  241. }
  242. /* Lock and counter that allow block_fatal_signals/unblock_fatal_signals pairs
  243. to occur in different threads and even overlap in time. */
  244. gl_lock_define_initialized (static, fatal_signals_block_lock)
  245. static unsigned int fatal_signals_block_counter = 0;
  246. /* Temporarily delay the catchable fatal signals. */
  247. void
  248. block_fatal_signals (void)
  249. {
  250. bool mt = gl_multithreaded ();
  251. if (mt) gl_lock_lock (fatal_signals_block_lock);
  252. if (fatal_signals_block_counter++ == 0)
  253. {
  254. init_fatal_signal_set ();
  255. sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
  256. }
  257. if (mt) gl_lock_unlock (fatal_signals_block_lock);
  258. }
  259. /* Stop delaying the catchable fatal signals. */
  260. void
  261. unblock_fatal_signals (void)
  262. {
  263. bool mt = gl_multithreaded ();
  264. if (mt) gl_lock_lock (fatal_signals_block_lock);
  265. if (fatal_signals_block_counter == 0)
  266. /* There are more calls to unblock_fatal_signals() than to
  267. block_fatal_signals(). */
  268. abort ();
  269. if (--fatal_signals_block_counter == 0)
  270. {
  271. init_fatal_signal_set ();
  272. sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
  273. }
  274. if (mt) gl_lock_unlock (fatal_signals_block_lock);
  275. }
  276. unsigned int
  277. get_fatal_signals (int signals[64])
  278. {
  279. init_fatal_signal_set ();
  280. {
  281. int *p = signals;
  282. size_t i;
  283. for (i = 0; i < num_fatal_signals; i++)
  284. if (fatal_signals[i] >= 0)
  285. *p++ = fatal_signals[i];
  286. return p - signals;
  287. }
  288. }
  289. const sigset_t *
  290. get_fatal_signal_set (void)
  291. {
  292. init_fatal_signal_set ();
  293. return &fatal_signal_set;
  294. }