• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
23 extern 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]
31 class 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 
37 static PyObject *
tb_create_raw(PyTracebackObject * next,PyFrameObject * frame,int lasti,int lineno)38 tb_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
62 TracebackType.__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 
69 Create a new traceback object.
70 [clinic start generated code]*/
71 
72 static PyObject *
tb_new_impl(PyTypeObject * type,PyObject * tb_next,PyFrameObject * tb_frame,int tb_lasti,int tb_lineno)73 tb_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 
89 static PyObject *
tb_dir(PyTracebackObject * self,PyObject * Py_UNUSED (ignored))90 tb_dir(PyTracebackObject *self, PyObject *Py_UNUSED(ignored))
91 {
92     return Py_BuildValue("[ssss]", "tb_frame", "tb_next",
93                                    "tb_lasti", "tb_lineno");
94 }
95 
96 static PyObject *
tb_next_get(PyTracebackObject * self,void * Py_UNUSED (_))97 tb_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 
107 static int
tb_next_set(PyTracebackObject * self,PyObject * new_next,void * Py_UNUSED (_))108 tb_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 
145 static PyMethodDef tb_methods[] = {
146    {"__dir__", (PyCFunction)tb_dir, METH_NOARGS},
147    {NULL, NULL, 0, NULL},
148 };
149 
150 static 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 
157 static PyGetSetDef tb_getsetters[] = {
158     {"tb_next", (getter)tb_next_get, (setter)tb_next_set, NULL, NULL},
159     {NULL}      /* Sentinel */
160 };
161 
162 static void
tb_dealloc(PyTracebackObject * tb)163 tb_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 
173 static int
tb_traverse(PyTracebackObject * tb,visitproc visit,void * arg)174 tb_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 
181 static int
tb_clear(PyTracebackObject * tb)182 tb_clear(PyTracebackObject *tb)
183 {
184     Py_CLEAR(tb->tb_next);
185     Py_CLEAR(tb->tb_frame);
186     return 0;
187 }
188 
189 PyTypeObject 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 
231 PyObject*
_PyTraceBack_FromFrame(PyObject * tb_next,PyFrameObject * frame)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 
242 int
PyTraceBack_Here(PyFrameObject * frame)243 PyTraceBack_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). */
_PyTraceback_Add(const char * funcname,const char * filename,int lineno)258 void _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 
290 error:
291     _PyErr_ChainExceptions(exc, val, tb);
292 }
293 
294 static PyObject *
_Py_FindSourceFile(PyObject * filename,char * namebuf,size_t namelen,PyObject * io)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 
365 error:
366     result = NULL;
367 finally:
368     Py_DECREF(filebytes);
369     return result;
370 }
371 
372 int
_Py_DisplaySourceLine(PyObject * f,PyObject * filename,int lineno,int indent)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 
504 static int
tb_displayline(PyObject * f,PyObject * filename,int lineno,PyObject * name)505 tb_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 
526 static const int TB_RECURSIVE_CUTOFF = 3; // Also hardcoded in traceback.py.
527 
528 static int
tb_print_line_repeated(PyObject * f,long cnt)529 tb_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 
545 static int
tb_printinternal(PyTracebackObject * tb,PyObject * f,long limit)546 tb_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 
596 int
PyTraceBack_Print(PyObject * v,PyObject * f)597 PyTraceBack_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 
631 void
_Py_DumpDecimal(int fd,size_t value)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. */
655 void
_Py_DumpHexadecimal(int fd,uintptr_t value,Py_ssize_t width)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 
678 void
_Py_DumpASCII(int fd,PyObject * text)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 
764 done:
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 
774 static void
dump_frame(int fd,PyFrameObject * frame)775 dump_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 
811 static void
dump_traceback(int fd,PyThreadState * tstate,int write_header)812 dump_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. */
856 void
_Py_DumpTraceback(int fd,PyThreadState * tstate)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 
867 static void
write_thread_id(int fd,PyThreadState * tstate,int is_current)868 write_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. */
886 const char*
_Py_DumpTracebackThreads(int fd,PyInterpreterState * interp,PyThreadState * current_tstate)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