diff --git a/Include/internal/pycore_traceback.h b/Include/internal/pycore_traceback.h index d71dd288699..a4f125e073d 100644 --- a/Include/internal/pycore_traceback.h +++ b/Include/internal/pycore_traceback.h @@ -100,6 +100,7 @@ extern int _Py_WriteIndentedMargin(int, const char*, PyObject *); extern int _Py_WriteIndent(int, PyObject *); // Export for the faulthandler module +PyAPI_FUNC(void) _Py_InitDumpStack(void); PyAPI_FUNC(void) _Py_DumpStack(int fd); #ifdef __cplusplus diff --git a/Misc/NEWS.d/next/Library/2025-07-28-20-48-32.gh-issue-137185.fgI7-B.rst b/Misc/NEWS.d/next/Library/2025-07-28-20-48-32.gh-issue-137185.fgI7-B.rst new file mode 100644 index 00000000000..89398dff147 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-28-20-48-32.gh-issue-137185.fgI7-B.rst @@ -0,0 +1,2 @@ +Fix a potential async-signal-safety issue in :mod:`faulthandler` when +printing C stack traces. diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index d49ce794d88..2495faa3817 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -525,6 +525,11 @@ faulthandler_enable(void) } #endif + // gh-137185: Initialize C stack trace dumping outside of the signal + // handler. Specifically, we call backtrace() to ensure that libgcc is + // dynamically loaded outside of the signal handler. + _Py_InitDumpStack(); + for (size_t i=0; i < faulthandler_nsignals; i++) { fault_handler_t *handler; int err; diff --git a/Python/traceback.c b/Python/traceback.c index f3c5644aeb1..11e52936f30 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -1327,3 +1327,13 @@ _Py_DumpStack(int fd) PUTS(fd, " \n"); } #endif + +void +_Py_InitDumpStack(void) +{ +#ifdef CAN_C_BACKTRACE + // gh-137185: Call backtrace() once to force libgcc to be loaded early. + void *callstack[1]; + (void)backtrace(callstack, 1); +#endif +}