Skip to content

Commit 2821264

Browse files
Acquire GIL or stop the world when calling _Py_DumpTracebackThreads from faulthandler_thread
1 parent 2f60b8f commit 2821264

4 files changed

Lines changed: 42 additions & 6 deletions

File tree

Include/internal/pycore_traceback.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,16 @@ extern void _Py_DumpTraceback(
5656
It is better to pass NULL to interp and current_tstate, the function tries
5757
different options to retrieve this information.
5858
59+
If skip_current_tstate is 1 then first tstate (current_tstate) will be skiped.
60+
This flag used in faulthandler_thread to skip self.
61+
5962
This function is signal safe. */
6063

6164
extern const char* _Py_DumpTracebackThreads(
6265
int fd,
6366
PyInterpreterState *interp,
64-
PyThreadState *current_tstate);
67+
PyThreadState *current_tstate,
68+
int skip_current_tstate);
6569

6670
/* Write a Unicode object into the file descriptor fd. Encode the string to
6771
ASCII using the backslashreplace error handler.

Modules/faulthandler.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ faulthandler_dump_traceback(int fd, int all_threads,
205205
PyThreadState *tstate = PyGILState_GetThisThreadState();
206206

207207
if (all_threads == 1) {
208-
(void)_Py_DumpTracebackThreads(fd, NULL, tstate);
208+
(void)_Py_DumpTracebackThreads(fd, NULL, tstate, 0);
209209
}
210210
else {
211211
if (all_threads == FT_IGNORE_ALL_THREADS) {
@@ -273,7 +273,7 @@ faulthandler_dump_traceback_py_impl(PyObject *module, PyObject *file,
273273
/* gh-128400: Accessing other thread states while they're running
274274
* isn't safe if those threads are running. */
275275
_PyEval_StopTheWorld(interp);
276-
errmsg = _Py_DumpTracebackThreads(fd, NULL, tstate);
276+
errmsg = _Py_DumpTracebackThreads(fd, NULL, tstate, 0);
277277
_PyEval_StartTheWorld(interp);
278278
if (errmsg != NULL) {
279279
PyErr_SetString(PyExc_RuntimeError, errmsg);
@@ -677,6 +677,13 @@ faulthandler_is_enabled_impl(PyObject *module)
677677
return fatal_error.enabled;
678678
}
679679

680+
// TODO: remove
681+
static int
682+
interp_is_freed(PyInterpreterState *interp)
683+
{
684+
return _PyMem_IsPtrFreed(interp);
685+
}
686+
680687
static void
681688
faulthandler_thread(void *unused)
682689
{
@@ -703,7 +710,25 @@ faulthandler_thread(void *unused)
703710

704711
(void)_Py_write_noraise(thread.fd, thread.header, (int)thread.header_len);
705712

706-
errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, NULL);
713+
PyInterpreterState *interp = thread.interp;
714+
assert(interp != NULL);
715+
716+
if (!interp_is_freed(interp)) {
717+
718+
#ifdef Py_GIL_DISABLED
719+
_PyEval_StopTheWorld(interp);
720+
#else
721+
PyGILState_STATE gil_state = PyGILState_Ensure();
722+
#endif
723+
errmsg = _Py_DumpTracebackThreads(thread.fd, interp, NULL, 1);
724+
725+
#ifdef Py_GIL_DISABLED
726+
_PyEval_StartTheWorld(interp);
727+
#else
728+
PyGILState_Release(gil_state);
729+
#endif
730+
}
731+
707732
ok = (errmsg == NULL);
708733

709734
if (thread.exit)

Python/pylifecycle.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3139,7 +3139,7 @@ _Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp,
31393139

31403140
/* display the current Python stack */
31413141
#ifndef Py_GIL_DISABLED
3142-
_Py_DumpTracebackThreads(fd, interp, tstate);
3142+
_Py_DumpTracebackThreads(fd, interp, tstate, 0);
31433143
#else
31443144
_Py_DumpTraceback(fd, tstate);
31453145
#endif

Python/traceback.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1239,7 +1239,8 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current)
12391239
handlers if signals were received. */
12401240
const char*
12411241
_Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
1242-
PyThreadState *current_tstate)
1242+
PyThreadState *current_tstate,
1243+
int skip_current_tstate)
12431244
{
12441245
if (current_tstate == NULL) {
12451246
/* _Py_DumpTracebackThreads() is called from signal handlers by
@@ -1289,6 +1290,12 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
12891290
_Py_BEGIN_SUPPRESS_IPH
12901291
do
12911292
{
1293+
if (skip_current_tstate && current_tstate == tstate) {
1294+
tstate = PyThreadState_Next(tstate);
1295+
skip_current_tstate = 0;
1296+
continue;
1297+
}
1298+
12921299
if (nthreads != 0)
12931300
PUTS(fd, "\n");
12941301
if (nthreads >= MAX_NTHREADS) {

0 commit comments

Comments
 (0)