https://github.com/python/cpython/commit/5d9e46e4c9c6b7b6dabdafbe9b8c51bf74695572
commit: 5d9e46e4c9c6b7b6dabdafbe9b8c51bf74695572
branch: 3.14
author: Donghee Na <[email protected]>
committer: corona10 <[email protected]>
date: 2026-07-08T13:59:03Z
summary:

[3.14] gh-153083: Defer GC tracking of an array to the end of construction. 
(gh-153284) (gh-153337)

(cherry picked from commit 8615062fd580934fc431746f64b1ac7ee6ef8e88)

files:
A Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst
M Include/internal/pycore_object.h
M Modules/arraymodule.c

diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index ca44b2c10998a92..a25998af96bb933 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -875,7 +875,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
index 000000000000000..b6d96851e17342f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst
@@ -0,0 +1,2 @@
+Defer GC tracking of an :class:`array.array` to the end of its construction.
+Patch by Donghee Na.
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 532433d2c486555..758a06f0e2b51ca 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -13,6 +13,7 @@
 #include "pycore_ceval.h"         // _PyEval_GetBuiltin()
 #include "pycore_modsupport.h"    // _PyArg_NoKeywords()
 #include "pycore_moduleobject.h"  // _PyModule_GetState()
+#include "pycore_object.h"        // _PyObject_GC_TRACK()
 #include "pycore_weakref.h"       // FT_CLEAR_WEAKREFS()
 
 #include <stddef.h>               // offsetof()
@@ -696,7 +697,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;
@@ -711,7 +713,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;
     }
@@ -733,6 +735,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)
 {
@@ -942,13 +954,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;
 }
 
@@ -1019,7 +1032,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;
     }
@@ -1030,6 +1043,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
 }
@@ -1047,16 +1061,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;
 }
 
@@ -2534,17 +2551,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;
@@ -2556,6 +2573,7 @@ array_subscr(PyObject *op, PyObject *item)
                        itemsize);
             }
 
+            _PyObject_GC_TRACK(result);
             return result;
         }
     }
@@ -2855,7 +2873,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;
@@ -2943,6 +2961,8 @@ array_new(PyTypeObject *type, PyObject *args, PyObject 
*kwds)
                 }
                 Py_DECREF(it);
             }
+            // Track only once fully built.
+            _PyObject_GC_TRACK(a);
             return a;
         }
     }
@@ -3035,7 +3055,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, array_tp_traverse},
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to