summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/object.h2
-rw-r--r--Objects/object.c50
-rw-r--r--Objects/typeobject.c5
-rw-r--r--Python/bltinmodule.c18
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
}