• 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 /* Format an integer in range [0; 0xffffffff] to decimal and write it
626    into the file fd.
627 
628    This function is signal safe. */
629 
630 void
_Py_DumpDecimal(int fd,unsigned long value)631 _Py_DumpDecimal(int fd, unsigned long value)
632 {
633     /* maximum number of characters required for output of %lld or %p.
634        We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits,
635        plus 1 for the null byte.  53/22 is an upper bound for log10(256). */
636     char buffer[1 + (sizeof(unsigned long)*53-1) / 22 + 1];
637     char *ptr, *end;
638 
639     end = &buffer[Py_ARRAY_LENGTH(buffer) - 1];
640     ptr = end;
641     *ptr = '\0';
642     do {
643         --ptr;
644         assert(ptr >= buffer);
645         *ptr = '0' + (value % 10);
646         value /= 10;
647     } while (value);
648 
649     _Py_write_noraise(fd, ptr, end - ptr);
650 }
651 
652 /* Format an integer in range [0; 0xffffffff] to hexadecimal of 'width' digits,
653    and write it into the file fd.
654 
655    This function is signal safe. */
656 
657 void
_Py_DumpHexadecimal(int fd,unsigned long value,Py_ssize_t width)658 _Py_DumpHexadecimal(int fd, unsigned long value, Py_ssize_t width)
659 {
660     char buffer[sizeof(unsigned long) * 2 + 1], *ptr, *end;
661     const Py_ssize_t size = Py_ARRAY_LENGTH(buffer) - 1;
662 
663     if (width > size)
664         width = size;
665     /* it's ok if width is negative */
666 
667     end = &buffer[size];
668     ptr = end;
669     *ptr = '\0';
670     do {
671         --ptr;
672         assert(ptr >= buffer);
673         *ptr = Py_hexdigits[value & 15];
674         value >>= 4;
675     } while ((end - ptr) < width || value);
676 
677     _Py_write_noraise(fd, ptr, end - ptr);
678 }
679 
680 void
_Py_DumpASCII(int fd,PyObject * text)681 _Py_DumpASCII(int fd, PyObject *text)
682 {
683     PyASCIIObject *ascii = (PyASCIIObject *)text;
684     Py_ssize_t i, size;
685     int truncated;
686     int kind;
687     void *data = NULL;
688     wchar_t *wstr = NULL;
689     Py_UCS4 ch;
690 
691     if (!PyUnicode_Check(text))
692         return;
693 
694     size = ascii->length;
695     kind = ascii->state.kind;
696     if (kind == PyUnicode_WCHAR_KIND) {
697         wstr = ((PyASCIIObject *)text)->wstr;
698         if (wstr == NULL)
699             return;
700         size = ((PyCompactUnicodeObject *)text)->wstr_length;
701     }
702     else if (ascii->state.compact) {
703         if (ascii->state.ascii)
704             data = ((PyASCIIObject*)text) + 1;
705         else
706             data = ((PyCompactUnicodeObject*)text) + 1;
707     }
708     else {
709         data = ((PyUnicodeObject *)text)->data.any;
710         if (data == NULL)
711             return;
712     }
713 
714     if (MAX_STRING_LENGTH < size) {
715         size = MAX_STRING_LENGTH;
716         truncated = 1;
717     }
718     else {
719         truncated = 0;
720     }
721 
722     for (i=0; i < size; i++) {
723         if (kind != PyUnicode_WCHAR_KIND)
724             ch = PyUnicode_READ(kind, data, i);
725         else
726             ch = wstr[i];
727         if (' ' <= ch && ch <= 126) {
728             /* printable ASCII character */
729             char c = (char)ch;
730             _Py_write_noraise(fd, &c, 1);
731         }
732         else if (ch <= 0xff) {
733             PUTS(fd, "\\x");
734             _Py_DumpHexadecimal(fd, ch, 2);
735         }
736         else if (ch <= 0xffff) {
737             PUTS(fd, "\\u");
738             _Py_DumpHexadecimal(fd, ch, 4);
739         }
740         else {
741             PUTS(fd, "\\U");
742             _Py_DumpHexadecimal(fd, ch, 8);
743         }
744     }
745     if (truncated) {
746         PUTS(fd, "...");
747     }
748 }
749 
750 /* Write a frame into the file fd: "File "xxx", line xxx in xxx".
751 
752    This function is signal safe. */
753 
754 static void
dump_frame(int fd,PyFrameObject * frame)755 dump_frame(int fd, PyFrameObject *frame)
756 {
757     PyCodeObject *code = PyFrame_GetCode(frame);
758     PUTS(fd, "  File ");
759     if (code->co_filename != NULL
760         && PyUnicode_Check(code->co_filename))
761     {
762         PUTS(fd, "\"");
763         _Py_DumpASCII(fd, code->co_filename);
764         PUTS(fd, "\"");
765     } else {
766         PUTS(fd, "???");
767     }
768 
769     /* PyFrame_GetLineNumber() was introduced in Python 2.7.0 and 3.2.0 */
770     int lineno = PyCode_Addr2Line(code, frame->f_lasti);
771     PUTS(fd, ", line ");
772     if (lineno >= 0) {
773         _Py_DumpDecimal(fd, (unsigned long)lineno);
774     }
775     else {
776         PUTS(fd, "???");
777     }
778     PUTS(fd, " in ");
779 
780     if (code->co_name != NULL
781        && PyUnicode_Check(code->co_name)) {
782         _Py_DumpASCII(fd, code->co_name);
783     }
784     else {
785         PUTS(fd, "???");
786     }
787 
788     PUTS(fd, "\n");
789     Py_DECREF(code);
790 }
791 
792 static void
dump_traceback(int fd,PyThreadState * tstate,int write_header)793 dump_traceback(int fd, PyThreadState *tstate, int write_header)
794 {
795     PyFrameObject *frame;
796     unsigned int depth;
797 
798     if (write_header) {
799         PUTS(fd, "Stack (most recent call first):\n");
800     }
801 
802     frame = PyThreadState_GetFrame(tstate);
803     if (frame == NULL) {
804         PUTS(fd, "<no Python frame>\n");
805         return;
806     }
807 
808     depth = 0;
809     while (1) {
810         if (MAX_FRAME_DEPTH <= depth) {
811             Py_DECREF(frame);
812             PUTS(fd, "  ...\n");
813             break;
814         }
815         if (!PyFrame_Check(frame)) {
816             Py_DECREF(frame);
817             break;
818         }
819         dump_frame(fd, frame);
820         PyFrameObject *back = PyFrame_GetBack(frame);
821         Py_DECREF(frame);
822 
823         if (back == NULL) {
824             break;
825         }
826         frame = back;
827         depth++;
828     }
829 }
830 
831 /* Dump the traceback of a Python thread into fd. Use write() to write the
832    traceback and retry if write() is interrupted by a signal (failed with
833    EINTR), but don't call the Python signal handler.
834 
835    The caller is responsible to call PyErr_CheckSignals() to call Python signal
836    handlers if signals were received. */
837 void
_Py_DumpTraceback(int fd,PyThreadState * tstate)838 _Py_DumpTraceback(int fd, PyThreadState *tstate)
839 {
840     dump_traceback(fd, tstate, 1);
841 }
842 
843 /* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
844    is_current is true, "Thread 0xHHHH:\n" otherwise.
845 
846    This function is signal safe. */
847 
848 static void
write_thread_id(int fd,PyThreadState * tstate,int is_current)849 write_thread_id(int fd, PyThreadState *tstate, int is_current)
850 {
851     if (is_current)
852         PUTS(fd, "Current thread 0x");
853     else
854         PUTS(fd, "Thread 0x");
855     _Py_DumpHexadecimal(fd,
856                         tstate->thread_id,
857                         sizeof(unsigned long) * 2);
858     PUTS(fd, " (most recent call first):\n");
859 }
860 
861 /* Dump the traceback of all Python threads into fd. Use write() to write the
862    traceback and retry if write() is interrupted by a signal (failed with
863    EINTR), but don't call the Python signal handler.
864 
865    The caller is responsible to call PyErr_CheckSignals() to call Python signal
866    handlers if signals were received. */
867 const char*
_Py_DumpTracebackThreads(int fd,PyInterpreterState * interp,PyThreadState * current_tstate)868 _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
869                          PyThreadState *current_tstate)
870 {
871     PyThreadState *tstate;
872     unsigned int nthreads;
873 
874     if (current_tstate == NULL) {
875         /* _Py_DumpTracebackThreads() is called from signal handlers by
876            faulthandler.
877 
878            SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals
879            and are thus delivered to the thread that caused the fault. Get the
880            Python thread state of the current thread.
881 
882            PyThreadState_Get() doesn't give the state of the thread that caused
883            the fault if the thread released the GIL, and so
884            _PyThreadState_GET() cannot be used. Read the thread specific
885            storage (TSS) instead: call PyGILState_GetThisThreadState(). */
886         current_tstate = PyGILState_GetThisThreadState();
887     }
888 
889     if (interp == NULL) {
890         if (current_tstate == NULL) {
891             interp = _PyGILState_GetInterpreterStateUnsafe();
892             if (interp == NULL) {
893                 /* We need the interpreter state to get Python threads */
894                 return "unable to get the interpreter state";
895             }
896         }
897         else {
898             interp = current_tstate->interp;
899         }
900     }
901     assert(interp != NULL);
902 
903     /* Get the current interpreter from the current thread */
904     tstate = PyInterpreterState_ThreadHead(interp);
905     if (tstate == NULL)
906         return "unable to get the thread head state";
907 
908     /* Dump the traceback of each thread */
909     tstate = PyInterpreterState_ThreadHead(interp);
910     nthreads = 0;
911     _Py_BEGIN_SUPPRESS_IPH
912     do
913     {
914         if (nthreads != 0)
915             PUTS(fd, "\n");
916         if (nthreads >= MAX_NTHREADS) {
917             PUTS(fd, "...\n");
918             break;
919         }
920         write_thread_id(fd, tstate, tstate == current_tstate);
921         dump_traceback(fd, tstate, 0);
922         tstate = PyThreadState_Next(tstate);
923         nthreads++;
924     } while (tstate != NULL);
925     _Py_END_SUPPRESS_IPH
926 
927     return NULL;
928 }
929 
930