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