mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-140815: Fix faulthandler for invalid/freed frame (#140921)
faulthandler now detects if a frame or a code object is invalid or freed. Add helper functions: * _PyCode_SafeAddr2Line() * _PyFrame_SafeGetCode() * _PyFrame_SafeGetLasti() _PyMem_IsPtrFreed() now detects pointers in [-0xff, 0xff] range as freed.
This commit is contained in:
parent
08115d241a
commit
a84181c31b
6 changed files with 128 additions and 33 deletions
|
|
@ -1028,14 +1028,24 @@ _Py_DumpWideString(int fd, wchar_t *str)
|
|||
|
||||
/* Write a frame into the file fd: "File "xxx", line xxx in xxx".
|
||||
|
||||
This function is signal safe. */
|
||||
This function is signal safe.
|
||||
|
||||
static void
|
||||
Return 0 on success. Return -1 if the frame is invalid. */
|
||||
|
||||
static int
|
||||
dump_frame(int fd, _PyInterpreterFrame *frame)
|
||||
{
|
||||
assert(frame->owner < FRAME_OWNED_BY_INTERPRETER);
|
||||
if (frame->owner == FRAME_OWNED_BY_INTERPRETER) {
|
||||
/* Ignore trampoline frame */
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyCodeObject *code =_PyFrame_GetCode(frame);
|
||||
PyCodeObject *code = _PyFrame_SafeGetCode(frame);
|
||||
if (code == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
PUTS(fd, " File ");
|
||||
if (code->co_filename != NULL
|
||||
&& PyUnicode_Check(code->co_filename))
|
||||
|
|
@ -1043,29 +1053,36 @@ dump_frame(int fd, _PyInterpreterFrame *frame)
|
|||
PUTS(fd, "\"");
|
||||
_Py_DumpASCII(fd, code->co_filename);
|
||||
PUTS(fd, "\"");
|
||||
} else {
|
||||
PUTS(fd, "???");
|
||||
}
|
||||
int lasti = PyUnstable_InterpreterFrame_GetLasti(frame);
|
||||
int lineno = _PyCode_Addr2LineNoTstate(code, lasti);
|
||||
else {
|
||||
PUTS(fd, "???");
|
||||
res = -1;
|
||||
}
|
||||
|
||||
PUTS(fd, ", line ");
|
||||
int lasti = _PyFrame_SafeGetLasti(frame);
|
||||
int lineno = -1;
|
||||
if (lasti >= 0) {
|
||||
lineno = _PyCode_SafeAddr2Line(code, lasti);
|
||||
}
|
||||
if (lineno >= 0) {
|
||||
_Py_DumpDecimal(fd, (size_t)lineno);
|
||||
}
|
||||
else {
|
||||
PUTS(fd, "???");
|
||||
res = -1;
|
||||
}
|
||||
PUTS(fd, " in ");
|
||||
|
||||
if (code->co_name != NULL
|
||||
&& PyUnicode_Check(code->co_name)) {
|
||||
PUTS(fd, " in ");
|
||||
if (code->co_name != NULL && PyUnicode_Check(code->co_name)) {
|
||||
_Py_DumpASCII(fd, code->co_name);
|
||||
}
|
||||
else {
|
||||
PUTS(fd, "???");
|
||||
res = -1;
|
||||
}
|
||||
|
||||
PUTS(fd, "\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1108,17 +1125,6 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
|
|||
|
||||
unsigned int depth = 0;
|
||||
while (1) {
|
||||
if (frame->owner == FRAME_OWNED_BY_INTERPRETER) {
|
||||
/* Trampoline frame */
|
||||
frame = frame->previous;
|
||||
if (frame == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Can't have more than one shim frame in a row */
|
||||
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
|
||||
}
|
||||
|
||||
if (MAX_FRAME_DEPTH <= depth) {
|
||||
if (MAX_FRAME_DEPTH < depth) {
|
||||
PUTS(fd, "plus ");
|
||||
|
|
@ -1128,7 +1134,15 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
|
|||
break;
|
||||
}
|
||||
|
||||
dump_frame(fd, frame);
|
||||
if (_PyMem_IsPtrFreed(frame)) {
|
||||
PUTS(fd, " <freed frame>\n");
|
||||
break;
|
||||
}
|
||||
if (dump_frame(fd, frame) < 0) {
|
||||
PUTS(fd, " <invalid frame>\n");
|
||||
break;
|
||||
}
|
||||
|
||||
frame = frame->previous;
|
||||
if (frame == NULL) {
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue