]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-145713: make bytearray.resize thread-safe on free-threading (#145714)
authorThomas Kowalski <thom.kowa@gmail.com>
Wed, 11 Mar 2026 07:27:26 +0000 (08:27 +0100)
committerGitHub <noreply@github.com>
Wed, 11 Mar 2026 07:27:26 +0000 (12:57 +0530)
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Lib/test/test_bytes.py
Misc/NEWS.d/next/Core_and_Builtins/2026-03-09-00-00-00.gh-issue-145713.KR6azvzI.rst [new file with mode: 0644]
Objects/bytearrayobject.c
Objects/clinic/bytearrayobject.c.h

index 1c64bf888f9d272e88876f94b029e1e0404aedd3..876ecd4467b0a2a4fb6ed34b995cebd92779cb0f 100644 (file)
@@ -2908,6 +2908,22 @@ class FreeThreadingTest(unittest.TestCase):
             check([iter_next] + [iter_reduce] * 10, iter(ba))  # for tsan
             check([iter_next] + [iter_setstate] * 10, iter(ba))  # for tsan
 
+    @unittest.skipUnless(support.Py_GIL_DISABLED, 'this test can only possibly fail with GIL disabled')
+    @threading_helper.reap_threads
+    @threading_helper.requires_working_threading()
+    def test_free_threading_bytearray_resize(self):
+        def resize_stress(ba):
+            for _ in range(1000):
+                try:
+                    ba.resize(1000)
+                    ba.resize(1)
+                except (BufferError, ValueError):
+                    pass
+
+        ba = bytearray(100)
+        threads = [threading.Thread(target=resize_stress, args=(ba,)) for _ in range(4)]
+        with threading_helper.start_threads(threads):
+            pass
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-09-00-00-00.gh-issue-145713.KR6azvzI.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-09-00-00-00.gh-issue-145713.KR6azvzI.rst
new file mode 100644 (file)
index 0000000..2cf83ef
--- /dev/null
@@ -0,0 +1,3 @@
+Make :meth:`bytearray.resize` thread-safe in the free-threaded build by
+using a critical section and calling the lock-held variant of the resize
+function.
index 7f09769e12f05fc3b07a1b17ab85cc33d34947bc..e2fea94e099626a0af2e01f088d16d1bd7b4381f 100644 (file)
@@ -1506,6 +1506,7 @@ bytearray_removesuffix_impl(PyByteArrayObject *self, Py_buffer *suffix)
 
 
 /*[clinic input]
+@critical_section
 bytearray.resize
     size: Py_ssize_t
         New size to resize to.
@@ -1515,10 +1516,10 @@ Resize the internal buffer of bytearray to len.
 
 static PyObject *
 bytearray_resize_impl(PyByteArrayObject *self, Py_ssize_t size)
-/*[clinic end generated code: output=f73524922990b2d9 input=6c9a260ca7f72071]*/
+/*[clinic end generated code: output=f73524922990b2d9 input=116046316a2b5cfc]*/
 {
     Py_ssize_t start_size = PyByteArray_GET_SIZE(self);
-    int result = PyByteArray_Resize((PyObject *)self, size);
+    int result = bytearray_resize_lock_held((PyObject *)self, size);
     if (result < 0) {
         return NULL;
     }
index be704ccf68f6694200176d421993fd37af12856a..cf60d0ceadc7d12f787602d15a5e4bb9c426aeae 100644 (file)
@@ -625,7 +625,9 @@ bytearray_resize(PyObject *self, PyObject *arg)
         }
         size = ival;
     }
+    Py_BEGIN_CRITICAL_SECTION(self);
     return_value = bytearray_resize_impl((PyByteArrayObject *)self, size);
+    Py_END_CRITICAL_SECTION();
 
 exit:
     return return_value;
@@ -1833,4 +1835,4 @@ bytearray_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
     return bytearray_sizeof_impl((PyByteArrayObject *)self);
 }
-/*[clinic end generated code: output=5eddefde2a001ceb input=a9049054013a1b77]*/
+/*[clinic end generated code: output=2d76ef023928424f input=a9049054013a1b77]*/