mirror of https://github.com/python/cpython
gh-110052: Fix faulthandler for freed tstate (#110069)
faulthandler now detected freed interp and freed tstate, and no longer dereference them.
This commit is contained in:
parent
235aacdeed
commit
2e37a38bcb
|
@ -174,7 +174,6 @@ faulthandler_dump_traceback(int fd, int all_threads,
|
|||
PyInterpreterState *interp)
|
||||
{
|
||||
static volatile int reentrant = 0;
|
||||
PyThreadState *tstate;
|
||||
|
||||
if (reentrant)
|
||||
return;
|
||||
|
@ -189,7 +188,7 @@ faulthandler_dump_traceback(int fd, int all_threads,
|
|||
fault if the thread released the GIL, and so this function cannot be
|
||||
used. Read the thread specific storage (TSS) instead: call
|
||||
PyGILState_GetThisThreadState(). */
|
||||
tstate = PyGILState_GetThisThreadState();
|
||||
PyThreadState *tstate = PyGILState_GetThisThreadState();
|
||||
|
||||
if (all_threads) {
|
||||
(void)_Py_DumpTracebackThreads(fd, NULL, tstate);
|
||||
|
|
|
@ -1215,23 +1215,45 @@ dump_frame(int fd, _PyInterpreterFrame *frame)
|
|||
PUTS(fd, "\n");
|
||||
}
|
||||
|
||||
static int
|
||||
tstate_is_freed(PyThreadState *tstate)
|
||||
{
|
||||
if (_PyMem_IsPtrFreed(tstate)) {
|
||||
return 1;
|
||||
}
|
||||
if (_PyMem_IsPtrFreed(tstate->interp)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
interp_is_freed(PyInterpreterState *interp)
|
||||
{
|
||||
return _PyMem_IsPtrFreed(interp);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dump_traceback(int fd, PyThreadState *tstate, int write_header)
|
||||
{
|
||||
_PyInterpreterFrame *frame;
|
||||
unsigned int depth;
|
||||
|
||||
if (write_header) {
|
||||
PUTS(fd, "Stack (most recent call first):\n");
|
||||
}
|
||||
|
||||
frame = tstate->current_frame;
|
||||
if (tstate_is_freed(tstate)) {
|
||||
PUTS(fd, " <tstate is freed>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
_PyInterpreterFrame *frame = tstate->current_frame;
|
||||
if (frame == NULL) {
|
||||
PUTS(fd, " <no Python frame>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
depth = 0;
|
||||
unsigned int depth = 0;
|
||||
while (1) {
|
||||
if (MAX_FRAME_DEPTH <= depth) {
|
||||
PUTS(fd, " ...\n");
|
||||
|
@ -1295,9 +1317,6 @@ const char*
|
|||
_Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
|
||||
PyThreadState *current_tstate)
|
||||
{
|
||||
PyThreadState *tstate;
|
||||
unsigned int nthreads;
|
||||
|
||||
if (current_tstate == NULL) {
|
||||
/* _Py_DumpTracebackThreads() is called from signal handlers by
|
||||
faulthandler.
|
||||
|
@ -1313,6 +1332,10 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
|
|||
current_tstate = PyGILState_GetThisThreadState();
|
||||
}
|
||||
|
||||
if (current_tstate != NULL && tstate_is_freed(current_tstate)) {
|
||||
return "tstate is freed";
|
||||
}
|
||||
|
||||
if (interp == NULL) {
|
||||
if (current_tstate == NULL) {
|
||||
interp = _PyGILState_GetInterpreterStateUnsafe();
|
||||
|
@ -1327,14 +1350,18 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
|
|||
}
|
||||
assert(interp != NULL);
|
||||
|
||||
if (interp_is_freed(interp)) {
|
||||
return "interp is freed";
|
||||
}
|
||||
|
||||
/* Get the current interpreter from the current thread */
|
||||
tstate = PyInterpreterState_ThreadHead(interp);
|
||||
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
|
||||
if (tstate == NULL)
|
||||
return "unable to get the thread head state";
|
||||
|
||||
/* Dump the traceback of each thread */
|
||||
tstate = PyInterpreterState_ThreadHead(interp);
|
||||
nthreads = 0;
|
||||
unsigned int nthreads = 0;
|
||||
_Py_BEGIN_SUPPRESS_IPH
|
||||
do
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue