mirror of
https://github.com/python/cpython.git
synced 2025-07-16 07:45:20 +00:00
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 2e37a38bcb
)
This commit is contained in:
parent
efe83ad276
commit
615d7fc34a
2 changed files with 39 additions and 12 deletions
|
@ -231,7 +231,6 @@ faulthandler_dump_traceback(int fd, int all_threads,
|
||||||
PyInterpreterState *interp)
|
PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
static volatile int reentrant = 0;
|
static volatile int reentrant = 0;
|
||||||
PyThreadState *tstate;
|
|
||||||
|
|
||||||
if (reentrant)
|
if (reentrant)
|
||||||
return;
|
return;
|
||||||
|
@ -246,7 +245,7 @@ faulthandler_dump_traceback(int fd, int all_threads,
|
||||||
fault if the thread released the GIL, and so this function cannot be
|
fault if the thread released the GIL, and so this function cannot be
|
||||||
used. Read the thread specific storage (TSS) instead: call
|
used. Read the thread specific storage (TSS) instead: call
|
||||||
PyGILState_GetThisThreadState(). */
|
PyGILState_GetThisThreadState(). */
|
||||||
tstate = PyGILState_GetThisThreadState();
|
PyThreadState *tstate = PyGILState_GetThisThreadState();
|
||||||
|
|
||||||
if (all_threads) {
|
if (all_threads) {
|
||||||
(void)_Py_DumpTracebackThreads(fd, NULL, tstate);
|
(void)_Py_DumpTracebackThreads(fd, NULL, tstate);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "pycore_parser.h" // _PyParser_ASTFromString
|
#include "pycore_parser.h" // _PyParser_ASTFromString
|
||||||
#include "pycore_pyarena.h" // _PyArena_Free()
|
#include "pycore_pyarena.h" // _PyArena_Free()
|
||||||
#include "pycore_pyerrors.h" // _PyErr_Fetch()
|
#include "pycore_pyerrors.h" // _PyErr_Fetch()
|
||||||
|
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
|
||||||
#include "pycore_pystate.h" // _PyThreadState_GET()
|
#include "pycore_pystate.h" // _PyThreadState_GET()
|
||||||
#include "pycore_traceback.h" // EXCEPTION_TB_HEADER
|
#include "pycore_traceback.h" // EXCEPTION_TB_HEADER
|
||||||
|
|
||||||
|
@ -1234,23 +1235,45 @@ dump_frame(int fd, _PyInterpreterFrame *frame)
|
||||||
PUTS(fd, "\n");
|
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
|
static void
|
||||||
dump_traceback(int fd, PyThreadState *tstate, int write_header)
|
dump_traceback(int fd, PyThreadState *tstate, int write_header)
|
||||||
{
|
{
|
||||||
_PyInterpreterFrame *frame;
|
|
||||||
unsigned int depth;
|
|
||||||
|
|
||||||
if (write_header) {
|
if (write_header) {
|
||||||
PUTS(fd, "Stack (most recent call first):\n");
|
PUTS(fd, "Stack (most recent call first):\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = tstate->cframe->current_frame;
|
if (tstate_is_freed(tstate)) {
|
||||||
|
PUTS(fd, " <tstate is freed>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_PyInterpreterFrame *frame = tstate->cframe->current_frame;
|
||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
PUTS(fd, " <no Python frame>\n");
|
PUTS(fd, " <no Python frame>\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
depth = 0;
|
unsigned int depth = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (MAX_FRAME_DEPTH <= depth) {
|
if (MAX_FRAME_DEPTH <= depth) {
|
||||||
PUTS(fd, " ...\n");
|
PUTS(fd, " ...\n");
|
||||||
|
@ -1305,9 +1328,6 @@ const char*
|
||||||
_Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
|
_Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
|
||||||
PyThreadState *current_tstate)
|
PyThreadState *current_tstate)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate;
|
|
||||||
unsigned int nthreads;
|
|
||||||
|
|
||||||
if (current_tstate == NULL) {
|
if (current_tstate == NULL) {
|
||||||
/* _Py_DumpTracebackThreads() is called from signal handlers by
|
/* _Py_DumpTracebackThreads() is called from signal handlers by
|
||||||
faulthandler.
|
faulthandler.
|
||||||
|
@ -1323,6 +1343,10 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
|
||||||
current_tstate = PyGILState_GetThisThreadState();
|
current_tstate = PyGILState_GetThisThreadState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (current_tstate != NULL && tstate_is_freed(current_tstate)) {
|
||||||
|
return "tstate is freed";
|
||||||
|
}
|
||||||
|
|
||||||
if (interp == NULL) {
|
if (interp == NULL) {
|
||||||
if (current_tstate == NULL) {
|
if (current_tstate == NULL) {
|
||||||
interp = _PyGILState_GetInterpreterStateUnsafe();
|
interp = _PyGILState_GetInterpreterStateUnsafe();
|
||||||
|
@ -1337,14 +1361,18 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
|
||||||
}
|
}
|
||||||
assert(interp != NULL);
|
assert(interp != NULL);
|
||||||
|
|
||||||
|
if (interp_is_freed(interp)) {
|
||||||
|
return "interp is freed";
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the current interpreter from the current thread */
|
/* Get the current interpreter from the current thread */
|
||||||
tstate = PyInterpreterState_ThreadHead(interp);
|
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
|
||||||
if (tstate == NULL)
|
if (tstate == NULL)
|
||||||
return "unable to get the thread head state";
|
return "unable to get the thread head state";
|
||||||
|
|
||||||
/* Dump the traceback of each thread */
|
/* Dump the traceback of each thread */
|
||||||
tstate = PyInterpreterState_ThreadHead(interp);
|
tstate = PyInterpreterState_ThreadHead(interp);
|
||||||
nthreads = 0;
|
unsigned int nthreads = 0;
|
||||||
_Py_BEGIN_SUPPRESS_IPH
|
_Py_BEGIN_SUPPRESS_IPH
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue