15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from cpython.ref cimport PyObject, Py_INCREF, Py_DECREF, Py_XDECREF, Py_XINCREF 25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from cpython.exc cimport PyErr_Fetch, PyErr_Restore 35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from cpython.pystate cimport PyThreadState_Get 45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cimport cython 65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)loglevel = 0 85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)reflog = [] 95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cdef log(level, action, obj, lineno): 115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if loglevel >= level: 125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) reflog.append((lineno, action, id(obj))) 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)LOG_NONE, LOG_ALL = range(2) 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)@cython.final 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cdef class Context(object): 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef readonly object name, filename 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef readonly dict refs 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef readonly list errors 215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef readonly Py_ssize_t start 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def __cinit__(self, name, line=0, filename=None): 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.name = name 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.start = line 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.filename = filename 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.refs = {} # id -> (count, [lineno]) 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.errors = [] 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef regref(self, obj, lineno, bint is_null): 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) log(LOG_ALL, u'regref', u"<NULL>" if is_null else obj, lineno) 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if is_null: 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.errors.append(u"NULL argument on line %d" % lineno) 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) id_ = id(obj) 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) count, linenumbers = self.refs.get(id_, (0, [])) 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.refs[id_] = (count + 1, linenumbers) 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) linenumbers.append(lineno) 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef bint delref(self, obj, lineno, bint is_null) except -1: 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # returns whether it is ok to do the decref operation 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) log(LOG_ALL, u'delref', u"<NULL>" if is_null else obj, lineno) 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if is_null: 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.errors.append(u"NULL argument on line %d" % lineno) 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return False 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) id_ = id(obj) 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) count, linenumbers = self.refs.get(id_, (0, [])) 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if count == 0: 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.errors.append(u"Too many decrefs on line %d, reference acquired on lines %r" % 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (lineno, linenumbers)) 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return False 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) elif count == 1: 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) del self.refs[id_] 545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return True 555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) else: 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.refs[id_] = (count - 1, linenumbers) 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return True 585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef end(self): 605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if self.refs: 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) msg = u"References leaked:" 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for count, linenos in self.refs.itervalues(): 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) msg += u"\n (%d) acquired on lines: %s" % (count, u", ".join([u"%d" % x for x in linenos])) 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.errors.append(msg) 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if self.errors: 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return u"\n".join([u'REFNANNY: '+error for error in self.errors]) 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) else: 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return None 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cdef void report_unraisable(object e=None): 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) try: 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if e is None: 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) import sys 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) e = sys.exc_info()[1] 755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) print u"refnanny raised an exception: %s" % e 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) except: 775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pass # We absolutely cannot exit with an exception 785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# All Python operations must happen after any existing 805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# exception has been fetched, in case we are called from 815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# exception-handling code. 825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cdef PyObject* SetupContext(char* funcname, int lineno, char* filename) except NULL: 845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if Context is None: 855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # Context may be None during finalize phase. 865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # In that case, we don't want to be doing anything fancy 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # like caching and resetting exceptions. 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return NULL 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef (PyObject*) type = NULL, value = NULL, tb = NULL, result = NULL 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyThreadState_Get() 915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyErr_Fetch(&type, &value, &tb) 925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) try: 935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ctx = Context(funcname, lineno, filename) 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Py_INCREF(ctx) 955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) result = <PyObject*>ctx 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) except Exception, e: 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) report_unraisable(e) 985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyErr_Restore(type, value, tb) 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return result 1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cdef void GOTREF(PyObject* ctx, PyObject* p_obj, int lineno): 1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if ctx == NULL: return 1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef (PyObject*) type = NULL, value = NULL, tb = NULL 1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyErr_Fetch(&type, &value, &tb) 1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) try: 1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) try: 1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if p_obj is NULL: 1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (<Context>ctx).regref(None, lineno, True) 1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) else: 1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (<Context>ctx).regref(<object>p_obj, lineno, False) 1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) except: 1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) report_unraisable() 1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) except: 1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # __Pyx_GetException may itself raise errors 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pass 1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyErr_Restore(type, value, tb) 1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cdef int GIVEREF_and_report(PyObject* ctx, PyObject* p_obj, int lineno): 1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if ctx == NULL: return 1 1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef (PyObject*) type = NULL, value = NULL, tb = NULL 1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef bint decref_ok = False 1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyErr_Fetch(&type, &value, &tb) 1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) try: 1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) try: 1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if p_obj is NULL: 1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) decref_ok = (<Context>ctx).delref(None, lineno, True) 1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) else: 1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) decref_ok = (<Context>ctx).delref(<object>p_obj, lineno, False) 1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) except: 1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) report_unraisable() 1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) except: 1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # __Pyx_GetException may itself raise errors 1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pass 1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyErr_Restore(type, value, tb) 1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return decref_ok 1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cdef void GIVEREF(PyObject* ctx, PyObject* p_obj, int lineno): 1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GIVEREF_and_report(ctx, p_obj, lineno) 1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cdef void INCREF(PyObject* ctx, PyObject* obj, int lineno): 1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Py_XINCREF(obj) 1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyThreadState_Get() 1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GOTREF(ctx, obj, lineno) 1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cdef void DECREF(PyObject* ctx, PyObject* obj, int lineno): 1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if GIVEREF_and_report(ctx, obj, lineno): 1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Py_XDECREF(obj) 1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyThreadState_Get() 1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cdef void FinishContext(PyObject** ctx): 1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if ctx == NULL or ctx[0] == NULL: return 1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef (PyObject*) type = NULL, value = NULL, tb = NULL 1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef object errors = None 1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cdef Context context 1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyThreadState_Get() 1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyErr_Fetch(&type, &value, &tb) 1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) try: 1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) try: 1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) context = <Context>ctx[0] 1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) errors = context.end() 1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if errors: 1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) print u"%s: %s()" % (context.filename.decode('latin1'), 1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) context.name.decode('latin1')) 1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) print errors 1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) context = None 1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) except: 1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) report_unraisable() 1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) except: 1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # __Pyx_GetException may itself raise errors 1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pass 1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Py_XDECREF(ctx[0]) 1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ctx[0] = NULL 1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyErr_Restore(type, value, tb) 1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ctypedef struct RefNannyAPIStruct: 1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) void (*INCREF)(PyObject*, PyObject*, int) 1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) void (*DECREF)(PyObject*, PyObject*, int) 1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) void (*GOTREF)(PyObject*, PyObject*, int) 1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) void (*GIVEREF)(PyObject*, PyObject*, int) 1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PyObject* (*SetupContext)(char*, int, char*) except NULL 1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) void (*FinishContext)(PyObject**) 1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cdef RefNannyAPIStruct api 1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)api.INCREF = INCREF 1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)api.DECREF = DECREF 1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)api.GOTREF = GOTREF 1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)api.GIVEREF = GIVEREF 1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)api.SetupContext = SetupContext 1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)api.FinishContext = FinishContext 1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cdef extern from "Python.h": 1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) object PyLong_FromVoidPtr(void*) 1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)RefNannyAPI = PyLong_FromVoidPtr(<void*>&api) 195