ยปCore Development>Code coverage>Modules/faulthandler.c

Python code coverage for Modules/faulthandler.c

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