Skip to content

Commit 53d9cd9

Browse files
gh-81057: Move faulthandler Globals to _PyRuntimeState (gh-100152)
#81057
1 parent 8790d4d commit 53d9cd9

File tree

9 files changed

+120
-73
lines changed

9 files changed

+120
-73
lines changed
+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#ifndef Py_INTERNAL_FAULTHANDLER_H
2+
#define Py_INTERNAL_FAULTHANDLER_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#ifndef Py_BUILD_CORE
8+
# error "this header requires Py_BUILD_CORE define"
9+
#endif
10+
11+
#ifdef HAVE_SIGACTION
12+
# include <signal.h>
13+
#endif
14+
15+
16+
#ifndef MS_WINDOWS
17+
/* register() is useless on Windows, because only SIGSEGV, SIGABRT and
18+
SIGILL can be handled by the process, and these signals can only be used
19+
with enable(), not using register() */
20+
# define FAULTHANDLER_USER
21+
#endif
22+
23+
24+
#ifdef HAVE_SIGACTION
25+
/* Using an alternative stack requires sigaltstack()
26+
and sigaction() SA_ONSTACK */
27+
# ifdef HAVE_SIGALTSTACK
28+
# define FAULTHANDLER_USE_ALT_STACK
29+
# endif
30+
typedef struct sigaction _Py_sighandler_t;
31+
#else
32+
typedef PyOS_sighandler_t _Py_sighandler_t;
33+
#endif // HAVE_SIGACTION
34+
35+
36+
#ifdef FAULTHANDLER_USER
37+
struct faulthandler_user_signal {
38+
int enabled;
39+
PyObject *file;
40+
int fd;
41+
int all_threads;
42+
int chain;
43+
_Py_sighandler_t previous;
44+
PyInterpreterState *interp;
45+
};
46+
#endif /* FAULTHANDLER_USER */
47+
48+
49+
struct _faulthandler_runtime_state {
50+
struct {
51+
int enabled;
52+
PyObject *file;
53+
int fd;
54+
int all_threads;
55+
PyInterpreterState *interp;
56+
#ifdef MS_WINDOWS
57+
void *exc_handler;
58+
#endif
59+
} fatal_error;
60+
61+
struct {
62+
PyObject *file;
63+
int fd;
64+
PY_TIMEOUT_T timeout_us; /* timeout in microseconds */
65+
int repeat;
66+
PyInterpreterState *interp;
67+
int exit;
68+
char *header;
69+
size_t header_len;
70+
/* The main thread always holds this lock. It is only released when
71+
faulthandler_thread() is interrupted before this thread exits, or at
72+
Python exit. */
73+
PyThread_type_lock cancel_event;
74+
/* released by child thread when joined */
75+
PyThread_type_lock running;
76+
} thread;
77+
78+
#ifdef FAULTHANDLER_USER
79+
struct faulthandler_user_signal *user_signals;
80+
#endif
81+
82+
#ifdef FAULTHANDLER_USE_ALT_STACK
83+
stack_t stack;
84+
stack_t old_stack;
85+
#endif
86+
};
87+
88+
#define _faulthandler_runtime_state_INIT \
89+
{ \
90+
.fatal_error = { \
91+
.fd = -1, \
92+
}, \
93+
}
94+
95+
96+
#ifdef __cplusplus
97+
}
98+
#endif
99+
#endif /* !Py_INTERNAL_FAULTHANDLER_H */

