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