blob: 59bb3f0d1516481a642548c599cd0a38426c68bc [file] [log] [blame]
Guido van Rossumf70e43a1991-02-19 12:39:46 +00001
Guido van Rossum3f5da241990-12-20 15:06:42 +00002/* Traceback implementation */
3
Guido van Rossum65bf9f21997-04-29 18:33:38 +00004#include "Python.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +00005
Jeremy Hylton3e0055f2005-10-20 19:59:25 +00006#include "code.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +00007#include "frameobject.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +00008#include "structmember.h"
Guido van Rossum7169dbb1992-02-26 15:17:59 +00009#include "osdefs.h"
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +000010#ifdef HAVE_FCNTL_H
11#include <fcntl.h>
12#endif
Guido van Rossum3f5da241990-12-20 15:06:42 +000013
Nicholas Bastina7604bf2004-03-21 18:37:23 +000014#define OFF(x) offsetof(PyTracebackObject, x)
Guido van Rossum3f5da241990-12-20 15:06:42 +000015
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +000016/* Method from Parser/tokenizer.c */
17extern char * PyTokenizer_FindEncoding(int);
18
Collin Winter3eed7652007-08-14 17:53:54 +000019static PyObject *
20tb_dir(PyTracebackObject *self)
21{
22 return Py_BuildValue("[ssss]", "tb_frame", "tb_next",
23 "tb_lasti", "tb_lineno");
24}
25
26static PyMethodDef tb_methods[] = {
27 {"__dir__", (PyCFunction)tb_dir, METH_NOARGS},
28 {NULL, NULL, 0, NULL},
29};
30
Neal Norwitz8dfc4a92007-08-11 06:39:53 +000031static PyMemberDef tb_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000032 {"tb_next", T_OBJECT, OFF(tb_next), READONLY},
33 {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY},
34 {"tb_lasti", T_INT, OFF(tb_lasti), READONLY},
35 {"tb_lineno", T_INT, OFF(tb_lineno), READONLY},
36 {NULL} /* Sentinel */
Guido van Rossum3f5da241990-12-20 15:06:42 +000037};
38
Guido van Rossum3f5da241990-12-20 15:06:42 +000039static void
Nicholas Bastina7604bf2004-03-21 18:37:23 +000040tb_dealloc(PyTracebackObject *tb)
Guido van Rossum3f5da241990-12-20 15:06:42 +000041{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000042 PyObject_GC_UnTrack(tb);
43 Py_TRASHCAN_SAFE_BEGIN(tb)
44 Py_XDECREF(tb->tb_next);
45 Py_XDECREF(tb->tb_frame);
46 PyObject_GC_Del(tb);
47 Py_TRASHCAN_SAFE_END(tb)
Guido van Rossum3f5da241990-12-20 15:06:42 +000048}
49
Jeremy Hyltonfd14d8e2001-10-22 22:17:41 +000050static int
Nicholas Bastina7604bf2004-03-21 18:37:23 +000051tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)
Jeremy Hyltonfd14d8e2001-10-22 22:17:41 +000052{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000053 Py_VISIT(tb->tb_next);
54 Py_VISIT(tb->tb_frame);
55 return 0;
Jeremy Hyltonfd14d8e2001-10-22 22:17:41 +000056}
57
58static void
Nicholas Bastina7604bf2004-03-21 18:37:23 +000059tb_clear(PyTracebackObject *tb)
Jeremy Hyltonfd14d8e2001-10-22 22:17:41 +000060{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000061 Py_CLEAR(tb->tb_next);
62 Py_CLEAR(tb->tb_frame);
Jeremy Hyltonfd14d8e2001-10-22 22:17:41 +000063}
64
Tim Petersd7c36522001-10-22 19:34:09 +000065PyTypeObject PyTraceBack_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000066 PyVarObject_HEAD_INIT(&PyType_Type, 0)
67 "traceback",
68 sizeof(PyTracebackObject),
69 0,
70 (destructor)tb_dealloc, /*tp_dealloc*/
71 0, /*tp_print*/
72 0, /*tp_getattr*/
73 0, /*tp_setattr*/
74 0, /*tp_reserved*/
75 0, /*tp_repr*/
76 0, /*tp_as_number*/
77 0, /*tp_as_sequence*/
78 0, /*tp_as_mapping*/
79 0, /* tp_hash */
80 0, /* tp_call */
81 0, /* tp_str */
82 PyObject_GenericGetAttr, /* tp_getattro */
83 0, /* tp_setattro */
84 0, /* tp_as_buffer */
85 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
86 0, /* tp_doc */
87 (traverseproc)tb_traverse, /* tp_traverse */
88 (inquiry)tb_clear, /* tp_clear */
89 0, /* tp_richcompare */
90 0, /* tp_weaklistoffset */
91 0, /* tp_iter */
92 0, /* tp_iternext */
93 tb_methods, /* tp_methods */
94 tb_memberlist, /* tp_members */
95 0, /* tp_getset */
96 0, /* tp_base */
97 0, /* tp_dict */
Guido van Rossum3f5da241990-12-20 15:06:42 +000098};
99
Nicholas Bastina7604bf2004-03-21 18:37:23 +0000100static PyTracebackObject *
101newtracebackobject(PyTracebackObject *next, PyFrameObject *frame)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000102{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000103 PyTracebackObject *tb;
104 if ((next != NULL && !PyTraceBack_Check(next)) ||
105 frame == NULL || !PyFrame_Check(frame)) {
106 PyErr_BadInternalCall();
107 return NULL;
108 }
109 tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
110 if (tb != NULL) {
111 Py_XINCREF(next);
112 tb->tb_next = next;
113 Py_XINCREF(frame);
114 tb->tb_frame = frame;
115 tb->tb_lasti = frame->f_lasti;
116 tb->tb_lineno = PyFrame_GetLineNumber(frame);
117 PyObject_GC_Track(tb);
118 }
119 return tb;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000120}
121
Guido van Rossum3f5da241990-12-20 15:06:42 +0000122int
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000123PyTraceBack_Here(PyFrameObject *frame)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000124{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000125 PyThreadState *tstate = PyThreadState_GET();
126 PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback;
127 PyTracebackObject *tb = newtracebackobject(oldtb, frame);
128 if (tb == NULL)
129 return -1;
130 tstate->curexc_traceback = (PyObject *)tb;
131 Py_XDECREF(oldtb);
132 return 0;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000133}
134
Victor Stinner0fe25a42010-06-17 23:08:50 +0000135static PyObject *
136_Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *io)
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000137{
Victor Stinner0fe25a42010-06-17 23:08:50 +0000138 Py_ssize_t i;
139 PyObject *binary;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000140 PyObject *v;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000141 Py_ssize_t npath;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000142 size_t taillen;
143 PyObject *syspath;
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000144 PyObject *path;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000145 const char* tail;
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000146 PyObject *filebytes;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000147 const char* filepath;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000148 Py_ssize_t len;
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000149 PyObject* result;
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000150
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000151 filebytes = PyUnicode_EncodeFSDefault(filename);
152 if (filebytes == NULL) {
Victor Stinner0fe25a42010-06-17 23:08:50 +0000153 PyErr_Clear();
154 return NULL;
155 }
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000156 filepath = PyBytes_AS_STRING(filebytes);
Victor Stinner0fe25a42010-06-17 23:08:50 +0000157
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158 /* Search tail of filename in sys.path before giving up */
Victor Stinner0fe25a42010-06-17 23:08:50 +0000159 tail = strrchr(filepath, SEP);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000160 if (tail == NULL)
Victor Stinner0fe25a42010-06-17 23:08:50 +0000161 tail = filepath;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000162 else
163 tail++;
164 taillen = strlen(tail);
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000165
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000166 syspath = PySys_GetObject("path");
167 if (syspath == NULL || !PyList_Check(syspath))
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000168 goto error;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000169 npath = PyList_Size(syspath);
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000170
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000171 for (i = 0; i < npath; i++) {
172 v = PyList_GetItem(syspath, i);
173 if (v == NULL) {
174 PyErr_Clear();
175 break;
176 }
177 if (!PyUnicode_Check(v))
178 continue;
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000179 path = PyUnicode_EncodeFSDefault(v);
Victor Stinner0fe25a42010-06-17 23:08:50 +0000180 if (path == NULL) {
181 PyErr_Clear();
182 continue;
183 }
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000184 len = PyBytes_GET_SIZE(path);
185 if (len + 1 + (Py_ssize_t)taillen >= (Py_ssize_t)namelen - 1) {
186 Py_DECREF(path);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000187 continue; /* Too long */
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000188 }
189 strcpy(namebuf, PyBytes_AS_STRING(path));
190 Py_DECREF(path);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000191 if (strlen(namebuf) != len)
192 continue; /* v contains '\0' */
193 if (len > 0 && namebuf[len-1] != SEP)
194 namebuf[len++] = SEP;
195 strcpy(namebuf+len, tail);
Victor Stinner0fe25a42010-06-17 23:08:50 +0000196
197 binary = PyObject_CallMethod(io, "open", "ss", namebuf, "rb");
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000198 if (binary != NULL) {
199 result = binary;
200 goto finally;
201 }
Victor Stinner0fe25a42010-06-17 23:08:50 +0000202 PyErr_Clear();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000203 }
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000204 goto error;
205
206error:
207 result = NULL;
208finally:
209 Py_DECREF(filebytes);
210 return result;
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000211}
212
Christian Heimes33fe8092008-04-13 13:53:33 +0000213int
Victor Stinner0fe25a42010-06-17 23:08:50 +0000214_Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000215{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000216 int err = 0;
217 int fd;
218 int i;
219 char *found_encoding;
220 char *encoding;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000221 PyObject *io;
222 PyObject *binary;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000223 PyObject *fob = NULL;
224 PyObject *lineobj = NULL;
Antoine Pitroub86680e2010-10-14 21:15:17 +0000225 PyObject *res;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000226 char buf[MAXPATHLEN+1];
227 Py_UNICODE *u, *p;
228 Py_ssize_t len;
Christian Heimes679db4a2008-01-18 09:56:22 +0000229
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000230 /* open the file */
231 if (filename == NULL)
232 return 0;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000233
234 io = PyImport_ImportModuleNoBlock("io");
235 if (io == NULL)
236 return -1;
237 binary = PyObject_CallMethod(io, "open", "Os", filename, "rb");
238
239 if (binary == NULL) {
240 binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io);
241 if (binary == NULL) {
242 Py_DECREF(io);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000243 return 0;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000244 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000245 }
Christian Heimes33fe8092008-04-13 13:53:33 +0000246
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000247 /* use the right encoding to decode the file as unicode */
Victor Stinner0fe25a42010-06-17 23:08:50 +0000248 fd = PyObject_AsFileDescriptor(binary);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000249 found_encoding = PyTokenizer_FindEncoding(fd);
Victor Stinner0fe25a42010-06-17 23:08:50 +0000250 encoding = (found_encoding != NULL) ? found_encoding : "utf-8";
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000251 lseek(fd, 0, 0); /* Reset position */
Victor Stinner0fe25a42010-06-17 23:08:50 +0000252 fob = PyObject_CallMethod(io, "TextIOWrapper", "Os", binary, encoding);
253 Py_DECREF(io);
254 Py_DECREF(binary);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000255 PyMem_FREE(found_encoding);
Victor Stinner0fe25a42010-06-17 23:08:50 +0000256
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000257 if (fob == NULL) {
258 PyErr_Clear();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000259 return 0;
260 }
Christian Heimes33fe8092008-04-13 13:53:33 +0000261
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000262 /* get the line number lineno */
263 for (i = 0; i < lineno; i++) {
264 Py_XDECREF(lineobj);
265 lineobj = PyFile_GetLine(fob, -1);
266 if (!lineobj) {
267 err = -1;
268 break;
269 }
270 }
Antoine Pitroub86680e2010-10-14 21:15:17 +0000271 res = PyObject_CallMethod(fob, "close", "");
272 if (res)
273 Py_DECREF(res);
274 else
275 PyErr_Clear();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000276 Py_DECREF(fob);
277 if (!lineobj || !PyUnicode_Check(lineobj)) {
278 Py_XDECREF(lineobj);
279 return err;
280 }
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000281
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000282 /* remove the indentation of the line */
283 u = PyUnicode_AS_UNICODE(lineobj);
284 len = PyUnicode_GET_SIZE(lineobj);
285 for (p=u; *p == ' ' || *p == '\t' || *p == '\014'; p++)
286 len--;
287 if (u != p) {
288 PyObject *truncated;
289 truncated = PyUnicode_FromUnicode(p, len);
290 if (truncated) {
291 Py_DECREF(lineobj);
292 lineobj = truncated;
293 } else {
294 PyErr_Clear();
295 }
296 }
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000297
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 /* Write some spaces before the line */
299 strcpy(buf, " ");
300 assert (strlen(buf) == 10);
301 while (indent > 0) {
302 if(indent < 10)
303 buf[indent] = '\0';
304 err = PyFile_WriteString(buf, f);
305 if (err != 0)
306 break;
307 indent -= 10;
308 }
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000309
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000310 /* finally display the line */
311 if (err == 0)
312 err = PyFile_WriteObject(lineobj, f, Py_PRINT_RAW);
313 Py_DECREF(lineobj);
314 if (err == 0)
315 err = PyFile_WriteString("\n", f);
316 return err;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000317}
318
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000319static int
Victor Stinner0fe25a42010-06-17 23:08:50 +0000320tb_displayline(PyObject *f, PyObject *filename, int lineno, PyObject *name)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000321{
Victor Stinner0fe25a42010-06-17 23:08:50 +0000322 int err;
323 PyObject *line;
Christian Heimes33fe8092008-04-13 13:53:33 +0000324
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 if (filename == NULL || name == NULL)
326 return -1;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000327 line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n",
328 filename, lineno, name);
329 if (line == NULL)
330 return -1;
331 err = PyFile_WriteObject(line, f, Py_PRINT_RAW);
332 Py_DECREF(line);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000333 if (err != 0)
334 return err;
335 return _Py_DisplaySourceLine(f, filename, lineno, 4);
Christian Heimes33fe8092008-04-13 13:53:33 +0000336}
337
338static int
339tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
340{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000341 int err = 0;
342 long depth = 0;
343 PyTracebackObject *tb1 = tb;
344 while (tb1 != NULL) {
345 depth++;
346 tb1 = tb1->tb_next;
347 }
348 while (tb != NULL && err == 0) {
349 if (depth <= limit) {
350 err = tb_displayline(f,
Victor Stinner0fe25a42010-06-17 23:08:50 +0000351 tb->tb_frame->f_code->co_filename,
352 tb->tb_lineno,
353 tb->tb_frame->f_code->co_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000354 }
355 depth--;
356 tb = tb->tb_next;
357 if (err == 0)
358 err = PyErr_CheckSignals();
359 }
360 return err;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000361}
362
Christian Heimes0fbab7f2007-12-04 21:55:18 +0000363#define PyTraceBack_LIMIT 1000
364
Guido van Rossum3f5da241990-12-20 15:06:42 +0000365int
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000366PyTraceBack_Print(PyObject *v, PyObject *f)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000367{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000368 int err;
369 PyObject *limitv;
370 long limit = PyTraceBack_LIMIT;
Christian Heimes0fbab7f2007-12-04 21:55:18 +0000371
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000372 if (v == NULL)
373 return 0;
374 if (!PyTraceBack_Check(v)) {
375 PyErr_BadInternalCall();
376 return -1;
377 }
378 limitv = PySys_GetObject("tracebacklimit");
379 if (limitv) {
380 PyObject *exc_type, *exc_value, *exc_tb;
Christian Heimes0fbab7f2007-12-04 21:55:18 +0000381
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000382 PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
383 limit = PyLong_AsLong(limitv);
384 if (limit == -1 && PyErr_Occurred()) {
385 if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
386 limit = PyTraceBack_LIMIT;
387 }
388 else {
389 Py_XDECREF(exc_type);
390 Py_XDECREF(exc_value);
391 Py_XDECREF(exc_tb);
392 return 0;
393 }
394 }
395 else if (limit <= 0) {
396 limit = PyTraceBack_LIMIT;
397 }
398 PyErr_Restore(exc_type, exc_value, exc_tb);
399 }
400 err = PyFile_WriteString("Traceback (most recent call last):\n", f);
401 if (!err)
402 err = tb_printinternal((PyTracebackObject *)v, f, limit);
403 return err;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000404}