1 #include "Python.h"
2 #include "pythread.h"
3 #include <signal.h>
4 #include <object.h>
5 #include <frameobject.h>
6 #include <signal.h>
7 #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
8 # include <pthread.h>
9 #endif
10 #ifdef MS_WINDOWS
11 # include <windows.h>
12 #endif
13 #ifdef HAVE_SYS_RESOURCE_H
14 # include <sys/resource.h>
15 #endif
16
17 /* Allocate at maximum 100 MiB of the stack to raise the stack overflow */
18 #define STACK_OVERFLOW_MAX_SIZE (100 * 1024 * 1024)
19
20 #define FAULTHANDLER_LATER
21
22 #ifndef MS_WINDOWS
23 /* register() is useless on Windows, because only SIGSEGV, SIGABRT and
24 SIGILL can be handled by the process, and these signals can only be used
25 with enable(), not using register() */
26 # define FAULTHANDLER_USER
27 #endif
28
29 #define PUTS(fd, str) _Py_write_noraise(fd, str, strlen(str))
30
31 _Py_IDENTIFIER(enable);
32 _Py_IDENTIFIER(fileno);
33 _Py_IDENTIFIER(flush);
34 _Py_IDENTIFIER(stderr);
35
36 #ifdef HAVE_SIGACTION
37 typedef struct sigaction _Py_sighandler_t;
38 #else
39 typedef PyOS_sighandler_t _Py_sighandler_t;
40 #endif
41
42 typedef struct {
43 int signum;
44 int enabled;
45 const char* name;
46 _Py_sighandler_t previous;
47 int all_threads;
48 } fault_handler_t;
49
50 static struct {
51 int enabled;
52 PyObject *file;
53 int fd;
54 int all_threads;
55 PyInterpreterState *interp;
56 #ifdef MS_WINDOWS
57 void *exc_handler;
58 #endif
59 } fatal_error = {0, NULL, -1, 0};
60
61 #ifdef FAULTHANDLER_LATER
62 static struct {
63 PyObject *file;
64 int fd;
65 PY_TIMEOUT_T timeout_us; /* timeout in microseconds */
66 int repeat;
67 PyInterpreterState *interp;
68 int exit;
69 char *header;
70 size_t header_len;
71 /* The main thread always holds this lock. It is only released when
72 faulthandler_thread() is interrupted before this thread exits, or at
73 Python exit. */
74 PyThread_type_lock cancel_event;
75 /* released by child thread when joined */
76 PyThread_type_lock running;
77 } thread;
78 #endif
79
80 #ifdef FAULTHANDLER_USER
81 typedef struct {
82 int enabled;
83 PyObject *file;
84 int fd;
85 int all_threads;
86 int chain;
87 _Py_sighandler_t previous;
88 PyInterpreterState *interp;
89 } user_signal_t;
90
91 static user_signal_t *user_signals;
92
93 /* the following macros come from Python: Modules/signalmodule.c */
94 #ifndef NSIG
95 # if defined(_NSIG)
96 # define NSIG _NSIG /* For BSD/SysV */
97 # elif defined(_SIGMAX)
98 # define NSIG (_SIGMAX + 1) /* For QNX */
99 # elif defined(SIGMAX)
100 # define NSIG (SIGMAX + 1) /* For djgpp */
101 # else
102 # define NSIG 64 /* Use a reasonable default value */
103 # endif
104 #endif
105
106 static void faulthandler_user(int signum);
107 #endif /* FAULTHANDLER_USER */
108
109
110 static fault_handler_t faulthandler_handlers[] = {
111 #ifdef SIGBUS
112 {SIGBUS, 0, "Bus error", },
113 #endif
114 #ifdef SIGILL
115 {SIGILL, 0, "Illegal instruction", },
116 #endif
117 {SIGFPE, 0, "Floating point exception", },
118 {SIGABRT, 0, "Aborted", },
119 /* define SIGSEGV at the end to make it the default choice if searching the
120 handler fails in faulthandler_fatal_error() */
121 {SIGSEGV, 0, "Segmentation fault", }
122 };
123 static const size_t faulthandler_nsignals = \
124 Py_ARRAY_LENGTH(faulthandler_handlers);
125
126 #ifdef HAVE_SIGALTSTACK
127 static stack_t stack;
128 static stack_t old_stack;
129 #endif
130
131
132 /* Get the file descriptor of a file by calling its fileno() method and then
133 call its flush() method.
134
135 If file is NULL or Py_None, use sys.stderr as the new file.
136 If file is an integer, it will be treated as file descriptor.
137
138 On success, return the file descriptor and write the new file into *file_ptr.
139 On error, return -1. */
140
141 static int
faulthandler_get_fileno(PyObject ** file_ptr)142 faulthandler_get_fileno(PyObject **file_ptr)
143 {
144 PyObject *result;
145 long fd_long;
146 int fd;
147 PyObject *file = *file_ptr;
148
149 if (file == NULL || file == Py_None) {
150 file = _PySys_GetObjectId(&PyId_stderr);
151 if (file == NULL) {
152 PyErr_SetString(PyExc_RuntimeError, "unable to get sys.stderr");
153 return -1;
154 }
155 if (file == Py_None) {
156 PyErr_SetString(PyExc_RuntimeError, "sys.stderr is None");
157 return -1;
158 }
159 }
160 else if (PyLong_Check(file)) {
161 fd = _PyLong_AsInt(file);
162 if (fd == -1 && PyErr_Occurred())
163 return -1;
164 if (fd < 0) {
165 PyErr_SetString(PyExc_ValueError,
166 "file is not a valid file descripter");
167 return -1;
168 }
169 *file_ptr = NULL;
170 return fd;
171 }
172
173 result = _PyObject_CallMethodId(file, &PyId_fileno, NULL);
174 if (result == NULL)
175 return -1;
176
177 fd = -1;
178 if (PyLong_Check(result)) {
179 fd_long = PyLong_AsLong(result);
180 if (0 <= fd_long && fd_long < INT_MAX)
181 fd = (int)fd_long;
182 }
183 Py_DECREF(result);
184
185 if (fd == -1) {
186 PyErr_SetString(PyExc_RuntimeError,
187 "file.fileno() is not a valid file descriptor");
188 return -1;
189 }
190
191 result = _PyObject_CallMethodId(file, &PyId_flush, NULL);
192 if (result != NULL)
193 Py_DECREF(result);
194 else {
195 /* ignore flush() error */
196 PyErr_Clear();
197 }
198 *file_ptr = file;
199 return fd;
200 }
201
202 /* Get the state of the current thread: only call this function if the current
203 thread holds the GIL. Raise an exception on error. */
204 static PyThreadState*
get_thread_state(void)205 get_thread_state(void)
206 {
207 PyThreadState *tstate = _PyThreadState_UncheckedGet();
208 if (tstate == NULL) {
209 /* just in case but very unlikely... */
210 PyErr_SetString(PyExc_RuntimeError,
211 "unable to get the current thread state");
212 return NULL;
213 }
214 return tstate;
215 }
216
217 static void
faulthandler_dump_traceback(int fd,int all_threads,PyInterpreterState * interp)218 faulthandler_dump_traceback(int fd, int all_threads,
219 PyInterpreterState *interp)
220 {
221 static volatile int reentrant = 0;
222 PyThreadState *tstate;
223
224 if (reentrant)
225 return;
226
227 reentrant = 1;
228
229 /* SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and
230 are thus delivered to the thread that caused the fault. Get the Python
231 thread state of the current thread.
232
233 PyThreadState_Get() doesn't give the state of the thread that caused the
234 fault if the thread released the GIL, and so this function cannot be
235 used. Read the thread specific storage (TSS) instead: call
236 PyGILState_GetThisThreadState(). */
237 tstate = PyGILState_GetThisThreadState();
238
239 if (all_threads) {
240 (void)_Py_DumpTracebackThreads(fd, NULL, tstate);
241 }
242 else {
243 if (tstate != NULL)
244 _Py_DumpTraceback(fd, tstate);
245 }
246
247 reentrant = 0;
248 }
249
250 static PyObject*
faulthandler_dump_traceback_py(PyObject * self,PyObject * args,PyObject * kwargs)251 faulthandler_dump_traceback_py(PyObject *self,
252 PyObject *args, PyObject *kwargs)
253 {
254 static char *kwlist[] = {"file", "all_threads", NULL};
255 PyObject *file = NULL;
256 int all_threads = 1;
257 PyThreadState *tstate;
258 const char *errmsg;
259 int fd;
260
261 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
262 "|Oi:dump_traceback", kwlist,
263 &file, &all_threads))
264 return NULL;
265
266 fd = faulthandler_get_fileno(&file);
267 if (fd < 0)
268 return NULL;
269
270 tstate = get_thread_state();
271 if (tstate == NULL)
272 return NULL;
273
274 if (all_threads) {
275 errmsg = _Py_DumpTracebackThreads(fd, NULL, tstate);
276 if (errmsg != NULL) {
277 PyErr_SetString(PyExc_RuntimeError, errmsg);
278 return NULL;
279 }
280 }
281 else {
282 _Py_DumpTraceback(fd, tstate);
283 }
284
285 if (PyErr_CheckSignals())
286 return NULL;
287
288 Py_RETURN_NONE;
289 }
290
291 static void
faulthandler_disable_fatal_handler(fault_handler_t * handler)292 faulthandler_disable_fatal_handler(fault_handler_t *handler)
293 {
294 if (!handler->enabled)
295 return;
296 handler->enabled = 0;
297 #ifdef HAVE_SIGACTION
298 (void)sigaction(handler->signum, &handler->previous, NULL);
299 #else
300 (void)signal(handler->signum, handler->previous);
301 #endif
302 }
303
304
305 /* Handler for SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL signals.
306
307 Display the current Python traceback, restore the previous handler and call
308 the previous handler.
309
310 On Windows, don't explicitly call the previous handler, because the Windows
311 signal handler would not be called (for an unknown reason). The execution of
312 the program continues at faulthandler_fatal_error() exit, but the same
313 instruction will raise the same fault (signal), and so the previous handler
314 will be called.
315
316 This function is signal-safe and should only call signal-safe functions. */
317
318 static void
faulthandler_fatal_error(int signum)319 faulthandler_fatal_error(int signum)
320 {
321 const int fd = fatal_error.fd;
322 size_t i;
323 fault_handler_t *handler = NULL;
324 int save_errno = errno;
325
326 if (!fatal_error.enabled)
327 return;
328
329 for (i=0; i < faulthandler_nsignals; i++) {
330 handler = &faulthandler_handlers[i];
331 if (handler->signum == signum)
332 break;
333 }
334 if (handler == NULL) {
335 /* faulthandler_nsignals == 0 (unlikely) */
336 return;
337 }
338
339 /* restore the previous handler */
340 faulthandler_disable_fatal_handler(handler);
341
342 PUTS(fd, "Fatal Python error: ");
343 PUTS(fd, handler->name);
344 PUTS(fd, "\n\n");
345
346 faulthandler_dump_traceback(fd, fatal_error.all_threads,
347 fatal_error.interp);
348
349 errno = save_errno;
350 #ifdef MS_WINDOWS
351 if (signum == SIGSEGV) {
352 /* don't explicitly call the previous handler for SIGSEGV in this signal
353 handler, because the Windows signal handler would not be called */
354 return;
355 }
356 #endif
357 /* call the previous signal handler: it is called immediately if we use
358 sigaction() thanks to SA_NODEFER flag, otherwise it is deferred */
359 raise(signum);
360 }
361
362 #ifdef MS_WINDOWS
363 static int
faulthandler_ignore_exception(DWORD code)364 faulthandler_ignore_exception(DWORD code)
365 {
366 /* bpo-30557: ignore exceptions which are not errors */
367 if (!(code & 0x80000000)) {
368 return 1;
369 }
370 /* bpo-31701: ignore MSC and COM exceptions
371 E0000000 + code */
372 if (code == 0xE06D7363 /* MSC exception ("Emsc") */
373 || code == 0xE0434352 /* COM Callable Runtime exception ("ECCR") */) {
374 return 1;
375 }
376 /* Interesting exception: log it with the Python traceback */
377 return 0;
378 }
379
380 static LONG WINAPI
faulthandler_exc_handler(struct _EXCEPTION_POINTERS * exc_info)381 faulthandler_exc_handler(struct _EXCEPTION_POINTERS *exc_info)
382 {
383 const int fd = fatal_error.fd;
384 DWORD code = exc_info->ExceptionRecord->ExceptionCode;
385 DWORD flags = exc_info->ExceptionRecord->ExceptionFlags;
386
387 if (faulthandler_ignore_exception(code)) {
388 /* ignore the exception: call the next exception handler */
389 return EXCEPTION_CONTINUE_SEARCH;
390 }
391
392 PUTS(fd, "Windows fatal exception: ");
393 switch (code)
394 {
395 /* only format most common errors */
396 case EXCEPTION_ACCESS_VIOLATION: PUTS(fd, "access violation"); break;
397 case EXCEPTION_FLT_DIVIDE_BY_ZERO: PUTS(fd, "float divide by zero"); break;
398 case EXCEPTION_FLT_OVERFLOW: PUTS(fd, "float overflow"); break;
399 case EXCEPTION_INT_DIVIDE_BY_ZERO: PUTS(fd, "int divide by zero"); break;
400 case EXCEPTION_INT_OVERFLOW: PUTS(fd, "integer overflow"); break;
401 case EXCEPTION_IN_PAGE_ERROR: PUTS(fd, "page error"); break;
402 case EXCEPTION_STACK_OVERFLOW: PUTS(fd, "stack overflow"); break;
403 default:
404 PUTS(fd, "code 0x");
405 _Py_DumpHexadecimal(fd, code, 8);
406 }
407 PUTS(fd, "\n\n");
408
409 if (code == EXCEPTION_ACCESS_VIOLATION) {
410 /* disable signal handler for SIGSEGV */
411 for (size_t i=0; i < faulthandler_nsignals; i++) {
412 fault_handler_t *handler = &faulthandler_handlers[i];
413 if (handler->signum == SIGSEGV) {
414 faulthandler_disable_fatal_handler(handler);
415 break;
416 }
417 }
418 }
419
420 faulthandler_dump_traceback(fd, fatal_error.all_threads,
421 fatal_error.interp);
422
423 /* call the next exception handler */
424 return EXCEPTION_CONTINUE_SEARCH;
425 }
426 #endif
427
428 /* Install the handler for fatal signals, faulthandler_fatal_error(). */
429
430 static int
faulthandler_enable(void)431 faulthandler_enable(void)
432 {
433 if (fatal_error.enabled) {
434 return 0;
435 }
436 fatal_error.enabled = 1;
437
438 for (size_t i=0; i < faulthandler_nsignals; i++) {
439 fault_handler_t *handler;
440 #ifdef HAVE_SIGACTION
441 struct sigaction action;
442 #endif
443 int err;
444
445 handler = &faulthandler_handlers[i];
446 assert(!handler->enabled);
447 #ifdef HAVE_SIGACTION
448 action.sa_handler = faulthandler_fatal_error;
449 sigemptyset(&action.sa_mask);
450 /* Do not prevent the signal from being received from within
451 its own signal handler */
452 action.sa_flags = SA_NODEFER;
453 #ifdef HAVE_SIGALTSTACK
454 if (stack.ss_sp != NULL) {
455 /* Call the signal handler on an alternate signal stack
456 provided by sigaltstack() */
457 action.sa_flags |= SA_ONSTACK;
458 }
459 #endif
460 err = sigaction(handler->signum, &action, &handler->previous);
461 #else
462 handler->previous = signal(handler->signum,
463 faulthandler_fatal_error);
464 err = (handler->previous == SIG_ERR);
465 #endif
466 if (err) {
467 PyErr_SetFromErrno(PyExc_RuntimeError);
468 return -1;
469 }
470
471 handler->enabled = 1;
472 }
473
474 #ifdef MS_WINDOWS
475 assert(fatal_error.exc_handler == NULL);
476 fatal_error.exc_handler = AddVectoredExceptionHandler(1, faulthandler_exc_handler);
477 #endif
478 return 0;
479 }
480
481 static PyObject*
faulthandler_py_enable(PyObject * self,PyObject * args,PyObject * kwargs)482 faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs)
483 {
484 static char *kwlist[] = {"file", "all_threads", NULL};
485 PyObject *file = NULL;
486 int all_threads = 1;
487 int fd;
488 PyThreadState *tstate;
489
490 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
491 "|Oi:enable", kwlist, &file, &all_threads))
492 return NULL;
493
494 fd = faulthandler_get_fileno(&file);
495 if (fd < 0)
496 return NULL;
497
498 tstate = get_thread_state();
499 if (tstate == NULL)
500 return NULL;
501
502 Py_XINCREF(file);
503 Py_XSETREF(fatal_error.file, file);
504 fatal_error.fd = fd;
505 fatal_error.all_threads = all_threads;
506 fatal_error.interp = tstate->interp;
507
508 if (faulthandler_enable() < 0) {
509 return NULL;
510 }
511
512 Py_RETURN_NONE;
513 }
514
515 static void
faulthandler_disable(void)516 faulthandler_disable(void)
517 {
518 if (fatal_error.enabled) {
519 fatal_error.enabled = 0;
520 for (size_t i=0; i < faulthandler_nsignals; i++) {
521 fault_handler_t *handler;
522 handler = &faulthandler_handlers[i];
523 faulthandler_disable_fatal_handler(handler);
524 }
525 }
526 #ifdef MS_WINDOWS
527 if (fatal_error.exc_handler != NULL) {
528 RemoveVectoredExceptionHandler(fatal_error.exc_handler);
529 fatal_error.exc_handler = NULL;
530 }
531 #endif
532 Py_CLEAR(fatal_error.file);
533 }
534
535 static PyObject*
faulthandler_disable_py(PyObject * self)536 faulthandler_disable_py(PyObject *self)
537 {
538 if (!fatal_error.enabled) {
539 Py_RETURN_FALSE;
540 }
541 faulthandler_disable();
542 Py_RETURN_TRUE;
543 }
544
545 static PyObject*
faulthandler_is_enabled(PyObject * self)546 faulthandler_is_enabled(PyObject *self)
547 {
548 return PyBool_FromLong(fatal_error.enabled);
549 }
550
551 #ifdef FAULTHANDLER_LATER
552
553 static void
faulthandler_thread(void * unused)554 faulthandler_thread(void *unused)
555 {
556 PyLockStatus st;
557 const char* errmsg;
558 int ok;
559 #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
560 sigset_t set;
561
562 /* we don't want to receive any signal */
563 sigfillset(&set);
564 pthread_sigmask(SIG_SETMASK, &set, NULL);
565 #endif
566
567 do {
568 st = PyThread_acquire_lock_timed(thread.cancel_event,
569 thread.timeout_us, 0);
570 if (st == PY_LOCK_ACQUIRED) {
571 PyThread_release_lock(thread.cancel_event);
572 break;
573 }
574 /* Timeout => dump traceback */
575 assert(st == PY_LOCK_FAILURE);
576
577 _Py_write_noraise(thread.fd, thread.header, (int)thread.header_len);
578
579 errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, NULL);
580 ok = (errmsg == NULL);
581
582 if (thread.exit)
583 _exit(1);
584 } while (ok && thread.repeat);
585
586 /* The only way out */
587 PyThread_release_lock(thread.running);
588 }
589
590 static void
cancel_dump_traceback_later(void)591 cancel_dump_traceback_later(void)
592 {
593 /* Notify cancellation */
594 PyThread_release_lock(thread.cancel_event);
595
596 /* Wait for thread to join */
597 PyThread_acquire_lock(thread.running, 1);
598 PyThread_release_lock(thread.running);
599
600 /* The main thread should always hold the cancel_event lock */
601 PyThread_acquire_lock(thread.cancel_event, 1);
602
603 Py_CLEAR(thread.file);
604 if (thread.header) {
605 PyMem_Free(thread.header);
606 thread.header = NULL;
607 }
608 }
609
610 #define SEC_TO_US (1000 * 1000)
611
612 static char*
format_timeout(_PyTime_t us)613 format_timeout(_PyTime_t us)
614 {
615 unsigned long sec, min, hour;
616 char buffer[100];
617
618 /* the downcast is safe: the caller check that 0 < us <= LONG_MAX */
619 sec = (unsigned long)(us / SEC_TO_US);
620 us %= SEC_TO_US;
621
622 min = sec / 60;
623 sec %= 60;
624 hour = min / 60;
625 min %= 60;
626
627 if (us != 0) {
628 PyOS_snprintf(buffer, sizeof(buffer),
629 "Timeout (%lu:%02lu:%02lu.%06u)!\n",
630 hour, min, sec, (unsigned int)us);
631 }
632 else {
633 PyOS_snprintf(buffer, sizeof(buffer),
634 "Timeout (%lu:%02lu:%02lu)!\n",
635 hour, min, sec);
636 }
637 return _PyMem_Strdup(buffer);
638 }
639
640 static PyObject*
faulthandler_dump_traceback_later(PyObject * self,PyObject * args,PyObject * kwargs)641 faulthandler_dump_traceback_later(PyObject *self,
642 PyObject *args, PyObject *kwargs)
643 {
644 static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL};
645 PyObject *timeout_obj;
646 _PyTime_t timeout, timeout_us;
647 int repeat = 0;
648 PyObject *file = NULL;
649 int fd;
650 int exit = 0;
651 PyThreadState *tstate;
652 char *header;
653 size_t header_len;
654
655 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
656 "O|iOi:dump_traceback_later", kwlist,
657 &timeout_obj, &repeat, &file, &exit))
658 return NULL;
659
660 if (_PyTime_FromSecondsObject(&timeout, timeout_obj,
661 _PyTime_ROUND_TIMEOUT) < 0) {
662 return NULL;
663 }
664 timeout_us = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_TIMEOUT);
665 if (timeout_us <= 0) {
666 PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0");
667 return NULL;
668 }
669 /* Limit to LONG_MAX seconds for format_timeout() */
670 if (timeout_us >= PY_TIMEOUT_MAX || timeout_us / SEC_TO_US >= LONG_MAX) {
671 PyErr_SetString(PyExc_OverflowError,
672 "timeout value is too large");
673 return NULL;
674 }
675
676 tstate = get_thread_state();
677 if (tstate == NULL)
678 return NULL;
679
680 fd = faulthandler_get_fileno(&file);
681 if (fd < 0)
682 return NULL;
683
684 /* format the timeout */
685 header = format_timeout(timeout_us);
686 if (header == NULL)
687 return PyErr_NoMemory();
688 header_len = strlen(header);
689
690 /* Cancel previous thread, if running */
691 cancel_dump_traceback_later();
692
693 Py_XINCREF(file);
694 Py_XSETREF(thread.file, file);
695 thread.fd = fd;
696 /* the downcast is safe: we check that 0 < timeout_us < PY_TIMEOUT_MAX */
697 thread.timeout_us = (PY_TIMEOUT_T)timeout_us;
698 thread.repeat = repeat;
699 thread.interp = tstate->interp;
700 thread.exit = exit;
701 thread.header = header;
702 thread.header_len = header_len;
703
704 /* Arm these locks to serve as events when released */
705 PyThread_acquire_lock(thread.running, 1);
706
707 if (PyThread_start_new_thread(faulthandler_thread, NULL) == PYTHREAD_INVALID_THREAD_ID) {
708 PyThread_release_lock(thread.running);
709 Py_CLEAR(thread.file);
710 PyMem_Free(header);
711 thread.header = NULL;
712 PyErr_SetString(PyExc_RuntimeError,
713 "unable to start watchdog thread");
714 return NULL;
715 }
716
717 Py_RETURN_NONE;
718 }
719
720 static PyObject*
faulthandler_cancel_dump_traceback_later_py(PyObject * self)721 faulthandler_cancel_dump_traceback_later_py(PyObject *self)
722 {
723 cancel_dump_traceback_later();
724 Py_RETURN_NONE;
725 }
726 #endif /* FAULTHANDLER_LATER */
727
728 #ifdef FAULTHANDLER_USER
729 static int
faulthandler_register(int signum,int chain,_Py_sighandler_t * p_previous)730 faulthandler_register(int signum, int chain, _Py_sighandler_t *p_previous)
731 {
732 #ifdef HAVE_SIGACTION
733 struct sigaction action;
734 action.sa_handler = faulthandler_user;
735 sigemptyset(&action.sa_mask);
736 /* if the signal is received while the kernel is executing a system
737 call, try to restart the system call instead of interrupting it and
738 return EINTR. */
739 action.sa_flags = SA_RESTART;
740 if (chain) {
741 /* do not prevent the signal from being received from within its
742 own signal handler */
743 action.sa_flags = SA_NODEFER;
744 }
745 #ifdef HAVE_SIGALTSTACK
746 if (stack.ss_sp != NULL) {
747 /* Call the signal handler on an alternate signal stack
748 provided by sigaltstack() */
749 action.sa_flags |= SA_ONSTACK;
750 }
751 #endif
752 return sigaction(signum, &action, p_previous);
753 #else
754 _Py_sighandler_t previous;
755 previous = signal(signum, faulthandler_user);
756 if (p_previous != NULL)
757 *p_previous = previous;
758 return (previous == SIG_ERR);
759 #endif
760 }
761
762 /* Handler of user signals (e.g. SIGUSR1).
763
764 Dump the traceback of the current thread, or of all threads if
765 thread.all_threads is true.
766
767 This function is signal safe and should only call signal safe functions. */
768
769 static void
faulthandler_user(int signum)770 faulthandler_user(int signum)
771 {
772 user_signal_t *user;
773 int save_errno = errno;
774
775 user = &user_signals[signum];
776 if (!user->enabled)
777 return;
778
779 faulthandler_dump_traceback(user->fd, user->all_threads, user->interp);
780
781 #ifdef HAVE_SIGACTION
782 if (user->chain) {
783 (void)sigaction(signum, &user->previous, NULL);
784 errno = save_errno;
785
786 /* call the previous signal handler */
787 raise(signum);
788
789 save_errno = errno;
790 (void)faulthandler_register(signum, user->chain, NULL);
791 errno = save_errno;
792 }
793 #else
794 if (user->chain) {
795 errno = save_errno;
796 /* call the previous signal handler */
797 user->previous(signum);
798 }
799 #endif
800 }
801
802 static int
check_signum(int signum)803 check_signum(int signum)
804 {
805 for (size_t i=0; i < faulthandler_nsignals; i++) {
806 if (faulthandler_handlers[i].signum == signum) {
807 PyErr_Format(PyExc_RuntimeError,
808 "signal %i cannot be registered, "
809 "use enable() instead",
810 signum);
811 return 0;
812 }
813 }
814 if (signum < 1 || NSIG <= signum) {
815 PyErr_SetString(PyExc_ValueError, "signal number out of range");
816 return 0;
817 }
818 return 1;
819 }
820
821 static PyObject*
faulthandler_register_py(PyObject * self,PyObject * args,PyObject * kwargs)822 faulthandler_register_py(PyObject *self,
823 PyObject *args, PyObject *kwargs)
824 {
825 static char *kwlist[] = {"signum", "file", "all_threads", "chain", NULL};
826 int signum;
827 PyObject *file = NULL;
828 int all_threads = 1;
829 int chain = 0;
830 int fd;
831 user_signal_t *user;
832 _Py_sighandler_t previous;
833 PyThreadState *tstate;
834 int err;
835
836 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
837 "i|Oii:register", kwlist,
838 &signum, &file, &all_threads, &chain))
839 return NULL;
840
841 if (!check_signum(signum))
842 return NULL;
843
844 tstate = get_thread_state();
845 if (tstate == NULL)
846 return NULL;
847
848 fd = faulthandler_get_fileno(&file);
849 if (fd < 0)
850 return NULL;
851
852 if (user_signals == NULL) {
853 user_signals = PyMem_Malloc(NSIG * sizeof(user_signal_t));
854 if (user_signals == NULL)
855 return PyErr_NoMemory();
856 memset(user_signals, 0, NSIG * sizeof(user_signal_t));
857 }
858 user = &user_signals[signum];
859
860 if (!user->enabled) {
861 err = faulthandler_register(signum, chain, &previous);
862 if (err) {
863 PyErr_SetFromErrno(PyExc_OSError);
864 return NULL;
865 }
866
867 user->previous = previous;
868 }
869
870 Py_XINCREF(file);
871 Py_XSETREF(user->file, file);
872 user->fd = fd;
873 user->all_threads = all_threads;
874 user->chain = chain;
875 user->interp = tstate->interp;
876 user->enabled = 1;
877
878 Py_RETURN_NONE;
879 }
880
881 static int
faulthandler_unregister(user_signal_t * user,int signum)882 faulthandler_unregister(user_signal_t *user, int signum)
883 {
884 if (!user->enabled)
885 return 0;
886 user->enabled = 0;
887 #ifdef HAVE_SIGACTION
888 (void)sigaction(signum, &user->previous, NULL);
889 #else
890 (void)signal(signum, user->previous);
891 #endif
892 Py_CLEAR(user->file);
893 user->fd = -1;
894 return 1;
895 }
896
897 static PyObject*
faulthandler_unregister_py(PyObject * self,PyObject * args)898 faulthandler_unregister_py(PyObject *self, PyObject *args)
899 {
900 int signum;
901 user_signal_t *user;
902 int change;
903
904 if (!PyArg_ParseTuple(args, "i:unregister", &signum))
905 return NULL;
906
907 if (!check_signum(signum))
908 return NULL;
909
910 if (user_signals == NULL)
911 Py_RETURN_FALSE;
912
913 user = &user_signals[signum];
914 change = faulthandler_unregister(user, signum);
915 return PyBool_FromLong(change);
916 }
917 #endif /* FAULTHANDLER_USER */
918
919
920 static void
faulthandler_suppress_crash_report(void)921 faulthandler_suppress_crash_report(void)
922 {
923 #ifdef MS_WINDOWS
924 UINT mode;
925
926 /* Configure Windows to not display the Windows Error Reporting dialog */
927 mode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
928 SetErrorMode(mode | SEM_NOGPFAULTERRORBOX);
929 #endif
930
931 #ifdef HAVE_SYS_RESOURCE_H
932 struct rlimit rl;
933
934 /* Disable creation of core dump */
935 if (getrlimit(RLIMIT_CORE, &rl) == 0) {
936 rl.rlim_cur = 0;
937 setrlimit(RLIMIT_CORE, &rl);
938 }
939 #endif
940
941 #ifdef _MSC_VER
942 /* Visual Studio: configure abort() to not display an error message nor
943 open a popup asking to report the fault. */
944 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
945 #endif
946 }
947
948 static PyObject *
faulthandler_read_null(PyObject * self,PyObject * args)949 faulthandler_read_null(PyObject *self, PyObject *args)
950 {
951 volatile int *x;
952 volatile int y;
953
954 faulthandler_suppress_crash_report();
955 x = NULL;
956 y = *x;
957 return PyLong_FromLong(y);
958
959 }
960
961 static void
faulthandler_raise_sigsegv(void)962 faulthandler_raise_sigsegv(void)
963 {
964 faulthandler_suppress_crash_report();
965 #if defined(MS_WINDOWS)
966 /* For SIGSEGV, faulthandler_fatal_error() restores the previous signal
967 handler and then gives back the execution flow to the program (without
968 explicitly calling the previous error handler). In a normal case, the
969 SIGSEGV was raised by the kernel because of a fault, and so if the
970 program retries to execute the same instruction, the fault will be
971 raised again.
972
973 Here the fault is simulated by a fake SIGSEGV signal raised by the
974 application. We have to raise SIGSEGV at lease twice: once for
975 faulthandler_fatal_error(), and one more time for the previous signal
976 handler. */
977 while(1)
978 raise(SIGSEGV);
979 #else
980 raise(SIGSEGV);
981 #endif
982 }
983
984 static PyObject *
faulthandler_sigsegv(PyObject * self,PyObject * args)985 faulthandler_sigsegv(PyObject *self, PyObject *args)
986 {
987 int release_gil = 0;
988 if (!PyArg_ParseTuple(args, "|i:_sigsegv", &release_gil))
989 return NULL;
990
991 if (release_gil) {
992 Py_BEGIN_ALLOW_THREADS
993 faulthandler_raise_sigsegv();
994 Py_END_ALLOW_THREADS
995 } else {
996 faulthandler_raise_sigsegv();
997 }
998 Py_RETURN_NONE;
999 }
1000
1001 static void
faulthandler_fatal_error_thread(void * plock)1002 faulthandler_fatal_error_thread(void *plock)
1003 {
1004 #ifndef __clang__
1005 PyThread_type_lock *lock = (PyThread_type_lock *)plock;
1006 #endif
1007
1008 Py_FatalError("in new thread");
1009
1010 #ifndef __clang__
1011 /* Issue #28152: Py_FatalError() is declared with
1012 __attribute__((__noreturn__)). GCC emits a warning without
1013 "PyThread_release_lock()" (compiler bug?), but Clang is smarter and
1014 emits a warning on the return. */
1015
1016 /* notify the caller that we are done */
1017 PyThread_release_lock(lock);
1018 #endif
1019 }
1020
1021 static PyObject *
faulthandler_fatal_error_c_thread(PyObject * self,PyObject * args)1022 faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args)
1023 {
1024 long thread;
1025 PyThread_type_lock lock;
1026
1027 faulthandler_suppress_crash_report();
1028
1029 lock = PyThread_allocate_lock();
1030 if (lock == NULL)
1031 return PyErr_NoMemory();
1032
1033 PyThread_acquire_lock(lock, WAIT_LOCK);
1034
1035 thread = PyThread_start_new_thread(faulthandler_fatal_error_thread, lock);
1036 if (thread == -1) {
1037 PyThread_free_lock(lock);
1038 PyErr_SetString(PyExc_RuntimeError, "unable to start the thread");
1039 return NULL;
1040 }
1041
1042 /* wait until the thread completes: it will never occur, since Py_FatalError()
1043 exits the process immediately. */
1044 PyThread_acquire_lock(lock, WAIT_LOCK);
1045 PyThread_release_lock(lock);
1046 PyThread_free_lock(lock);
1047
1048 Py_RETURN_NONE;
1049 }
1050
1051 static PyObject *
faulthandler_sigfpe(PyObject * self,PyObject * args)1052 faulthandler_sigfpe(PyObject *self, PyObject *args)
1053 {
1054 /* Do an integer division by zero: raise a SIGFPE on Intel CPU, but not on
1055 PowerPC. Use volatile to disable compile-time optimizations. */
1056 volatile int x = 1, y = 0, z;
1057 faulthandler_suppress_crash_report();
1058 z = x / y;
1059 /* If the division by zero didn't raise a SIGFPE (e.g. on PowerPC),
1060 raise it manually. */
1061 raise(SIGFPE);
1062 /* This line is never reached, but we pretend to make something with z
1063 to silence a compiler warning. */
1064 return PyLong_FromLong(z);
1065 }
1066
1067 static PyObject *
faulthandler_sigabrt(PyObject * self,PyObject * args)1068 faulthandler_sigabrt(PyObject *self, PyObject *args)
1069 {
1070 faulthandler_suppress_crash_report();
1071 abort();
1072 Py_RETURN_NONE;
1073 }
1074
1075 static PyObject *
faulthandler_fatal_error_py(PyObject * self,PyObject * args)1076 faulthandler_fatal_error_py(PyObject *self, PyObject *args)
1077 {
1078 char *message;
1079 int release_gil = 0;
1080 if (!PyArg_ParseTuple(args, "y|i:fatal_error", &message, &release_gil))
1081 return NULL;
1082 faulthandler_suppress_crash_report();
1083 if (release_gil) {
1084 Py_BEGIN_ALLOW_THREADS
1085 Py_FatalError(message);
1086 Py_END_ALLOW_THREADS
1087 }
1088 else {
1089 Py_FatalError(message);
1090 }
1091 Py_RETURN_NONE;
1092 }
1093
1094 #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1095 #define FAULTHANDLER_STACK_OVERFLOW
1096
1097 #ifdef __INTEL_COMPILER
1098 /* Issue #23654: Turn off ICC's tail call optimization for the
1099 * stack_overflow generator. ICC turns the recursive tail call into
1100 * a loop. */
1101 # pragma intel optimization_level 0
1102 #endif
1103 static
1104 uintptr_t
stack_overflow(uintptr_t min_sp,uintptr_t max_sp,size_t * depth)1105 stack_overflow(uintptr_t min_sp, uintptr_t max_sp, size_t *depth)
1106 {
1107 /* allocate 4096 bytes on the stack at each call */
1108 unsigned char buffer[4096];
1109 uintptr_t sp = (uintptr_t)&buffer;
1110 *depth += 1;
1111 if (sp < min_sp || max_sp < sp)
1112 return sp;
1113 buffer[0] = 1;
1114 buffer[4095] = 0;
1115 return stack_overflow(min_sp, max_sp, depth);
1116 }
1117
1118 static PyObject *
faulthandler_stack_overflow(PyObject * self)1119 faulthandler_stack_overflow(PyObject *self)
1120 {
1121 size_t depth, size;
1122 uintptr_t sp = (uintptr_t)&depth;
1123 uintptr_t stop;
1124
1125 faulthandler_suppress_crash_report();
1126 depth = 0;
1127 stop = stack_overflow(sp - STACK_OVERFLOW_MAX_SIZE,
1128 sp + STACK_OVERFLOW_MAX_SIZE,
1129 &depth);
1130 if (sp < stop)
1131 size = stop - sp;
1132 else
1133 size = sp - stop;
1134 PyErr_Format(PyExc_RuntimeError,
1135 "unable to raise a stack overflow (allocated %zu bytes "
1136 "on the stack, %zu recursive calls)",
1137 size, depth);
1138 return NULL;
1139 }
1140 #endif /* defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION) */
1141
1142
1143 static int
faulthandler_traverse(PyObject * module,visitproc visit,void * arg)1144 faulthandler_traverse(PyObject *module, visitproc visit, void *arg)
1145 {
1146 #ifdef FAULTHANDLER_LATER
1147 Py_VISIT(thread.file);
1148 #endif
1149 #ifdef FAULTHANDLER_USER
1150 if (user_signals != NULL) {
1151 for (size_t signum=0; signum < NSIG; signum++)
1152 Py_VISIT(user_signals[signum].file);
1153 }
1154 #endif
1155 Py_VISIT(fatal_error.file);
1156 return 0;
1157 }
1158
1159 #ifdef MS_WINDOWS
1160 static PyObject *
faulthandler_raise_exception(PyObject * self,PyObject * args)1161 faulthandler_raise_exception(PyObject *self, PyObject *args)
1162 {
1163 unsigned int code, flags = 0;
1164 if (!PyArg_ParseTuple(args, "I|I:_raise_exception", &code, &flags))
1165 return NULL;
1166 faulthandler_suppress_crash_report();
1167 RaiseException(code, flags, 0, NULL);
1168 Py_RETURN_NONE;
1169 }
1170 #endif
1171
1172 PyDoc_STRVAR(module_doc,
1173 "faulthandler module.");
1174
1175 static PyMethodDef module_methods[] = {
1176 {"enable",
1177 (PyCFunction)faulthandler_py_enable, METH_VARARGS|METH_KEYWORDS,
1178 PyDoc_STR("enable(file=sys.stderr, all_threads=True): "
1179 "enable the fault handler")},
1180 {"disable", (PyCFunction)faulthandler_disable_py, METH_NOARGS,
1181 PyDoc_STR("disable(): disable the fault handler")},
1182 {"is_enabled", (PyCFunction)faulthandler_is_enabled, METH_NOARGS,
1183 PyDoc_STR("is_enabled()->bool: check if the handler is enabled")},
1184 {"dump_traceback",
1185 (PyCFunction)faulthandler_dump_traceback_py, METH_VARARGS|METH_KEYWORDS,
1186 PyDoc_STR("dump_traceback(file=sys.stderr, all_threads=True): "
1187 "dump the traceback of the current thread, or of all threads "
1188 "if all_threads is True, into file")},
1189 #ifdef FAULTHANDLER_LATER
1190 {"dump_traceback_later",
1191 (PyCFunction)faulthandler_dump_traceback_later, METH_VARARGS|METH_KEYWORDS,
1192 PyDoc_STR("dump_traceback_later(timeout, repeat=False, file=sys.stderrn, exit=False):\n"
1193 "dump the traceback of all threads in timeout seconds,\n"
1194 "or each timeout seconds if repeat is True. If exit is True, "
1195 "call _exit(1) which is not safe.")},
1196 {"cancel_dump_traceback_later",
1197 (PyCFunction)faulthandler_cancel_dump_traceback_later_py, METH_NOARGS,
1198 PyDoc_STR("cancel_dump_traceback_later():\ncancel the previous call "
1199 "to dump_traceback_later().")},
1200 #endif
1201
1202 #ifdef FAULTHANDLER_USER
1203 {"register",
1204 (PyCFunction)faulthandler_register_py, METH_VARARGS|METH_KEYWORDS,
1205 PyDoc_STR("register(signum, file=sys.stderr, all_threads=True, chain=False): "
1206 "register a handler for the signal 'signum': dump the "
1207 "traceback of the current thread, or of all threads if "
1208 "all_threads is True, into file")},
1209 {"unregister",
1210 faulthandler_unregister_py, METH_VARARGS|METH_KEYWORDS,
1211 PyDoc_STR("unregister(signum): unregister the handler of the signal "
1212 "'signum' registered by register()")},
1213 #endif
1214
1215 {"_read_null", faulthandler_read_null, METH_NOARGS,
1216 PyDoc_STR("_read_null(): read from NULL, raise "
1217 "a SIGSEGV or SIGBUS signal depending on the platform")},
1218 {"_sigsegv", faulthandler_sigsegv, METH_VARARGS,
1219 PyDoc_STR("_sigsegv(release_gil=False): raise a SIGSEGV signal")},
1220 {"_fatal_error_c_thread", faulthandler_fatal_error_c_thread, METH_NOARGS,
1221 PyDoc_STR("fatal_error_c_thread(): "
1222 "call Py_FatalError() in a new C thread.")},
1223 {"_sigabrt", faulthandler_sigabrt, METH_NOARGS,
1224 PyDoc_STR("_sigabrt(): raise a SIGABRT signal")},
1225 {"_sigfpe", (PyCFunction)faulthandler_sigfpe, METH_NOARGS,
1226 PyDoc_STR("_sigfpe(): raise a SIGFPE signal")},
1227 {"_fatal_error", faulthandler_fatal_error_py, METH_VARARGS,
1228 PyDoc_STR("_fatal_error(message): call Py_FatalError(message)")},
1229 #ifdef FAULTHANDLER_STACK_OVERFLOW
1230 {"_stack_overflow", (PyCFunction)faulthandler_stack_overflow, METH_NOARGS,
1231 PyDoc_STR("_stack_overflow(): recursive call to raise a stack overflow")},
1232 #endif
1233 #ifdef MS_WINDOWS
1234 {"_raise_exception", faulthandler_raise_exception, METH_VARARGS,
1235 PyDoc_STR("raise_exception(code, flags=0): Call RaiseException(code, flags).")},
1236 #endif
1237 {NULL, NULL} /* sentinel */
1238 };
1239
1240 static struct PyModuleDef module_def = {
1241 PyModuleDef_HEAD_INIT,
1242 "faulthandler",
1243 module_doc,
1244 0, /* non-negative size to be able to unload the module */
1245 module_methods,
1246 NULL,
1247 faulthandler_traverse,
1248 NULL,
1249 NULL
1250 };
1251
1252 PyMODINIT_FUNC
PyInit_faulthandler(void)1253 PyInit_faulthandler(void)
1254 {
1255 PyObject *m = PyModule_Create(&module_def);
1256 if (m == NULL)
1257 return NULL;
1258
1259 /* Add constants for unit tests */
1260 #ifdef MS_WINDOWS
1261 /* RaiseException() codes (prefixed by an underscore) */
1262 if (PyModule_AddIntConstant(m, "_EXCEPTION_ACCESS_VIOLATION",
1263 EXCEPTION_ACCESS_VIOLATION))
1264 return NULL;
1265 if (PyModule_AddIntConstant(m, "_EXCEPTION_INT_DIVIDE_BY_ZERO",
1266 EXCEPTION_INT_DIVIDE_BY_ZERO))
1267 return NULL;
1268 if (PyModule_AddIntConstant(m, "_EXCEPTION_STACK_OVERFLOW",
1269 EXCEPTION_STACK_OVERFLOW))
1270 return NULL;
1271
1272 /* RaiseException() flags (prefixed by an underscore) */
1273 if (PyModule_AddIntConstant(m, "_EXCEPTION_NONCONTINUABLE",
1274 EXCEPTION_NONCONTINUABLE))
1275 return NULL;
1276 if (PyModule_AddIntConstant(m, "_EXCEPTION_NONCONTINUABLE_EXCEPTION",
1277 EXCEPTION_NONCONTINUABLE_EXCEPTION))
1278 return NULL;
1279 #endif
1280
1281 return m;
1282 }
1283
1284 static int
faulthandler_init_enable(void)1285 faulthandler_init_enable(void)
1286 {
1287 PyObject *module = PyImport_ImportModule("faulthandler");
1288 if (module == NULL) {
1289 return -1;
1290 }
1291
1292 PyObject *res = _PyObject_CallMethodId(module, &PyId_enable, NULL);
1293 Py_DECREF(module);
1294 if (res == NULL) {
1295 return -1;
1296 }
1297 Py_DECREF(res);
1298
1299 return 0;
1300 }
1301
1302 _PyInitError
_PyFaulthandler_Init(int enable)1303 _PyFaulthandler_Init(int enable)
1304 {
1305 #ifdef HAVE_SIGALTSTACK
1306 int err;
1307
1308 /* Try to allocate an alternate stack for faulthandler() signal handler to
1309 * be able to allocate memory on the stack, even on a stack overflow. If it
1310 * fails, ignore the error. */
1311 stack.ss_flags = 0;
1312 stack.ss_size = SIGSTKSZ;
1313 stack.ss_sp = PyMem_Malloc(stack.ss_size);
1314 if (stack.ss_sp != NULL) {
1315 err = sigaltstack(&stack, &old_stack);
1316 if (err) {
1317 PyMem_Free(stack.ss_sp);
1318 stack.ss_sp = NULL;
1319 }
1320 }
1321 #endif
1322 #ifdef FAULTHANDLER_LATER
1323 thread.file = NULL;
1324 thread.cancel_event = PyThread_allocate_lock();
1325 thread.running = PyThread_allocate_lock();
1326 if (!thread.cancel_event || !thread.running) {
1327 return _Py_INIT_ERR("failed to allocate locks for faulthandler");
1328 }
1329 PyThread_acquire_lock(thread.cancel_event, 1);
1330 #endif
1331
1332 if (enable) {
1333 if (faulthandler_init_enable() < 0) {
1334 return _Py_INIT_ERR("failed to enable faulthandler");
1335 }
1336 }
1337 return _Py_INIT_OK();
1338 }
1339
_PyFaulthandler_Fini(void)1340 void _PyFaulthandler_Fini(void)
1341 {
1342 #ifdef FAULTHANDLER_LATER
1343 /* later */
1344 if (thread.cancel_event) {
1345 cancel_dump_traceback_later();
1346 PyThread_release_lock(thread.cancel_event);
1347 PyThread_free_lock(thread.cancel_event);
1348 thread.cancel_event = NULL;
1349 }
1350 if (thread.running) {
1351 PyThread_free_lock(thread.running);
1352 thread.running = NULL;
1353 }
1354 #endif
1355
1356 #ifdef FAULTHANDLER_USER
1357 /* user */
1358 if (user_signals != NULL) {
1359 for (size_t signum=0; signum < NSIG; signum++) {
1360 faulthandler_unregister(&user_signals[signum], signum);
1361 }
1362 PyMem_Free(user_signals);
1363 user_signals = NULL;
1364 }
1365 #endif
1366
1367 /* fatal */
1368 faulthandler_disable();
1369 #ifdef HAVE_SIGALTSTACK
1370 if (stack.ss_sp != NULL) {
1371 /* Fetch the current alt stack */
1372 stack_t current_stack = {};
1373 if (sigaltstack(NULL, ¤t_stack) == 0) {
1374 if (current_stack.ss_sp == stack.ss_sp) {
1375 /* The current alt stack is the one that we installed.
1376 It is safe to restore the old stack that we found when
1377 we installed ours */
1378 sigaltstack(&old_stack, NULL);
1379 } else {
1380 /* Someone switched to a different alt stack and didn't
1381 restore ours when they were done (if they're done).
1382 There's not much we can do in this unlikely case */
1383 }
1384 }
1385 PyMem_Free(stack.ss_sp);
1386 stack.ss_sp = NULL;
1387 }
1388 #endif
1389 }
1390