traceback.c 10.7 KB
Newer Older
1

Guido van Rossum's avatar
Guido van Rossum committed
2 3
/* Traceback implementation */

Guido van Rossum's avatar
Guido van Rossum committed
4
#include "Python.h"
Guido van Rossum's avatar
Guido van Rossum committed
5

Jeremy Hylton's avatar
Jeremy Hylton committed
6
#include "code.h"
Guido van Rossum's avatar
Guido van Rossum committed
7 8
#include "frameobject.h"
#include "structmember.h"
9
#include "osdefs.h"
10 11 12
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
Guido van Rossum's avatar
Guido van Rossum committed
13

14
#define OFF(x) offsetof(PyTracebackObject, x)
Guido van Rossum's avatar
Guido van Rossum committed
15

16 17 18
/* Method from Parser/tokenizer.c */
extern char * PyTokenizer_FindEncoding(int);

19 20 21 22 23 24 25 26 27 28 29 30
static PyObject *
tb_dir(PyTracebackObject *self)
{
    return Py_BuildValue("[ssss]", "tb_frame", "tb_next",
                                   "tb_lasti", "tb_lineno");
}

static PyMethodDef tb_methods[] = {
   {"__dir__", (PyCFunction)tb_dir, METH_NOARGS},
   {NULL, NULL, 0, NULL},
};

31
static PyMemberDef tb_memberlist[] = {
32 33 34 35 36
    {"tb_next",         T_OBJECT,       OFF(tb_next),   READONLY},
    {"tb_frame",        T_OBJECT,       OFF(tb_frame),  READONLY},
    {"tb_lasti",        T_INT,          OFF(tb_lasti),  READONLY},
    {"tb_lineno",       T_INT,          OFF(tb_lineno), READONLY},
    {NULL}      /* Sentinel */
Guido van Rossum's avatar
Guido van Rossum committed
37 38 39
};

static void
40
tb_dealloc(PyTracebackObject *tb)
Guido van Rossum's avatar
Guido van Rossum committed
41
{
42 43 44 45 46 47
    PyObject_GC_UnTrack(tb);
    Py_TRASHCAN_SAFE_BEGIN(tb)
    Py_XDECREF(tb->tb_next);
    Py_XDECREF(tb->tb_frame);
    PyObject_GC_Del(tb);
    Py_TRASHCAN_SAFE_END(tb)
Guido van Rossum's avatar
Guido van Rossum committed
48 49
}

50
static int
51
tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)
52
{
53 54 55
    Py_VISIT(tb->tb_next);
    Py_VISIT(tb->tb_frame);
    return 0;
56 57 58
}

static void
59
tb_clear(PyTracebackObject *tb)
60
{
61 62
    Py_CLEAR(tb->tb_next);
    Py_CLEAR(tb->tb_frame);
63 64
}

65
PyTypeObject PyTraceBack_Type = {
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "traceback",
    sizeof(PyTracebackObject),
    0,
    (destructor)tb_dealloc, /*tp_dealloc*/
    0,                  /*tp_print*/
    0,    /*tp_getattr*/
    0,                  /*tp_setattr*/
    0,                  /*tp_reserved*/
    0,                  /*tp_repr*/
    0,                  /*tp_as_number*/
    0,                  /*tp_as_sequence*/
    0,                  /*tp_as_mapping*/
    0,                  /* tp_hash */
    0,                  /* tp_call */
    0,                  /* tp_str */
    PyObject_GenericGetAttr,                    /* tp_getattro */
    0,                  /* tp_setattro */
    0,                                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
    0,                                          /* tp_doc */
    (traverseproc)tb_traverse,                  /* tp_traverse */
    (inquiry)tb_clear,                          /* tp_clear */
    0,                                          /* tp_richcompare */
    0,                                          /* tp_weaklistoffset */
    0,                                          /* tp_iter */
    0,                                          /* tp_iternext */
    tb_methods,         /* tp_methods */
    tb_memberlist,      /* tp_members */
    0,                                          /* tp_getset */
    0,                                          /* tp_base */
    0,                                          /* tp_dict */
Guido van Rossum's avatar
Guido van Rossum committed
98 99
};

100 101
static PyTracebackObject *
newtracebackobject(PyTracebackObject *next, PyFrameObject *frame)
Guido van Rossum's avatar
Guido van Rossum committed
102
{
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
    PyTracebackObject *tb;
    if ((next != NULL && !PyTraceBack_Check(next)) ||
                    frame == NULL || !PyFrame_Check(frame)) {
        PyErr_BadInternalCall();
        return NULL;
    }
    tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
    if (tb != NULL) {
        Py_XINCREF(next);
        tb->tb_next = next;
        Py_XINCREF(frame);
        tb->tb_frame = frame;
        tb->tb_lasti = frame->f_lasti;
        tb->tb_lineno = PyFrame_GetLineNumber(frame);
        PyObject_GC_Track(tb);
    }
    return tb;
Guido van Rossum's avatar
Guido van Rossum committed
120 121 122
}

