LCOV - code coverage report
Current view: top level - Python - traceback.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 33 143 23.1 %
Date: 2017-04-19 Functions: 4 9 44.4 %

          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             : #include "traceback.h"
      11             : 
      12             : #define OFF(x) offsetof(PyTracebackObject, x)
      13             : 
      14             : static PyMemberDef tb_memberlist[] = {
      15             :     {"tb_next",         T_OBJECT,       OFF(tb_next), READONLY},
      16             :     {"tb_frame",        T_OBJECT,       OFF(tb_frame), READONLY},
      17             :     {"tb_lasti",        T_INT,          OFF(tb_lasti), READONLY},
      18             :     {"tb_lineno",       T_INT,          OFF(tb_lineno), READONLY},
      19             :     {NULL}      /* Sentinel */
      20             : };
      21             : 
      22             : static void
      23        2154 : tb_dealloc(PyTracebackObject *tb)
      24             : {
      25        2154 :     PyObject_GC_UnTrack(tb);
      26        2154 :     Py_TRASHCAN_SAFE_BEGIN(tb)
      27        2154 :     Py_XDECREF(tb->tb_next);
      28        2154 :     Py_XDECREF(tb->tb_frame);
      29        2154 :     PyObject_GC_Del(tb);
      30        2154 :     Py_TRASHCAN_SAFE_END(tb)
      31        2154 : }
      32             : 
      33             : static int
      34          28 : tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)
      35             : {
      36          28 :     Py_VISIT(tb->tb_next);
      37          28 :     Py_VISIT(tb->tb_frame);
      38          28 :     return 0;
      39             : }
      40             : 
      41             : static void
      42           0 : tb_clear(PyTracebackObject *tb)
      43             : {
      44           0 :     Py_CLEAR(tb->tb_next);
      45           0 :     Py_CLEAR(tb->tb_frame);
      46           0 : }
      47             : 
      48             : PyTypeObject PyTraceBack_Type = {
      49             :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
      50             :     "traceback",
      51             :     sizeof(PyTracebackObject),
      52             :     0,
      53             :     (destructor)tb_dealloc, /*tp_dealloc*/
      54             :     0,                  /*tp_print*/
      55             :     0,              /*tp_getattr*/
      56             :     0,                  /*tp_setattr*/
      57             :     0,                  /*tp_compare*/
      58             :     0,                  /*tp_repr*/
      59             :     0,                  /*tp_as_number*/
      60             :     0,                  /*tp_as_sequence*/
      61             :     0,                  /*tp_as_mapping*/
      62             :     0,                  /* tp_hash */
      63             :     0,                  /* tp_call */
      64             :     0,                  /* tp_str */
      65             :     0,                  /* tp_getattro */
      66             :     0,                  /* tp_setattro */
      67             :     0,                                          /* tp_as_buffer */
      68             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
      69             :     0,                                          /* tp_doc */
      70             :     (traverseproc)tb_traverse,                  /* tp_traverse */
      71             :     (inquiry)tb_clear,                          /* tp_clear */
      72             :     0,                                          /* tp_richcompare */
      73             :     0,                                          /* tp_weaklistoffset */
      74             :     0,                                          /* tp_iter */
      75             :     0,                                          /* tp_iternext */
      76             :     0,                                          /* tp_methods */
      77             :     tb_memberlist,                              /* tp_members */
      78             :     0,                                          /* tp_getset */
      79             :     0,                                          /* tp_base */
      80             :     0,                                          /* tp_dict */
      81             : };
      82             : 
      83             : static PyTracebackObject *
      84        2154 : newtracebackobject(PyTracebackObject *next, PyFrameObject *frame)
      85             : {
      86             :     PyTracebackObject *tb;
      87        2154 :     if ((next != NULL && !PyTraceBack_Check(next)) ||
      88        2154 :                     frame == NULL || !PyFrame_Check(frame)) {
      89           0 :         PyErr_BadInternalCall();
      90           0 :         return NULL;
      91             :     }
      92        2154 :     tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
      93        2154 :     if (tb != NULL) {
      94        2154 :         Py_XINCREF(next);
      95        2154 :         tb->tb_next = next;
      96        2154 :         Py_XINCREF(frame);
      97        2154 :         tb->tb_frame = frame;
      98        2154 :         tb->tb_lasti = frame->f_lasti;
      99        2154 :         tb->tb_lineno = PyFrame_GetLineNumber(frame);
     100        2154 :         PyObject_GC_Track(tb);
     101             :     }
     102        2154 :     return tb;
     103             : }
     104             : 
     105             : int
     106        2154 : PyTraceBack_Here(PyFrameObject *frame)
     107             : {
     108        2154 :     PyThreadState *tstate = PyThreadState_GET();
     109        2154 :     PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback;
     110        2154 :     PyTracebackObject *tb = newtracebackobject(oldtb, frame);
     111        2154 :     if (tb == NULL)
     112           0 :         return -1;
     113        2154 :     tstate->curexc_traceback = (PyObject *)tb;
     114        2154 :     Py_XDECREF(oldtb);
     115        2154 :     return 0;
     116             : }
     117             : 
     118             : int
     119           0 : _Py_DisplaySourceLine(PyObject *f, const char *filename, int lineno, int indent)
     120             : {
     121           0 :     int err = 0;
     122           0 :     FILE *xfp = NULL;
     123             :     char linebuf[2000];
     124             :     int i;
     125             :     char namebuf[MAXPATHLEN+1];
     126             : 
     127           0 :     if (filename == NULL)
     128           0 :         return -1;
     129             :     /* This is needed by Emacs' compile command */
     130             : #define FMT "  File \"%.500s\", line %d, in %.500s\n"
     131           0 :     xfp = fopen(filename, "r" PY_STDIOTEXTMODE);
     132           0 :     if (xfp == NULL) {
     133             :         /* Search tail of filename in sys.path before giving up */
     134             :         PyObject *path;
     135           0 :         const char *tail = strrchr(filename, SEP);
     136           0 :         if (tail == NULL)
     137           0 :             tail = filename;
     138             :         else
     139           0 :             tail++;
     140           0 :         path = PySys_GetObject("path");
     141           0 :         if (path != NULL && PyList_Check(path)) {
     142           0 :             Py_ssize_t _npath = PyList_Size(path);
     143           0 :             int npath = Py_SAFE_DOWNCAST(_npath, Py_ssize_t, int);
     144           0 :             size_t taillen = strlen(tail);
     145           0 :             for (i = 0; i < npath; i++) {
     146           0 :                 PyObject *v = PyList_GetItem(path, i);
     147           0 :                 if (v == NULL) {
     148           0 :                     PyErr_Clear();
     149           0 :                     break;
     150             :                 }
     151           0 :                 if (PyString_Check(v)) {
     152             :                     size_t len;
     153           0 :                     len = PyString_GET_SIZE(v);
     154           0 :                     if (len + 1 + taillen >= MAXPATHLEN)
     155           0 :                         continue; /* Too long */
     156           0 :                     strcpy(namebuf, PyString_AsString(v));
     157           0 :                     if (strlen(namebuf) != len)
     158           0 :                         continue; /* v contains '\0' */
     159           0 :                     if (len > 0 && namebuf[len-1] != SEP)
     160           0 :                         namebuf[len++] = SEP;
     161           0 :                     strcpy(namebuf+len, tail);
     162           0 :                     xfp = fopen(namebuf, "r" PY_STDIOTEXTMODE);
     163           0 :                     if (xfp != NULL) {
     164           0 :                         break;
     165             :                     }
     166             :                 }
     167             :             }
     168             :         }
     169             :     }
     170             : 
     171           0 :     if (xfp == NULL)
     172           0 :         return err;
     173             : 
     174           0 :     for (i = 0; i < lineno; i++) {
     175           0 :         char* pLastChar = &linebuf[sizeof(linebuf)-2];
     176             :         do {
     177           0 :             *pLastChar = '\0';
     178           0 :             if (Py_UniversalNewlineFgets(linebuf, sizeof linebuf, xfp, NULL) == NULL)
     179           0 :                 break;
     180             :             /* fgets read *something*; if it didn't get as
     181             :                far as pLastChar, it must have found a newline
     182             :                or hit the end of the file;              if pLastChar is \n,
     183             :                it obviously found a newline; else we haven't
     184             :                yet seen a newline, so must continue */
     185           0 :         } while (*pLastChar != '\0' && *pLastChar != '\n');
     186             :     }
     187           0 :     if (i == lineno) {
     188             :         char buf[11];
     189           0 :         char *p = linebuf;
     190           0 :         while (*p == ' ' || *p == '\t' || *p == '\014')
     191           0 :             p++;
     192             : 
     193             :         /* Write some spaces before the line */
     194           0 :         strcpy(buf, "          ");
     195             :         assert (strlen(buf) == 10);
     196           0 :         while (indent > 0) {
     197           0 :             if(indent < 10)
     198           0 :                 buf[indent] = '\0';
     199           0 :             err = PyFile_WriteString(buf, f);
     200           0 :             if (err != 0)
     201           0 :                 break;
     202           0 :             indent -= 10;
     203             :         }
     204             : 
     205           0 :         if (err == 0)
     206           0 :             err = PyFile_WriteString(p, f);
     207           0 :         if (err == 0 && strchr(p, '\n') == NULL)
     208           0 :             err = PyFile_WriteString("\n", f);
     209             :     }
     210           0 :     fclose(xfp);
     211           0 :     return err;
     212             : }
     213             : 
     214             : static int
     215           0 : tb_displayline(PyObject *f, const char *filename, int lineno, const char *name)
     216             : {
     217           0 :     int err = 0;
     218             :     char linebuf[2000];
     219             : 
     220           0 :     if (filename == NULL || name == NULL)
     221           0 :         return -1;
     222             :     /* This is needed by Emacs' compile command */
     223             : #define FMT "  File \"%.500s\", line %d, in %.500s\n"
     224           0 :     PyOS_snprintf(linebuf, sizeof(linebuf), FMT, filename, lineno, name);
     225           0 :     err = PyFile_WriteString(linebuf, f);
     226           0 :     if (err != 0)
     227           0 :         return err;
     228           0 :     return _Py_DisplaySourceLine(f, filename, lineno, 4);
     229             : }
     230             : 
     231             : static int
     232           0 : tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
     233             : {
     234           0 :     int err = 0;
     235           0 :     long depth = 0;
     236           0 :     PyTracebackObject *tb1 = tb;
     237           0 :     while (tb1 != NULL) {
     238           0 :         depth++;
     239           0 :         tb1 = tb1->tb_next;
     240             :     }
     241           0 :     while (tb != NULL && err == 0) {
     242           0 :         if (depth <= limit) {
     243           0 :             err = tb_displayline(f,
     244           0 :                 PyString_AsString(
     245           0 :                     tb->tb_frame->f_code->co_filename),
     246             :                 tb->tb_lineno,
     247           0 :                 PyString_AsString(tb->tb_frame->f_code->co_name));
     248             :         }
     249           0 :         depth--;
     250           0 :         tb = tb->tb_next;
     251           0 :         if (err == 0)
     252           0 :             err = PyErr_CheckSignals();
     253             :     }
     254           0 :     return err;
     255             : }
     256             : 
     257             : int
     258           0 : PyTraceBack_Print(PyObject *v, PyObject *f)
     259             : {
     260             :     int err;
     261             :     PyObject *limitv;
     262           0 :     long limit = 1000;
     263           0 :     if (v == NULL)
     264           0 :         return 0;
     265           0 :     if (!PyTraceBack_Check(v)) {
     266           0 :         PyErr_BadInternalCall();
     267           0 :         return -1;
     268             :     }
     269           0 :     limitv = PySys_GetObject("tracebacklimit");
     270           0 :     if (limitv && PyInt_Check(limitv)) {
     271           0 :         limit = PyInt_AsLong(limitv);
     272           0 :         if (limit <= 0)
     273           0 :             return 0;
     274             :     }
     275           0 :     err = PyFile_WriteString("Traceback (most recent call last):\n", f);
     276           0 :     if (!err)
     277           0 :         err = tb_printinternal((PyTracebackObject *)v, f, limit);
     278           0 :     return err;
     279             : }

Generated by: LCOV version 1.10