summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/object.h1
-rw-r--r--Objects/object.c17
-rw-r--r--Python/pythonrun.c11
3 files changed, 26 insertions, 3 deletions
diff --git a/Include/object.h b/Include/object.h
index 3ac7538..3c7264f 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -582,6 +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_PrintReferenceAddresses(FILE *);
PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force);
#else
diff --git a/Objects/object.c b/Objects/object.c
index c876219..49b9839 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -2022,19 +2022,34 @@ _Py_Dealloc(PyObject *op)
(*dealloc)(op);
}
+/* Print all live objects. Because PyObject_Print is called, the
+ * interpreter must be in a healthy state.
+ */
void
_Py_PrintReferences(FILE *fp)
{
PyObject *op;
fprintf(fp, "Remaining objects:\n");
for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) {
- fprintf(fp, "[%d] ", op->ob_refcnt);
+ fprintf(fp, "%p [%d] ", op, op->ob_refcnt);
if (PyObject_Print(op, fp, 0) != 0)
PyErr_Clear();
putc('\n', fp);
}
}
+/* Print the addresses of all live objects. Unlike _Py_PrintReferences, this
+ * doesn't make any calls to the Python C API, so is always safe to call.
+ */
+void
+_Py_PrintReferenceAddresses(FILE *fp)
+{
+ PyObject *op;
+ fprintf(fp, "Remaining object addresses:\n");
+ for (op = refchain._ob_next; op != &refchain; op = op->_ob_next)
+ fprintf(fp, "%p [%d]\n", op, op->ob_refcnt);
+}
+
PyObject *
_Py_GetObjects(PyObject *self, PyObject *args)
{
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 4cfb664..0a9a637 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -284,9 +284,8 @@ Py_Finalize(void)
* Alas, a lot of stuff may still be alive now that will be cleaned
* up later.
*/
- if (Py_GETENV("PYTHONDUMPREFS")) {
+ if (Py_GETENV("PYTHONDUMPREFS"))
_Py_PrintReferences(stderr);
- }
#endif /* Py_TRACE_REFS */
/* Now we decref the exception classes. After this point nothing
@@ -325,6 +324,14 @@ Py_Finalize(void)
PyGrammar_RemoveAccelerators(&_PyParser_Grammar);
+#ifdef Py_TRACE_REFS
+ /* Display addresses (& refcnts) of all objects still alive.
+ * An address can be used to find the repr of the object, printed
+ * above by _Py_PrintReferences.
+ */
+ if (Py_GETENV("PYTHONDUMPREFS"))
+ _Py_PrintReferenceAddresses(stderr);
+#endif /* Py_TRACE_REFS */
#ifdef PYMALLOC_DEBUG
if (Py_GETENV("PYTHONMALLOCSTATS"))
_PyObject_DebugMallocStats();