int
123
PyTraceBack_Here(PyFrameObject *frame)
Guido van Rossum's avatar
Guido van Rossum committed
124
{
125 126 127 128 129 130 131 132
    PyThreadState *tstate = PyThreadState_GET();
    PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback;
    PyTracebackObject *tb = newtracebackobject(oldtb, frame);
    if (tb == NULL)
        return -1;
    tstate->curexc_traceback = (PyObject *)tb;
    Py_XDECREF(oldtb);
    return 0;
Guido van Rossum's avatar
Guido van Rossum committed
133 134
}

135 136
static PyObject *
_Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *io)
137
{
138 139
    Py_ssize_t i;
    PyObject *binary;
140
    PyObject *v;
141
    Py_ssize_t npath;
142 143
    size_t taillen;
    PyObject *syspath;
144
    PyObject *path;
145
    const char* tail;
146
    PyObject *filebytes;
147
    const char* filepath;
148
    Py_ssize_t len;
149
    PyObject* result;
150

151 152
    filebytes = PyUnicode_EncodeFSDefault(filename);
    if (filebytes == NULL) {
153 154 155
        PyErr_Clear();
        return NULL;
    }
156
    filepath = PyBytes_AS_STRING(filebytes);
157

158
    /* Search tail of filename in sys.path before giving up */
159
    tail = strrchr(filepath, SEP);
160
    if (tail == NULL)
161
        tail = filepath;
162 163 164 165 166 167
    else
        tail++;
    taillen = strlen(tail);

    syspath = PySys_GetObject("path");
    if (syspath == NULL || !PyList_Check(syspath))
168
        goto error;
169
    npath = PyList_Size(syspath);
170 171 172 173 174 175 176 177 178

    for (i = 0; i < npath; i++) {
        v = PyList_GetItem(syspath, i);
        if (v == NULL) {
            PyErr_Clear();
            break;
        }
        if (!PyUnicode_Check(v))
            continue;
179
        path = PyUnicode_EncodeFSDefault(v);
180 181 182 183
        if (path == NULL) {
            PyErr_Clear();
            continue;
        }
184 185 186
        len = PyBytes_GET_SIZE(path);
        if (len + 1 + (Py_ssize_t)taillen >= (Py_ssize_t)namelen - 1) {
            Py_DECREF(path);
187
            continue; /* Too long */
188 189 190
        }
        strcpy(namebuf, PyBytes_AS_STRING(path));
        Py_DECREF(path);
191 192 193 194 195
        if (strlen(namebuf) != len)
            continue; /* v contains '\0' */
        if (len > 0 && namebuf[len-1] != SEP)
            namebuf[len++] = SEP;
        strcpy(namebuf+len, tail);
196 197

        binary = PyObject_CallMethod(io, "open", "ss", namebuf, "rb");
198 199 200 201
        if (binary != NULL) {
            result = binary;
            goto finally;
        }
202
        PyErr_Clear();
203
    }
204 205 206 207 208 209 210
    goto error;

error:
    result = NULL;
finally:
    Py_DECREF(filebytes);
    return result;
211 212
}

Christian Heimes's avatar
Christian Heimes committed
213
int
214
_Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent)
Guido van Rossum's avatar
Guido van Rossum committed
215
{
216 217 218 219 220
    int err = 0;
    int fd;
    int i;
    char *found_encoding;
    char *encoding;
221 222
    PyObject *io;
    PyObject *binary;
223 224
    PyObject *fob = NULL;
    PyObject *lineobj = NULL;
225
    PyObject *res;
226 227 228 229 230 231 232
    char buf[MAXPATHLEN+1];
    Py_UNICODE *u, *p;
    Py_ssize_t len;

    /* open the file */
    if (filename == NULL)
        return 0;
233 234 235 236 237 238 239 240 241 242

    io = PyImport_ImportModuleNoBlock("io");
    if (io == NULL)
        return -1;
    binary = PyObject_CallMethod(io, "open", "Os", filename, "rb");

    if (binary == NULL) {
        binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io);
        if (binary == NULL) {
            Py_DECREF(io);
243
            return 0;
244
        }
245 246 247
    }

    /* use the right encoding to decode the file as unicode */
248
    fd = PyObject_AsFileDescriptor(binary);
249
    found_encoding = PyTokenizer_FindEncoding(fd);
250
    encoding = (found_encoding != NULL) ? found_encoding : "utf-8";
251
    lseek(fd, 0, 0); /* Reset position */
252 253 254
    fob = PyObject_CallMethod(io, "TextIOWrapper", "Os", binary, encoding);
    Py_DECREF(io);
    Py_DECREF(binary);
255
    PyMem_FREE(found_encoding);
256

