diff options
-rw-r--r-- | Include/object.h | 2 | ||||
-rw-r--r-- | Objects/object.c | 50 | ||||
-rw-r--r-- | Objects/typeobject.c | 5 | ||||
-rw-r--r-- | Python/bltinmodule.c | 18 |
4 files changed, 54 insertions, 21 deletions
diff --git a/Include/object.h b/Include/object.h index 89445c0..3ac7538 100644 --- a/Include/object.h +++ b/Include/object.h @@ -582,7 +582,7 @@ PyAPI_FUNC(void) _Py_NewReference(PyObject *); PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); PyAPI_FUNC(void) _Py_Dealloc(PyObject *); PyAPI_FUNC(void) _Py_PrintReferences(FILE *); -PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *); +PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force); #else /* Without Py_TRACE_REFS, there's little enough to do that we expand code diff --git a/Objects/object.c b/Objects/object.c index 059b36a..0a8d2f1 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -18,19 +18,42 @@ int Py_DivisionWarningFlag; Do not call them otherwise, they do not initialize the object! */ #ifdef Py_TRACE_REFS -/* Head of doubly-linked list of all objects. */ +/* Head of circular doubly-linked list of all objects. These are linked + * together via the _ob_prev and _ob_next members of a PyObject, which + * exist only in a Py_TRACE_REFS build. + */ static PyObject refchain = {&refchain, &refchain}; -/* Insert op at the fron of the doubly-linked list of all objects. */ +/* Insert op at the front of the list of all objects. If force is true, + * op is added even if _ob_prev and _ob_next are non-NULL already. If + * force is false amd _ob_prev or _ob_next are non-NULL, do nothing. + * force should be true if and only if op points to freshly allocated, + * uninitialized memory, or you've unlinked op from the list and are + * relinking it into the font. + * Note that objects are normally added to the list via _Py_NewReference, + * which is called by PyObject_Init. Not all objects are initialized that + * way, though; exceptions include statically allocated type objects, and + * statically allocated singletons (like Py_True and Py_None). + */ void -_Py_AddToAllObjects(PyObject *op) +_Py_AddToAllObjects(PyObject *op, int force) { - op->_ob_next = refchain._ob_next; - op->_ob_prev = &refchain; - refchain._ob_next->_ob_prev = op; - refchain._ob_next = op; -} +#ifdef Py_DEBUG + if (!force) { + /* If it's initialized memory, op must be in or out of + * the list unambiguously. + */ + assert((op->_ob_prev == NULL) == (op->_ob_next == NULL)); + } #endif + if (force || op->_ob_prev == NULL) { + op->_ob_next = refchain._ob_next; + op->_ob_prev = &refchain; + refchain._ob_next->_ob_prev = op; + refchain._ob_next = op; + } +} +#endif /* Py_TRACE_REFS */ #ifdef COUNT_ALLOCS static PyTypeObject *type_list; @@ -100,11 +123,10 @@ inc_count(PyTypeObject *tp) Py_INCREF(tp); type_list = tp; #ifdef Py_TRACE_REFS - /* Also insert in the doubly-linked list of all objects. */ - if (tp->_ob_prev == NULL) { - assert(tp->_ob_next == NULL); - _Py_AddToAllObjects((PyObject *)tp); - } + /* Also insert in the doubly-linked list of all objects, + * if not already there. + */ + _Py_AddToAllObjects((PyObject *)tp, 0); #endif } tp->tp_allocs++; @@ -1963,7 +1985,7 @@ _Py_NewReference(PyObject *op) { _Py_INC_REFTOTAL; op->ob_refcnt = 1; - _Py_AddToAllObjects(op); + _Py_AddToAllObjects(op, 1); _Py_INC_TPALLOCS(op); } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 8dfb939..4acee5a 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3058,10 +3058,7 @@ PyType_Ready(PyTypeObject *type) * to get type objects into the doubly-linked list of all objects. * Still, not all type objects go thru PyType_Ready. */ - if (type->_ob_next == NULL) { - assert(type->_ob_prev == NULL); - _Py_AddToAllObjects((PyObject *)type); - } + _Py_AddToAllObjects((PyObject *)type, 0); #endif /* Initialize tp_base (defaults to BaseObject unless that's us) */ diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index e246591..29e11e5 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -1818,9 +1818,22 @@ _PyBuiltin_Init(void) return NULL; dict = PyModule_GetDict(mod); +#ifdef Py_TRACE_REFS + /* __builtin__ exposes a number of statically allocated objects + * that, before this code was added in 2.3, never showed up in + * the list of "all objects" maintained by Py_TRACE_REFS. As a + * result, programs leaking references to None and False (etc) + * couldn't be diagnosed by examining sys.getobjects(0). + */ +#define ADD_TO_ALL(OBJECT) _Py_AddToAllObjects((PyObject *)(OBJECT), 0) +#else +#define ADD_TO_ALL(OBJECT) (void)0 +#endif + #define SETBUILTIN(NAME, OBJECT) \ - if (PyDict_SetItemString(dict, NAME, (PyObject *)OBJECT) < 0) \ - return NULL + if (PyDict_SetItemString(dict, NAME, (PyObject *)OBJECT) < 0) \ + return NULL; \ + ADD_TO_ALL(OBJECT) SETBUILTIN("None", Py_None); SETBUILTIN("Ellipsis", Py_Ellipsis); @@ -1864,6 +1877,7 @@ _PyBuiltin_Init(void) Py_XDECREF(debug); return mod; +#undef ADD_TO_ALL #undef SETBUILTIN } |