Include/internal/pycore_runtime.h

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extern "C" {
1313
#include "pycore_dict_state.h" // struct _Py_dict_runtime_state
1414
#include "pycore_dtoa.h" // struct _dtoa_runtime_state
1515
#include "pycore_floatobject.h" // struct _Py_float_runtime_state
16+
#include "pycore_faulthandler.h" // struct _faulthandler_runtime_state
1617
#include "pycore_function.h" // struct _func_runtime_state
1718
#include "pycore_global_objects.h" // struct _Py_global_objects
1819
#include "pycore_import.h" // struct _import_runtime_state
@@ -140,6 +141,7 @@ typedef struct pyruntimestate {
140141
struct _getargs_runtime_state getargs;
141142
struct _dtoa_runtime_state dtoa;
142143
struct _fileutils_state fileutils;
144+
struct _faulthandler_runtime_state faulthandler;
143145
struct _tracemalloc_runtime_state tracemalloc;
144146

145147
PyPreConfig preconfig;

Include/internal/pycore_runtime_init.h

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ extern "C" {
5454
.fileutils = { \
5555
.force_ascii = -1, \
5656
}, \
57+
.faulthandler = _faulthandler_runtime_state_INIT, \
5758
.tracemalloc = _tracemalloc_runtime_state_INIT, \
5859
.float_state = { \
5960
.float_format = _py_float_format_unknown, \

Makefile.pre.in

+1
Original file line numberDiff line numberDiff line change
@@ -1634,6 +1634,7 @@ PYTHON_HEADERS= \
16341634
$(srcdir)/Include/internal/pycore_descrobject.h \
16351635
$(srcdir)/Include/internal/pycore_dtoa.h \
16361636
$(srcdir)/Include/internal/pycore_exceptions.h \
1637+
$(srcdir)/Include/internal/pycore_faulthandler.h \
16371638
$(srcdir)/Include/internal/pycore_fileutils.h \
16381639
$(srcdir)/Include/internal/pycore_floatobject.h \
16391640
$(srcdir)/Include/internal/pycore_format.h \

Modules/faulthandler.c

+9-63
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@
1818
# include <sys/resource.h>
1919
#endif
2020

21-
/* Using an alternative stack requires sigaltstack()
22-
and sigaction() SA_ONSTACK */
23-
#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
24-
# define FAULTHANDLER_USE_ALT_STACK
25-
#endif
26-
2721
#if defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_LINUX_AUXVEC_H) && defined(HAVE_SYS_AUXV_H)
2822
# include <linux/auxvec.h> // AT_MINSIGSTKSZ
2923
# include <sys/auxv.h> // getauxval()
@@ -32,13 +26,6 @@
3226
/* Allocate at maximum 100 MiB of the stack to raise the stack overflow */
3327
#define STACK_OVERFLOW_MAX_SIZE (100 * 1024 * 1024)
3428

35-
#ifndef MS_WINDOWS
36-
/* register() is useless on Windows, because only SIGSEGV, SIGABRT and
37-
SIGILL can be handled by the process, and these signals can only be used
38-
with enable(), not using register() */
39-
# define FAULTHANDLER_USER
40-
#endif
41-
4229
#define PUTS(fd, str) _Py_write_noraise(fd, str, strlen(str))
4330

4431

@@ -58,12 +45,6 @@
5845
#endif
5946

6047

61-
#ifdef HAVE_SIGACTION
62-
typedef struct sigaction _Py_sighandler_t;
63-
#else
64-
typedef PyOS_sighandler_t _Py_sighandler_t;
65-
#endif
66-
6748
typedef struct {
6849
int signum;
6950
int enabled;
@@ -72,47 +53,12 @@ typedef struct {
7253
int all_threads;
7354
} fault_handler_t;
7455

75-
static struct {
76-
int enabled;
77-
PyObject *file;
78-
int fd;
79-
int all_threads;
80-
PyInterpreterState *interp;
81-
#ifdef MS_WINDOWS
82-
void *exc_handler;
83-
#endif
84-
} fatal_error = {0, NULL, -1, 0};
85-
86-
static struct {
87-
PyObject *file;
88-
int fd;
89-
PY_TIMEOUT_T timeout_us; /* timeout in microseconds */
90-
int repeat;
91-
PyInterpreterState *interp;
92-
int exit;
93-
char *header;
94-
size_t header_len;
95-
/* The main thread always holds this lock. It is only released when
96-
faulthandler_thread() is interrupted before this thread exits, or at
97-
Python exit. */
98-
PyThread_type_lock cancel_event;
99-
/* released by child thread when joined */
100-
PyThread_type_lock running;
101-
} thread;
56+
#define fatal_error _PyRuntime.faulthandler.fatal_error
57+
#define thread _PyRuntime.faulthandler.thread
10258

10359
#ifdef FAULTHANDLER_USER
104-
typedef struct {
105-
int enabled;
106-
PyObject *file;
107-
int fd;
108-
int all_threads;
109-
int chain;
110-
_Py_sighandler_t previous;
111-
PyInterpreterState *interp;
112-
} user_signal_t;
113-
114-
static user_signal_t *user_signals;
115-
60+
#define user_signals _PyRuntime.faulthandler.user_signals
61+
typedef struct faulthandler_user_signal user_signal_t;
11662
static void faulthandler_user(int signum);
11763
#endif /* FAULTHANDLER_USER */
11864

@@ -134,8 +80,8 @@ static const size_t faulthandler_nsignals = \
13480
Py_ARRAY_LENGTH(faulthandler_handlers);
13581

13682
#ifdef FAULTHANDLER_USE_ALT_STACK
137-
static stack_t stack;
138-
static stack_t old_stack;
83+
# define stack _PyRuntime.faulthandler.stack
84+
# define old_stack _PyRuntime.faulthandler.old_stack
13985
#endif
14086

14187

@@ -1094,7 +1040,7 @@ faulthandler_fatal_error_thread(void *plock)
10941040
static PyObject *
10951041
faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args)
10961042
{
1097-
long thread;
1043+
long tid;
10981044
PyThread_type_lock lock;
10991045

11001046
faulthandler_suppress_crash_report();
@@ -1105,8 +1051,8 @@ faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args)
11051051

11061052
PyThread_acquire_lock(lock, WAIT_LOCK);
11071053

1108-
thread = PyThread_start_new_thread(faulthandler_fatal_error_thread, lock);
1109-
if (thread == -1) {
1054+
tid = PyThread_start_new_thread(faulthandler_fatal_error_thread, lock);
1055+
if (tid == -1) {
11101056
PyThread_free_lock(lock);
11111057
PyErr_SetString(PyExc_RuntimeError, "unable to start the thread");
11121058
return NULL;

PCbuild/pythoncore.vcxproj

+1
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@
214214
<ClInclude Include="..\Include\internal\pycore_dict_state.h" />
215215
<ClInclude Include="..\Include\internal\pycore_dtoa.h" />
216216
<ClInclude Include="..\Include\internal\pycore_exceptions.h" />
217+
<ClInclude Include="..\Include\internal\pycore_faulthandler.h" />
217218
<ClInclude Include="..\Include\internal\pycore_fileutils.h" />
218219
<ClInclude Include="..\Include\internal\pycore_floatobject.h" />
219220
<ClInclude Include="..\Include\internal\pycore_format.h" />

PCbuild/pythoncore.vcxproj.filters

+6
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,9 @@
549549
<ClInclude Include="..\Include\internal\pycore_exceptions.h">
550550
<Filter>Include\internal</Filter>
551551
</ClInclude>
552+
<ClInclude Include="..\Include\internal\pycore_faulthandler.h">
553+
<Filter>Include\internal</Filter>
554+
</ClInclude>
552555
<ClInclude Include="..\Include\internal\pycore_fileutils.h">
553556
<Filter>Include\internal</Filter>
554557
</ClInclude>
@@ -558,6 +561,9 @@
558561
<ClInclude Include="..\Include\internal\pycore_format.h">
559562
<Filter>Include\internal</Filter>
560563
</ClInclude>
564+
<ClInclude Include="..\Include\internal\pycore_function.h">
565+
<Filter>Include\internal</Filter>
566+
</ClInclude>
561567
<ClInclude Include="..\Include\internal\pycore_gc.h">
562568
<Filter>Include\internal</Filter>
563569
</ClInclude>

Tools/c-analyzer/cpython/globals-to-fix.tsv

-10
Original file line numberDiff line numberDiff line change
@@ -361,23 +361,13 @@ Modules/itertoolsmodule.c - tee_type -
361361
Modules/itertoolsmodule.c - teedataobject_type -
362362
Modules/itertoolsmodule.c - ziplongest_type -
363363

364-
##-----------------------
365-
## state
366-
367-
Modules/faulthandler.c - fatal_error -
368-
Modules/faulthandler.c - thread -
369-
Modules/faulthandler.c - user_signals -
370-
Modules/faulthandler.c - stack -
371-
Modules/faulthandler.c - old_stack -
372-
373364

374365
##################################
375366
## global non-objects to fix in builtin modules
376367

377368
##-----------------------
378369
## state
379370

380-
Modules/faulthandler.c faulthandler_dump_traceback reentrant -
381371
Modules/signalmodule.c - is_tripped -
382372
Modules/signalmodule.c - signal_global_state -
383373
Modules/signalmodule.c - wakeup -

Tools/c-analyzer/cpython/ignored.tsv

+1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ Python/sysmodule.c - _preinit_xoptions -
151151

152152
# thread-safety
153153
# XXX need race protection?
154+
Modules/faulthandler.c faulthandler_dump_traceback reentrant -
154155
Python/pylifecycle.c _Py_FatalErrorFormat reentrant -
155156
Python/pylifecycle.c fatal_error reentrant -
156157

0 commit comments

Comments
 (0)