Line data Source code
1 :
2 : /* Traceback implementation */
3 :
4 : #include "Python.h"
5 :
6 : #include "pycore_ast.h" // asdl_seq_*
7 : #include "pycore_call.h" // _PyObject_CallMethodFormat()
8 : #include "pycore_compile.h" // _PyAST_Optimize
9 : #include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH
10 : #include "pycore_frame.h" // _PyFrame_GetCode()
11 : #include "pycore_interp.h" // PyInterpreterState.gc
12 : #include "pycore_parser.h" // _PyParser_ASTFromString
13 : #include "pycore_pyarena.h" // _PyArena_Free()
14 : #include "pycore_pyerrors.h" // _PyErr_Fetch()
15 : #include "pycore_pystate.h" // _PyThreadState_GET()
16 : #include "pycore_traceback.h" // EXCEPTION_TB_HEADER
17 :
18 : #include "../Parser/pegen.h" // _PyPegen_byte_offset_to_character_offset()
19 : #include "frameobject.h" // PyFrame_New()
20 : #include "structmember.h" // PyMemberDef
21 : #include "osdefs.h" // SEP
22 : #ifdef HAVE_FCNTL_H
23 : # include <fcntl.h>
24 : #endif
25 :
26 : #define OFF(x) offsetof(PyTracebackObject, x)
27 :
28 : #define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
29 : #define MAX_STRING_LENGTH 500
30 : #define MAX_FRAME_DEPTH 100
31 : #define MAX_NTHREADS 100
32 :
33 : /* Function from Parser/tokenizer.c */
34 : extern char* _PyTokenizer_FindEncodingFilename(int, PyObject *);
35 :
36 : /*[clinic input]
37 : class TracebackType "PyTracebackObject *" "&PyTraceback_Type"
38 : [clinic start generated code]*/
39 : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=928fa06c10151120]*/
40 :
41 : #include "clinic/traceback.c.h"
42 :
43 : static PyObject *
44 6344410 : tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti,
45 : int lineno)
46 : {
47 : PyTracebackObject *tb;
48 6344410 : if ((next != NULL && !PyTraceBack_Check(next)) ||
49 6344410 : frame == NULL || !PyFrame_Check(frame)) {
50 0 : PyErr_BadInternalCall();
51 0 : return NULL;
52 : }
53 6344410 : tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
54 6344410 : if (tb != NULL) {
55 6344410 : Py_XINCREF(next);
56 6344410 : tb->tb_next = next;
57 6344410 : Py_XINCREF(frame);
58 6344410 : tb->tb_frame = frame;
59 6344410 : tb->tb_lasti = lasti;
60 6344410 : tb->tb_lineno = lineno;
61 6344410 : PyObject_GC_Track(tb);
62 : }
63 6344410 : return (PyObject *)tb;
64 : }
65 :
66 : /*[clinic input]
67 : @classmethod
68 : TracebackType.__new__ as tb_new
69 :
70 : tb_next: object
71 : tb_frame: object(type='PyFrameObject *', subclass_of='&PyFrame_Type')
72 : tb_lasti: int
73 : tb_lineno: int
74 :
75 : Create a new traceback object.
76 : [clinic start generated code]*/
77 :
78 : static PyObject *
79 5 : tb_new_impl(PyTypeObject *type, PyObject *tb_next, PyFrameObject *tb_frame,
80 : int tb_lasti, int tb_lineno)
81 : /*[clinic end generated code: output=fa077debd72d861a input=01cbe8ec8783fca7]*/
82 : {
83 5 : if (tb_next == Py_None) {
84 3 : tb_next = NULL;
85 2 : } else if (!PyTraceBack_Check(tb_next)) {
86 1 : return PyErr_Format(PyExc_TypeError,
87 : "expected traceback object or None, got '%s'",
88 1 : Py_TYPE(tb_next)->tp_name);
89 : }
90 :
91 4 : return tb_create_raw((PyTracebackObject *)tb_next, tb_frame, tb_lasti,
92 : tb_lineno);
93 : }
94 :
95 : static PyObject *
96 1 : tb_dir(PyTracebackObject *self, PyObject *Py_UNUSED(ignored))
97 : {
98 1 : return Py_BuildValue("[ssss]", "tb_frame", "tb_next",
99 : "tb_lasti", "tb_lineno");
100 : }
101 :
102 : static PyObject *
103 269092 : tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_))
104 : {
105 269092 : PyObject* ret = (PyObject*)self->tb_next;
106 269092 : if (!ret) {
107 190627 : ret = Py_None;
108 : }
109 269092 : Py_INCREF(ret);
110 269092 : return ret;
111 : }
112 :
113 : static int
114 202 : tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_))
115 : {
116 202 : if (!new_next) {
117 1 : PyErr_Format(PyExc_TypeError, "can't delete tb_next attribute");
118 1 : return -1;
119 : }
120 :
121 : /* We accept None or a traceback object, and map None -> NULL (inverse of
122 : tb_next_get) */
123 201 : if (new_next == Py_None) {
124 197 : new_next = NULL;
125 4 : } else if (!PyTraceBack_Check(new_next)) {
126 1 : PyErr_Format(PyExc_TypeError,
127 : "expected traceback object, got '%s'",
128 1 : Py_TYPE(new_next)->tp_name);
129 1 : return -1;
130 : }
131 :
132 : /* Check for loops */
133 200 : PyTracebackObject *cursor = (PyTracebackObject *)new_next;
134 202 : while (cursor) {
135 4 : if (cursor == self) {
136 2 : PyErr_Format(PyExc_ValueError, "traceback loop detected");
137 2 : return -1;
138 : }
139 2 : cursor = cursor->tb_next;
140 : }
141 :
142 198 : PyObject *old_next = (PyObject*)self->tb_next;
143 198 : Py_XINCREF(new_next);
144 198 : self->tb_next = (PyTracebackObject *)new_next;
145 198 : Py_XDECREF(old_next);
146 :
147 198 : return 0;
148 : }
149 :
150 :
151 : static PyMethodDef tb_methods[] = {
152 : {"__dir__", _PyCFunction_CAST(tb_dir), METH_NOARGS},
153 : {NULL, NULL, 0, NULL},
154 : };
155 :
156 : static PyMemberDef tb_memberlist[] = {
157 : {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY|PY_AUDIT_READ},
158 : {"tb_lasti", T_INT, OFF(tb_lasti), READONLY},
159 : {"tb_lineno", T_INT, OFF(tb_lineno), READONLY},
160 : {NULL} /* Sentinel */
161 : };
162 :
163 : static PyGetSetDef tb_getsetters[] = {
164 : {"tb_next", (getter)tb_next_get, (setter)tb_next_set, NULL, NULL},
165 : {NULL} /* Sentinel */
166 : };
167 :
168 : static void
169 6345110 : tb_dealloc(PyTracebackObject *tb)
170 : {
171 6345110 : PyObject_GC_UnTrack(tb);
172 6345110 : Py_TRASHCAN_BEGIN(tb, tb_dealloc)
173 6344380 : Py_XDECREF(tb->tb_next);
174 6344380 : Py_XDECREF(tb->tb_frame);
175 6344380 : PyObject_GC_Del(tb);
176 6344380 : Py_TRASHCAN_END
177 6345110 : }
178 :
179 : static int
180 6500760 : tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)
181 : {
182 6500760 : Py_VISIT(tb->tb_next);
183 6500760 : Py_VISIT(tb->tb_frame);
184 6500760 : return 0;
185 : }
186 :
187 : static int
188 923 : tb_clear(PyTracebackObject *tb)
189 : {
190 923 : Py_CLEAR(tb->tb_next);
191 923 : Py_CLEAR(tb->tb_frame);
192 923 : return 0;
193 : }
194 :
195 : PyTypeObject PyTraceBack_Type = {
196 : PyVarObject_HEAD_INIT(&PyType_Type, 0)
197 : "traceback",
198 : sizeof(PyTracebackObject),
199 : 0,
200 : (destructor)tb_dealloc, /*tp_dealloc*/
201 : 0, /*tp_vectorcall_offset*/
202 : 0, /*tp_getattr*/
203 : 0, /*tp_setattr*/
204 : 0, /*tp_as_async*/
205 : 0, /*tp_repr*/
206 : 0, /*tp_as_number*/
207 : 0, /*tp_as_sequence*/
208 : 0, /*tp_as_mapping*/
209 : 0, /* tp_hash */
210 : 0, /* tp_call */
211 : 0, /* tp_str */
212 : PyObject_GenericGetAttr, /* tp_getattro */
213 : 0, /* tp_setattro */
214 : 0, /* tp_as_buffer */
215 : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
216 : tb_new__doc__, /* tp_doc */
217 : (traverseproc)tb_traverse, /* tp_traverse */
218 : (inquiry)tb_clear, /* tp_clear */
219 : 0, /* tp_richcompare */
220 : 0, /* tp_weaklistoffset */
221 : 0, /* tp_iter */
222 : 0, /* tp_iternext */
223 : tb_methods, /* tp_methods */
224 : tb_memberlist, /* tp_members */
225 : tb_getsetters, /* tp_getset */
226 : 0, /* tp_base */
227 : 0, /* tp_dict */
228 : 0, /* tp_descr_get */
229 : 0, /* tp_descr_set */
230 : 0, /* tp_dictoffset */
231 : 0, /* tp_init */
232 : 0, /* tp_alloc */
233 : tb_new, /* tp_new */
234 : };
235 :
236 :
237 : PyObject*
238 6344400 : _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame)
239 : {
240 6344400 : assert(tb_next == NULL || PyTraceBack_Check(tb_next));
241 6344400 : assert(frame != NULL);
242 6344400 : int addr = _PyInterpreterFrame_LASTI(frame->f_frame) * sizeof(_Py_CODEUNIT);
243 6344400 : return tb_create_raw((PyTracebackObject *)tb_next, frame, addr,
244 : PyFrame_GetLineNumber(frame));
245 : }
246 :
247 :
248 : int
249 6344350 : PyTraceBack_Here(PyFrameObject *frame)
250 : {
251 : PyObject *exc, *val, *tb, *newtb;
252 6344350 : PyErr_Fetch(&exc, &val, &tb);
253 6344350 : newtb = _PyTraceBack_FromFrame(tb, frame);
254 6344350 : if (newtb == NULL) {
255 0 : _PyErr_ChainExceptions(exc, val, tb);
256 0 : return -1;
257 : }
258 6344350 : PyErr_Restore(exc, val, newtb);
259 6344350 : Py_XDECREF(tb);
260 6344350 : return 0;
261 : }
262 :
263 : /* Insert a frame into the traceback for (funcname, filename, lineno). */
264 30 : void _PyTraceback_Add(const char *funcname, const char *filename, int lineno)
265 : {
266 : PyObject *globals;
267 : PyCodeObject *code;
268 : PyFrameObject *frame;
269 : PyObject *exc, *val, *tb;
270 30 : PyThreadState *tstate = _PyThreadState_GET();
271 :
272 : /* Save and clear the current exception. Python functions must not be
273 : called with an exception set. Calling Python functions happens when
274 : the codec of the filesystem encoding is implemented in pure Python. */
275 30 : _PyErr_Fetch(tstate, &exc, &val, &tb);
276 :
277 30 : globals = PyDict_New();
278 30 : if (!globals)
279 0 : goto error;
280 30 : code = PyCode_NewEmpty(filename, funcname, lineno);
281 30 : if (!code) {
282 0 : Py_DECREF(globals);
283 0 : goto error;
284 : }
285 30 : frame = PyFrame_New(tstate, code, globals, NULL);
286 30 : Py_DECREF(globals);
287 30 : Py_DECREF(code);
288 30 : if (!frame)
289 0 : goto error;
290 30 : frame->f_lineno = lineno;
291 :
292 30 : _PyErr_Restore(tstate, exc, val, tb);
293 30 : PyTraceBack_Here(frame);
294 30 : Py_DECREF(frame);
295 30 : return;
296 :
297 0 : error:
298 0 : _PyErr_ChainExceptions(exc, val, tb);
299 : }
300 :
301 : static PyObject *
302 48 : _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *io)
303 : {
304 : Py_ssize_t i;
305 : PyObject *binary;
306 : PyObject *v;
307 : Py_ssize_t npath;
308 : size_t taillen;
309 : PyObject *syspath;
310 : PyObject *path;
311 : const char* tail;
312 : PyObject *filebytes;
313 : const char* filepath;
314 : Py_ssize_t len;
315 : PyObject* result;
316 48 : PyObject *open = NULL;
317 :
318 48 : filebytes = PyUnicode_EncodeFSDefault(filename);
319 48 : if (filebytes == NULL) {
320 0 : PyErr_Clear();
321 0 : return NULL;
322 : }
323 48 : filepath = PyBytes_AS_STRING(filebytes);
324 :
325 : /* Search tail of filename in sys.path before giving up */
326 48 : tail = strrchr(filepath, SEP);
327 48 : if (tail == NULL)
328 8 : tail = filepath;
329 : else
330 40 : tail++;
331 48 : taillen = strlen(tail);
332 :
333 48 : PyThreadState *tstate = _PyThreadState_GET();
334 48 : syspath = _PySys_GetAttr(tstate, &_Py_ID(path));
335 48 : if (syspath == NULL || !PyList_Check(syspath))
336 0 : goto error;
337 48 : npath = PyList_Size(syspath);
338 :
339 48 : open = PyObject_GetAttr(io, &_Py_ID(open));
340 212 : for (i = 0; i < npath; i++) {
341 164 : v = PyList_GetItem(syspath, i);
342 164 : if (v == NULL) {
343 0 : PyErr_Clear();
344 0 : break;
345 : }
346 164 : if (!PyUnicode_Check(v))
347 0 : continue;
348 164 : path = PyUnicode_EncodeFSDefault(v);
349 164 : if (path == NULL) {
350 0 : PyErr_Clear();
351 0 : continue;
352 : }
353 164 : len = PyBytes_GET_SIZE(path);
354 164 : if (len + 1 + (Py_ssize_t)taillen >= (Py_ssize_t)namelen - 1) {
355 0 : Py_DECREF(path);
356 0 : continue; /* Too long */
357 : }
358 164 : strcpy(namebuf, PyBytes_AS_STRING(path));
359 164 : Py_DECREF(path);
360 164 : if (strlen(namebuf) != (size_t)len)
361 0 : continue; /* v contains '\0' */
362 164 : if (len > 0 && namebuf[len-1] != SEP)
363 164 : namebuf[len++] = SEP;
364 164 : strcpy(namebuf+len, tail);
365 :
366 164 : binary = _PyObject_CallMethodFormat(tstate, open, "ss", namebuf, "rb");
367 164 : if (binary != NULL) {
368 0 : result = binary;
369 0 : goto finally;
370 : }
371 164 : PyErr_Clear();
372 : }
373 48 : goto error;
374 :
375 48 : error:
376 48 : result = NULL;
377 48 : finally:
378 48 : Py_XDECREF(open);
379 48 : Py_DECREF(filebytes);
380 48 : return result;
381 : }
382 :
383 : /* Writes indent spaces. Returns 0 on success and non-zero on failure.
384 : */
385 : int
386 3105 : _Py_WriteIndent(int indent, PyObject *f)
387 : {
388 3105 : char buf[11] = " ";
389 3105 : assert(strlen(buf) == 10);
390 3913 : while (indent > 0) {
391 808 : if (indent < 10) {
392 733 : buf[indent] = '\0';
393 : }
394 808 : if (PyFile_WriteString(buf, f) < 0) {
395 0 : return -1;
396 : }
397 808 : indent -= 10;
398 : }
399 3105 : return 0;
400 : }
401 :
402 : /* Writes indent spaces, followed by the margin if it is not `\0`.
403 : Returns 0 on success and non-zero on failure.
404 : */
405 : int
406 2530 : _Py_WriteIndentedMargin(int indent, const char *margin, PyObject *f)
407 : {
408 2530 : if (_Py_WriteIndent(indent, f) < 0) {
409 0 : return -1;
410 : }
411 2530 : if (margin) {
412 2392 : if (PyFile_WriteString(margin, f) < 0) {
413 33 : return -1;
414 : }
415 : }
416 2497 : return 0;
417 : }
418 :
419 : static int
420 646 : display_source_line_with_margin(PyObject *f, PyObject *filename, int lineno, int indent,
421 : int margin_indent, const char *margin,
422 : int *truncation, PyObject **line)
423 : {
424 : int fd;
425 : int i;
426 : char *found_encoding;
427 : const char *encoding;
428 : PyObject *io;
429 : PyObject *binary;
430 646 : PyObject *fob = NULL;
431 646 : PyObject *lineobj = NULL;
432 : PyObject *res;
433 : char buf[MAXPATHLEN+1];
434 : int kind;
435 : const void *data;
436 :
437 : /* open the file */
438 646 : if (filename == NULL)
439 0 : return 0;
440 :
441 : /* Do not attempt to open things like <string> or <stdin> */
442 646 : assert(PyUnicode_Check(filename));
443 646 : if (PyUnicode_READ_CHAR(filename, 0) == '<') {
444 129 : Py_ssize_t len = PyUnicode_GET_LENGTH(filename);
445 129 : if (len > 0 && PyUnicode_READ_CHAR(filename, len - 1) == '>') {
446 113 : return 0;
447 : }
448 : }
449 :
450 533 : io = PyImport_ImportModule("io");
451 533 : if (io == NULL) {
452 9 : return -1;
453 : }
454 :
455 524 : binary = _PyObject_CallMethod(io, &_Py_ID(open), "Os", filename, "rb");
456 524 : if (binary == NULL) {
457 48 : PyErr_Clear();
458 :
459 48 : binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io);
460 48 : if (binary == NULL) {
461 48 : Py_DECREF(io);
462 48 : return -1;
463 : }
464 : }
465 :
466 : /* use the right encoding to decode the file as unicode */
467 476 : fd = PyObject_AsFileDescriptor(binary);
468 476 : if (fd < 0) {
469 0 : Py_DECREF(io);
470 0 : Py_DECREF(binary);
471 0 : return 0;
472 : }
473 476 : found_encoding = _PyTokenizer_FindEncodingFilename(fd, filename);
474 476 : if (found_encoding == NULL)
475 464 : PyErr_Clear();
476 476 : encoding = (found_encoding != NULL) ? found_encoding : "utf-8";
477 : /* Reset position */
478 476 : if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
479 0 : Py_DECREF(io);
480 0 : Py_DECREF(binary);
481 0 : PyMem_Free(found_encoding);
482 0 : return 0;
483 : }
484 476 : fob = _PyObject_CallMethod(io, &_Py_ID(TextIOWrapper),
485 : "Os", binary, encoding);
486 476 : Py_DECREF(io);
487 476 : PyMem_Free(found_encoding);
488 :
489 476 : if (fob == NULL) {
490 1 : PyErr_Clear();
491 :
492 1 : res = PyObject_CallMethodNoArgs(binary, &_Py_ID(close));
493 1 : Py_DECREF(binary);
494 1 : if (res)
495 0 : Py_DECREF(res);
496 : else
497 1 : PyErr_Clear();
498 1 : return 0;
499 : }
500 475 : Py_DECREF(binary);
501 :
502 : /* get the line number lineno */
503 456277 : for (i = 0; i < lineno; i++) {
504 455802 : Py_XDECREF(lineobj);
505 455802 : lineobj = PyFile_GetLine(fob, -1);
506 455802 : if (!lineobj) {
507 0 : PyErr_Clear();
508 0 : break;
509 : }
510 : }
511 475 : res = PyObject_CallMethodNoArgs(fob, &_Py_ID(close));
512 475 : if (res) {
513 474 : Py_DECREF(res);
514 : }
515 : else {
516 1 : PyErr_Clear();
517 : }
518 475 : Py_DECREF(fob);
519 475 : if (!lineobj || !PyUnicode_Check(lineobj)) {
520 0 : Py_XDECREF(lineobj);
521 0 : return -1;
522 : }
523 :
524 475 : if (line) {
525 474 : Py_INCREF(lineobj);
526 474 : *line = lineobj;
527 : }
528 :
529 : /* remove the indentation of the line */
530 475 : kind = PyUnicode_KIND(lineobj);
531 475 : data = PyUnicode_DATA(lineobj);
532 6005 : for (i=0; i < PyUnicode_GET_LENGTH(lineobj); i++) {
533 6005 : Py_UCS4 ch = PyUnicode_READ(kind, data, i);
534 6005 : if (ch != ' ' && ch != '\t' && ch != '\014')
535 475 : break;
536 : }
537 475 : if (i) {
538 : PyObject *truncated;
539 456 : truncated = PyUnicode_Substring(lineobj, i, PyUnicode_GET_LENGTH(lineobj));
540 456 : if (truncated) {
541 456 : Py_DECREF(lineobj);
542 456 : lineobj = truncated;
543 : } else {
544 0 : PyErr_Clear();
545 : }
546 : }
547 :
548 475 : if (truncation != NULL) {
549 474 : *truncation = i - indent;
550 : }
551 :
552 475 : if (_Py_WriteIndentedMargin(margin_indent, margin, f) < 0) {
553 0 : goto error;
554 : }
555 :
556 : /* Write some spaces before the line */
557 475 : if (_Py_WriteIndent(indent, f) < 0) {
558 0 : goto error;
559 : }
560 :
561 : /* finally display the line */
562 475 : if (PyFile_WriteObject(lineobj, f, Py_PRINT_RAW) < 0) {
563 0 : goto error;
564 : }
565 :
566 475 : if (PyFile_WriteString("\n", f) < 0) {
567 0 : goto error;
568 : }
569 :
570 475 : Py_DECREF(lineobj);
571 475 : return 0;
572 0 : error:
573 0 : Py_DECREF(lineobj);
574 0 : return -1;
575 : }
576 :
577 : int
578 11 : _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent,
579 : int *truncation, PyObject **line)
580 : {
581 11 : return display_source_line_with_margin(f, filename, lineno, indent, 0,
582 : NULL, truncation, line);
583 : }
584 :
585 : /* AST based Traceback Specialization
586 : *
587 : * When displaying a new traceback line, for certain syntactical constructs
588 : * (e.g a subscript, an arithmetic operation) we try to create a representation
589 : * that separates the primary source of error from the rest.
590 : *
591 : * Example specialization of BinOp nodes:
592 : * Traceback (most recent call last):
593 : * File "/home/isidentical/cpython/cpython/t.py", line 10, in <module>
594 : * add_values(1, 2, 'x', 3, 4)
595 : * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
596 : * File "/home/isidentical/cpython/cpython/t.py", line 2, in add_values
597 : * return a + b + c + d + e
598 : * ~~~~~~^~~
599 : * TypeError: 'NoneType' object is not subscriptable
600 : */
601 :
602 : #define IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\f'))
603 :
604 : static int
605 328 : extract_anchors_from_expr(const char *segment_str, expr_ty expr, Py_ssize_t *left_anchor, Py_ssize_t *right_anchor,
606 : char** primary_error_char, char** secondary_error_char)
607 : {
608 328 : switch (expr->kind) {
609 25 : case BinOp_kind: {
610 25 : expr_ty left = expr->v.BinOp.left;
611 25 : expr_ty right = expr->v.BinOp.right;
612 43 : for (int i = left->end_col_offset; i < right->col_offset; i++) {
613 43 : if (IS_WHITESPACE(segment_str[i])) {
614 18 : continue;
615 : }
616 :
617 25 : *left_anchor = i;
618 25 : *right_anchor = i + 1;
619 :
620 : // Check whether if this a two-character operator (e.g //)
621 25 : if (i + 1 < right->col_offset && !IS_WHITESPACE(segment_str[i + 1])) {
622 7 : ++*right_anchor;
623 : }
624 :
625 : // Set the error characters
626 25 : *primary_error_char = "~";
627 25 : *secondary_error_char = "^";
628 25 : break;
629 : }
630 25 : return 1;
631 : }
632 4 : case Subscript_kind: {
633 4 : *left_anchor = expr->v.Subscript.value->end_col_offset;
634 4 : *right_anchor = expr->v.Subscript.slice->end_col_offset + 1;
635 :
636 : // Set the error characters
637 4 : *primary_error_char = "~";
638 4 : *secondary_error_char = "^";
639 4 : return 1;
640 : }
641 299 : default:
642 299 : return 0;
643 : }
644 : }
645 :
646 : static int
647 442 : extract_anchors_from_stmt(const char *segment_str, stmt_ty statement, Py_ssize_t *left_anchor, Py_ssize_t *right_anchor,
648 : char** primary_error_char, char** secondary_error_char)
649 : {
650 442 : switch (statement->kind) {
651 328 : case Expr_kind: {
652 328 : return extract_anchors_from_expr(segment_str, statement->v.Expr.value, left_anchor, right_anchor,
653 : primary_error_char, secondary_error_char);
654 : }
655 114 : default:
656 114 : return 0;
657 : }
658 : }
659 :
660 : static int
661 444 : extract_anchors_from_line(PyObject *filename, PyObject *line,
662 : Py_ssize_t start_offset, Py_ssize_t end_offset,
663 : Py_ssize_t *left_anchor, Py_ssize_t *right_anchor,
664 : char** primary_error_char, char** secondary_error_char)
665 : {
666 444 : int res = -1;
667 444 : PyArena *arena = NULL;
668 444 : PyObject *segment = PyUnicode_Substring(line, start_offset, end_offset);
669 444 : if (!segment) {
670 0 : goto done;
671 : }
672 :
673 444 : const char *segment_str = PyUnicode_AsUTF8(segment);
674 444 : if (!segment_str) {
675 0 : goto done;
676 : }
677 :
678 444 : arena = _PyArena_New();
679 444 : if (!arena) {
680 0 : goto done;
681 : }
682 :
683 444 : PyCompilerFlags flags = _PyCompilerFlags_INIT;
684 :
685 : _PyASTOptimizeState state;
686 444 : state.optimize = _Py_GetConfig()->optimization_level;
687 444 : state.ff_features = 0;
688 :
689 444 : mod_ty module = _PyParser_ASTFromString(segment_str, filename, Py_file_input,
690 : &flags, arena);
691 444 : if (!module) {
692 1 : goto done;
693 : }
694 443 : if (!_PyAST_Optimize(module, arena, &state)) {
695 0 : goto done;
696 : }
697 :
698 443 : assert(module->kind == Module_kind);
699 885 : if (asdl_seq_LEN(module->v.Module.body) == 1) {
700 442 : stmt_ty statement = asdl_seq_GET(module->v.Module.body, 0);
701 442 : res = extract_anchors_from_stmt(segment_str, statement, left_anchor, right_anchor,
702 : primary_error_char, secondary_error_char);
703 : } else {
704 1 : res = 0;
705 : }
706 :
707 444 : done:
708 444 : if (res > 0) {
709 29 : *left_anchor += start_offset;
710 29 : *right_anchor += start_offset;
711 : }
712 444 : Py_XDECREF(segment);
713 444 : if (arena) {
714 444 : _PyArena_Free(arena);
715 : }
716 444 : return res;
717 : }
718 :
719 : #define _TRACEBACK_SOURCE_LINE_INDENT 4
720 :
721 : static inline int
722 162 : ignore_source_errors(void) {
723 162 : if (PyErr_Occurred()) {
724 1 : if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
725 0 : return -1;
726 : }
727 1 : PyErr_Clear();
728 : }
729 162 : return 0;
730 : }
731 :
732 : static inline int
733 473 : print_error_location_carets(PyObject *f, int offset, Py_ssize_t start_offset, Py_ssize_t end_offset,
734 : Py_ssize_t right_start_offset, Py_ssize_t left_end_offset,
735 : const char *primary, const char *secondary) {
736 473 : int special_chars = (left_end_offset != -1 || right_start_offset != -1);
737 : const char *str;
738 14506 : while (++offset <= end_offset) {
739 14033 : if (offset <= start_offset || offset > end_offset) {
740 3491 : str = " ";
741 10542 : } else if (special_chars && left_end_offset < offset && offset <= right_start_offset) {
742 46 : str = secondary;
743 : } else {
744 10496 : str = primary;
745 : }
746 14033 : if (PyFile_WriteString(str, f) < 0) {
747 0 : return -1;
748 : }
749 : }
750 473 : if (PyFile_WriteString("\n", f) < 0) {
751 0 : return -1;
752 : }
753 473 : return 0;
754 : }
755 :
756 : static int
757 635 : tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int lineno,
758 : PyFrameObject *frame, PyObject *name, int margin_indent, const char *margin)
759 : {
760 635 : if (filename == NULL || name == NULL) {
761 0 : return -1;
762 : }
763 :
764 635 : if (_Py_WriteIndentedMargin(margin_indent, margin, f) < 0) {
765 0 : return -1;
766 : }
767 :
768 635 : PyObject *line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n",
769 : filename, lineno, name);
770 635 : if (line == NULL) {
771 0 : return -1;
772 : }
773 :
774 635 : int res = PyFile_WriteObject(line, f, Py_PRINT_RAW);
775 635 : Py_DECREF(line);
776 635 : if (res < 0) {
777 0 : return -1;
778 : }
779 :
780 635 : int err = 0;
781 :
782 635 : int truncation = _TRACEBACK_SOURCE_LINE_INDENT;
783 635 : PyObject* source_line = NULL;
784 635 : int rc = display_source_line_with_margin(
785 : f, filename, lineno, _TRACEBACK_SOURCE_LINE_INDENT,
786 : margin_indent, margin, &truncation, &source_line);
787 635 : if (rc != 0 || !source_line) {
788 : /* ignore errors since we can't report them, can we? */
789 161 : err = ignore_source_errors();
790 161 : goto done;
791 : }
792 :
793 474 : int code_offset = tb->tb_lasti;
794 474 : PyCodeObject* code = frame->f_frame->f_code;
795 :
796 : int start_line;
797 : int end_line;
798 : int start_col_byte_offset;
799 : int end_col_byte_offset;
800 474 : if (!PyCode_Addr2Location(code, code_offset, &start_line, &start_col_byte_offset,
801 : &end_line, &end_col_byte_offset)) {
802 0 : goto done;
803 : }
804 :
805 474 : if (start_line < 0 || end_line < 0
806 474 : || start_col_byte_offset < 0
807 473 : || end_col_byte_offset < 0)
808 : {
809 1 : goto done;
810 : }
811 :
812 : // When displaying errors, we will use the following generic structure:
813 : //
814 : // ERROR LINE ERROR LINE ERROR LINE ERROR LINE ERROR LINE ERROR LINE ERROR LINE
815 : // ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~
816 : // | |-> left_end_offset | |-> left_offset
817 : // |-> start_offset |-> right_start_offset
818 : //
819 : // In general we will only have (start_offset, end_offset) but we can gather more information
820 : // by analyzing the AST of the text between *start_offset* and *end_offset*. If this succeeds
821 : // we could get *left_end_offset* and *right_start_offset* and some selection of characters for
822 : // the different ranges (primary_error_char and secondary_error_char). If we cannot obtain the
823 : // AST information or we cannot identify special ranges within it, then left_end_offset and
824 : // right_end_offset will be set to -1.
825 :
826 : // Convert the utf-8 byte offset to the actual character offset so we print the right number of carets.
827 473 : assert(source_line);
828 473 : Py_ssize_t start_offset = _PyPegen_byte_offset_to_character_offset(source_line, start_col_byte_offset);
829 473 : if (start_offset < 0) {
830 0 : err = ignore_source_errors() < 0;
831 0 : goto done;
832 : }
833 :
834 473 : Py_ssize_t end_offset = _PyPegen_byte_offset_to_character_offset(source_line, end_col_byte_offset);
835 473 : if (end_offset < 0) {
836 0 : err = ignore_source_errors() < 0;
837 0 : goto done;
838 : }
839 :
840 473 : Py_ssize_t left_end_offset = -1;
841 473 : Py_ssize_t right_start_offset = -1;
842 :
843 473 : char *primary_error_char = "^";
844 473 : char *secondary_error_char = primary_error_char;
845 :
846 473 : if (start_line == end_line) {
847 444 : int res = extract_anchors_from_line(filename, source_line, start_offset, end_offset,
848 : &left_end_offset, &right_start_offset,
849 : &primary_error_char, &secondary_error_char);
850 444 : if (res < 0 && ignore_source_errors() < 0) {
851 0 : goto done;
852 : }
853 : }
854 : else {
855 : // If this is a multi-line expression, then we will highlight until
856 : // the last non-whitespace character.
857 29 : const char *source_line_str = PyUnicode_AsUTF8(source_line);
858 29 : if (!source_line_str) {
859 0 : goto done;
860 : }
861 :
862 29 : Py_ssize_t i = PyUnicode_GET_LENGTH(source_line);
863 29 : while (--i >= 0) {
864 29 : if (!IS_WHITESPACE(source_line_str[i])) {
865 29 : break;
866 : }
867 : }
868 :
869 29 : end_offset = i + 1;
870 : }
871 :
872 473 : if (_Py_WriteIndentedMargin(margin_indent, margin, f) < 0) {
873 0 : err = -1;
874 0 : goto done;
875 : }
876 :
877 473 : if (print_error_location_carets(f, truncation, start_offset, end_offset,
878 : right_start_offset, left_end_offset,
879 : primary_error_char, secondary_error_char) < 0) {
880 0 : err = -1;
881 0 : goto done;
882 : }
883 :
884 473 : done:
885 635 : Py_XDECREF(source_line);
886 635 : return err;
887 : }
888 :
889 : static const int TB_RECURSIVE_CUTOFF = 3; // Also hardcoded in traceback.py.
890 :
891 : static int
892 6 : tb_print_line_repeated(PyObject *f, long cnt)
893 : {
894 6 : cnt -= TB_RECURSIVE_CUTOFF;
895 6 : PyObject *line = PyUnicode_FromFormat(
896 : (cnt > 1)
897 : ? " [Previous line repeated %ld more times]\n"
898 : : " [Previous line repeated %ld more time]\n",
899 : cnt);
900 6 : if (line == NULL) {
901 0 : return -1;
902 : }
903 6 : int err = PyFile_WriteObject(line, f, Py_PRINT_RAW);
904 6 : Py_DECREF(line);
905 6 : return err;
906 : }
907 :
908 : static int
909 312 : tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit,
910 : int indent, const char *margin)
911 : {
912 312 : PyCodeObject *code = NULL;
913 312 : Py_ssize_t depth = 0;
914 312 : PyObject *last_file = NULL;
915 312 : int last_line = -1;
916 312 : PyObject *last_name = NULL;
917 312 : long cnt = 0;
918 312 : PyTracebackObject *tb1 = tb;
919 2921 : while (tb1 != NULL) {
920 2609 : depth++;
921 2609 : tb1 = tb1->tb_next;
922 : }
923 315 : while (tb != NULL && depth > limit) {
924 3 : depth--;
925 3 : tb = tb->tb_next;
926 : }
927 2918 : while (tb != NULL) {
928 2606 : code = PyFrame_GetCode(tb->tb_frame);
929 2606 : if (last_file == NULL ||
930 2294 : code->co_filename != last_file ||
931 2211 : last_line == -1 || tb->tb_lineno != last_line ||
932 1988 : last_name == NULL || code->co_name != last_name) {
933 618 : if (cnt > TB_RECURSIVE_CUTOFF) {
934 5 : if (tb_print_line_repeated(f, cnt) < 0) {
935 0 : goto error;
936 : }
937 : }
938 618 : last_file = code->co_filename;
939 618 : last_line = tb->tb_lineno;
940 618 : last_name = code->co_name;
941 618 : cnt = 0;
942 : }
943 2606 : cnt++;
944 2606 : if (cnt <= TB_RECURSIVE_CUTOFF) {
945 635 : if (tb_displayline(tb, f, code->co_filename, tb->tb_lineno,
946 : tb->tb_frame, code->co_name, indent, margin) < 0) {
947 0 : goto error;
948 : }
949 :
950 635 : if (PyErr_CheckSignals() < 0) {
951 0 : goto error;
952 : }
953 : }
954 2606 : Py_CLEAR(code);
955 2606 : tb = tb->tb_next;
956 : }
957 312 : if (cnt > TB_RECURSIVE_CUTOFF) {
958 1 : if (tb_print_line_repeated(f, cnt) < 0) {
959 0 : goto error;
960 : }
961 : }
962 312 : return 0;
963 0 : error:
964 0 : Py_XDECREF(code);
965 0 : return -1;
966 : }
967 :
968 : #define PyTraceBack_LIMIT 1000
969 :
970 : int
971 315 : _PyTraceBack_Print_Indented(PyObject *v, int indent, const char *margin,
972 : const char *header_margin, const char *header, PyObject *f)
973 : {
974 : PyObject *limitv;
975 315 : long limit = PyTraceBack_LIMIT;
976 :
977 315 : if (v == NULL) {
978 0 : return 0;
979 : }
980 315 : if (!PyTraceBack_Check(v)) {
981 0 : PyErr_BadInternalCall();
982 0 : return -1;
983 : }
984 315 : limitv = PySys_GetObject("tracebacklimit");
985 315 : if (limitv && PyLong_Check(limitv)) {
986 : int overflow;
987 8 : limit = PyLong_AsLongAndOverflow(limitv, &overflow);
988 8 : if (overflow > 0) {
989 1 : limit = LONG_MAX;
990 : }
991 7 : else if (limit <= 0) {
992 3 : return 0;
993 : }
994 : }
995 312 : if (_Py_WriteIndentedMargin(indent, header_margin, f) < 0) {
996 0 : return -1;
997 : }
998 :
999 312 : if (PyFile_WriteString(header, f) < 0) {
1000 0 : return -1;
1001 : }
1002 :
1003 312 : if (tb_printinternal((PyTracebackObject *)v, f, limit, indent, margin) < 0) {
1004 0 : return -1;
1005 : }
1006 :
1007 312 : return 0;
1008 : }
1009 :
1010 : int
1011 33 : PyTraceBack_Print(PyObject *v, PyObject *f)
1012 : {
1013 33 : int indent = 0;
1014 33 : const char *margin = NULL;
1015 33 : const char *header_margin = NULL;
1016 33 : const char *header = EXCEPTION_TB_HEADER;
1017 :
1018 33 : return _PyTraceBack_Print_Indented(v, indent, margin, header_margin, header, f);
1019 : }
1020 :
1021 : /* Format an integer in range [0; 0xffffffff] to decimal and write it
1022 : into the file fd.
1023 :
1024 : This function is signal safe. */
1025 :
1026 : void
1027 53 : _Py_DumpDecimal(int fd, size_t value)
1028 : {
1029 : /* maximum number of characters required for output of %lld or %p.
1030 : We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits,
1031 : plus 1 for the null byte. 53/22 is an upper bound for log10(256). */
1032 : char buffer[1 + (sizeof(size_t)*53-1) / 22 + 1];
1033 : char *ptr, *end;
1034 :
1035 53 : end = &buffer[Py_ARRAY_LENGTH(buffer) - 1];
1036 53 : ptr = end;
1037 53 : *ptr = '\0';
1038 : do {
1039 112 : --ptr;
1040 112 : assert(ptr >= buffer);
1041 112 : *ptr = '0' + (value % 10);
1042 112 : value /= 10;
1043 112 : } while (value);
1044 :
1045 53 : _Py_write_noraise(fd, ptr, end - ptr);
1046 53 : }
1047 :
1048 : /* Format an integer as hexadecimal with width digits into fd file descriptor.
1049 : The function is signal safe. */
1050 : void
1051 16 : _Py_DumpHexadecimal(int fd, uintptr_t value, Py_ssize_t width)
1052 : {
1053 : char buffer[sizeof(uintptr_t) * 2 + 1], *ptr, *end;
1054 16 : const Py_ssize_t size = Py_ARRAY_LENGTH(buffer) - 1;
1055 :
1056 16 : if (width > size)
1057 0 : width = size;
1058 : /* it's ok if width is negative */
1059 :
1060 16 : end = &buffer[size];
1061 16 : ptr = end;
1062 16 : *ptr = '\0';
1063 : do {
1064 256 : --ptr;
1065 256 : assert(ptr >= buffer);
1066 256 : *ptr = Py_hexdigits[value & 15];
1067 256 : value >>= 4;
1068 256 : } while ((end - ptr) < width || value);
1069 :
1070 16 : _Py_write_noraise(fd, ptr, end - ptr);
1071 16 : }
1072 :
1073 : void
1074 106 : _Py_DumpASCII(int fd, PyObject *text)
1075 : {
1076 106 : PyASCIIObject *ascii = _PyASCIIObject_CAST(text);
1077 : Py_ssize_t i, size;
1078 : int truncated;
1079 : int kind;
1080 106 : void *data = NULL;
1081 : Py_UCS4 ch;
1082 :
1083 106 : if (!PyUnicode_Check(text))
1084 0 : return;
1085 :
1086 106 : size = ascii->length;
1087 106 : kind = ascii->state.kind;
1088 106 : if (ascii->state.compact) {
1089 106 : if (ascii->state.ascii)
1090 106 : data = ascii + 1;
1091 : else
1092 0 : data = _PyCompactUnicodeObject_CAST(text) + 1;
1093 : }
1094 : else {
1095 0 : data = _PyUnicodeObject_CAST(text)->data.any;
1096 0 : if (data == NULL)
1097 0 : return;
1098 : }
1099 :
1100 106 : if (MAX_STRING_LENGTH < size) {
1101 1 : size = MAX_STRING_LENGTH;
1102 1 : truncated = 1;
1103 : }
1104 : else {
1105 105 : truncated = 0;
1106 : }
1107 :
1108 : // Is an ASCII string?
1109 106 : if (ascii->state.ascii) {
1110 106 : assert(kind == PyUnicode_1BYTE_KIND);
1111 106 : char *str = data;
1112 :
1113 106 : int need_escape = 0;
1114 1694 : for (i=0; i < size; i++) {
1115 1588 : ch = str[i];
1116 1588 : if (!(' ' <= ch && ch <= 126)) {
1117 0 : need_escape = 1;
1118 0 : break;
1119 : }
1120 : }
1121 106 : if (!need_escape) {
1122 : // The string can be written with a single write() syscall
1123 106 : _Py_write_noraise(fd, str, size);
1124 106 : goto done;
1125 : }
1126 : }
1127 :
1128 0 : for (i=0; i < size; i++) {
1129 0 : ch = PyUnicode_READ(kind, data, i);
1130 0 : if (' ' <= ch && ch <= 126) {
1131 : /* printable ASCII character */
1132 0 : char c = (char)ch;
1133 0 : _Py_write_noraise(fd, &c, 1);
1134 : }
1135 0 : else if (ch <= 0xff) {
1136 0 : PUTS(fd, "\\x");
1137 0 : _Py_DumpHexadecimal(fd, ch, 2);
1138 : }
1139 0 : else if (ch <= 0xffff) {
1140 0 : PUTS(fd, "\\u");
1141 0 : _Py_DumpHexadecimal(fd, ch, 4);
1142 : }
1143 : else {
1144 0 : PUTS(fd, "\\U");
1145 0 : _Py_DumpHexadecimal(fd, ch, 8);
1146 : }
1147 : }
1148 :
1149 0 : done:
1150 106 : if (truncated) {
1151 1 : PUTS(fd, "...");
1152 : }
1153 : }
1154 :
1155 : /* Write a frame into the file fd: "File "xxx", line xxx in xxx".
1156 :
1157 : This function is signal safe. */
1158 :
1159 : static void
1160 53 : dump_frame(int fd, _PyInterpreterFrame *frame)
1161 : {
1162 53 : PyCodeObject *code = frame->f_code;
1163 53 : PUTS(fd, " File ");
1164 53 : if (code->co_filename != NULL
1165 53 : && PyUnicode_Check(code->co_filename))
1166 : {
1167 53 : PUTS(fd, "\"");
1168 53 : _Py_DumpASCII(fd, code->co_filename);
1169 53 : PUTS(fd, "\"");
1170 : } else {
1171 0 : PUTS(fd, "???");
1172 : }
1173 :
1174 53 : int lineno = _PyInterpreterFrame_GetLine(frame);
1175 53 : PUTS(fd, ", line ");
1176 53 : if (lineno >= 0) {
1177 53 : _Py_DumpDecimal(fd, (size_t)lineno);
1178 : }
1179 : else {
1180 0 : PUTS(fd, "???");
1181 : }
1182 53 : PUTS(fd, " in ");
1183 :
1184 53 : if (code->co_name != NULL
1185 53 : && PyUnicode_Check(code->co_name)) {
1186 53 : _Py_DumpASCII(fd, code->co_name);
1187 : }
1188 : else {
1189 0 : PUTS(fd, "???");
1190 : }
1191 :
1192 53 : PUTS(fd, "\n");
1193 53 : }
1194 :
1195 : static void
1196 24 : dump_traceback(int fd, PyThreadState *tstate, int write_header)
1197 : {
1198 : _PyInterpreterFrame *frame;
1199 : unsigned int depth;
1200 :
1201 24 : if (write_header) {
1202 8 : PUTS(fd, "Stack (most recent call first):\n");
1203 : }
1204 :
1205 24 : frame = tstate->cframe->current_frame;
1206 24 : if (frame == NULL) {
1207 2 : PUTS(fd, " <no Python frame>\n");
1208 2 : return;
1209 : }
1210 :
1211 22 : depth = 0;
1212 : while (1) {
1213 53 : if (MAX_FRAME_DEPTH <= depth) {
1214 0 : PUTS(fd, " ...\n");
1215 0 : break;
1216 : }
1217 53 : dump_frame(fd, frame);
1218 53 : frame = frame->previous;
1219 53 : if (frame == NULL) {
1220 22 : break;
1221 : }
1222 31 : depth++;
1223 : }
1224 : }
1225 :
1226 : /* Dump the traceback of a Python thread into fd. Use write() to write the
1227 : traceback and retry if write() is interrupted by a signal (failed with
1228 : EINTR), but don't call the Python signal handler.
1229 :
1230 : The caller is responsible to call PyErr_CheckSignals() to call Python signal
1231 : handlers if signals were received. */
1232 : void
1233 8 : _Py_DumpTraceback(int fd, PyThreadState *tstate)
1234 : {
1235 8 : dump_traceback(fd, tstate, 1);
1236 8 : }
1237 :
1238 : /* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
1239 : is_current is true, "Thread 0xHHHH:\n" otherwise.
1240 :
1241 : This function is signal safe. */
1242 :
1243 : static void
1244 16 : write_thread_id(int fd, PyThreadState *tstate, int is_current)
1245 : {
1246 16 : if (is_current)
1247 5 : PUTS(fd, "Current thread 0x");
1248 : else
1249 11 : PUTS(fd, "Thread 0x");
1250 16 : _Py_DumpHexadecimal(fd,
1251 : tstate->thread_id,
1252 : sizeof(unsigned long) * 2);
1253 16 : PUTS(fd, " (most recent call first):\n");
1254 16 : }
1255 :
1256 : /* Dump the traceback of all Python threads into fd. Use write() to write the
1257 : traceback and retry if write() is interrupted by a signal (failed with
1258 : EINTR), but don't call the Python signal handler.
1259 :
1260 : The caller is responsible to call PyErr_CheckSignals() to call Python signal
1261 : handlers if signals were received. */
1262 : const char*
1263 18 : _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
1264 : PyThreadState *current_tstate)
1265 : {
1266 : PyThreadState *tstate;
1267 : unsigned int nthreads;
1268 :
1269 18 : if (current_tstate == NULL) {
1270 : /* _Py_DumpTracebackThreads() is called from signal handlers by
1271 : faulthandler.
1272 :
1273 : SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals
1274 : and are thus delivered to the thread that caused the fault. Get the
1275 : Python thread state of the current thread.
1276 :
1277 : PyThreadState_Get() doesn't give the state of the thread that caused
1278 : the fault if the thread released the GIL, and so
1279 : _PyThreadState_GET() cannot be used. Read the thread specific
1280 : storage (TSS) instead: call PyGILState_GetThisThreadState(). */
1281 13 : current_tstate = PyGILState_GetThisThreadState();
1282 : }
1283 :
1284 18 : if (interp == NULL) {
1285 7 : if (current_tstate == NULL) {
1286 4 : interp = _PyGILState_GetInterpreterStateUnsafe();
1287 4 : if (interp == NULL) {
1288 : /* We need the interpreter state to get Python threads */
1289 4 : return "unable to get the interpreter state";
1290 : }
1291 : }
1292 : else {
1293 3 : interp = current_tstate->interp;
1294 : }
1295 : }
1296 14 : assert(interp != NULL);
1297 :
1298 : /* Get the current interpreter from the current thread */
1299 14 : tstate = PyInterpreterState_ThreadHead(interp);
1300 14 : if (tstate == NULL)
1301 0 : return "unable to get the thread head state";
1302 :
1303 : /* Dump the traceback of each thread */
1304 14 : tstate = PyInterpreterState_ThreadHead(interp);
1305 14 : nthreads = 0;
1306 : _Py_BEGIN_SUPPRESS_IPH
1307 : do
1308 : {
1309 16 : if (nthreads != 0)
1310 2 : PUTS(fd, "\n");
1311 16 : if (nthreads >= MAX_NTHREADS) {
1312 0 : PUTS(fd, "...\n");
1313 0 : break;
1314 : }
1315 16 : write_thread_id(fd, tstate, tstate == current_tstate);
1316 16 : if (tstate == current_tstate && tstate->interp->gc.collecting) {
1317 0 : PUTS(fd, " Garbage-collecting\n");
1318 : }
1319 16 : dump_traceback(fd, tstate, 0);
1320 16 : tstate = PyThreadState_Next(tstate);
1321 16 : nthreads++;
1322 16 : } while (tstate != NULL);
1323 : _Py_END_SUPPRESS_IPH
1324 :
1325 14 : return NULL;
1326 : }
1327 :
|