]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-145713: make bytearray.resize thread-safe on free-threading (#145714) ...
authorThomas Kowalski <thom.kowa@gmail.com>
Fri, 13 Mar 2026 15:04:24 +0000 (16:04 +0100)
committerGitHub <noreply@github.com>
Fri, 13 Mar 2026 15:04:24 +0000 (20:34 +0530)
gh-145713: make bytearray.resize thread-safe on free-threading (#145714)

(cherry picked from commit c3955e049fd5dbd3d92bc95fed4442964156293d)

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 05c328b78a3ede1d0a99d51eebc24a8523f09bed..2f38e75199c4d1a014eba2b9f6c0eceba1f4a2ea 100644 (file)
@@ -2770,6 +2770,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 8c7c8685d63b502b2f58edf916f7a810f0bfd3cd..a04b9176c94aedce716efc6373d492e23ea2fec6 100644 (file)
@@ -1552,6 +1552,7 @@ bytearray_removesuffix_impl(PyByteArrayObject *self, Py_buffer *suffix)
 
 
 /*[clinic input]
+@critical_section
 bytearray.resize
     size: Py_ssize_t
         New size to resize to.
@@ -1561,10 +1562,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 6f13865177dde52a6f09b9c08ce038904521c205..58920a4d353c6b0f684b9e228d0d842c72e37b49 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;
@@ -1796,4 +1798,4 @@ bytearray_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
     return bytearray_sizeof_impl((PyByteArrayObject *)self);
 }
-/*[clinic end generated code: output=fdfe41139c91e409 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=bca62cf335d48127 input=a9049054013a1b77]*/