]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.15] gh-153083: Defer GC tracking of an array to the end of construction. (gh-15328...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 8 Jul 2026 12:59:13 +0000 (14:59 +0200)
committerGitHub <noreply@github.com>
Wed, 8 Jul 2026 12:59:13 +0000 (12:59 +0000)
gh-153083: Defer GC tracking of an array to the end of construction. (gh-153284)
(cherry picked from commit 8615062fd580934fc431746f64b1ac7ee6ef8e88)

Co-authored-by: Donghee Na <donghee.na@python.org>
Include/internal/pycore_object.h
Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst [new file with mode: 0644]
Modules/arraymodule.c

index c2c508c1a71c5c019e3d333376f399413b4ff607..a15685450f54db9f1bae65a9f74277a563c68e87 100644 (file)
@@ -873,7 +873,8 @@ static inline int _PyType_SUPPORTS_WEAKREFS(PyTypeObject *type) {
     return (type->tp_weaklistoffset != 0);
 }
 
-extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
+// Export for 'array' shared extension.
+PyAPI_FUNC(PyObject*) _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
 PyAPI_FUNC(PyObject *) _PyType_NewManagedObject(PyTypeObject *type);
 
 extern PyTypeObject* _PyType_CalculateMetaclass(PyTypeObject *, PyObject *);
diff --git a/Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst b/Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst
new file mode 100644 (file)
index 0000000..b6d9685
--- /dev/null
@@ -0,0 +1,2 @@
+Defer GC tracking of an :class:`array.array` to the end of its construction.
+Patch by Donghee Na.
index a775896db874a6edaf1270ffe61e487f660c8d54..46aec5f201c849b4bd2019ea6e7bbc534bbf63c4 100644 (file)
@@ -14,6 +14,7 @@
 #include "pycore_floatobject.h"   // _PY_FLOAT_BIG_ENDIAN
 #include "pycore_modsupport.h"    // _PyArg_NoKeywords()
 #include "pycore_moduleobject.h"  // _PyModule_GetState()
+#include "pycore_object.h"        // _PyObject_GC_TRACK()
 #include "pycore_tuple.h"         // _PyTuple_FromPairSteal
 #include "pycore_weakref.h"       // FT_CLEAR_WEAKREFS()
 
@@ -796,7 +797,8 @@ class array.array "arrayobject *" "ArrayType"
 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=a5c29edf59f176a3]*/
 
 static PyObject *
-newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
+newarrayobject_untracked(PyTypeObject *type, Py_ssize_t size,
+                         const struct arraydescr *descr)
 {
     arrayobject *op;
     size_t nbytes;
@@ -811,7 +813,7 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
         return PyErr_NoMemory();
     }
     nbytes = size * descr->itemsize;
-    op = (arrayobject *) type->tp_alloc(type, 0);
+    op = (arrayobject *) _PyType_AllocNoTrack(type, 0);
     if (op == NULL) {
         return NULL;
     }
@@ -833,6 +835,16 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
     return (PyObject *) op;
 }
 
+static PyObject *
+newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
+{
+    PyObject *op = newarrayobject_untracked(type, size, descr);
+    if (op != NULL) {
+        _PyObject_GC_TRACK(op);
+    }
+    return op;
+}
+
 static PyObject *
 getarrayitem(PyObject *op, Py_ssize_t i)
 {
@@ -1034,13 +1046,14 @@ array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
         ihigh = ilow;
     else if (ihigh > Py_SIZE(a))
         ihigh = Py_SIZE(a);
-    np = (arrayobject *) newarrayobject(state->ArrayType, ihigh - ilow, a->ob_descr);
+    np = (arrayobject *) newarrayobject_untracked(state->ArrayType, ihigh - ilow, a->ob_descr);
     if (np == NULL)
         return NULL;
     if (ihigh > ilow) {
         memcpy(np->ob_item, a->ob_item + ilow * a->ob_descr->itemsize,
                (ihigh-ilow) * a->ob_descr->itemsize);
     }
+    _PyObject_GC_TRACK(np);
     return (PyObject *)np;
 }
 
@@ -1111,7 +1124,7 @@ array_concat(PyObject *op, PyObject *bb)
         return PyErr_NoMemory();
     }
     size = Py_SIZE(a) + Py_SIZE(b);
-    np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
+    np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr);
     if (np == NULL) {
         return NULL;
     }
@@ -1122,6 +1135,7 @@ array_concat(PyObject *op, PyObject *bb)
         memcpy(np->ob_item + Py_SIZE(a)*a->ob_descr->itemsize,
                b->ob_item, Py_SIZE(b)*b->ob_descr->itemsize);
     }
+    _PyObject_GC_TRACK(np);
     return (PyObject *)np;
 #undef b
 }
@@ -1139,16 +1153,19 @@ array_repeat(PyObject *op, Py_ssize_t n)
         return PyErr_NoMemory();
     }
     Py_ssize_t size = array_length * n;
-    arrayobject* np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
+    arrayobject* np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr);
     if (np == NULL)
         return NULL;
-    if (size == 0)
+    if (size == 0) {
+        _PyObject_GC_TRACK(np);
         return (PyObject *)np;
+    }
 
     const Py_ssize_t oldbytes = array_length * a->ob_descr->itemsize;
     const Py_ssize_t newbytes = oldbytes * n;
     _PyBytes_Repeat(np->ob_item, newbytes, a->ob_item, oldbytes);
 
+    _PyObject_GC_TRACK(np);
     return (PyObject *)np;
 }
 
@@ -2741,17 +2758,17 @@ array_subscr(PyObject *op, PyObject *item)
             return newarrayobject(state->ArrayType, 0, self->ob_descr);
         }
         else if (step == 1) {
-            PyObject *result = newarrayobject(state->ArrayType,
-                                    slicelength, self->ob_descr);
+            PyObject *result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr);
             if (result == NULL)
                 return NULL;
             memcpy(((arrayobject *)result)->ob_item,
                    self->ob_item + start * itemsize,
                    slicelength * itemsize);
+            _PyObject_GC_TRACK(result);
             return result;
         }
         else {
-            result = newarrayobject(state->ArrayType, slicelength, self->ob_descr);
+            result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr);
             if (!result) return NULL;
 
             ar = (arrayobject*)result;
@@ -2763,6 +2780,7 @@ array_subscr(PyObject *op, PyObject *item)
                        itemsize);
             }
 
+            _PyObject_GC_TRACK(result);
             return result;
         }
     }
@@ -3060,7 +3078,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
             else
                 len = 0;
 
-            a = newarrayobject(type, len, descr);
+            a = newarrayobject_untracked(type, len, descr);
             if (a == NULL) {
                 Py_XDECREF(it);
                 return NULL;
@@ -3148,6 +3166,8 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
                 }
                 Py_DECREF(it);
             }
+            // Track only once fully built.
+            _PyObject_GC_TRACK(a);
             return a;
         }
     }
@@ -3243,7 +3263,7 @@ static PyType_Slot array_slots[] = {
     {Py_tp_methods, array_methods},
     {Py_tp_members, array_members},
     {Py_tp_getset, array_getsets},
-    {Py_tp_alloc, PyType_GenericAlloc},
+    {Py_tp_alloc, _PyType_AllocNoTrack},
     {Py_tp_new, array_new},
     {Py_tp_traverse, _PyObject_VisitType},