Skip to content

gh-81057: Move faulthandler Globals to _PyRuntimeState #100152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions Include/internal/pycore_faulthandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#ifndef Py_INTERNAL_FAULTHANDLER_H
#define Py_INTERNAL_FAULTHANDLER_H
#ifdef __cplusplus
extern "C" {
#endif

#ifndef Py_BUILD_CORE
# error "this header requires Py_BUILD_CORE define"
#endif

#ifdef HAVE_SIGACTION
# include <signal.h>
#endif


#ifndef MS_WINDOWS
/* register() is useless on Windows, because only SIGSEGV, SIGABRT and
SIGILL can be handled by the process, and these signals can only be used
with enable(), not using register() */
# define FAULTHANDLER_USER
#endif


#ifdef HAVE_SIGACTION
/* Using an alternative stack requires sigaltstack()
and sigaction() SA_ONSTACK */
# ifdef HAVE_SIGALTSTACK
# define FAULTHANDLER_USE_ALT_STACK
# endif
typedef struct sigaction _Py_sighandler_t;
#else
typedef PyOS_sighandler_t _Py_sighandler_t;
#endif // HAVE_SIGACTION


#ifdef FAULTHANDLER_USER
struct faulthandler_user_signal {
int enabled;
PyObject *file;
int fd;
int all_threads;
int chain;
_Py_sighandler_t previous;
PyInterpreterState *interp;
};
#endif /* FAULTHANDLER_USER */


struct _faulthandler_runtime_state {
struct {
int enabled;
PyObject *file;
int fd;
int all_threads;
PyInterpreterState *interp;
#ifdef MS_WINDOWS
void *exc_handler;
#endif
} fatal_error;

struct {
PyObject *file;
int fd;
PY_TIMEOUT_T timeout_us; /* timeout in microseconds */
int repeat;
PyInterpreterState *interp;
int exit;
char *header;
size_t header_len;
/* The main thread always holds this lock. It is only released when
faulthandler_thread() is interrupted before this thread exits, or at
Python exit. */
PyThread_type_lock cancel_event;
/* released by child thread when joined */
PyThread_type_lock running;
} thread;

#ifdef FAULTHANDLER_USER
struct faulthandler_user_signal *user_signals;
#endif

#ifdef FAULTHANDLER_USE_ALT_STACK
stack_t stack;
stack_t old_stack;
#endif
};

#define _faulthandler_runtime_state_INIT \
{ \
.fatal_error = { \
.fd = -1, \
}, \
}


#ifdef __cplusplus
}
#endif
#endif /* !Py_INTERNAL_FAULTHANDLER_H */
2 changes: 2 additions & 0 deletions Include/internal/pycore_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extern "C" {
#include "pycore_dict_state.h" // struct _Py_dict_runtime_state
#include "pycore_dtoa.h" // struct _dtoa_runtime_state
#include "pycore_floatobject.h" // struct _Py_float_runtime_state
#include "pycore_faulthandler.h" // struct _faulthandler_runtime_state
#include "pycore_function.h" // struct _func_runtime_state
#include "pycore_global_objects.h" // struct _Py_global_objects
#include "pycore_import.h" // struct _import_runtime_state
Expand Down Expand Up @@ -140,6 +141,7 @@ typedef struct pyruntimestate {
struct _getargs_runtime_state getargs;
struct _dtoa_runtime_state dtoa;
struct _fileutils_state fileutils;
struct _faulthandler_runtime_state faulthandler;
struct _tracemalloc_runtime_state tracemalloc;

PyPreConfig preconfig;
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_runtime_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ extern "C" {
.fileutils = { \
.force_ascii = -1, \
}, \
.faulthandler = _faulthandler_runtime_state_INIT, \
.tracemalloc = _tracemalloc_runtime_state_INIT, \
.float_state = { \
.float_format = _py_float_format_unknown, \
Expand Down
1 change: 1 addition & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_descrobject.h \
$(srcdir)/Include/internal/pycore_dtoa.h \
$(srcdir)/Include/internal/pycore_exceptions.h \
$(srcdir)/Include/internal/pycore_faulthandler.h \
$(srcdir)/Include/internal/pycore_fileutils.h \
$(srcdir)/Include/internal/pycore_floatobject.h \
$(srcdir)/Include/internal/pycore_format.h \
Expand Down
72 changes: 9 additions & 63 deletions Modules/faulthandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@
# include <sys/resource.h>
#endif

/* Using an alternative stack requires sigaltstack()
and sigaction() SA_ONSTACK */
#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
# define FAULTHANDLER_USE_ALT_STACK
#endif

#if defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_LINUX_AUXVEC_H) && defined(HAVE_SYS_AUXV_H)
# include <linux/auxvec.h> // AT_MINSIGSTKSZ
# include <sys/auxv.h> // getauxval()
Expand All @@ -32,13 +26,6 @@
/* Allocate at maximum 100 MiB of the stack to raise the stack overflow */
#define STACK_OVERFLOW_MAX_SIZE (100 * 1024 * 1024)

#ifndef MS_WINDOWS
/* register() is useless on Windows, because only SIGSEGV, SIGABRT and
SIGILL can be handled by the process, and these signals can only be used
with enable(), not using register() */
# define FAULTHANDLER_USER
#endif

#define PUTS(fd, str) _Py_write_noraise(fd, str, strlen(str))


Expand All @@ -58,12 +45,6 @@
#endif


#ifdef HAVE_SIGACTION
typedef struct sigaction _Py_sighandler_t;
#else
typedef PyOS_sighandler_t _Py_sighandler_t;
#endif

typedef struct {
int signum;
int enabled;
Expand All @@ -72,47 +53,12 @@ typedef struct {
int all_threads;
} fault_handler_t;

static struct {
int enabled;
PyObject *file;
int fd;
int all_threads;
PyInterpreterState *interp;
#ifdef MS_WINDOWS
void *exc_handler;
#endif
} fatal_error = {0, NULL, -1, 0};

static struct {
PyObject *file;
int fd;
PY_TIMEOUT_T timeout_us; /* timeout in microseconds */
int repeat;
PyInterpreterState *interp;
int exit;
char *header;
size_t header_len;
/* The main thread always holds this lock. It is only released when
faulthandler_thread() is interrupted before this thread exits, or at
Python exit. */
PyThread_type_lock cancel_event;
/* released by child thread when joined */
PyThread_type_lock running;
} thread;
#define fatal_error _PyRuntime.faulthandler.fatal_error
#define thread _PyRuntime.faulthandler.thread

#ifdef FAULTHANDLER_USER
typedef struct {
int enabled;
PyObject *file;
int fd;
int all_threads;
int chain;
_Py_sighandler_t previous;
PyInterpreterState *interp;
} user_signal_t;

static user_signal_t *user_signals;

#define user_signals _PyRuntime.faulthandler.user_signals
typedef struct faulthandler_user_signal user_signal_t;
static void faulthandler_user(int signum);
#endif /* FAULTHANDLER_USER */

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

#ifdef FAULTHANDLER_USE_ALT_STACK
static stack_t stack;
static stack_t old_stack;
# define stack _PyRuntime.faulthandler.stack
# define old_stack _PyRuntime.faulthandler.old_stack
#endif


Expand Down Expand Up @@ -1094,7 +1040,7 @@ faulthandler_fatal_error_thread(void *plock)
static PyObject *
faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args)
{
long thread;
long tid;
PyThread_type_lock lock;

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

PyThread_acquire_lock(lock, WAIT_LOCK);

thread = PyThread_start_new_thread(faulthandler_fatal_error_thread, lock);
if (thread == -1) {
tid = PyThread_start_new_thread(faulthandler_fatal_error_thread, lock);
if (tid == -1) {
PyThread_free_lock(lock);
PyErr_SetString(PyExc_RuntimeError, "unable to start the thread");
return NULL;
Expand Down
1 change: 1 addition & 0 deletions PCbuild/pythoncore.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@
<ClInclude Include="..\Include\internal\pycore_dict_state.h" />
<ClInclude Include="..\Include\internal\pycore_dtoa.h" />
<ClInclude Include="..\Include\internal\pycore_exceptions.h" />
<ClInclude Include="..\Include\internal\pycore_faulthandler.h" />
<ClInclude Include="..\Include\internal\pycore_fileutils.h" />
<ClInclude Include="..\Include\internal\pycore_floatobject.h" />
<ClInclude Include="..\Include\internal\pycore_format.h" />
Expand Down
6 changes: 6 additions & 0 deletions PCbuild/pythoncore.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,9 @@
<ClInclude Include="..\Include\internal\pycore_exceptions.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_faulthandler.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_fileutils.h">
<Filter>Include\internal</Filter>
</ClInclude>
Expand All @@ -558,6 +561,9 @@
<ClInclude Include="..\Include\internal\pycore_format.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_function.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_gc.h">
<Filter>Include\internal</Filter>
</ClInclude>
Expand Down
10 changes: 0 additions & 10 deletions Tools/c-analyzer/cpython/globals-to-fix.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -361,23 +361,13 @@ Modules/itertoolsmodule.c - tee_type -
Modules/itertoolsmodule.c - teedataobject_type -
Modules/itertoolsmodule.c - ziplongest_type -

##-----------------------
## state

Modules/faulthandler.c - fatal_error -
Modules/faulthandler.c - thread -
Modules/faulthandler.c - user_signals -
Modules/faulthandler.c - stack -
Modules/faulthandler.c - old_stack -


##################################
## global non-objects to fix in builtin modules

##-----------------------
## state

Modules/faulthandler.c faulthandler_dump_traceback reentrant -
Modules/signalmodule.c - is_tripped -
Modules/signalmodule.c - signal_global_state -
Modules/signalmodule.c - wakeup -
Expand Down
1 change: 1 addition & 0 deletions Tools/c-analyzer/cpython/ignored.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ Python/sysmodule.c - _preinit_xoptions -

# thread-safety
# XXX need race protection?
Modules/faulthandler.c faulthandler_dump_traceback reentrant -
Python/pylifecycle.c _Py_FatalErrorFormat reentrant -
Python/pylifecycle.c fatal_error reentrant -

Expand Down