1
2/* Traceback implementation */
3
4#include "Python.h"
5
6#include "code.h"
7#include "pycore_interp.h" // PyInterpreterState.gc
8#include "frameobject.h" // PyFrame_GetBack()
9#include "structmember.h" // PyMemberDef
10#include "osdefs.h" // SEP
11#ifdef HAVE_FCNTL_H
12#include <fcntl.h>
13#endif
14
15#define OFF(x) offsetof(PyTracebackObject, x)
16
17#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
18#define MAX_STRING_LENGTH 500
19#define MAX_FRAME_DEPTH 100
20#define MAX_NTHREADS 100
21
22/* Function from Parser/tokenizer.c */
23extern char * PyTokenizer_FindEncodingFilename(int, PyObject *);
24
25_Py_IDENTIFIER(TextIOWrapper);
26_Py_IDENTIFIER(close);
27_Py_IDENTIFIER(open);
28_Py_IDENTIFIER(path);
29
30/*[clinic input]
31class TracebackType "PyTracebackObject *" "&PyTraceback_Type"
32[clinic start generated code]*/
33/*[clinic end generated code: output=da39a3ee5e6b4b0d input=928fa06c10151120]*/
34
35#include "clinic/traceback.c.h"
36
37static PyObject *
38tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti,
39 int lineno)
40{
41 PyTracebackObject *tb;
42 if ((next != NULL && !PyTraceBack_Check(next)) ||
43 frame == NULL || !PyFrame_Check(frame)) {
44 PyErr_BadInternalCall();
45 return NULL;
46 }
47 tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
48 if (tb != NULL) {
49 Py_XINCREF(next);
50 tb->tb_next = next;
51 Py_XINCREF(frame);
52 tb->tb_frame = frame;
53 tb->tb_lasti = lasti;
54 tb->tb_lineno = lineno;
55 PyObject_GC_Track(tb);
56 }
57 return (PyObject *)tb;
58}
59
60/*[clinic input]
61@classmethod
62TracebackType.__new__ as tb_new
63
64 tb_next: object
65 tb_frame: object(type='PyFrameObject *', subclass_of='&PyFrame_Type')
66 tb_lasti: int
67 tb_lineno: int
68
69Create a new traceback object.
70[clinic start generated code]*/
71
72static PyObject *
73tb_new_impl(PyTypeObject *type, PyObject *tb_next, PyFrameObject *tb_frame,
74 int tb_lasti, int tb_lineno)
75/*[clinic end generated code: output=fa077debd72d861a input=01cbe8ec8783fca7]*/
76{
77 if (tb_next == Py_None) {
78 tb_next = NULL;
79 } else if (!PyTraceBack_Check(tb_next)) {
80 return PyErr_Format(PyExc_TypeError,
81 "expected traceback object or None, got '%s'",
82 Py_TYPE(tb_next)->tp_name);
83 }
84
85 return tb_create_raw((PyTracebackObject *)tb_next, tb_frame, tb_lasti,
86 tb_lineno);
87}
88
89static PyObject *
90tb_dir(PyTracebackObject *self, PyObject *Py_UNUSED(ignored))
91{
92 return Py_BuildValue("[ssss]", "tb_frame", "tb_next",
93 "tb_lasti", "tb_lineno");
94}
95
96static PyObject *
97tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_))
98{
99 PyObject* ret = (PyObject*)self->tb_next;
100 if (!ret) {
101 ret = Py_None;
102 }
103 Py_INCREF(ret);
104 return ret;
105}
106
107static int
108tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_))
109{
110 if (!new_next) {
111 PyErr_Format(PyExc_TypeError, "can't delete tb_next attribute");
112 return -1;
113 }
114
115 /* We accept None or a traceback object, and map None -> NULL (inverse of
116 tb_next_get) */
117 if (new_next == Py_None) {
118 new_next = NULL;
119 } else if (!PyTraceBack_Check(new_next)) {
120 PyErr_Format(PyExc_TypeError,
121 "expected traceback object, got '%s'",
122 Py_TYPE(new_next)->tp_name);
123 return -1;
124 }
125
126 /* Check for loops */
127 PyTracebackObject *cursor = (PyTracebackObject *)new_next;
128 while (cursor) {
129 if (cursor == self) {
130 PyErr_Format(PyExc_ValueError, "traceback loop detected");
131 return -1;
132 }
133 cursor = cursor->tb_next;
134 }
135
136 PyObject *old_next = (PyObject*)self->tb_next;
137 Py_XINCREF(new_next);
138 self->tb_next = (PyTracebackObject *)new_next;
139 Py_XDECREF(old_next);
140
141 return 0;
142}
143
144
145static PyMethodDef tb_methods[] = {
146 {"__dir__", (PyCFunction)tb_dir, METH_NOARGS},
147 {NULL, NULL, 0, NULL},
148};
149
150static PyMemberDef tb_memberlist[] = {
151 {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY|PY_AUDIT_READ},
152 {"tb_lasti", T_INT, OFF(tb_lasti), READONLY},
153 {"tb_lineno", T_INT, OFF(tb_lineno), READONLY},
154 {NULL} /* Sentinel */
155};
156
157static PyGetSetDef tb_getsetters[] = {
158 {"tb_next", (getter)tb_next_get, (setter)tb_next_set, NULL, NULL},
159 {NULL} /* Sentinel */
160};
161
162static void
163tb_dealloc(PyTracebackObject *tb)
164{
165 PyObject_GC_UnTrack(tb);
166 Py_TRASHCAN_BEGIN(tb, tb_dealloc)
167 Py_XDECREF(tb->tb_next);
168 Py_XDECREF(tb->tb_frame);
169 PyObject_GC_Del(tb);
170 Py_TRASHCAN_END
171}
172
173static int
174tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)
175{
176 Py_VISIT(tb->tb_next);
177 Py_VISIT(tb->tb_frame);
178 return 0;
179}
180
181static int
182tb_clear(PyTracebackObject *tb)
183{
184 Py_CLEAR(tb->tb_next);
185 Py_CLEAR(tb->tb_frame);
186 return 0;
187}
188
189PyTypeObject PyTraceBack_Type = {
190 PyVarObject_HEAD_INIT(&PyType_Type, 0)
191 "traceback",
192 sizeof(PyTracebackObject),
193 0,
194 (destructor)tb_dealloc, /*tp_dealloc*/
195 0, /*tp_vectorcall_offset*/
196 0, /*tp_getattr*/
197 0, /*tp_setattr*/
198 0, /*tp_as_async*/
199 0, /*tp_repr*/
200 0, /*tp_as_number*/
201 0, /*tp_as_sequence*/
202 0, /*tp_as_mapping*/
203 0, /* tp_hash */
204 0, /* tp_call */
205 0, /* tp_str */
206 PyObject_GenericGetAttr, /* tp_getattro */
207 0, /* tp_setattro */
208 0, /* tp_as_buffer */
209 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
210 tb_new__doc__, /* tp_doc */
211 (traverseproc)tb_traverse, /* tp_traverse */
212 (inquiry)tb_clear, /* tp_clear */
213 0, /* tp_richcompare */
214 0, /* tp_weaklistoffset */
215 0, /* tp_iter */
216 0, /* tp_iternext */
217 tb_methods, /* tp_methods */
218 tb_memberlist, /* tp_members */
219 tb_getsetters, /* tp_getset */
220 0, /* tp_base */
221 0, /* tp_dict */
222 0, /* tp_descr_get */
223 0, /* tp_descr_set */
224 0, /* tp_dictoffset */
225 0, /* tp_init */
226 0, /* tp_alloc */
227 tb_new, /* tp_new */
228};
229
230
231PyObject*
232_PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame)
233{
234 assert(tb_next == NULL || PyTraceBack_Check(tb_next));
235 assert(frame != NULL);
236
237 return tb_create_raw((PyTracebackObject *)tb_next, frame, frame->f_lasti*sizeof(_Py_CODEUNIT),
238 PyFrame_GetLineNumber(frame));
239}
240
241
242int
243PyTraceBack_Here(PyFrameObject *frame)
244{
245 PyObject *exc, *val, *tb, *newtb;
246 PyErr_Fetch(&exc, &val, &tb);
247 newtb = _PyTraceBack_FromFrame(tb, frame);
248 if (newtb == NULL) {
249 _PyErr_ChainExceptions(exc, val, tb);
250 return -1;
251 }
252 PyErr_Restore(exc, val, newtb);
253 Py_XDECREF(tb);
254 return 0;
255}
256
257/* Insert a frame into the traceback for (funcname, filename, lineno). */
258void _PyTraceback_Add(const char *funcname, const char *filename, int lineno)
259{
260 PyObject *globals;
261 PyCodeObject *code;
262 PyFrameObject *frame;
263 PyObject *exc, *val, *tb;
264
265 /* Save and clear the current exception. Python functions must not be
266 called with an exception set. Calling Python functions happens when
267 the codec of the filesystem encoding is implemented in pure Python. */
268 PyErr_Fetch(&exc, &val, &tb);
269
270 globals = PyDict_New();
271 if (!globals)
272 goto error;
273 code = PyCode_NewEmpty(filename, funcname, lineno);
274 if (!code) {
275 Py_DECREF(globals);
276 goto error;
277 }
278 frame = PyFrame_New(PyThreadState_Get(), code, globals, NULL);
279 Py_DECREF(globals);
280 Py_DECREF(code);
281 if (!frame)
282 goto error;
283 frame->f_lineno = lineno;
284
285 PyErr_Restore(exc, val, tb);
286 PyTraceBack_Here(frame);
287 Py_DECREF(frame);
288 return;
289
290error:
291 _PyErr_ChainExceptions(exc, val, tb);
292}
293
294static PyObject *
295_Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *io)
296{
297 Py_ssize_t i;
298 PyObject *binary;
299 PyObject *v;
300 Py_ssize_t npath;
301 size_t taillen;
302 PyObject *syspath;
303 PyObject *path;
304 const char* tail;
305 PyObject *filebytes;
306 const char* filepath;
307 Py_ssize_t len;
308 PyObject* result;
309
310 filebytes = PyUnicode_EncodeFSDefault(filename);
311 if (filebytes == NULL) {
312 PyErr_Clear();
313 return NULL;
314 }
315 filepath = PyBytes_AS_STRING(filebytes);
316
317 /* Search tail of filename in sys.path before giving up */
318 tail = strrchr(filepath, SEP);
319 if (tail == NULL)
320 tail = filepath;
321 else
322 tail++;
323 taillen = strlen(tail);
324
325 syspath = _PySys_GetObjectId(&PyId_path);
326 if (syspath == NULL || !PyList_Check(syspath))
327 goto error;
328 npath = PyList_Size(syspath);
329
330 for (i = 0; i < npath; i++) {
331 v = PyList_GetItem(syspath, i);
332 if (v == NULL) {
333 PyErr_Clear();
334 break;
335 }
336 if (!PyUnicode_Check(v))
337 continue;
338 path = PyUnicode_EncodeFSDefault(v);
339 if (path == NULL) {
340 PyErr_Clear();
341 continue;
342 }
343 len = PyBytes_GET_SIZE(path);
344 if (len + 1 + (Py_ssize_t)taillen >= (Py_ssize_t)namelen - 1) {
345 Py_DECREF(path);
346 continue; /* Too long */
347 }
348 strcpy(namebuf, PyBytes_AS_STRING(path));
349 Py_DECREF(path);
350 if (strlen(namebuf) != (size_t)len)
351 continue; /* v contains '\0' */
352 if (len > 0 && namebuf[len-1] != SEP)
353 namebuf[len++] = SEP;
354 strcpy(namebuf+len, tail);
355
356 binary = _PyObject_CallMethodId(io, &PyId_open, "ss", namebuf, "rb");
357 if (binary != NULL) {
358 result = binary;
359 goto finally;
360 }
361 PyErr_Clear();
362 }
363 goto error;
364
365error:
366 result = NULL;
367finally:
368 Py_DECREF(filebytes);
369 return result;
370}
371
372int
373_Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent)
374{
375 int err = 0;
376 int fd;
377 int i;
378 char *found_encoding;
379 const char *encoding;
380 PyObject *io;
381 PyObject *binary;
382 PyObject *fob = NULL;
383 PyObject *lineobj = NULL;
384 PyObject *res;
385 char buf[MAXPATHLEN+1];
386 int kind;
387 const void *data;
388
389 /* open the file */
390 if (filename == NULL)
391 return 0;
392
393 io = PyImport_ImportModuleNoBlock("io");
394 if (io == NULL)
395 return -1;
396 binary = _PyObject_CallMethodId(io, &PyId_open, "Os", filename, "rb");
397
398 if (binary == NULL) {
399 PyErr_Clear();
400
401 binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io);
402 if (binary == NULL) {
403 Py_DECREF(io);
404 return -1;
405 }
406 }
407
408 /* use the right encoding to decode the file as unicode */
409 fd = PyObject_AsFileDescriptor(binary);
410 if (fd < 0) {
411 Py_DECREF(io);
412 Py_DECREF(binary);
413 return 0;
414 }
415 found_encoding = PyTokenizer_FindEncodingFilename(fd, filename);
416 if (found_encoding == NULL)
417 PyErr_Clear();
418 encoding = (found_encoding != NULL) ? found_encoding : "utf-8";
419 /* Reset position */
420 if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
421 Py_DECREF(io);
422 Py_DECREF(binary);
423 PyMem_Free(found_encoding);
424 return 0;
425 }
426 fob = _PyObject_CallMethodId(io, &PyId_TextIOWrapper, "Os", binary, encoding);
427 Py_DECREF(io);
428 PyMem_Free(found_encoding);
429
430 if (fob == NULL) {
431 PyErr_Clear();
432
433 res = _PyObject_CallMethodIdNoArgs(binary, &PyId_close);
434 Py_DECREF(binary);
435 if (res)
436 Py_DECREF(res);
437 else
438 PyErr_Clear();
439 return 0;
440 }
441 Py_DECREF(binary);
442
443 /* get the line number lineno */
444 for (i = 0; i < lineno; i++) {
445 Py_XDECREF(lineobj);
446 lineobj = PyFile_GetLine(fob, -1);
447 if (!lineobj) {
448 PyErr_Clear();
449 err = -1;
450 break;
451 }
452 }
453 res = _PyObject_CallMethodIdNoArgs(fob, &PyId_close);
454 if (res)
455 Py_DECREF(res);
456 else
457 PyErr_Clear();
458 Py_DECREF(fob);
459 if (!lineobj || !PyUnicode_Check(lineobj)) {
460 Py_XDECREF(lineobj);
461 return err;
462 }
463
464 /* remove the indentation of the line */
465 kind = PyUnicode_KIND(lineobj);
466 data = PyUnicode_DATA(lineobj);
467 for (i=0; i < PyUnicode_GET_LENGTH(lineobj); i++) {
468 Py_UCS4 ch = PyUnicode_READ(kind, data, i);
469 if (ch != ' ' && ch != '\t' && ch != '\014')
470 break;
471 }
472 if (i) {
473 PyObject *truncated;
474 truncated = PyUnicode_Substring(lineobj, i, PyUnicode_GET_LENGTH(lineobj));
475 if (truncated) {
476 Py_DECREF(lineobj);
477 lineobj = truncated;
478 } else {
479 PyErr_Clear();
480 }
481 }
482
483 /* Write some spaces before the line */
484 strcpy(buf, " ");
485 assert (strlen(buf) == 10);
486 while (indent > 0) {
487 if (indent < 10)
488 buf[indent] = '\0';
489 err = PyFile_WriteString(buf, f);
490 if (err != 0)
491 break;
492 indent -= 10;
493 }
494
495 /* finally display the line */
496 if (err == 0)
497 err = PyFile_WriteObject(lineobj, f, Py_PRINT_RAW);
498 Py_DECREF(lineobj);
499 if (err == 0)
500 err = PyFile_WriteString("\n", f);
501 return err;
502}
503
504static int
505tb_displayline(PyObject *f, PyObject *filename, int lineno, PyObject *name)
506{
507 int err;
508 PyObject *line;
509
510 if (filename == NULL || name == NULL)
511 return -1;
512 line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n",
513 filename, lineno, name);
514 if (line == NULL)
515 return -1;
516 err = PyFile_WriteObject(line, f, Py_PRINT_RAW);
517 Py_DECREF(line);
518 if (err != 0)
519 return err;
520 /* ignore errors since we can't report them, can we? */
521 if (_Py_DisplaySourceLine(f, filename, lineno, 4))
522 PyErr_Clear();
523 return err;
524}
525
526static const int TB_RECURSIVE_CUTOFF = 3; // Also hardcoded in traceback.py.
527
528static int
529tb_print_line_repeated(PyObject *f, long cnt)
530{
531 cnt -= TB_RECURSIVE_CUTOFF;
532 PyObject *line = PyUnicode_FromFormat(
533 (cnt > 1)
534 ? " [Previous line repeated %ld more times]\n"
535 : " [Previous line repeated %ld more time]\n",
536 cnt);
537 if (line == NULL) {
538 return -1;
539 }
540 int err = PyFile_WriteObject(line, f, Py_PRINT_RAW);
541 Py_DECREF(line);
542 return err;
543}
544
545static int
546tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
547{
548 int err = 0;
549 Py_ssize_t depth = 0;
550 PyObject *last_file = NULL;
551 int last_line = -1;
552 PyObject *last_name = NULL;
553 long cnt = 0;
554 PyTracebackObject *tb1 = tb;
555 while (tb1 != NULL) {
556 depth++;
557 tb1 = tb1->tb_next;
558 }
559 while (tb != NULL && depth > limit) {
560 depth--;
561 tb = tb->tb_next;
562 }
563 while (tb != NULL && err == 0) {
564 PyCodeObject *code = PyFrame_GetCode(tb->tb_frame);
565 if (last_file == NULL ||
566 code->co_filename != last_file ||
567 last_line == -1 || tb->tb_lineno != last_line ||
568 last_name == NULL || code->co_name != last_name) {
569 if (cnt > TB_RECURSIVE_CUTOFF) {
570 err = tb_print_line_repeated(f, cnt);
571 }
572 last_file = code->co_filename;
573 last_line = tb->tb_lineno;
574 last_name = code->co_name;
575 cnt = 0;
576 }
577 cnt++;
578 if (err == 0 && cnt <= TB_RECURSIVE_CUTOFF) {
579 err = tb_displayline(f, code->co_filename, tb->tb_lineno,
580 code->co_name);
581 if (err == 0) {
582 err = PyErr_CheckSignals();
583 }
584 }
585 Py_DECREF(code);
586 tb = tb->tb_next;
587 }
588 if (err == 0 && cnt > TB_RECURSIVE_CUTOFF) {
589 err = tb_print_line_repeated(f, cnt);
590 }
591 return err;
592}
593
594#define PyTraceBack_LIMIT 1000
595
596int
597PyTraceBack_Print(PyObject *v, PyObject *f)
598{
599 int err;
600 PyObject *limitv;
601 long limit = PyTraceBack_LIMIT;
602
603 if (v == NULL)
604 return 0;
605 if (!PyTraceBack_Check(v)) {
606 PyErr_BadInternalCall();
607 return -1;
608 }
609 limitv = PySys_GetObject("tracebacklimit");
610 if (limitv && PyLong_Check(limitv)) {
611 int overflow;
612 limit = PyLong_AsLongAndOverflow(limitv, &overflow);
613 if (overflow > 0) {
614 limit = LONG_MAX;
615 }
616 else if (limit <= 0) {
617 return 0;
618 }
619 }
620 err = PyFile_WriteString("Traceback (most recent call last):\n", f);
621 if (!err)
622 err = tb_printinternal((PyTracebackObject *)v, f, limit);
623 return err;
624}
625
626/* Format an integer in range [0; 0xffffffff] to decimal and write it
627 into the file fd.
628
629 This function is signal safe. */
630
631void
632_Py_DumpDecimal(int fd, size_t value)
633{
634 /* maximum number of characters required for output of %lld or %p.
635 We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits,
636 plus 1 for the null byte. 53/22 is an upper bound for log10(256). */
637 char buffer[1 + (sizeof(size_t)*53-1) / 22 + 1];
638 char *ptr, *end;
639
640 end = &buffer[Py_ARRAY_LENGTH(buffer) - 1];
641 ptr = end;
642 *ptr = '\0';
643 do {
644 --ptr;
645 assert(ptr >= buffer);
646 *ptr = '0' + (value % 10);
647 value /= 10;
648 } while (value);
649
650 _Py_write_noraise(fd, ptr, end - ptr);
651}
652
653/* Format an integer as hexadecimal with width digits into fd file descriptor.
654 The function is signal safe. */
655void
656_Py_DumpHexadecimal(int fd, uintptr_t value, Py_ssize_t width)
657{
658 char buffer[sizeof(uintptr_t) * 2 + 1], *ptr, *end;
659 const Py_ssize_t size = Py_ARRAY_LENGTH(buffer) - 1;
660
661 if (width > size)
662 width = size;
663 /* it's ok if width is negative */
664
665 end = &buffer[size];
666 ptr = end;
667 *ptr = '\0';
668 do {
669 --ptr;
670 assert(ptr >= buffer);
671 *ptr = Py_hexdigits[value & 15];
672 value >>= 4;
673 } while ((end - ptr) < width || value);
674
675 _Py_write_noraise(fd, ptr, end - ptr);
676}
677
678void
679_Py_DumpASCII(int fd, PyObject *text)
680{
681 PyASCIIObject *ascii = (PyASCIIObject *)text;
682 Py_ssize_t i, size;
683 int truncated;
684 int kind;
685 void *data = NULL;
686 wchar_t *wstr = NULL;
687 Py_UCS4 ch;
688
689 if (!PyUnicode_Check(text))
690 return;
691
692 size = ascii->length;
693 kind = ascii->state.kind;
694 if (kind == PyUnicode_WCHAR_KIND) {
695 wstr = ((PyASCIIObject *)text)->wstr;
696 if (wstr == NULL)
697 return;
698 size = ((PyCompactUnicodeObject *)text)->wstr_length;
699 }
700 else if (ascii->state.compact) {
701 if (ascii->state.ascii)
702 data = ((PyASCIIObject*)text) + 1;
703 else
704 data = ((PyCompactUnicodeObject*)text) + 1;
705 }
706 else {
707 data = ((PyUnicodeObject *)text)->data.any;
708 if (data == NULL)
709 return;
710 }
711
712 if (MAX_STRING_LENGTH < size) {
713 size = MAX_STRING_LENGTH;
714 truncated = 1;
715 }
716 else {
717 truncated = 0;
718 }
719
720 // Is an ASCII string?
721 if (ascii->state.ascii) {
722 assert(kind == PyUnicode_1BYTE_KIND);
723 char *str = data;
724
725 int need_escape = 0;
726 for (i=0; i < size; i++) {
727 ch = str[i];
728 if (!(' ' <= ch && ch <= 126)) {
729 need_escape = 1;
730 break;
731 }
732 }
733 if (!need_escape) {
734 // The string can be written with a single write() syscall
735 _Py_write_noraise(fd, str, size);
736 goto done;
737 }
738 }
739
740 for (i=0; i < size; i++) {
741 if (kind != PyUnicode_WCHAR_KIND)
742 ch = PyUnicode_READ(kind, data, i);
743 else
744 ch = wstr[i];
745 if (' ' <= ch && ch <= 126) {
746 /* printable ASCII character */
747 char c = (char)ch;
748 _Py_write_noraise(fd, &c, 1);
749 }
750 else if (ch <= 0xff) {
751 PUTS(fd, "\\x");
752 _Py_DumpHexadecimal(fd, ch, 2);
753 }
754 else if (ch <= 0xffff) {
755 PUTS(fd, "\\u");
756 _Py_DumpHexadecimal(fd, ch, 4);
757 }
758 else {
759 PUTS(fd, "\\U");
760 _Py_DumpHexadecimal(fd, ch, 8);
761 }
762 }
763
764done:
765 if (truncated) {
766 PUTS(fd, "...");
767 }
768}
769
770/* Write a frame into the file fd: "File "xxx", line xxx in xxx".
771
772 This function is signal safe. */
773
774static void
775dump_frame(int fd, PyFrameObject *frame)
776{
777 PyCodeObject *code = PyFrame_GetCode(frame);
778 PUTS(fd, " File ");
779 if (code->co_filename != NULL
780 && PyUnicode_Check(code->co_filename))
781 {
782 PUTS(fd, "\"");
783 _Py_DumpASCII(fd, code->co_filename);
784 PUTS(fd, "\"");
785 } else {
786 PUTS(fd, "???");
787 }
788
789 int lineno = PyFrame_GetLineNumber(frame);
790 PUTS(fd, ", line ");
791 if (lineno >= 0) {
792 _Py_DumpDecimal(fd, (size_t)lineno);
793 }
794 else {
795 PUTS(fd, "???");
796 }
797 PUTS(fd, " in ");
798
799 if (code->co_name != NULL
800 && PyUnicode_Check(code->co_name)) {
801 _Py_DumpASCII(fd, code->co_name);
802 }
803 else {
804 PUTS(fd, "???");
805 }
806
807 PUTS(fd, "\n");
808 Py_DECREF(code);
809}
810
811static void
812dump_traceback(int fd, PyThreadState *tstate, int write_header)
813{
814 PyFrameObject *frame;
815 unsigned int depth;
816
817 if (write_header) {
818 PUTS(fd, "Stack (most recent call first):\n");
819 }
820
821 // Use a borrowed reference. Avoid Py_INCREF/Py_DECREF, since this function
822 // can be called in a signal handler by the faulthandler module which must
823 // not modify Python objects.
824 frame = tstate->frame;
825 if (frame == NULL) {
826 PUTS(fd, " <no Python frame>\n");
827 return;
828 }
829
830 depth = 0;
831 while (1) {
832 if (MAX_FRAME_DEPTH <= depth) {
833 PUTS(fd, " ...\n");
834 break;
835 }
836 if (!PyFrame_Check(frame)) {
837 break;
838 }
839 dump_frame(fd, frame);
840 PyFrameObject *back = frame->f_back;
841
842 if (back == NULL) {
843 break;
844 }
845 frame = back;
846 depth++;
847 }
848}
849
850/* Dump the traceback of a Python thread into fd. Use write() to write the
851 traceback and retry if write() is interrupted by a signal (failed with
852 EINTR), but don't call the Python signal handler.
853
854 The caller is responsible to call PyErr_CheckSignals() to call Python signal
855 handlers if signals were received. */
856void
857_Py_DumpTraceback(int fd, PyThreadState *tstate)
858{
859 dump_traceback(fd, tstate, 1);
860}
861
862/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
863 is_current is true, "Thread 0xHHHH:\n" otherwise.
864
865 This function is signal safe. */
866
867static void
868write_thread_id(int fd, PyThreadState *tstate, int is_current)
869{
870 if (is_current)
871 PUTS(fd, "Current thread 0x");
872 else
873 PUTS(fd, "Thread 0x");
874 _Py_DumpHexadecimal(fd,
875 tstate->thread_id,
876 sizeof(unsigned long) * 2);
877 PUTS(fd, " (most recent call first):\n");
878}
879
880/* Dump the traceback of all Python threads into fd. Use write() to write the
881 traceback and retry if write() is interrupted by a signal (failed with
882 EINTR), but don't call the Python signal handler.
883
884 The caller is responsible to call PyErr_CheckSignals() to call Python signal
885 handlers if signals were received. */
886const char*
887_Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
888 PyThreadState *current_tstate)
889{
890 PyThreadState *tstate;
891 unsigned int nthreads;
892
893 if (current_tstate == NULL) {
894 /* _Py_DumpTracebackThreads() is called from signal handlers by
895 faulthandler.
896
897 SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals
898 and are thus delivered to the thread that caused the fault. Get the
899 Python thread state of the current thread.
900
901 PyThreadState_Get() doesn't give the state of the thread that caused
902 the fault if the thread released the GIL, and so
903 _PyThreadState_GET() cannot be used. Read the thread specific
904 storage (TSS) instead: call PyGILState_GetThisThreadState(). */
905 current_tstate = PyGILState_GetThisThreadState();
906 }
907
908 if (interp == NULL) {
909 if (current_tstate == NULL) {
910 interp = _PyGILState_GetInterpreterStateUnsafe();
911 if (interp == NULL) {
912 /* We need the interpreter state to get Python threads */
913 return "unable to get the interpreter state";
914 }
915 }
916 else {
917 interp = current_tstate->interp;
918 }
919 }
920 assert(interp != NULL);
921
922 /* Get the current interpreter from the current thread */
923 tstate = PyInterpreterState_ThreadHead(interp);
924 if (tstate == NULL)
925 return "unable to get the thread head state";
926
927 /* Dump the traceback of each thread */
928 tstate = PyInterpreterState_ThreadHead(interp);
929 nthreads = 0;
930 _Py_BEGIN_SUPPRESS_IPH
931 do
932 {
933 if (nthreads != 0)
934 PUTS(fd, "\n");
935 if (nthreads >= MAX_NTHREADS) {
936 PUTS(fd, "...\n");
937 break;
938 }
939 write_thread_id(fd, tstate, tstate == current_tstate);
940 if (tstate == current_tstate && tstate->interp->gc.collecting) {
941 PUTS(fd, " Garbage-collecting\n");
942 }
943 dump_traceback(fd, tstate, 0);
944 tstate = PyThreadState_Next(tstate);
945 nthreads++;
946 } while (tstate != NULL);
947 _Py_END_SUPPRESS_IPH
948
949 return NULL;
950}
951
952