[3.13] gh-116008: Detect freed thread state in faulthandler (#141988) (#142017)

gh-116008: Detect freed thread state in faulthandler (#141988)

Add _PyMem_IsULongFreed() function.

(cherry picked from commit d5d9e89dde)
This commit is contained in:
Victor Stinner 2025-11-27 17:55:31 +01:00 committed by GitHub
parent 9756d8c637
commit 80b752285d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 37 additions and 3 deletions

View file

@ -960,6 +960,9 @@ tstate_is_freed(PyThreadState *tstate)
if (_PyMem_IsPtrFreed(tstate->interp)) {
return 1;
}
if (_PyMem_IsULongFreed(tstate->thread_id)) {
return 1;
}
return 0;
}
@ -979,7 +982,7 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
}
if (tstate_is_freed(tstate)) {
PUTS(fd, " <tstate is freed>\n");
PUTS(fd, " <freed thread state>\n");
return;
}
@ -1004,12 +1007,16 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
PUTS(fd, " <freed frame>\n");
break;
}
// Read frame->previous early since memory can be freed during
// dump_frame()
_PyInterpreterFrame *previous = frame->previous;
if (dump_frame(fd, frame) < 0) {
PUTS(fd, " <invalid frame>\n");
break;
}
frame = frame->previous;
frame = previous;
if (frame == NULL) {
break;
}
@ -1100,7 +1107,6 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
return "unable to get the thread head state";
/* Dump the traceback of each thread */
tstate = PyInterpreterState_ThreadHead(interp);
unsigned int nthreads = 0;
_Py_BEGIN_SUPPRESS_IPH
do
@ -1111,11 +1117,18 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
PUTS(fd, "...\n");
break;
}
if (tstate_is_freed(tstate)) {
PUTS(fd, "<freed thread state>\n");
break;
}
write_thread_id(fd, tstate, tstate == current_tstate);
if (tstate == current_tstate && tstate->interp->gc.collecting) {
PUTS(fd, " Garbage-collecting\n");
}
dump_traceback(fd, tstate, 0);
tstate = PyThreadState_Next(tstate);
nthreads++;
} while (tstate != NULL);