summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Python/traceback.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tools/python3/Python/traceback.c')
-rw-r--r--contrib/tools/python3/Python/traceback.c513
1 files changed, 102 insertions, 411 deletions
diff --git a/contrib/tools/python3/Python/traceback.c b/contrib/tools/python3/Python/traceback.c
index fba3594e97c..81960a76927 100644
--- a/contrib/tools/python3/Python/traceback.c
+++ b/contrib/tools/python3/Python/traceback.c
@@ -3,9 +3,8 @@
#include "Python.h"
-#include "pycore_ast.h" // asdl_seq_*
+#include "pycore_ast.h" // asdl_seq_GET()
#include "pycore_call.h" // _PyObject_CallMethodFormat()
-#include "pycore_compile.h" // _PyAST_Optimize
#include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH
#include "pycore_frame.h" // _PyFrame_GetCode()
#include "pycore_interp.h" // PyInterpreterState.gc
@@ -13,30 +12,31 @@
#include "pycore_pyarena.h" // _PyArena_Free()
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
#include "pycore_pystate.h" // _PyThreadState_GET()
+#include "pycore_sysmodule.h" // _PySys_GetOptionalAttr()
#include "pycore_traceback.h" // EXCEPTION_TB_HEADER
-#include "../Parser/pegen.h" // _PyPegen_byte_offset_to_character_offset()
#include "frameobject.h" // PyFrame_New()
-#include "structmember.h" // PyMemberDef
+
#include "osdefs.h" // SEP
-#ifdef HAVE_FCNTL_H
-# include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> // lseek()
#endif
+
#define OFF(x) offsetof(PyTracebackObject, x)
+#define PUTS(fd, str) (void)_Py_write_noraise(fd, str, (int)strlen(str))
-#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
#define MAX_STRING_LENGTH 500
#define MAX_FRAME_DEPTH 100
#define MAX_NTHREADS 100
-/* Function from Parser/tokenizer.c */
+/* Function from Parser/tokenizer/file_tokenizer.c */
extern char* _PyTokenizer_FindEncodingFilename(int, PyObject *);
/*[clinic input]
-class TracebackType "PyTracebackObject *" "&PyTraceback_Type"
+class traceback "PyTracebackObject *" "&PyTraceback_Type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=928fa06c10151120]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=cf96294b2bebc811]*/
#include "clinic/traceback.c.h"
@@ -63,7 +63,7 @@ tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti,
/*[clinic input]
@classmethod
-TracebackType.__new__ as tb_new
+traceback.__new__ as tb_new
tb_next: object
tb_frame: object(type='PyFrameObject *', subclass_of='&PyFrame_Type')
@@ -76,7 +76,7 @@ Create a new traceback object.
static PyObject *
tb_new_impl(PyTypeObject *type, PyObject *tb_next, PyFrameObject *tb_frame,
int tb_lasti, int tb_lineno)
-/*[clinic end generated code: output=fa077debd72d861a input=01cbe8ec8783fca7]*/
+/*[clinic end generated code: output=fa077debd72d861a input=b88143145454cb59]*/
{
if (tb_next == Py_None) {
tb_next = NULL;
@@ -109,12 +109,9 @@ tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_))
static int
tb_get_lineno(PyTracebackObject* tb) {
- PyFrameObject* frame = tb->tb_frame;
+ _PyInterpreterFrame* frame = tb->tb_frame->f_frame;
assert(frame != NULL);
- PyCodeObject *code = PyFrame_GetCode(frame);
- int lineno = PyCode_Addr2Line(code, tb->tb_lasti);
- Py_DECREF(code);
- return lineno;
+ return PyCode_Addr2Line(_PyFrame_GetCode(frame), tb->tb_lasti);
}
static PyObject *
@@ -171,8 +168,8 @@ static PyMethodDef tb_methods[] = {
};
static PyMemberDef tb_memberlist[] = {
- {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY|PY_AUDIT_READ},
- {"tb_lasti", T_INT, OFF(tb_lasti), READONLY},
+ {"tb_frame", _Py_T_OBJECT, OFF(tb_frame), Py_READONLY|Py_AUDIT_READ},
+ {"tb_lasti", Py_T_INT, OFF(tb_lasti), Py_READONLY},
{NULL} /* Sentinel */
};
@@ -349,12 +346,19 @@ _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *
taillen = strlen(tail);
PyThreadState *tstate = _PyThreadState_GET();
- syspath = _PySys_GetAttr(tstate, &_Py_ID(path));
- if (syspath == NULL || !PyList_Check(syspath))
+ if (_PySys_GetOptionalAttr(&_Py_ID(path), &syspath) < 0) {
+ PyErr_Clear();
+ goto error;
+ }
+ if (syspath == NULL || !PyList_Check(syspath)) {
goto error;
+ }
npath = PyList_Size(syspath);
open = PyObject_GetAttr(io, &_Py_ID(open));
+ if (open == NULL) {
+ goto error;
+ }
for (i = 0; i < npath; i++) {
v = PyList_GetItem(syspath, i);
if (v == NULL) {
@@ -394,6 +398,7 @@ error:
result = NULL;
finally:
Py_XDECREF(open);
+ Py_XDECREF(syspath);
Py_DECREF(filebytes);
return result;
}
@@ -417,27 +422,9 @@ _Py_WriteIndent(int indent, PyObject *f)
return 0;
}
-/* Writes indent spaces, followed by the margin if it is not `\0`.
- Returns 0 on success and non-zero on failure.
- */
-int
-_Py_WriteIndentedMargin(int indent, const char *margin, PyObject *f)
-{
- if (_Py_WriteIndent(indent, f) < 0) {
- return -1;
- }
- if (margin) {
- if (PyFile_WriteString(margin, f) < 0) {
- return -1;
- }
- }
- return 0;
-}
-
static int
-display_source_line_with_margin(PyObject *f, PyObject *filename, int lineno, int indent,
- int margin_indent, const char *margin,
- int *truncation, PyObject **line)
+display_source_line(PyObject *f, PyObject *filename, int lineno, int indent,
+ int *truncation, PyObject **line)
{
int fd;
int i;
@@ -565,10 +552,6 @@ display_source_line_with_margin(PyObject *f, PyObject *filename, int lineno, int
*truncation = i - indent;
}
- if (_Py_WriteIndentedMargin(margin_indent, margin, f) < 0) {
- goto error;
- }
-
/* Write some spaces before the line */
if (_Py_WriteIndent(indent, f) < 0) {
goto error;
@@ -594,165 +577,11 @@ int
_Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent,
int *truncation, PyObject **line)
{
- return display_source_line_with_margin(f, filename, lineno, indent, 0,
- NULL, truncation, line);
+ return display_source_line(f, filename, lineno, indent, truncation, line);
}
-/* AST based Traceback Specialization
- *
- * When displaying a new traceback line, for certain syntactical constructs
- * (e.g a subscript, an arithmetic operation) we try to create a representation
- * that separates the primary source of error from the rest.
- *
- * Example specialization of BinOp nodes:
- * Traceback (most recent call last):
- * File "/home/isidentical/cpython/cpython/t.py", line 10, in <module>
- * add_values(1, 2, 'x', 3, 4)
- * File "/home/isidentical/cpython/cpython/t.py", line 2, in add_values
- * return a + b + c + d + e
- * ~~~~~~^~~
- * TypeError: 'NoneType' object is not subscriptable
- */
#define IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\f'))
-
-static int
-extract_anchors_from_expr(const char *segment_str, expr_ty expr, Py_ssize_t *left_anchor, Py_ssize_t *right_anchor,
- char** primary_error_char, char** secondary_error_char)
-{
- switch (expr->kind) {
- case BinOp_kind: {
- expr_ty left = expr->v.BinOp.left;
- expr_ty right = expr->v.BinOp.right;
- for (int i = left->end_col_offset; i < right->col_offset; i++) {
- if (IS_WHITESPACE(segment_str[i])) {
- continue;
- }
-
- *left_anchor = i;
- *right_anchor = i + 1;
-
- // Check whether if this a two-character operator (e.g //)
- if (i + 1 < right->col_offset && !IS_WHITESPACE(segment_str[i + 1])) {
- ++*right_anchor;
- }
-
- // Keep going if the current char is not ')'
- if (i+1 < right->col_offset && (segment_str[i] == ')')) {
- continue;
- }
-
- // Set the error characters
- *primary_error_char = "~";
- *secondary_error_char = "^";
- break;
- }
- return 1;
- }
- case Subscript_kind: {
- *left_anchor = expr->v.Subscript.value->end_col_offset;
- *right_anchor = expr->v.Subscript.slice->end_col_offset + 1;
- Py_ssize_t str_len = strlen(segment_str);
-
- // Move right_anchor and left_anchor forward to the first non-whitespace character that is not ']' and '['
- while (*left_anchor < str_len && (IS_WHITESPACE(segment_str[*left_anchor]) || segment_str[*left_anchor] != '[')) {
- ++*left_anchor;
- }
- while (*right_anchor < str_len && (IS_WHITESPACE(segment_str[*right_anchor]) || segment_str[*right_anchor] != ']')) {
- ++*right_anchor;
- }
- if (*right_anchor < str_len){
- *right_anchor += 1;
- }
-
- // Set the error characters
- *primary_error_char = "~";
- *secondary_error_char = "^";
- return 1;
- }
- default:
- return 0;
- }
-}
-
-static int
-extract_anchors_from_stmt(const char *segment_str, stmt_ty statement, Py_ssize_t *left_anchor, Py_ssize_t *right_anchor,
- char** primary_error_char, char** secondary_error_char)
-{
- switch (statement->kind) {
- case Expr_kind: {
- return extract_anchors_from_expr(segment_str, statement->v.Expr.value, left_anchor, right_anchor,
- primary_error_char, secondary_error_char);
- }
- default:
- return 0;
- }
-}
-
-static int
-extract_anchors_from_line(PyObject *filename, PyObject *line,
- Py_ssize_t start_offset, Py_ssize_t end_offset,
- Py_ssize_t *left_anchor, Py_ssize_t *right_anchor,
- char** primary_error_char, char** secondary_error_char)
-{
- int res = -1;
- PyArena *arena = NULL;
- PyObject *segment = PyUnicode_Substring(line, start_offset, end_offset);
- if (!segment) {
- goto done;
- }
-
- const char *segment_str = PyUnicode_AsUTF8(segment);
- if (!segment_str) {
- goto done;
- }
-
- arena = _PyArena_New();
- if (!arena) {
- goto done;
- }
-
- PyCompilerFlags flags = _PyCompilerFlags_INIT;
-
- _PyASTOptimizeState state;
- state.optimize = _Py_GetConfig()->optimization_level;
- state.ff_features = 0;
-
- mod_ty module = _PyParser_ASTFromString(segment_str, filename, Py_file_input,
- &flags, arena);
- if (!module) {
- goto done;
- }
- if (!_PyAST_Optimize(module, arena, &state)) {
- goto done;
- }
-
- assert(module->kind == Module_kind);
- if (asdl_seq_LEN(module->v.Module.body) == 1) {
- stmt_ty statement = asdl_seq_GET(module->v.Module.body, 0);
- res = extract_anchors_from_stmt(segment_str, statement, left_anchor, right_anchor,
- primary_error_char, secondary_error_char);
- } else {
- res = 0;
- }
-
-done:
- if (res > 0) {
- // Normalize the AST offsets to byte offsets and adjust them with the
- // start of the actual line (instead of the source code segment).
- assert(segment != NULL);
- assert(*left_anchor >= 0);
- assert(*right_anchor >= 0);
- *left_anchor = _PyPegen_byte_offset_to_character_offset(segment, *left_anchor) + start_offset;
- *right_anchor = _PyPegen_byte_offset_to_character_offset(segment, *right_anchor) + start_offset;
- }
- Py_XDECREF(segment);
- if (arena) {
- _PyArena_Free(arena);
- }
- return res;
-}
-
#define _TRACEBACK_SOURCE_LINE_INDENT 4
static inline int
@@ -766,42 +595,14 @@ ignore_source_errors(void) {
return 0;
}
-static inline int
-print_error_location_carets(PyObject *f, int offset, Py_ssize_t start_offset, Py_ssize_t end_offset,
- Py_ssize_t right_start_offset, Py_ssize_t left_end_offset,
- const char *primary, const char *secondary) {
- int special_chars = (left_end_offset != -1 || right_start_offset != -1);
- const char *str;
- while (++offset <= end_offset) {
- if (offset <= start_offset) {
- str = " ";
- } else if (special_chars && left_end_offset < offset && offset <= right_start_offset) {
- str = secondary;
- } else {
- str = primary;
- }
- if (PyFile_WriteString(str, f) < 0) {
- return -1;
- }
- }
- if (PyFile_WriteString("\n", f) < 0) {
- return -1;
- }
- return 0;
-}
-
static int
tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int lineno,
- PyFrameObject *frame, PyObject *name, int margin_indent, const char *margin)
+ PyFrameObject *frame, PyObject *name)
{
if (filename == NULL || name == NULL) {
return -1;
}
- if (_Py_WriteIndentedMargin(margin_indent, margin, f) < 0) {
- return -1;
- }
-
PyObject *line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n",
filename, lineno, name);
if (line == NULL) {
@@ -818,149 +619,13 @@ tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int linen
int truncation = _TRACEBACK_SOURCE_LINE_INDENT;
PyObject* source_line = NULL;
- int rc = display_source_line_with_margin(
+ int rc = display_source_line(
f, filename, lineno, _TRACEBACK_SOURCE_LINE_INDENT,
- margin_indent, margin, &truncation, &source_line);
+ &truncation, &source_line);
if (rc != 0 || !source_line) {
/* ignore errors since we can't report them, can we? */
err = ignore_source_errors();
- goto done;
- }
-
- int code_offset = tb->tb_lasti;
- PyCodeObject* code = frame->f_frame->f_code;
- const Py_ssize_t source_line_len = PyUnicode_GET_LENGTH(source_line);
-
- int start_line;
- int end_line;
- int start_col_byte_offset;
- int end_col_byte_offset;
- if (!PyCode_Addr2Location(code, code_offset, &start_line, &start_col_byte_offset,
- &end_line, &end_col_byte_offset)) {
- goto done;
- }
-
- if (start_line < 0 || end_line < 0
- || start_col_byte_offset < 0
- || end_col_byte_offset < 0)
- {
- goto done;
- }
-
- // When displaying errors, we will use the following generic structure:
- //
- // ERROR LINE ERROR LINE ERROR LINE ERROR LINE ERROR LINE ERROR LINE ERROR LINE
- // ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~
- // | |-> left_end_offset | |-> end_offset
- // |-> start_offset |-> right_start_offset
- //
- // In general we will only have (start_offset, end_offset) but we can gather more information
- // by analyzing the AST of the text between *start_offset* and *end_offset*. If this succeeds
- // we could get *left_end_offset* and *right_start_offset* and some selection of characters for
- // the different ranges (primary_error_char and secondary_error_char). If we cannot obtain the
- // AST information or we cannot identify special ranges within it, then left_end_offset and
- // right_end_offset will be set to -1.
- //
- // To keep the column indicators pertinent, they are not shown when the primary character
- // spans the whole line.
-
- // Convert the utf-8 byte offset to the actual character offset so we print the right number of carets.
- assert(source_line);
- Py_ssize_t start_offset = _PyPegen_byte_offset_to_character_offset(source_line, start_col_byte_offset);
- if (start_offset < 0) {
- err = ignore_source_errors() < 0;
- goto done;
- }
-
- Py_ssize_t end_offset = _PyPegen_byte_offset_to_character_offset(source_line, end_col_byte_offset);
- if (end_offset < 0) {
- err = ignore_source_errors() < 0;
- goto done;
- }
-
- Py_ssize_t left_end_offset = -1;
- Py_ssize_t right_start_offset = -1;
-
- char *primary_error_char = "^";
- char *secondary_error_char = primary_error_char;
-
- if (start_line == end_line) {
- int res = extract_anchors_from_line(filename, source_line, start_offset, end_offset,
- &left_end_offset, &right_start_offset,
- &primary_error_char, &secondary_error_char);
- if (res < 0 && ignore_source_errors() < 0) {
- goto done;
- }
}
- else {
- // If this is a multi-line expression, then we will highlight until
- // the last non-whitespace character.
- const char *source_line_str = PyUnicode_AsUTF8(source_line);
- if (!source_line_str) {
- goto done;
- }
-
- Py_ssize_t i = source_line_len;
- while (--i >= 0) {
- if (!IS_WHITESPACE(source_line_str[i])) {
- break;
- }
- }
-
- end_offset = i + 1;
- }
-
- // Elide indicators if primary char spans the frame line
- Py_ssize_t stripped_line_len = source_line_len - truncation - _TRACEBACK_SOURCE_LINE_INDENT;
- bool has_secondary_ranges = (left_end_offset != -1 || right_start_offset != -1);
- if (end_offset - start_offset == stripped_line_len && !has_secondary_ranges) {
- goto done;
- }
-
- if (_Py_WriteIndentedMargin(margin_indent, margin, f) < 0) {
- err = -1;
- goto done;
- }
-
- // Convert all offsets to display offsets (e.g. the space they would take up if printed
- // on the screen).
- Py_ssize_t dp_start = _PyPegen_calculate_display_width(source_line, start_offset);
- if (dp_start < 0) {
- err = ignore_source_errors() < 0;
- goto done;
- }
-
- Py_ssize_t dp_end = _PyPegen_calculate_display_width(source_line, end_offset);
- if (dp_end < 0) {
- err = ignore_source_errors() < 0;
- goto done;
- }
-
- Py_ssize_t dp_left_end = -1;
- Py_ssize_t dp_right_start = -1;
- if (has_secondary_ranges) {
- dp_left_end = _PyPegen_calculate_display_width(source_line, left_end_offset);
- if (dp_left_end < 0) {
- err = ignore_source_errors() < 0;
- goto done;
- }
-
- dp_right_start = _PyPegen_calculate_display_width(source_line, right_start_offset);
- if (dp_right_start < 0) {
- err = ignore_source_errors() < 0;
- goto done;
- }
- }
-
-
- if (print_error_location_carets(f, truncation, dp_start, dp_end,
- dp_right_start, dp_left_end,
- primary_error_char, secondary_error_char) < 0) {
- err = -1;
- goto done;
- }
-
-done:
Py_XDECREF(source_line);
return err;
}
@@ -985,8 +650,7 @@ tb_print_line_repeated(PyObject *f, long cnt)
}
static int
-tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit,
- int indent, const char *margin)
+tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
{
PyCodeObject *code = NULL;
Py_ssize_t depth = 0;
@@ -1026,7 +690,7 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit,
cnt++;
if (cnt <= TB_RECURSIVE_CUTOFF) {
if (tb_displayline(tb, f, code->co_filename, tb_lineno,
- tb->tb_frame, code->co_name, indent, margin) < 0) {
+ tb->tb_frame, code->co_name) < 0) {
goto error;
}
@@ -1051,8 +715,7 @@ error:
#define PyTraceBack_LIMIT 1000
int
-_PyTraceBack_Print_Indented(PyObject *v, int indent, const char *margin,
- const char *header_margin, const char *header, PyObject *f)
+_PyTraceBack_Print(PyObject *v, const char *header, PyObject *f)
{
PyObject *limitv;
long limit = PyTraceBack_LIMIT;
@@ -1064,26 +727,27 @@ _PyTraceBack_Print_Indented(PyObject *v, int indent, const char *margin,
PyErr_BadInternalCall();
return -1;
}
- limitv = PySys_GetObject("tracebacklimit");
- if (limitv && PyLong_Check(limitv)) {
+ if (_PySys_GetOptionalAttrString("tracebacklimit", &limitv) < 0) {
+ return -1;
+ }
+ else if (limitv != NULL && PyLong_Check(limitv)) {
int overflow;
limit = PyLong_AsLongAndOverflow(limitv, &overflow);
if (overflow > 0) {
limit = LONG_MAX;
}
else if (limit <= 0) {
+ Py_DECREF(limitv);
return 0;
}
}
- if (_Py_WriteIndentedMargin(indent, header_margin, f) < 0) {
- return -1;
- }
+ Py_XDECREF(limitv);
if (PyFile_WriteString(header, f) < 0) {
return -1;
}
- if (tb_printinternal((PyTracebackObject *)v, f, limit, indent, margin) < 0) {
+ if (tb_printinternal((PyTracebackObject *)v, f, limit) < 0) {
return -1;
}
@@ -1093,12 +757,8 @@ _PyTraceBack_Print_Indented(PyObject *v, int indent, const char *margin,
int
PyTraceBack_Print(PyObject *v, PyObject *f)
{
- int indent = 0;
- const char *margin = NULL;
- const char *header_margin = NULL;
const char *header = EXCEPTION_TB_HEADER;
-
- return _PyTraceBack_Print_Indented(v, indent, margin, header_margin, header, f);
+ return _PyTraceBack_Print(v, header, f);
}
/* Format an integer in range [0; 0xffffffff] to decimal and write it
@@ -1125,7 +785,7 @@ _Py_DumpDecimal(int fd, size_t value)
value /= 10;
} while (value);
- _Py_write_noraise(fd, ptr, end - ptr);
+ (void)_Py_write_noraise(fd, ptr, end - ptr);
}
/* Format an integer as hexadecimal with width digits into fd file descriptor.
@@ -1150,7 +810,7 @@ _Py_DumpHexadecimal(int fd, uintptr_t value, Py_ssize_t width)
value >>= 4;
} while ((end - ptr) < width || value);
- _Py_write_noraise(fd, ptr, end - ptr);
+ (void)_Py_write_noraise(fd, ptr, end - ptr);
}
void
@@ -1203,7 +863,7 @@ _Py_DumpASCII(int fd, PyObject *text)
}
if (!need_escape) {
// The string can be written with a single write() syscall
- _Py_write_noraise(fd, str, size);
+ (void)_Py_write_noraise(fd, str, size);
goto done;
}
}
@@ -1213,7 +873,7 @@ _Py_DumpASCII(int fd, PyObject *text)
if (' ' <= ch && ch <= 126) {
/* printable ASCII character */
char c = (char)ch;
- _Py_write_noraise(fd, &c, 1);
+ (void)_Py_write_noraise(fd, &c, 1);
}
else if (ch <= 0xff) {
PUTS(fd, "\\x");
@@ -1237,14 +897,24 @@ done:
/* 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_CSTACK);
+ if (frame->owner == FRAME_OWNED_BY_CSTACK) {
+ /* Ignore trampoline frame */
+ return 0;
+ }
+
+ PyCodeObject *code = _PyFrame_SafeGetCode(frame);
+ if (code == NULL) {
+ return -1;
+ }
- PyCodeObject *code = frame->f_code;
+ int res = 0;
PUTS(fd, " File ");
if (code->co_filename != NULL
&& PyUnicode_Check(code->co_filename))
@@ -1252,29 +922,36 @@ dump_frame(int fd, _PyInterpreterFrame *frame)
PUTS(fd, "\"");
_Py_DumpASCII(fd, code->co_filename);
PUTS(fd, "\"");
- } else {
+ }
+ else {
PUTS(fd, "???");
+ res = -1;
}
- int lineno = PyUnstable_InterpreterFrame_GetLine(frame);
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
@@ -1286,6 +963,9 @@ tstate_is_freed(PyThreadState *tstate)
if (_PyMem_IsPtrFreed(tstate->interp)) {
return 1;
}
+ if (_PyMem_IsULongFreed(tstate->thread_id)) {
+ return 1;
+ }
return 0;
}
@@ -1305,11 +985,11 @@ 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;
}
- _PyInterpreterFrame *frame = tstate->cframe->current_frame;
+ _PyInterpreterFrame *frame = tstate->current_frame;
if (frame == NULL) {
PUTS(fd, " <no Python frame>\n");
return;
@@ -1317,24 +997,29 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
unsigned int depth = 0;
while (1) {
- if (frame->owner == FRAME_OWNED_BY_CSTACK) {
- /* Trampoline frame */
- frame = frame->previous;
- if (frame == NULL) {
- break;
+ if (MAX_FRAME_DEPTH <= depth) {
+ if (MAX_FRAME_DEPTH < depth) {
+ PUTS(fd, "plus ");
+ _Py_DumpDecimal(fd, depth);
+ PUTS(fd, " frames\n");
}
+ break;
+ }
- /* Can't have more than one shim frame in a row */
- assert(frame->owner != FRAME_OWNED_BY_CSTACK);
+ if (_PyMem_IsPtrFreed(frame)) {
+ PUTS(fd, " <freed frame>\n");
+ break;
}
+ // Read frame->previous early since memory can be freed during
+ // dump_frame()
+ _PyInterpreterFrame *previous = frame->previous;
- if (MAX_FRAME_DEPTH <= depth) {
- PUTS(fd, " ...\n");
+ if (dump_frame(fd, frame) < 0) {
+ PUTS(fd, " <invalid frame>\n");
break;
}
- dump_frame(fd, frame);
- frame = frame->previous;
+ frame = previous;
if (frame == NULL) {
break;
}
@@ -1425,7 +1110,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
@@ -1436,11 +1120,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);