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