Skip to content

Commit ff56597

Browse files
authored
bpo-26558: Fix Py_FatalError() with GIL released (GH-10267) (GH-10270)
Don't call _Py_FatalError_PrintExc() nor flush_std_files() if the current thread doesn't hold the GIL, or if the current thread has no Python state thread. (cherry picked from commit 3a228ab)
1 parent 907b07e commit ff56597

File tree

1 file changed

+26
-10
lines changed

1 file changed

+26
-10
lines changed

‎Python/pylifecycle.c‎

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,12 +1356,6 @@ _Py_FatalError_PrintExc(int fd)
13561356
PyObject *exception, *v, *tb;
13571357
int has_tb;
13581358

1359-
if (PyThreadState_GET() == NULL) {
1360-
/* The GIL is released: trying to acquire it is likely to deadlock,
1361-
just give up. */
1362-
return 0;
1363-
}
1364-
13651359
PyErr_Fetch(&exception, &v, &tb);
13661360
if (exception == NULL) {
13671361
/* No current exception */
@@ -1425,18 +1419,40 @@ Py_FatalError(const char *msg)
14251419
fprintf(stderr, "Fatal Python error: %s\n", msg);
14261420
fflush(stderr); /* it helps in Windows debug build */
14271421

1428-
/* Print the exception (if an exception is set) with its traceback,
1429-
* or display the current Python stack. */
1430-
if (!_Py_FatalError_PrintExc(fd))
1422+
/* Check if the current thread has a Python thread state
1423+
and holds the GIL */
1424+
PyThreadState *tss_tstate = PyGILState_GetThisThreadState();
1425+
if (tss_tstate != NULL) {
1426+
PyThreadState *tstate = PyThreadState_GET();
1427+
if (tss_tstate != tstate) {
1428+
/* The Python thread does not hold the GIL */
1429+
tss_tstate = NULL;
1430+
}
1431+
}
1432+
else {
1433+
/* Py_FatalError() has been called from a C thread
1434+
which has no Python thread state. */
1435+
}
1436+
int has_tstate_and_gil = (tss_tstate != NULL);
1437+
1438+
if (has_tstate_and_gil) {
1439+
/* If an exception is set, print the exception with its traceback */
1440+
if (!_Py_FatalError_PrintExc(fd)) {
1441+
/* No exception is set, or an exception is set without traceback */
1442+
_Py_FatalError_DumpTracebacks(fd);
1443+
}
1444+
}
1445+
else {
14311446
_Py_FatalError_DumpTracebacks(fd);
1447+
}
14321448

14331449
/* The main purpose of faulthandler is to display the traceback. We already
14341450
* did our best to display it. So faulthandler can now be disabled.
14351451
* (Don't trigger it on abort().) */
14361452
_PyFaulthandler_Fini();
14371453

14381454
/* Check if the current Python thread hold the GIL */
1439-
if (PyThreadState_GET() != NULL) {
1455+
if (has_tstate_and_gil) {
14401456
/* Flush sys.stdout and sys.stderr */
14411457
flush_std_files();
14421458
}

0 commit comments

Comments
 (0)