2 /* Traceback implementation */
7 #include "frameobject.h"
8 #include "structmember.h"
10 #include "traceback.h"
15 #define OFF(x) offsetof(PyTracebackObject, x)
17 /* Method from Parser/tokenizer.c */
18 extern char * PyTokenizer_FindEncoding(int);
21 tb_dir(PyTracebackObject
*self
)
23 return Py_BuildValue("[ssss]", "tb_frame", "tb_next",
24 "tb_lasti", "tb_lineno");
27 static PyMethodDef tb_methods
[] = {
28 {"__dir__", (PyCFunction
)tb_dir
, METH_NOARGS
},
29 {NULL
, NULL
, 0, NULL
},
32 static PyMemberDef tb_memberlist
[] = {
33 {"tb_next", T_OBJECT
, OFF(tb_next
), READONLY
},
34 {"tb_frame", T_OBJECT
, OFF(tb_frame
), READONLY
},
35 {"tb_lasti", T_INT
, OFF(tb_lasti
), READONLY
},
36 {"tb_lineno", T_INT
, OFF(tb_lineno
), READONLY
},
41 tb_dealloc(PyTracebackObject
*tb
)
43 PyObject_GC_UnTrack(tb
);
44 Py_TRASHCAN_SAFE_BEGIN(tb
)
45 Py_XDECREF(tb
->tb_next
);
46 Py_XDECREF(tb
->tb_frame
);
48 Py_TRASHCAN_SAFE_END(tb
)
52 tb_traverse(PyTracebackObject
*tb
, visitproc visit
, void *arg
)
54 Py_VISIT(tb
->tb_next
);
55 Py_VISIT(tb
->tb_frame
);
60 tb_clear(PyTracebackObject
*tb
)
62 Py_CLEAR(tb
->tb_next
);
63 Py_CLEAR(tb
->tb_frame
);
66 PyTypeObject PyTraceBack_Type
= {
67 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
69 sizeof(PyTracebackObject
),
71 (destructor
)tb_dealloc
, /*tp_dealloc*/
83 PyObject_GenericGetAttr
, /* tp_getattro */
86 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
,/* tp_flags */
88 (traverseproc
)tb_traverse
, /* tp_traverse */
89 (inquiry
)tb_clear
, /* tp_clear */
90 0, /* tp_richcompare */
91 0, /* tp_weaklistoffset */
94 tb_methods
, /* tp_methods */
95 tb_memberlist
, /* tp_members */
101 static PyTracebackObject
*
102 newtracebackobject(PyTracebackObject
*next
, PyFrameObject
*frame
)
104 PyTracebackObject
*tb
;
105 if ((next
!= NULL
&& !PyTraceBack_Check(next
)) ||
106 frame
== NULL
|| !PyFrame_Check(frame
)) {
107 PyErr_BadInternalCall();
110 tb
= PyObject_GC_New(PyTracebackObject
, &PyTraceBack_Type
);
115 tb
->tb_frame
= frame
;
116 tb
->tb_lasti
= frame
->f_lasti
;
117 tb
->tb_lineno
= PyCode_Addr2Line(frame
->f_code
,
119 PyObject_GC_Track(tb
);
125 PyTraceBack_Here(PyFrameObject
*frame
)
127 PyThreadState
*tstate
= PyThreadState_GET();
128 PyTracebackObject
*oldtb
= (PyTracebackObject
*) tstate
->curexc_traceback
;
129 PyTracebackObject
*tb
= newtracebackobject(oldtb
, frame
);
132 tstate
->curexc_traceback
= (PyObject
*)tb
;
138 _Py_FindSourceFile(PyObject
*filename
, char* namebuf
, size_t namelen
, PyObject
*io
)
149 const char* filepath
;
153 filebytes
= PyUnicode_AsEncodedObject(filename
,
154 Py_FileSystemDefaultEncoding
, "surrogateescape");
155 if (filebytes
== NULL
) {
159 filepath
= PyBytes_AS_STRING(filebytes
);
161 /* Search tail of filename in sys.path before giving up */
162 tail
= strrchr(filepath
, SEP
);
167 taillen
= strlen(tail
);
169 syspath
= PySys_GetObject("path");
170 if (syspath
== NULL
|| !PyList_Check(syspath
))
172 npath
= PyList_Size(syspath
);
174 for (i
= 0; i
< npath
; i
++) {
175 v
= PyList_GetItem(syspath
, i
);
180 if (!PyUnicode_Check(v
))
183 path
= PyUnicode_AsEncodedObject(v
, Py_FileSystemDefaultEncoding
,
189 len
= PyBytes_GET_SIZE(path
);
190 if (len
+ 1 + (Py_ssize_t
)taillen
>= (Py_ssize_t
)namelen
- 1) {
192 continue; /* Too long */
194 strcpy(namebuf
, PyBytes_AS_STRING(path
));
196 if (strlen(namebuf
) != len
)
197 continue; /* v contains '\0' */
198 if (len
> 0 && namebuf
[len
-1] != SEP
)
199 namebuf
[len
++] = SEP
;
200 strcpy(namebuf
+len
, tail
);
202 binary
= PyObject_CallMethod(io
, "open", "ss", namebuf
, "rb");
203 if (binary
!= NULL
) {
214 Py_DECREF(filebytes
);
219 _Py_DisplaySourceLine(PyObject
*f
, PyObject
*filename
, int lineno
, int indent
)
224 char *found_encoding
;
228 PyObject
*fob
= NULL
;
229 PyObject
*lineobj
= NULL
;
231 char buf
[MAXPATHLEN
+1];
236 if (filename
== NULL
)
239 io
= PyImport_ImportModuleNoBlock("io");
242 binary
= PyObject_CallMethod(io
, "open", "Os", filename
, "rb");
244 if (binary
== NULL
) {
245 binary
= _Py_FindSourceFile(filename
, buf
, sizeof(buf
), io
);
246 if (binary
== NULL
) {
252 /* use the right encoding to decode the file as unicode */
253 fd
= PyObject_AsFileDescriptor(binary
);
254 found_encoding
= PyTokenizer_FindEncoding(fd
);
255 encoding
= (found_encoding
!= NULL
) ? found_encoding
: "utf-8";
256 lseek(fd
, 0, 0); /* Reset position */
257 fob
= PyObject_CallMethod(io
, "TextIOWrapper", "Os", binary
, encoding
);
260 PyMem_FREE(found_encoding
);
267 /* get the line number lineno */
268 for (i
= 0; i
< lineno
; i
++) {
270 lineobj
= PyFile_GetLine(fob
, -1);
276 res
= PyObject_CallMethod(fob
, "close", "");
282 if (!lineobj
|| !PyUnicode_Check(lineobj
)) {
287 /* remove the indentation of the line */
288 u
= PyUnicode_AS_UNICODE(lineobj
);
289 len
= PyUnicode_GET_SIZE(lineobj
);
290 for (p
=u
; *p
== ' ' || *p
== '\t' || *p
== '\014'; p
++)
294 truncated
= PyUnicode_FromUnicode(p
, len
);
303 /* Write some spaces before the line */
305 assert (strlen(buf
) == 10);
309 err
= PyFile_WriteString(buf
, f
);
315 /* finally display the line */
317 err
= PyFile_WriteObject(lineobj
, f
, Py_PRINT_RAW
);
320 err
= PyFile_WriteString("\n", f
);
325 tb_displayline(PyObject
*f
, PyObject
*filename
, int lineno
, PyObject
*name
)
330 if (filename
== NULL
|| name
== NULL
)
332 line
= PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n",
333 filename
, lineno
, name
);
336 err
= PyFile_WriteObject(line
, f
, Py_PRINT_RAW
);
340 return _Py_DisplaySourceLine(f
, filename
, lineno
, 4);
344 tb_printinternal(PyTracebackObject
*tb
, PyObject
*f
, long limit
)
348 PyTracebackObject
*tb1
= tb
;
349 while (tb1
!= NULL
) {
353 while (tb
!= NULL
&& err
== 0) {
354 if (depth
<= limit
) {
355 err
= tb_displayline(f
,
356 tb
->tb_frame
->f_code
->co_filename
,
358 tb
->tb_frame
->f_code
->co_name
);
363 err
= PyErr_CheckSignals();
368 #define PyTraceBack_LIMIT 1000
371 PyTraceBack_Print(PyObject
*v
, PyObject
*f
)
375 long limit
= PyTraceBack_LIMIT
;
379 if (!PyTraceBack_Check(v
)) {
380 PyErr_BadInternalCall();
383 limitv
= PySys_GetObject("tracebacklimit");
385 PyObject
*exc_type
, *exc_value
, *exc_tb
;
387 PyErr_Fetch(&exc_type
, &exc_value
, &exc_tb
);
388 limit
= PyLong_AsLong(limitv
);
389 if (limit
== -1 && PyErr_Occurred()) {
390 if (PyErr_ExceptionMatches(PyExc_OverflowError
)) {
391 limit
= PyTraceBack_LIMIT
;
394 Py_XDECREF(exc_type
);
395 Py_XDECREF(exc_value
);
400 else if (limit
<= 0) {
401 limit
= PyTraceBack_LIMIT
;
403 PyErr_Restore(exc_type
, exc_value
, exc_tb
);
405 err
= PyFile_WriteString("Traceback (most recent call last):\n", f
);
407 err
= tb_printinternal((PyTracebackObject
*)v
, f
, limit
);