257 258 259 260 261 262 263 264 265 266 267 268 269 270
    if (fob == NULL) {
        PyErr_Clear();
        return 0;
    }

    /* get the line number lineno */
    for (i = 0; i < lineno; i++) {
        Py_XDECREF(lineobj);
        lineobj = PyFile_GetLine(fob, -1);
        if (!lineobj) {
            err = -1;
            break;
        }
    }
271 272 273 274 275
    res = PyObject_CallMethod(fob, "close", "");
    if (res)
        Py_DECREF(res);
    else
        PyErr_Clear();
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
    Py_DECREF(fob);
    if (!lineobj || !PyUnicode_Check(lineobj)) {
        Py_XDECREF(lineobj);
        return err;
    }

    /* remove the indentation of the line */
    u = PyUnicode_AS_UNICODE(lineobj);
    len = PyUnicode_GET_SIZE(lineobj);
    for (p=u; *p == ' ' || *p == '\t' || *p == '\014'; p++)
        len--;
    if (u != p) {
        PyObject *truncated;
        truncated = PyUnicode_FromUnicode(p, len);
        if (truncated) {
            Py_DECREF(lineobj);
            lineobj = truncated;
        } else {
            PyErr_Clear();
        }
    }

    /* Write some spaces before the line */
    strcpy(buf, "          ");
    assert (strlen(buf) == 10);
    while (indent > 0) {
        if(indent < 10)
            buf[indent] = '\0';
        err = PyFile_WriteString(buf, f);
        if (err != 0)
            break;
        indent -= 10;
    }

    /* finally display the line */
    if (err == 0)
        err = PyFile_WriteObject(lineobj, f, Py_PRINT_RAW);
    Py_DECREF(lineobj);
    if  (err == 0)
        err = PyFile_WriteString("\n", f);
    return err;
Guido van Rossum's avatar
Guido van Rossum committed
317 318
}

319
static int
320
tb_displayline(PyObject *f, PyObject *filename, int lineno, PyObject *name)
Christian Heimes's avatar
Christian Heimes committed
321
{
322 323
    int err;
    PyObject *line;
Christian Heimes's avatar
Christian Heimes committed
324

325 326
    if (filename == NULL || name == NULL)
        return -1;
327 328 329 330 331 332
    line = PyUnicode_FromFormat("  File \"%U\", line %d, in %U\n",
                                filename, lineno, name);
    if (line == NULL)
        return -1;
    err = PyFile_WriteObject(line, f, Py_PRINT_RAW);
    Py_DECREF(line);
333 334 335
    if (err != 0)
        return err;
    return _Py_DisplaySourceLine(f, filename, lineno, 4);
Christian Heimes's avatar
Christian Heimes committed
336 337 338 339
}

static int
tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
Guido van Rossum's avatar
Guido van Rossum committed
340
{
341 342 343 344 345 346 347 348 349 350
    int err = 0;
    long depth = 0;
    PyTracebackObject *tb1 = tb;
    while (tb1 != NULL) {
        depth++;
        tb1 = tb1->tb_next;
    }
    while (tb != NULL && err == 0) {
        if (depth <= limit) {
            err = tb_displayline(f,
351 352 353
                                 tb->tb_frame->f_code->co_filename,
                                 tb->tb_lineno,
                                 tb->tb_frame->f_code->co_name);
354 355 356 357 358 359 360
        }
        depth--;
        tb = tb->tb_next;
        if (err == 0)
            err = PyErr_CheckSignals();
    }
    return err;
Guido van Rossum's avatar
Guido van Rossum committed
361 362
}

363 364
#define PyTraceBack_LIMIT 1000

Guido van Rossum's avatar
Guido van Rossum committed
365
int
366
PyTraceBack_Print(PyObject *v, PyObject *f)
Guido van Rossum's avatar
Guido van Rossum committed
367
{
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
    int err;
    PyObject *limitv;
    long limit = PyTraceBack_LIMIT;

    if (v == NULL)
        return 0;
    if (!PyTraceBack_Check(v)) {
        PyErr_BadInternalCall();
        return -1;
    }
    limitv = PySys_GetObject("tracebacklimit");
    if (limitv) {
        PyObject *exc_type, *exc_value, *exc_tb;

        PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
        limit = PyLong_AsLong(limitv);
        if (limit == -1 && PyErr_Occurred()) {
            if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
                limit = PyTraceBack_LIMIT;
            }
            else {
                Py_XDECREF(exc_type);
                Py_XDECREF(exc_value);
                Py_XDECREF(exc_tb);
                return 0;
            }
        }
        else if (limit <= 0) {
            limit = PyTraceBack_LIMIT;
        }
        PyErr_Restore(exc_type, exc_value, exc_tb);
    }
    err = PyFile_WriteString("Traceback (most recent call last):\n", f);
    if (!err)
        err = tb_printinternal((PyTracebackObject *)v, f, limit);
    return err;
Guido van Rossum's avatar
Guido van Rossum committed
404
}