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