]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] gh-107630: Revert "[3.12] gh-107080: Fix Py_TRACE_REFS Crashes Under Isolated...
authorEric Snow <ericsnowcurrently@gmail.com>
Sat, 5 Aug 2023 11:44:54 +0000 (05:44 -0600)
committerGitHub <noreply@github.com>
Sat, 5 Aug 2023 11:44:54 +0000 (13:44 +0200)
Revert "[3.12] gh-107080: Fix Py_TRACE_REFS Crashes Under Isolated Subinterpreters (gh-107567) (#107599)"

This reverts commit 58af2293c52a1ad3754d254690c0e54f787c545b.

Include/internal/pycore_object.h
Include/internal/pycore_object_state.h
Include/internal/pycore_runtime_init.h
Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst [deleted file]
Objects/object.c
Python/pylifecycle.c

index 5a9403456903ed2756a2b076fc6a5e1e103c5dbd..0981d1122fec5487bdee01b1d272b2452c7fa5dc 100644 (file)
@@ -271,8 +271,8 @@ extern void _PyDebug_PrintTotalRefs(void);
 
 #ifdef Py_TRACE_REFS
 extern void _Py_AddToAllObjects(PyObject *op, int force);
-extern void _Py_PrintReferences(PyInterpreterState *, FILE *);
-extern void _Py_PrintReferenceAddresses(PyInterpreterState *, FILE *);
+extern void _Py_PrintReferences(FILE *);
+extern void _Py_PrintReferenceAddresses(FILE *);
 #endif
 
 
index 65feb5af969f8bb5a345a740b44ca8b89ca50ecd..94005d7788143284cbb3dcae4f5fd5063c86c84c 100644 (file)
@@ -11,22 +11,17 @@ extern "C" {
 struct _py_object_runtime_state {
 #ifdef Py_REF_DEBUG
     Py_ssize_t interpreter_leaks;
-#endif
+#else
     int _not_used;
+#endif
 };
 
 struct _py_object_state {
 #ifdef Py_REF_DEBUG
     Py_ssize_t reftotal;
-#endif
-#ifdef Py_TRACE_REFS
-    /* 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.
-     */
-    PyObject refchain;
-#endif
+#else
     int _not_used;
+#endif
 };
 
 
index 7aace9f86119c41521582c4a6dccde60702fe355..4130188079cffae2f3fa63df32d6e5a9d15b2658 100644 (file)
@@ -101,7 +101,6 @@ extern PyTypeObject _PyExc_MemoryError;
                 { .threshold = 10, }, \
             }, \
         }, \
-        .object_state = _py_object_state_INIT(INTERP), \
         .dtoa = _dtoa_state_INIT(&(INTERP)), \
         .dict_state = _dict_state_INIT, \
         .func_state = { \
@@ -131,16 +130,6 @@ extern PyTypeObject _PyExc_MemoryError;
         .context_ver = 1, \
     }
 
-#ifdef Py_TRACE_REFS
-# define _py_object_state_INIT(INTERP) \
-    { \
-        .refchain = {&INTERP.object_state.refchain, &INTERP.object_state.refchain}, \
-    }
-#else
-# define _py_object_state_INIT(INTERP) \
-    { 0 }
-#endif
-
 
 // global objects
 
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst
deleted file mode 100644 (file)
index 5084c85..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Trace refs builds (``--with-trace-refs``) were crashing when used with
-isolated subinterpreters.  The problematic global state has been isolated to
-each interpreter.  Other fixing the crashes, this change does not affect
-users.
index b4c9416036c44e2555081fdb05b60957234b4f22..bd0fa40bd2a8511c11b4fcc69f3c061d96476061 100644 (file)
@@ -158,8 +158,11 @@ _PyDebug_PrintTotalRefs(void) {
    Do not call them otherwise, they do not initialize the object! */
 
 #ifdef Py_TRACE_REFS
-
-#define REFCHAIN(interp) &interp->object_state.refchain
+/* 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 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
@@ -184,11 +187,10 @@ _Py_AddToAllObjects(PyObject *op, int force)
     }
 #endif
     if (force || op->_ob_prev == NULL) {
-        PyObject *refchain = REFCHAIN(_PyInterpreterState_GET());
-        op->_ob_next = refchain->_ob_next;
-        op->_ob_prev = refchain;
-        refchain->_ob_next->_ob_prev = op;
-        refchain->_ob_next = op;
+        op->_ob_next = refchain._ob_next;
+        op->_ob_prev = &refchain;
+        refchain._ob_next->_ob_prev = op;
+        refchain._ob_next = op;
     }
 }
 #endif  /* Py_TRACE_REFS */
@@ -2204,8 +2206,7 @@ _Py_ForgetReference(PyObject *op)
         _PyObject_ASSERT_FAILED_MSG(op, "negative refcnt");
     }
 
