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