Home | History | Annotate | Download | only in coverage
      1 /* C-based Tracer for Coverage. */
      2 
      3 #include "Python.h"
      4 #include "compile.h"        /* in 2.3, this wasn't part of Python.h */
      5 #include "eval.h"           /* or this. */
      6 #include "structmember.h"
      7 #include "frameobject.h"
      8 
      9 /* Compile-time debugging helpers */
     10 #undef WHAT_LOG         /* Define to log the WHAT params in the trace function. */
     11 #undef TRACE_LOG        /* Define to log our bookkeeping. */
     12 #undef COLLECT_STATS    /* Collect counters: stats are printed when tracer is stopped. */
     13 
     14 #if COLLECT_STATS
     15 #define STATS(x)        x
     16 #else
     17 #define STATS(x)
     18 #endif
     19 
     20 /* Py 2.x and 3.x compatibility */
     21 
     22 #ifndef Py_TYPE
     23 #define Py_TYPE(o)    (((PyObject*)(o))->ob_type)
     24 #endif
     25 
     26 #if PY_MAJOR_VERSION >= 3
     27 
     28 #define MyText_Type         PyUnicode_Type
     29 #define MyText_Check(o)     PyUnicode_Check(o)
     30 #define MyText_AS_STRING(o) PyBytes_AS_STRING(PyUnicode_AsASCIIString(o))
     31 #define MyInt_FromLong(l)   PyLong_FromLong(l)
     32 
     33 #define MyType_HEAD_INIT    PyVarObject_HEAD_INIT(NULL, 0)
     34 
     35 #else
     36 
     37 #define MyText_Type         PyString_Type
     38 #define MyText_Check(o)     PyString_Check(o)
     39 #define MyText_AS_STRING(o) PyString_AS_STRING(o)
     40 #define MyInt_FromLong(l)   PyInt_FromLong(l)
     41 
     42 #define MyType_HEAD_INIT    PyObject_HEAD_INIT(NULL)  0,
     43 
     44 #endif /* Py3k */
     45 
     46 /* The values returned to indicate ok or error. */
     47 #define RET_OK      0
     48 #define RET_ERROR   -1
     49 
     50 /* An entry on the data stack.  For each call frame, we need to record the
     51     dictionary to capture data, and the last line number executed in that
     52     frame.
     53 */
     54 typedef struct {
     55     PyObject * file_data;  /* PyMem_Malloc'ed, a borrowed ref. */
     56     int last_line;
     57 } DataStackEntry;
     58 
     59 /* The CTracer type. */
     60 
     61 typedef struct {
     62     PyObject_HEAD
     63 
     64     /* Python objects manipulated directly by the Collector class. */
     65     PyObject * should_trace;
     66     PyObject * warn;
     67     PyObject * data;
     68     PyObject * should_trace_cache;
     69     PyObject * arcs;
     70 
     71     /* Has the tracer been started? */
     72     int started;
     73     /* Are we tracing arcs, or just lines? */
     74     int tracing_arcs;
     75 
     76     /*
     77         The data stack is a stack of dictionaries.  Each dictionary collects
     78         data for a single source file.  The data stack parallels the call stack:
     79         each call pushes the new frame's file data onto the data stack, and each
     80         return pops file data off.
     81 
     82         The file data is a dictionary whose form depends on the tracing options.
     83         If tracing arcs, the keys are line number pairs.  If not tracing arcs,
     84         the keys are line numbers.  In both cases, the value is irrelevant
     85         (None).
     86     */
     87     /* The index of the last-used entry in data_stack. */
     88     int depth;
     89     /* The file data at each level, or NULL if not recording. */
     90     DataStackEntry * data_stack;
     91     int data_stack_alloc;       /* number of entries allocated at data_stack. */
     92 
     93     /* The current file_data dictionary.  Borrowed. */
     94     PyObject * cur_file_data;
     95 
     96     /* The line number of the last line recorded, for tracing arcs.
     97         -1 means there was no previous line, as when entering a code object.
     98     */
     99     int last_line;
    100 
    101     /* The parent frame for the last exception event, to fix missing returns. */
    102     PyFrameObject * last_exc_back;
    103     int last_exc_firstlineno;
    104 
    105 #if COLLECT_STATS
    106     struct {
    107         unsigned int calls;
    108         unsigned int lines;
    109         unsigned int returns;
    110         unsigned int exceptions;
    111         unsigned int others;
    112         unsigned int new_files;
    113         unsigned int missed_returns;
    114         unsigned int stack_reallocs;
    115         unsigned int errors;
    116     } stats;
    117 #endif /* COLLECT_STATS */
    118 } CTracer;
    119 
    120 #define STACK_DELTA    100
    121 
    122 static int
    123 CTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused)
    124 {
    125 #if COLLECT_STATS
    126     self->stats.calls = 0;
    127     self->stats.lines = 0;
    128     self->stats.returns = 0;
    129     self->stats.exceptions = 0;
    130     self->stats.others = 0;
    131     self->stats.new_files = 0;
    132     self->stats.missed_returns = 0;
    133     self->stats.stack_reallocs = 0;
    134     self->stats.errors = 0;
    135 #endif /* COLLECT_STATS */
    136 
    137     self->should_trace = NULL;
    138     self->warn = NULL;
    139     self->data = NULL;
    140     self->should_trace_cache = NULL;
    141     self->arcs = NULL;
    142 
    143     self->started = 0;
    144     self->tracing_arcs = 0;
    145 
    146     self->depth = -1;
    147     self->data_stack = PyMem_Malloc(STACK_DELTA*sizeof(DataStackEntry));
    148     if (self->data_stack == NULL) {
    149         STATS( self->stats.errors++; )
    150         PyErr_NoMemory();
    151         return RET_ERROR;
    152     }
    153     self->data_stack_alloc = STACK_DELTA;
    154 
    155     self->cur_file_data = NULL;
    156     self->last_line = -1;
    157 
    158     self->last_exc_back = NULL;
    159 
    160     return RET_OK;
    161 }
    162 
    163 static void
    164 CTracer_dealloc(CTracer *self)
    165 {
    166     if (self->started) {
    167         PyEval_SetTrace(NULL, NULL);
    168     }
    169 
    170     Py_XDECREF(self->should_trace);
    171     Py_XDECREF(self->warn);
    172     Py_XDECREF(self->data);
    173     Py_XDECREF(self->should_trace_cache);
    174 
    175     PyMem_Free(self->data_stack);
    176 
    177     Py_TYPE(self)->tp_free((PyObject*)self);
    178 }
    179 
    180 #if TRACE_LOG
    181 static const char *
    182 indent(int n)
    183 {
    184     static const char * spaces =
    185         "                                                                    "
    186         "                                                                    "
    187         "                                                                    "
    188         "                                                                    "
    189         ;
    190     return spaces + strlen(spaces) - n*2;
    191 }
    192 
    193 static int logging = 0;
    194 /* Set these constants to be a file substring and line number to start logging. */
    195 static const char * start_file = "tests/views";
    196 static int start_line = 27;
    197 
    198 static void
    199 showlog(int depth, int lineno, PyObject * filename, const char * msg)
    200 {
    201     if (logging) {
    202         printf("%s%3d ", indent(depth), depth);
    203         if (lineno) {
    204             printf("%4d", lineno);
    205         }
    206         else {
    207             printf("    ");
    208         }
    209         if (filename) {
    210             printf(" %s", MyText_AS_STRING(filename));
    211         }
    212         if (msg) {
    213             printf(" %s", msg);
    214         }
    215         printf("\n");
    216     }
    217 }
    218 
    219 #define SHOWLOG(a,b,c,d)    showlog(a,b,c,d)
    220 #else
    221 #define SHOWLOG(a,b,c,d)
    222 #endif /* TRACE_LOG */
    223 
    224 #if WHAT_LOG
    225 static const char * what_sym[] = {"CALL", "EXC ", "LINE", "RET "};
    226 #endif
    227 
    228 /* Record a pair of integers in self->cur_file_data. */
    229 static int
    230 CTracer_record_pair(CTracer *self, int l1, int l2)
    231 {
    232     int ret = RET_OK;
    233 
    234     PyObject * t = PyTuple_New(2);
    235     if (t != NULL) {
    236         PyTuple_SET_ITEM(t, 0, MyInt_FromLong(l1));
    237         PyTuple_SET_ITEM(t, 1, MyInt_FromLong(l2));
    238         if (PyDict_SetItem(self->cur_file_data, t, Py_None) < 0) {
    239             STATS( self->stats.errors++; )
    240             ret = RET_ERROR;
    241         }
    242         Py_DECREF(t);
    243     }
    244     else {
    245         STATS( self->stats.errors++; )
    246         ret = RET_ERROR;
    247     }
    248     return ret;
    249 }
    250 
    251 /*
    252  * The Trace Function
    253  */
    254 static int
    255 CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unused)
    256 {
    257     int ret = RET_OK;
    258     PyObject * filename = NULL;
    259     PyObject * tracename = NULL;
    260 
    261     #if WHAT_LOG
    262     if (what <= sizeof(what_sym)/sizeof(const char *)) {
    263         printf("trace: %s @ %s %d\n", what_sym[what], MyText_AS_STRING(frame->f_code->co_filename), frame->f_lineno);
    264     }
    265     #endif
    266 
    267     #if TRACE_LOG
    268     if (strstr(MyText_AS_STRING(frame->f_code->co_filename), start_file) && frame->f_lineno == start_line) {
    269         logging = 1;
    270     }
    271     #endif
    272 
    273     /* See below for details on missing-return detection. */
    274     if (self->last_exc_back) {
    275         if (frame == self->last_exc_back) {
    276             /* Looks like someone forgot to send a return event. We'll clear
    277                the exception state and do the RETURN code here.  Notice that the
    278                frame we have in hand here is not the correct frame for the RETURN,
    279                that frame is gone.  Our handling for RETURN doesn't need the
    280                actual frame, but we do log it, so that will look a little off if
    281                you're looking at the detailed log.
    282 
    283                If someday we need to examine the frame when doing RETURN, then
    284                we'll need to keep more of the missed frame's state.
    285             */
    286             STATS( self->stats.missed_returns++; )
    287             if (self->depth >= 0) {
    288                 if (self->tracing_arcs && self->cur_file_data) {
    289                     if (CTracer_record_pair(self, self->last_line, -self->last_exc_firstlineno) < 0) {
    290                         return RET_ERROR;
    291                     }
    292                 }
    293                 SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "missedreturn");
    294                 self->cur_file_data = self->data_stack[self->depth].file_data;
    295                 self->last_line = self->data_stack[self->depth].last_line;
    296                 self->depth--;
    297             }
    298         }
    299         self->last_exc_back = NULL;
    300     }
    301 
    302 
    303     switch (what) {
    304     case PyTrace_CALL:      /* 0 */
    305         STATS( self->stats.calls++; )
    306         /* Grow the stack. */
    307         self->depth++;
    308         if (self->depth >= self->data_stack_alloc) {
    309             STATS( self->stats.stack_reallocs++; )
    310             /* We've outgrown our data_stack array: make it bigger. */
    311             int bigger = self->data_stack_alloc + STACK_DELTA;
    312             DataStackEntry * bigger_data_stack = PyMem_Realloc(self->data_stack, bigger * sizeof(DataStackEntry));
    313             if (bigger_data_stack == NULL) {
    314                 STATS( self->stats.errors++; )
    315                 PyErr_NoMemory();
    316                 self->depth--;
    317                 return RET_ERROR;
    318             }
    319             self->data_stack = bigger_data_stack;
    320             self->data_stack_alloc = bigger;
    321         }
    322 
    323         /* Push the current state on the stack. */
    324         self->data_stack[self->depth].file_data = self->cur_file_data;
    325         self->data_stack[self->depth].last_line = self->last_line;
    326 
    327         /* Check if we should trace this line. */
    328         filename = frame->f_code->co_filename;
    329         tracename = PyDict_GetItem(self->should_trace_cache, filename);
    330         if (tracename == NULL) {
    331             STATS( self->stats.new_files++; )
    332             /* We've never considered this file before. */
    333             /* Ask should_trace about it. */
    334             PyObject * args = Py_BuildValue("(OO)", filename, frame);
    335             tracename = PyObject_Call(self->should_trace, args, NULL);
    336             Py_DECREF(args);
    337             if (tracename == NULL) {
    338                 /* An error occurred inside should_trace. */
    339                 STATS( self->stats.errors++; )
    340                 return RET_ERROR;
    341             }
    342             if (PyDict_SetItem(self->should_trace_cache, filename, tracename) < 0) {
    343                 STATS( self->stats.errors++; )
    344                 return RET_ERROR;
    345             }
    346         }
    347         else {
    348             Py_INCREF(tracename);
    349         }
    350 
    351         /* If tracename is a string, then we're supposed to trace. */
    352         if (MyText_Check(tracename)) {
    353             PyObject * file_data = PyDict_GetItem(self->data, tracename);
    354             if (file_data == NULL) {
    355                 file_data = PyDict_New();
    356                 if (file_data == NULL) {
    357                     STATS( self->stats.errors++; )
    358                     return RET_ERROR;
    359                 }
    360                 ret = PyDict_SetItem(self->data, tracename, file_data);
    361                 Py_DECREF(file_data);
    362                 if (ret < 0) {
    363                     STATS( self->stats.errors++; )
    364                     return RET_ERROR;
    365                 }
    366             }
    367             self->cur_file_data = file_data;
    368             /* Make the frame right in case settrace(gettrace()) happens. */
    369             Py_INCREF(self);
    370             frame->f_trace = (PyObject*)self;
    371             SHOWLOG(self->depth, frame->f_lineno, filename, "traced");
    372         }
    373         else {
    374             self->cur_file_data = NULL;
    375             SHOWLOG(self->depth, frame->f_lineno, filename, "skipped");
    376         }
    377 
    378         Py_DECREF(tracename);
    379 
    380         self->last_line = -1;
    381         break;
    382 
    383     case PyTrace_RETURN:    /* 3 */
    384         STATS( self->stats.returns++; )
    385         /* A near-copy of this code is above in the missing-return handler. */
    386         if (self->depth >= 0) {
    387             if (self->tracing_arcs && self->cur_file_data) {
    388                 int first = frame->f_code->co_firstlineno;
    389                 if (CTracer_record_pair(self, self->last_line, -first) < 0) {
    390                     return RET_ERROR;
    391                 }
    392             }
    393 
    394             SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "return");
    395             self->cur_file_data = self->data_stack[self->depth].file_data;
    396             self->last_line = self->data_stack[self->depth].last_line;
    397             self->depth--;
    398         }
    399         break;
    400 
    401     case PyTrace_LINE:      /* 2 */
    402         STATS( self->stats.lines++; )
    403         if (self->depth >= 0) {
    404             SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "line");
    405             if (self->cur_file_data) {
    406                 /* We're tracing in this frame: record something. */
    407                 if (self->tracing_arcs) {
    408                     /* Tracing arcs: key is (last_line,this_line). */
    409                     if (CTracer_record_pair(self, self->last_line, frame->f_lineno) < 0) {
    410                         return RET_ERROR;
    411                     }
    412                 }
    413                 else {
    414                     /* Tracing lines: key is simply this_line. */
    415                     PyObject * this_line = MyInt_FromLong(frame->f_lineno);
    416                     if (this_line == NULL) {
    417                         STATS( self->stats.errors++; )
    418                         return RET_ERROR;
    419                     }
    420                     ret = PyDict_SetItem(self->cur_file_data, this_line, Py_None);
    421                     Py_DECREF(this_line);
    422                     if (ret < 0) {
    423                         STATS( self->stats.errors++; )
    424                         return RET_ERROR;
    425                     }
    426                 }
    427             }
    428             self->last_line = frame->f_lineno;
    429         }
    430         break;
    431 
    432     case PyTrace_EXCEPTION:
    433         /* Some code (Python 2.3, and pyexpat anywhere) fires an exception event
    434            without a return event.  To detect that, we'll keep a copy of the
    435            parent frame for an exception event.  If the next event is in that
    436            frame, then we must have returned without a return event.  We can
    437            synthesize the missing event then.
    438 
    439            Python itself fixed this problem in 2.4.  Pyexpat still has the bug.
    440            I've reported the problem with pyexpat as http://bugs.python.org/issue6359 .
    441            If it gets fixed, this code should still work properly.  Maybe some day
    442            the bug will be fixed everywhere coverage.py is supported, and we can
    443            remove this missing-return detection.
    444 
    445            More about this fix: http://nedbatchelder.com/blog/200907/a_nasty_little_bug.html
    446         */
    447         STATS( self->stats.exceptions++; )
    448         self->last_exc_back = frame->f_back;
    449         self->last_exc_firstlineno = frame->f_code->co_firstlineno;
    450         break;
    451 
    452     default:
    453         STATS( self->stats.others++; )
    454         break;
    455     }
    456 
    457     return RET_OK;
    458 }
    459 
    460 /*
    461  * Python has two ways to set the trace function: sys.settrace(fn), which
    462  * takes a Python callable, and PyEval_SetTrace(func, obj), which takes
    463  * a C function and a Python object.  The way these work together is that
    464  * sys.settrace(pyfn) calls PyEval_SetTrace(builtin_func, pyfn), using the
    465  * Python callable as the object in PyEval_SetTrace.  So sys.gettrace()
    466  * simply returns the Python object used as the second argument to
    467  * PyEval_SetTrace.  So sys.gettrace() will return our self parameter, which
    468  * means it must be callable to be used in sys.settrace().
    469  *
    470  * So we make our self callable, equivalent to invoking our trace function.
    471  *
    472  * To help with the process of replaying stored frames, this function has an
    473  * optional keyword argument:
    474  *
    475  *      def CTracer_call(frame, event, arg, lineno=0)
    476  *
    477  * If provided, the lineno argument is used as the line number, and the
    478  * frame's f_lineno member is ignored.
    479  */
    480 static PyObject *
    481 CTracer_call(CTracer *self, PyObject *args, PyObject *kwds)
    482 {
    483     PyFrameObject *frame;
    484     PyObject *what_str;
    485     PyObject *arg;
    486     int lineno = 0;
    487     int what;
    488     int orig_lineno;
    489     PyObject *ret = NULL;
    490 
    491     static char *what_names[] = {
    492         "call", "exception", "line", "return",
    493         "c_call", "c_exception", "c_return",
    494         NULL
    495         };
    496 
    497     #if WHAT_LOG
    498     printf("pytrace\n");
    499     #endif
    500 
    501     static char *kwlist[] = {"frame", "event", "arg", "lineno", NULL};
    502 
    503     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!O|i:Tracer_call", kwlist,
    504             &PyFrame_Type, &frame, &MyText_Type, &what_str, &arg, &lineno)) {
    505         goto done;
    506     }
    507 
    508     /* In Python, the what argument is a string, we need to find an int
    509        for the C function. */
    510     for (what = 0; what_names[what]; what++) {
    511         if (!strcmp(MyText_AS_STRING(what_str), what_names[what])) {
    512             break;
    513         }
    514     }
    515 
    516     /* Save off the frame's lineno, and use the forced one, if provided. */
    517     orig_lineno = frame->f_lineno;
    518     if (lineno > 0) {
    519         frame->f_lineno = lineno;
    520     }
    521 
    522     /* Invoke the C function, and return ourselves. */
    523     if (CTracer_trace(self, frame, what, arg) == RET_OK) {
    524         Py_INCREF(self);
    525         ret = (PyObject *)self;
    526     }
    527 
    528     /* Clean up. */
    529     frame->f_lineno = orig_lineno;
    530 
    531 done:
    532     return ret;
    533 }
    534 
    535 static PyObject *
    536 CTracer_start(CTracer *self, PyObject *args_unused)
    537 {
    538     PyEval_SetTrace((Py_tracefunc)CTracer_trace, (PyObject*)self);
    539     self->started = 1;
    540     self->tracing_arcs = self->arcs && PyObject_IsTrue(self->arcs);
    541     self->last_line = -1;
    542 
    543     /* start() returns a trace function usable with sys.settrace() */
    544     Py_INCREF(self);
    545     return (PyObject *)self;
    546 }
    547 
    548 static PyObject *
    549 CTracer_stop(CTracer *self, PyObject *args_unused)
    550 {
    551     if (self->started) {
    552         PyEval_SetTrace(NULL, NULL);
    553         self->started = 0;
    554     }
    555 
    556     return Py_BuildValue("");
    557 }
    558 
    559 static PyObject *
    560 CTracer_get_stats(CTracer *self)
    561 {
    562 #if COLLECT_STATS
    563     return Py_BuildValue(
    564         "{sI,sI,sI,sI,sI,sI,sI,sI,si,sI}",
    565         "calls", self->stats.calls,
    566         "lines", self->stats.lines,
    567         "returns", self->stats.returns,
    568         "exceptions", self->stats.exceptions,
    569         "others", self->stats.others,
    570         "new_files", self->stats.new_files,
    571         "missed_returns", self->stats.missed_returns,
    572         "stack_reallocs", self->stats.stack_reallocs,
    573         "stack_alloc", self->data_stack_alloc,
    574         "errors", self->stats.errors
    575         );
    576 #else
    577     return Py_BuildValue("");
    578 #endif /* COLLECT_STATS */
    579 }
    580 
    581 static PyMemberDef
    582 CTracer_members[] = {
    583     { "should_trace",       T_OBJECT, offsetof(CTracer, should_trace), 0,
    584             PyDoc_STR("Function indicating whether to trace a file.") },
    585 
    586     { "warn",               T_OBJECT, offsetof(CTracer, warn), 0,
    587             PyDoc_STR("Function for issuing warnings.") },
    588 
    589     { "data",               T_OBJECT, offsetof(CTracer, data), 0,
    590             PyDoc_STR("The raw dictionary of trace data.") },
    591 
    592     { "should_trace_cache", T_OBJECT, offsetof(CTracer, should_trace_cache), 0,
    593             PyDoc_STR("Dictionary caching should_trace results.") },
    594 
    595     { "arcs",               T_OBJECT, offsetof(CTracer, arcs), 0,
    596             PyDoc_STR("Should we trace arcs, or just lines?") },
    597 
    598     { NULL }
    599 };
    600 
    601 static PyMethodDef
    602 CTracer_methods[] = {
    603     { "start",      (PyCFunction) CTracer_start,        METH_VARARGS,
    604             PyDoc_STR("Start the tracer") },
    605 
    606     { "stop",       (PyCFunction) CTracer_stop,         METH_VARARGS,
    607             PyDoc_STR("Stop the tracer") },
    608 
    609     { "get_stats",  (PyCFunction) CTracer_get_stats,    METH_VARARGS,
    610             PyDoc_STR("Get statistics about the tracing") },
    611 
    612     { NULL }
    613 };
    614 
    615 static PyTypeObject
    616 CTracerType = {
    617     MyType_HEAD_INIT
    618     "coverage.CTracer",        /*tp_name*/
    619     sizeof(CTracer),           /*tp_basicsize*/
    620     0,                         /*tp_itemsize*/
    621     (destructor)CTracer_dealloc, /*tp_dealloc*/
    622     0,                         /*tp_print*/
    623     0,                         /*tp_getattr*/
    624     0,                         /*tp_setattr*/
    625     0,                         /*tp_compare*/
    626     0,                         /*tp_repr*/
    627     0,                         /*tp_as_number*/
    628     0,                         /*tp_as_sequence*/
    629     0,                         /*tp_as_mapping*/
    630     0,                         /*tp_hash */
    631     (ternaryfunc)CTracer_call, /*tp_call*/
    632     0,                         /*tp_str*/
    633     0,                         /*tp_getattro*/
    634     0,                         /*tp_setattro*/
    635     0,                         /*tp_as_buffer*/
    636     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
    637     "CTracer objects",         /* tp_doc */
    638     0,                         /* tp_traverse */
    639     0,                         /* tp_clear */
    640     0,                         /* tp_richcompare */
    641     0,                         /* tp_weaklistoffset */
    642     0,                         /* tp_iter */
    643     0,                         /* tp_iternext */
    644     CTracer_methods,           /* tp_methods */
    645     CTracer_members,           /* tp_members */
    646     0,                         /* tp_getset */
    647     0,                         /* tp_base */
    648     0,                         /* tp_dict */
    649     0,                         /* tp_descr_get */
    650     0,                         /* tp_descr_set */
    651     0,                         /* tp_dictoffset */
    652     (initproc)CTracer_init,    /* tp_init */
    653     0,                         /* tp_alloc */
    654     0,                         /* tp_new */
    655 };
    656 
    657 /* Module definition */
    658 
    659 #define MODULE_DOC PyDoc_STR("Fast coverage tracer.")
    660 
    661 #if PY_MAJOR_VERSION >= 3
    662 
    663 static PyModuleDef
    664 moduledef = {
    665     PyModuleDef_HEAD_INIT,
    666     "coverage.tracer",
    667     MODULE_DOC,
    668     -1,
    669     NULL,       /* methods */
    670     NULL,
    671     NULL,       /* traverse */
    672     NULL,       /* clear */
    673     NULL
    674 };
    675 
    676 
    677 PyObject *
    678 PyInit_tracer(void)
    679 {
    680     PyObject * mod = PyModule_Create(&moduledef);
    681     if (mod == NULL) {
    682         return NULL;
    683     }
    684 
    685     CTracerType.tp_new = PyType_GenericNew;
    686     if (PyType_Ready(&CTracerType) < 0) {
    687         Py_DECREF(mod);
    688         return NULL;
    689     }
    690 
    691     Py_INCREF(&CTracerType);
    692     PyModule_AddObject(mod, "CTracer", (PyObject *)&CTracerType);
    693 
    694     return mod;
    695 }
    696 
    697 #else
    698 
    699 void
    700 inittracer(void)
    701 {
    702     PyObject * mod;
    703 
    704     mod = Py_InitModule3("coverage.tracer", NULL, MODULE_DOC);
    705     if (mod == NULL) {
    706         return;
    707     }
    708 
    709     CTracerType.tp_new = PyType_GenericNew;
    710     if (PyType_Ready(&CTracerType) < 0) {
    711         return;
    712     }
    713 
    714     Py_INCREF(&CTracerType);
    715     PyModule_AddObject(mod, "CTracer", (PyObject *)&CTracerType);
    716 }
    717 
    718 #endif /* Py3k */
    719 
    720