-    PyObject *refchain = REFCHAIN(_PyInterpreterState_GET());
-    if (op == refchain ||
+    if (op == &refchain ||
         op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op)
     {
         _PyObject_ASSERT_FAILED_MSG(op, "invalid object chain");
@@ -2213,12 +2214,12 @@ _Py_ForgetReference(PyObject *op)
 
 #ifdef SLOW_UNREF_CHECK
     PyObject *p;
-    for (p = refchain->_ob_next; p != refchain; p = p->_ob_next) {
+    for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) {
         if (p == op) {
             break;
         }
     }
-    if (p == refchain) {
+    if (p == &refchain) {
         /* Not found */
         _PyObject_ASSERT_FAILED_MSG(op,
                                     "object not found in the objects list");
@@ -2234,15 +2235,11 @@ _Py_ForgetReference(PyObject *op)
  * interpreter must be in a healthy state.
  */
 void
-_Py_PrintReferences(PyInterpreterState *interp, FILE *fp)
+_Py_PrintReferences(FILE *fp)
 {
     PyObject *op;
-    if (interp == NULL) {
-        interp = _PyInterpreterState_Main();
-    }
     fprintf(fp, "Remaining objects:\n");
-    PyObject *refchain = REFCHAIN(interp);
-    for (op = refchain->_ob_next; op != refchain; op = op->_ob_next) {
+    for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) {
         fprintf(fp, "%p [%zd] ", (void *)op, Py_REFCNT(op));
         if (PyObject_Print(op, fp, 0) != 0) {
             PyErr_Clear();
@@ -2254,42 +2251,34 @@ _Py_PrintReferences(PyInterpreterState *interp, FILE *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.
  */
-// XXX This function is not safe to use if the interpreter has been
-// freed or is in an unhealthy state (e.g. late in finalization).
-// The call in Py_FinalizeEx() is okay since the main interpreter
-// is statically allocated.
 void
-_Py_PrintReferenceAddresses(PyInterpreterState *interp, FILE *fp)
+_Py_PrintReferenceAddresses(FILE *fp)
 {
     PyObject *op;
-    PyObject *refchain = REFCHAIN(interp);
     fprintf(fp, "Remaining object addresses:\n");
-    for (op = refchain->_ob_next; op != refchain; op = op->_ob_next)
+    for (op = refchain._ob_next; op != &refchain; op = op->_ob_next)
         fprintf(fp, "%p [%zd] %s\n", (void *)op,
             Py_REFCNT(op), Py_TYPE(op)->tp_name);
 }
 
-/* The implementation of sys.getobjects(). */
 PyObject *
 _Py_GetObjects(PyObject *self, PyObject *args)
 {
     int i, n;
     PyObject *t = NULL;
     PyObject *res, *op;
-    PyInterpreterState *interp = _PyInterpreterState_GET();
 
     if (!PyArg_ParseTuple(args, "i|O", &n, &t))
         return NULL;
-    PyObject *refchain = REFCHAIN(interp);
-    op = refchain->_ob_next;
+    op = refchain._ob_next;
     res = PyList_New(0);
     if (res == NULL)
         return NULL;
-    for (i = 0; (n == 0 || i < n) && op != refchain; i++) {
+    for (i = 0; (n == 0 || i < n) && op != &refchain; i++) {
         while (op == self || op == args || op == res || op == t ||
                (t != NULL && !Py_IS_TYPE(op, (PyTypeObject *) t))) {
             op = op->_ob_next;
-            if (op == refchain)
+            if (op == &refchain)
                 return res;
         }
         if (PyList_Append(res, op) < 0) {
@@ -2301,8 +2290,6 @@ _Py_GetObjects(PyObject *self, PyObject *args)
     return res;
 }
 
-#undef REFCHAIN
-
 #endif
 
 
index 5b8c8af179c0051b5efab6ea7e805b6441c945a1..a67fa26b3722785055e443ef736a2a08ce00773c 100644 (file)
@@ -1920,11 +1920,11 @@ Py_FinalizeEx(void)
     }
 
     if (dump_refs) {
-        _Py_PrintReferences(tstate->interp, stderr);
+        _Py_PrintReferences(stderr);
     }
 
     if (dump_refs_fp != NULL) {
-        _Py_PrintReferences(tstate->interp, dump_refs_fp);
+        _Py_PrintReferences(dump_refs_fp);
     }
 #endif /* Py_TRACE_REFS */
 
@@ -1960,11 +1960,11 @@ Py_FinalizeEx(void)
      */
 
     if (dump_refs) {
-        _Py_PrintReferenceAddresses(tstate->interp, stderr);
+        _Py_PrintReferenceAddresses(stderr);
     }
 
     if (dump_refs_fp != NULL) {
-        _Py_PrintReferenceAddresses(tstate->interp, dump_refs_fp);
+        _Py_PrintReferenceAddresses(dump_refs_fp);
         fclose(dump_refs_fp);
     }
 #endif /* Py_TRACE_REFS */