Skip to content

Commit 615d7fc

Browse files
authored
[3.11] gh-110052: Fix faulthandler for freed tstate (#110069) (#110072)
gh-110052: Fix faulthandler for freed tstate (#110069) faulthandler now detected freed interp and freed tstate, and no longer dereference them. Backport to 3.11: add pycore_pymem.h include to traceback.c. (cherry picked from commit 2e37a38)
1 parent efe83ad commit 615d7fc

File tree

2 files changed

+39
-12
lines changed

2 files changed

+39
-12
lines changed

Modules/faulthandler.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,6 @@ faulthandler_dump_traceback(int fd, int all_threads,
231231
PyInterpreterState *interp)
232232
{
233233
static volatile int reentrant = 0;
234-
PyThreadState *tstate;
235234

236235
if (reentrant)
237236
return;
@@ -246,7 +245,7 @@ faulthandler_dump_traceback(int fd, int all_threads,
246245
fault if the thread released the GIL, and so this function cannot be
247246
used. Read the thread specific storage (TSS) instead: call
248247
PyGILState_GetThisThreadState(). */
249-
tstate = PyGILState_GetThisThreadState();
248+
PyThreadState *tstate = PyGILState_GetThisThreadState();
250249

251250
if (all_threads) {
252251
(void)_Py_DumpTracebackThreads(fd, NULL, tstate);

Python/traceback.c

+38-10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "pycore_parser.h" // _PyParser_ASTFromString
1313
#include "pycore_pyarena.h" // _PyArena_Free()
1414
#include "pycore_pyerrors.h" // _PyErr_Fetch()
15+
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
1516
#include "pycore_pystate.h" // _PyThreadState_GET()
1617
#include "pycore_traceback.h" // EXCEPTION_TB_HEADER
1718

@@ -1234,23 +1235,45 @@ dump_frame(int fd, _PyInterpreterFrame *frame)
12341235
PUTS(fd, "\n");
12351236
}
12361237

1238+
static int
1239+
tstate_is_freed(PyThreadState *tstate)
1240+
{
1241+
if (_PyMem_IsPtrFreed(tstate)) {
1242+
return 1;
1243+
}
1244+
if (_PyMem_IsPtrFreed(tstate->interp)) {
1245+
return 1;
1246+
}
1247+
return 0;
1248+
}
1249+
1250+
1251+
static int
1252+
interp_is_freed(PyInterpreterState *interp)
1253+
{
1254+
return _PyMem_IsPtrFreed(interp);
1255+
}
1256+
1257+
12371258
static void
12381259
dump_traceback(int fd, PyThreadState *tstate, int write_header)
12391260
{
1240-
_PyInterpreterFrame *frame;
1241-
unsigned int depth;
1242-
12431261
if (write_header) {
12441262
PUTS(fd, "Stack (most recent call first):\n");
12451263
}
12461264

1247-
frame = tstate->cframe->current_frame;
1265+
if (tstate_is_freed(tstate)) {
1266+
PUTS(fd, " <tstate is freed>\n");
1267+
return;
1268+
}
1269+
1270+
_PyInterpreterFrame *frame = tstate->cframe->current_frame;
12481271
if (frame == NULL) {
12491272
PUTS(fd, " <no Python frame>\n");
12501273
return;
12511274
}
12521275

1253-
depth = 0;
1276+
unsigned int depth = 0;
12541277
while (1) {
12551278
if (MAX_FRAME_DEPTH <= depth) {
12561279
PUTS(fd, " ...\n");
@@ -1305,9 +1328,6 @@ const char*
13051328
_Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
13061329
PyThreadState *current_tstate)
13071330
{
1308-
PyThreadState *tstate;
1309-
unsigned int nthreads;
1310-
13111331
if (current_tstate == NULL) {
13121332
/* _Py_DumpTracebackThreads() is called from signal handlers by
13131333
faulthandler.
@@ -1323,6 +1343,10 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
13231343
current_tstate = PyGILState_GetThisThreadState();
13241344
}
13251345

1346+
if (current_tstate != NULL && tstate_is_freed(current_tstate)) {
1347+
return "tstate is freed";
1348+
}
1349+
13261350
if (interp == NULL) {
13271351
if (current_tstate == NULL) {
13281352
interp = _PyGILState_GetInterpreterStateUnsafe();
@@ -1337,14 +1361,18 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
13371361
}
13381362
assert(interp != NULL);
13391363

1364+
if (interp_is_freed(interp)) {
1365+
return "interp is freed";
1366+
}
1367+
13401368
/* Get the current interpreter from the current thread */
1341-
tstate = PyInterpreterState_ThreadHead(interp);
1369+
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
13421370
if (tstate == NULL)
13431371
return "unable to get the thread head state";
13441372

13451373
/* Dump the traceback of each thread */
13461374
tstate = PyInterpreterState_ThreadHead(interp);
1347-
nthreads = 0;
1375+
unsigned int nthreads = 0;
13481376
_Py_BEGIN_SUPPRESS_IPH
13491377
do
13501378
{

0 commit comments

Comments
 (0)