https://github.com/python/cpython/commit/71cb1655b944337f83f68b188c10fd13a3919163
commit: 71cb1655b944337f83f68b188c10fd13a3919163
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: hugovk <[email protected]>
date: 2026-08-14T17:54:37+09:00
summary:

[3.15] gh-154566: Fix array.byteswap() corrupting 'Zd' arrays with more than 
one element (GH-154567) (#155756)

gh-154566: Fix array.byteswap() corrupting 'Zd' arrays with more than one 
element (GH-154567)

Fix array.array.byteswap() corrupting data for 'Zd' (complex
double) arrays with more than one element: the 16-byte item loop advanced
the buffer pointer by only 8 bytes per iteration, causing items after the
first to be scrambled.
(cherry picked from commit 46c355fabff5833b77f72e26eb83f06b0e4d85ff)

Co-authored-by: PhysicistJohn <[email protected]>
Co-authored-by: Victor Stinner <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-07-23-20-00-00.gh-issue-154566.byteswap-zd.rst
M Lib/test/test_array.py
M Modules/arraymodule.c

diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
index 430f55f2129884..85cecc083f752e 100755
--- a/Lib/test/test_array.py
+++ b/Lib/test/test_array.py
@@ -1638,6 +1638,22 @@ def test_byteswap(self):
             b.byteswap()
             self.assertEqual(a, b)
 
+    def test_byteswap_single_call_result(self):
+        # A single byteswap() must swap each item's two halves (real,
+        # imag) independently. test_byteswap above only checks that
+        # byteswap() twice round-trips to the original, which passes
+        # even if a single call scrambles multi-item arrays.
+        a = array.array(self.typecode, self.example)
+        original = a.tobytes()
+        a.byteswap()
+        itemsize = a.itemsize
+        half = itemsize // 2
+        expected = bytearray()
+        for i in range(0, len(original), itemsize):
+            item = original[i:i + itemsize]
+            expected += item[half - 1::-1] + item[itemsize - 1:half - 1:-1]
+        self.assertEqual(a.tobytes(), bytes(expected))
+
 
 class HalfFloatTest(FPTest, unittest.TestCase):
     example = [-42.0, 0, 42, 1e2, -1e4]
diff --git 
a/Misc/NEWS.d/next/Library/2026-07-23-20-00-00.gh-issue-154566.byteswap-zd.rst 
b/Misc/NEWS.d/next/Library/2026-07-23-20-00-00.gh-issue-154566.byteswap-zd.rst
new file mode 100644
index 00000000000000..e86b9a979946cd
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Library/2026-07-23-20-00-00.gh-issue-154566.byteswap-zd.rst
@@ -0,0 +1,4 @@
+Fix :meth:`array.array.byteswap` corrupting data for ``'Zd'`` (complex
+double) arrays with more than one element: the 16-byte item loop advanced
+the buffer pointer by only 8 bytes per iteration, causing items after the
+first to be scrambled.
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 45cdf351cbb6ce..505c44d23735b4 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -1661,7 +1661,7 @@ array_array_byteswap_impl(arrayobject *self)
         break;
     case 16:
         assert(strcmp(self->ob_descr->typecode, "Zd") == 0);
-        for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 8) {
+        for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 16) {
             char t0 = p[0];
             char t1 = p[1];
             char t2 = p[2];

_______________________________________________
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