diff options
author | Victor Stinner <vstinner@python.org> | 2023-09-29 02:43:28 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-29 02:43:28 (GMT) |
commit | 615d7fc34a2b584ba39980db6ed99c90a90a445c (patch) | |
tree | b90f91d38e916635edb18bdc6d9d072934199f0b /Python/traceback.c | |
parent | efe83ad2762e3ea8b396b44947033445c9b31d04 (diff) | |
download | cpython-615d7fc34a2b584ba39980db6ed99c90a90a445c.zip cpython-615d7fc34a2b584ba39980db6ed99c90a90a445c.tar.gz cpython-615d7fc34a2b584ba39980db6ed99c90a90a445c.tar.bz2 |
[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 2e37a38bcbfbe1357436e030538290e7d00b668d)
Diffstat (limited to 'Python/traceback.c')
-rw-r--r-- | Python/traceback.c | 48 |
1 files changed, 38 insertions, 10 deletions
diff --git a/Python/traceback.c b/Python/traceback.c index 7010736..c4f5ec8 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -12,6 +12,7 @@ #include "pycore_parser.h" // _PyParser_ASTFromString #include "pycore_pyarena.h" // _PyArena_Free() #include "pycore_pyerrors.h" // _PyErr_Fetch() +#include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_traceback.h" // EXCEPTION_TB_HEADER @@ -1234,23 +1235,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->cframe->current_frame; + if (tstate_is_freed(tstate)) { + PUTS(fd, " <tstate is freed>\n"); + return; + } + + _PyInterpreterFrame *frame = tstate->cframe->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"); @@ -1305,9 +1328,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. @@ -1323,6 +1343,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(); @@ -1337,14 +1361,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 { |