Line data Source code
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) write(fd, str, 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 : static PyObject *
25 0 : tb_dir(PyTracebackObject *self)
26 : {
27 0 : return Py_BuildValue("[ssss]", "tb_frame", "tb_next",
28 : "tb_lasti", "tb_lineno");
29 : }
30 :
31 : static PyMethodDef tb_methods[] = {
32 : {"__dir__", (PyCFunction)tb_dir, METH_NOARGS},
33 : {NULL, NULL, 0, NULL},
34 : };
35 :
36 : static PyMemberDef tb_memberlist[] = {
37 : {"tb_next", T_OBJECT, OFF(tb_next), READONLY},
38 : {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY},
39 : {"tb_lasti", T_INT, OFF(tb_lasti), READONLY},
40 : {"tb_lineno", T_INT, OFF(tb_lineno), READONLY},
41 : {NULL} /* Sentinel */
42 : };
43 :
44 : static void
45 1272 : tb_dealloc(PyTracebackObject *tb)
46 : {
47 1272 : PyObject_GC_UnTrack(tb);
48 1272 : Py_TRASHCAN_SAFE_BEGIN(tb)
49 1272 : Py_XDECREF(tb->tb_next);
50 1272 : Py_XDECREF(tb->tb_frame);
51 1272 : PyObject_GC_Del(tb);
52 1272 : Py_TRASHCAN_SAFE_END(tb)
53 1272 : }
54 :
55 : static int
56 4 : tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)
57 : {
58 4 : Py_VISIT(tb->tb_next);
59 4 : Py_VISIT(tb->tb_frame);
60 4 : return 0;
61 : }
62 :
63 : static void
64 0 : tb_clear(PyTracebackObject *tb)
65 : {
66 0 : Py_CLEAR(tb->tb_next);
67 0 : Py_CLEAR(tb->tb_frame);
68 0 : }
69 :
70 : PyTypeObject PyTraceBack_Type = {
71 : PyVarObject_HEAD_INIT(&PyType_Type, 0)
72 : "traceback",
73 : sizeof(PyTracebackObject),
74 : 0,
75 : (destructor)tb_dealloc, /*tp_dealloc*/
76 : 0, /*tp_print*/
77 : 0, /*tp_getattr*/
78 : 0, /*tp_setattr*/
79 : 0, /*tp_reserved*/
80 : 0, /*tp_repr*/
81 : 0, /*tp_as_number*/
82 : 0, /*tp_as_sequence*/
83 : 0, /*tp_as_mapping*/
84 : 0, /* tp_hash */
85 : 0, /* tp_call */
86 : 0, /* tp_str */
87 : PyObject_GenericGetAttr, /* tp_getattro */
88 : 0, /* tp_setattro */
89 : 0, /* tp_as_buffer */
90 : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
91 : 0, /* tp_doc */
92 : (traverseproc)tb_traverse, /* tp_traverse */
93 : (inquiry)tb_clear, /* tp_clear */
94 : 0, /* tp_richcompare */
95 : 0, /* tp_weaklistoffset */
96 : 0, /* tp_iter */
97 : 0, /* tp_iternext */
98 : tb_methods, /* tp_methods */
99 : tb_memberlist, /* tp_members */
100 : 0, /* tp_getset */
101 : 0, /* tp_base */
102 : 0, /* tp_dict */
103 : };
104 :
105 : static PyTracebackObject *
106 1272 : newtracebackobject(PyTracebackObject *next, PyFrameObject *frame)
107 : {
108 : PyTracebackObject *tb;
109 1272 : if ((next != NULL && !PyTraceBack_Check(next)) ||
110 1272 : frame == NULL || !PyFrame_Check(frame)) {
111 0 : PyErr_BadInternalCall();
112 0 : return NULL;
113 : }
114 1272 : tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
115 1272 : if (tb != NULL) {
116 1272 : Py_XINCREF(next);
117 1272 : tb->tb_next = next;
118 1272 : Py_XINCREF(frame);
119 1272 : tb->tb_frame = frame;
120 1272 : tb->tb_lasti = frame->f_lasti;
121 1272 : tb->tb_lineno = PyFrame_GetLineNumber(frame);
122 1272 : PyObject_GC_Track(tb);
123 : }
124 1272 : return tb;
125 : }
126 :
127 : int
128 1272 : PyTraceBack_Here(PyFrameObject *frame)
129 : {
130 1272 : PyThreadState *tstate = PyThreadState_GET();
131 1272 : PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback;
132 1272 : PyTracebackObject *tb = newtracebackobject(oldtb, frame);
133 1272 : if (tb == NULL)
134 0 : return -1;
135 1272 : tstate->curexc_traceback = (PyObject *)tb;
136 1272 : Py_XDECREF(oldtb);
137 1272 : return 0;
138 : }
139 :
140 : static PyObject *
141 0 : _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *io)
142 : {
143 : Py_ssize_t i;
144 : PyObject *binary;
145 : PyObject *v;
146 : Py_ssize_t npath;
147 : size_t taillen;
148 : PyObject *syspath;
149 : PyObject *path;
150 : const char* tail;
151 : PyObject *filebytes;
152 : const char* filepath;
153 : Py_ssize_t len;
154 : PyObject* result;
155 : _Py_IDENTIFIER(open);
156 :
157 0 : filebytes = PyUnicode_EncodeFSDefault(filename);
158 0 : if (filebytes == NULL) {
159 0 : PyErr_Clear();
160 0 : return NULL;
161 : }
162 0 : filepath = PyBytes_AS_STRING(filebytes);
163 :
164 : /* Search tail of filename in sys.path before giving up */
165 0 : tail = strrchr(filepath, SEP);
166 0 : if (tail == NULL)
167 0 : tail = filepath;
168 : else
169 0 : tail++;
170 0 : taillen = strlen(tail);
171 :
172 0 : syspath = PySys_GetObject("path");
173 0 : if (syspath == NULL || !PyList_Check(syspath))
174 : goto error;
175 0 : npath = PyList_Size(syspath);
176 :
177 0 : for (i = 0; i < npath; i++) {
178 0 : v = PyList_GetItem(syspath, i);
179 0 : if (v == NULL) {
180 0 : PyErr_Clear();
181 0 : break;
182 : }
183 0 : if (!PyUnicode_Check(v))
184 0 : continue;
185 0 : path = PyUnicode_EncodeFSDefault(v);
186 0 : if (path == NULL) {
187 0 : PyErr_Clear();
188 0 : continue;
189 : }
190 0 : len = PyBytes_GET_SIZE(path);
191 0 : if (len + 1 + (Py_ssize_t)taillen >= (Py_ssize_t)namelen - 1) {
192 0 : Py_DECREF(path);
193 0 : continue; /* Too long */
194 : }
195 0 : strcpy(namebuf, PyBytes_AS_STRING(path));
196 0 : Py_DECREF(path);
197 0 : if (strlen(namebuf) != len)
198 0 : continue; /* v contains '\0' */
199 0 : if (len > 0 && namebuf[len-1] != SEP)
200 0 : namebuf[len++] = SEP;
201 0 : strcpy(namebuf+len, tail);
202 :
203 0 : binary = _PyObject_CallMethodId(io, &PyId_open, "ss", namebuf, "rb");
204 0 : if (binary != NULL) {
205 0 : result = binary;
206 0 : goto finally;
207 : }
208 0 : PyErr_Clear();
209 : }
210 0 : goto error;
211 :
212 : error:
213 0 : result = NULL;
214 : finally:
215 0 : Py_DECREF(filebytes);
216 0 : return result;
217 : }
218 :
219 : int
220 0 : _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent)
221 : {
222 0 : int err = 0;
223 : int fd;
224 : int i;
225 : char *found_encoding;
226 : char *encoding;
227 : PyObject *io;
228 : PyObject *binary;
229 0 : PyObject *fob = NULL;
230 0 : PyObject *lineobj = NULL;
231 : PyObject *res;
232 : char buf[MAXPATHLEN+1];
233 : int kind;
234 : void *data;
235 : _Py_IDENTIFIER(close);
236 : _Py_IDENTIFIER(open);
237 : _Py_IDENTIFIER(TextIOWrapper);
238 :
239 : /* open the file */
240 0 : if (filename == NULL)
241 0 : return 0;
242 :
243 0 : io = PyImport_ImportModuleNoBlock("io");
244 0 : if (io == NULL)
245 0 : return -1;
246 0 : binary = _PyObject_CallMethodId(io, &PyId_open, "Os", filename, "rb");
247 :
248 0 : if (binary == NULL) {
249 0 : binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io);
250 0 : if (binary == NULL) {
251 0 : Py_DECREF(io);
252 0 : return 0;
253 : }
254 : }
255 :
256 : /* use the right encoding to decode the file as unicode */
257 0 : fd = PyObject_AsFileDescriptor(binary);
258 0 : found_encoding = PyTokenizer_FindEncodingFilename(fd, filename);
259 0 : encoding = (found_encoding != NULL) ? found_encoding : "utf-8";
260 0 : lseek(fd, 0, 0); /* Reset position */
261 0 : fob = _PyObject_CallMethodId(io, &PyId_TextIOWrapper, "Os", binary, encoding);
262 0 : Py_DECREF(io);
263 0 : Py_DECREF(binary);
264 0 : PyMem_FREE(found_encoding);
265 :
266 0 : if (fob == NULL) {
267 0 : PyErr_Clear();
268 0 : return 0;
269 : }
270 :
271 : /* get the line number lineno */
272 0 : for (i = 0; i < lineno; i++) {
273 0 : Py_XDECREF(lineobj);
274 0 : lineobj = PyFile_GetLine(fob, -1);
275 0 : if (!lineobj) {
276 0 : err = -1;
277 0 : break;
278 : }
279 : }
280 0 : res = _PyObject_CallMethodId(fob, &PyId_close, "");
281 0 : if (res)
282 0 : Py_DECREF(res);
283 : else
284 0 : PyErr_Clear();
285 0 : Py_DECREF(fob);
286 0 : if (!lineobj || !PyUnicode_Check(lineobj)) {
287 0 : Py_XDECREF(lineobj);
288 0 : return err;
289 : }
290 :
291 : /* remove the indentation of the line */
292 0 : kind = PyUnicode_KIND(lineobj);
293 0 : data = PyUnicode_DATA(lineobj);
294 0 : for (i=0; i < PyUnicode_GET_LENGTH(lineobj); i++) {
295 0 : Py_UCS4 ch = PyUnicode_READ(kind, data, i);
296 0 : if (ch != ' ' && ch != '\t' && ch != '\014')
297 0 : break;
298 : }
299 0 : if (i) {
300 : PyObject *truncated;
301 0 : truncated = PyUnicode_Substring(lineobj, i, PyUnicode_GET_LENGTH(lineobj));
302 0 : if (truncated) {
303 0 : Py_DECREF(lineobj);
304 0 : lineobj = truncated;
305 : } else {
306 0 : PyErr_Clear();
307 : }
308 : }
309 :
310 : /* Write some spaces before the line */
311 0 : strcpy(buf, " ");
312 : assert (strlen(buf) == 10);
313 0 : while (indent > 0) {
314 0 : if(indent < 10)
315 0 : buf[indent] = '\0';
316 0 : err = PyFile_WriteString(buf, f);
317 0 : if (err != 0)
318 0 : break;
319 0 : indent -= 10;
320 : }
321 :
322 : /* finally display the line */
323 0 : if (err == 0)
324 0 : err = PyFile_WriteObject(lineobj, f, Py_PRINT_RAW);
325 0 : Py_DECREF(lineobj);
326 0 : if (err == 0)
327 0 : err = PyFile_WriteString("\n", f);
328 0 : return err;
329 : }
330 :
331 : static int
332 0 : tb_displayline(PyObject *f, PyObject *filename, int lineno, PyObject *name)
333 : {
334 : int err;
335 : PyObject *line;
336 :
337 0 : if (filename == NULL || name == NULL)
338 0 : return -1;
339 0 : line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n",
340 : filename, lineno, name);
341 0 : if (line == NULL)
342 0 : return -1;
343 0 : err = PyFile_WriteObject(line, f, Py_PRINT_RAW);
344 0 : Py_DECREF(line);
345 0 : if (err != 0)
346 0 : return err;
347 : /* ignore errors since we can't report them, can we? */
348 0 : if (_Py_DisplaySourceLine(f, filename, lineno, 4))
349 0 : PyErr_Clear();
350 0 : return err;
351 : }
352 :
353 : static int
354 0 : tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
355 : {
356 0 : int err = 0;
357 0 : long depth = 0;
358 0 : PyTracebackObject *tb1 = tb;
359 0 : while (tb1 != NULL) {
360 0 : depth++;
361 0 : tb1 = tb1->tb_next;
362 : }
363 0 : while (tb != NULL && err == 0) {
364 0 : if (depth <= limit) {
365 0 : err = tb_displayline(f,
366 0 : tb->tb_frame->f_code->co_filename,
367 : tb->tb_lineno,
368 0 : tb->tb_frame->f_code->co_name);
369 : }
370 0 : depth--;
371 0 : tb = tb->tb_next;
372 0 : if (err == 0)
373 0 : err = PyErr_CheckSignals();
374 : }
375 0 : return err;
376 : }
377 :
378 : #define PyTraceBack_LIMIT 1000
379 :
380 : int
381 0 : PyTraceBack_Print(PyObject *v, PyObject *f)
382 : {
383 : int err;
384 : PyObject *limitv;
385 0 : long limit = PyTraceBack_LIMIT;
386 :
387 0 : if (v == NULL)
388 0 : return 0;
389 0 : if (!PyTraceBack_Check(v)) {
390 0 : PyErr_BadInternalCall();
391 0 : return -1;
392 : }
393 0 : limitv = PySys_GetObject("tracebacklimit");
394 0 : if (limitv) {
395 : PyObject *exc_type, *exc_value, *exc_tb;
396 :
397 0 : PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
398 0 : limit = PyLong_AsLong(limitv);
399 0 : if (limit == -1 && PyErr_Occurred()) {
400 0 : if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
401 0 : limit = PyTraceBack_LIMIT;
402 : }
403 : else {
404 0 : Py_XDECREF(exc_type);
405 0 : Py_XDECREF(exc_value);
406 0 : Py_XDECREF(exc_tb);
407 0 : return 0;
408 : }
409 : }
410 0 : else if (limit <= 0) {
411 0 : limit = PyTraceBack_LIMIT;
412 : }
413 0 : PyErr_Restore(exc_type, exc_value, exc_tb);
414 : }
415 0 : err = PyFile_WriteString("Traceback (most recent call last):\n", f);
416 0 : if (!err)
417 0 : err = tb_printinternal((PyTracebackObject *)v, f, limit);
418 0 : return err;
419 : }
420 :
421 : /* Reverse a string. For example, "abcd" becomes "dcba".
422 :
423 : This function is signal safe. */
424 :
425 : static void
426 0 : reverse_string(char *text, const size_t len)
427 : {
428 : char tmp;
429 : size_t i, j;
430 0 : if (len == 0)
431 0 : return;
432 0 : for (i=0, j=len-1; i < j; i++, j--) {
433 0 : tmp = text[i];
434 0 : text[i] = text[j];
435 0 : text[j] = tmp;
436 : }
437 : }
438 :
439 : /* Format an integer in range [0; 999999] to decimal,
440 : and write it into the file fd.
441 :
442 : This function is signal safe. */
443 :
444 : static void
445 0 : dump_decimal(int fd, int value)
446 : {
447 : char buffer[7];
448 : int len;
449 0 : if (value < 0 || 999999 < value)
450 0 : return;
451 0 : len = 0;
452 : do {
453 0 : buffer[len] = '0' + (value % 10);
454 0 : value /= 10;
455 0 : len++;
456 0 : } while (value);
457 0 : reverse_string(buffer, len);
458 0 : write(fd, buffer, len);
459 : }
460 :
461 : /* Format an integer in range [0; 0xffffffff] to hexdecimal of 'width' digits,
462 : and write it into the file fd.
463 :
464 : This function is signal safe. */
465 :
466 : static void
467 0 : dump_hexadecimal(int width, unsigned long value, int fd)
468 : {
469 : int len;
470 : char buffer[sizeof(unsigned long) * 2 + 1];
471 0 : len = 0;
472 : do {
473 0 : buffer[len] = Py_hexdigits[value & 15];
474 0 : value >>= 4;
475 0 : len++;
476 0 : } while (len < width || value);
477 0 : reverse_string(buffer, len);
478 0 : write(fd, buffer, len);
479 0 : }
480 :
481 : /* Write an unicode object into the file fd using ascii+backslashreplace.
482 :
483 : This function is signal safe. */
484 :
485 : static void
486 0 : dump_ascii(int fd, PyObject *text)
487 : {
488 0 : PyASCIIObject *ascii = (PyASCIIObject *)text;
489 : Py_ssize_t i, size;
490 : int truncated;
491 : int kind;
492 0 : void *data = NULL;
493 0 : wchar_t *wstr = NULL;
494 : Py_UCS4 ch;
495 :
496 0 : size = ascii->length;
497 0 : kind = ascii->state.kind;
498 0 : if (ascii->state.compact) {
499 0 : if (ascii->state.ascii)
500 0 : data = ((PyASCIIObject*)text) + 1;
501 : else
502 0 : data = ((PyCompactUnicodeObject*)text) + 1;
503 : }
504 0 : else if (kind != PyUnicode_WCHAR_KIND) {
505 0 : data = ((PyUnicodeObject *)text)->data.any;
506 0 : if (data == NULL)
507 0 : return;
508 : }
509 : else {
510 0 : wstr = ((PyASCIIObject *)text)->wstr;
511 0 : if (wstr == NULL)
512 0 : return;
513 0 : size = ((PyCompactUnicodeObject *)text)->wstr_length;
514 : }
515 :
516 0 : if (MAX_STRING_LENGTH < size) {
517 0 : size = MAX_STRING_LENGTH;
518 0 : truncated = 1;
519 : }
520 : else
521 0 : truncated = 0;
522 :
523 0 : for (i=0; i < size; i++) {
524 0 : if (kind != PyUnicode_WCHAR_KIND)
525 0 : ch = PyUnicode_READ(kind, data, i);
526 : else
527 0 : ch = wstr[i];
528 0 : if (ch < 128) {
529 0 : char c = (char)ch;
530 0 : write(fd, &c, 1);
531 : }
532 0 : else if (ch < 0xff) {
533 0 : PUTS(fd, "\\x");
534 0 : dump_hexadecimal(2, ch, fd);
535 : }
536 0 : else if (ch < 0xffff) {
537 0 : PUTS(fd, "\\u");
538 0 : dump_hexadecimal(4, ch, fd);
539 : }
540 : else {
541 0 : PUTS(fd, "\\U");
542 0 : dump_hexadecimal(8, ch, fd);
543 : }
544 : }
545 0 : if (truncated)
546 0 : PUTS(fd, "...");
547 : }
548 :
549 : /* Write a frame into the file fd: "File "xxx", line xxx in xxx".
550 :
551 : This function is signal safe. */
552 :
553 : static void
554 0 : dump_frame(int fd, PyFrameObject *frame)
555 : {
556 : PyCodeObject *code;
557 : int lineno;
558 :
559 0 : code = frame->f_code;
560 0 : PUTS(fd, " File ");
561 0 : if (code != NULL && code->co_filename != NULL
562 0 : && PyUnicode_Check(code->co_filename))
563 : {
564 0 : write(fd, "\"", 1);
565 0 : dump_ascii(fd, code->co_filename);
566 0 : write(fd, "\"", 1);
567 : } else {
568 0 : PUTS(fd, "???");
569 : }
570 :
571 : /* PyFrame_GetLineNumber() was introduced in Python 2.7.0 and 3.2.0 */
572 0 : lineno = PyCode_Addr2Line(code, frame->f_lasti);
573 0 : PUTS(fd, ", line ");
574 0 : dump_decimal(fd, lineno);
575 0 : PUTS(fd, " in ");
576 :
577 0 : if (code != NULL && code->co_name != NULL
578 0 : && PyUnicode_Check(code->co_name))
579 0 : dump_ascii(fd, code->co_name);
580 : else
581 0 : PUTS(fd, "???");
582 :
583 0 : write(fd, "\n", 1);
584 0 : }
585 :
586 : static void
587 0 : dump_traceback(int fd, PyThreadState *tstate, int write_header)
588 : {
589 : PyFrameObject *frame;
590 : unsigned int depth;
591 :
592 0 : if (write_header)
593 0 : PUTS(fd, "Traceback (most recent call first):\n");
594 :
595 0 : frame = _PyThreadState_GetFrame(tstate);
596 0 : if (frame == NULL)
597 0 : return;
598 :
599 0 : depth = 0;
600 0 : while (frame != NULL) {
601 0 : if (MAX_FRAME_DEPTH <= depth) {
602 0 : PUTS(fd, " ...\n");
603 0 : break;
604 : }
605 0 : if (!PyFrame_Check(frame))
606 0 : break;
607 0 : dump_frame(fd, frame);
608 0 : frame = frame->f_back;
609 0 : depth++;
610 : }
611 : }
612 :
613 : void
614 0 : _Py_DumpTraceback(int fd, PyThreadState *tstate)
615 : {
616 0 : dump_traceback(fd, tstate, 1);
617 0 : }
618 :
619 : /* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
620 : is_current is true, "Thread 0xHHHH:\n" otherwise.
621 :
622 : This function is signal safe. */
623 :
624 : static void
625 0 : write_thread_id(int fd, PyThreadState *tstate, int is_current)
626 : {
627 0 : if (is_current)
628 0 : PUTS(fd, "Current thread 0x");
629 : else
630 0 : PUTS(fd, "Thread 0x");
631 0 : dump_hexadecimal(sizeof(long)*2, (unsigned long)tstate->thread_id, fd);
632 0 : PUTS(fd, ":\n");
633 0 : }
634 :
635 : const char*
636 0 : _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
637 : PyThreadState *current_thread)
638 : {
639 : PyThreadState *tstate;
640 : unsigned int nthreads;
641 :
642 : /* Get the current interpreter from the current thread */
643 0 : tstate = PyInterpreterState_ThreadHead(interp);
644 0 : if (tstate == NULL)
645 0 : return "unable to get the thread head state";
646 :
647 : /* Dump the traceback of each thread */
648 0 : tstate = PyInterpreterState_ThreadHead(interp);
649 0 : nthreads = 0;
650 : do
651 : {
652 0 : if (nthreads != 0)
653 0 : write(fd, "\n", 1);
654 0 : if (nthreads >= MAX_NTHREADS) {
655 0 : PUTS(fd, "...\n");
656 0 : break;
657 : }
658 0 : write_thread_id(fd, tstate, tstate == current_thread);
659 0 : dump_traceback(fd, tstate, 0);
660 0 : tstate = PyThreadState_Next(tstate);
661 0 : nthreads++;
662 0 : } while (tstate != NULL);
663 :
664 0 : return NULL;
665 : }
666 :
|