Skip to content

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

Open
PhysicistJohn wants to merge 1 commit into
python:mainfrom
PhysicistJohn:gh-154566-byteswap-zd-fix
Open

gh-154566: Fix array.byteswap() corrupting 'Zd' arrays with more than one element#154567
PhysicistJohn wants to merge 1 commit into
python:mainfrom
PhysicistJohn:gh-154566-byteswap-zd-fix

Conversation

@PhysicistJohn

Copy link
Copy Markdown

array.array('Zd', ...).byteswap() scrambled every item after the first
because the 16-byte-item loop advanced the pointer by 8 bytes instead of
16. Fixes gh-154566.

Adds a regression test that checks the actual byte-level result of a
single byteswap() call (the existing test only checked a double-call
round-trip, which passes even under the bug since the corruption happens
to be self-canceling on the second call).

…e than one element

The 16-byte-item loop in array_array_byteswap_impl() advanced the
buffer pointer by only 8 bytes per iteration, even though each
iteration swaps a full 16-byte item (two independent 8-byte halves
for the real/imaginary double components). This caused every item
after the first to overlap the previous iteration's byte window and
come out scrambled.

A single byteswap() call gave wrong bytes for the second item onward.
Calling byteswap() twice happened to round-trip back to the original
value (the corruption is self-canceling under double application),
which is why the existing test suite -- which only checked a
double-call round-trip -- didn't catch it. Added a regression test
that checks the actual byte-level result of a single call.
@python-cla-bot

This comment was marked as resolved.

Comment on lines +1 to +6
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. A single :meth:`!byteswap` call produced incorrect
results while a double call happened to round-trip back to the original
value, which is why the existing test suite did not catch it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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. A single :meth:`!byteswap` call produced incorrect
results while a double call happened to round-trip back to the original
value, which is why the existing test suite did not catch it.
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.

Comment thread Lib/test/test_array.py
Comment on lines +1616 to +1618
# halves (real, imag) independently. The pre-existing test only
# checked that byteswap() twice round-trips to the original,
# which passes even if a single call scrambles multi-item arrays.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# halves (real, imag) independently. The pre-existing test only
# checked that byteswap() twice round-trips to the original,
# which passes even if a single call scrambles multi-item arrays.
# halves (real, imag) independently.

Comment thread Lib/test/test_array.py
Comment on lines +1619 to +1626
a = array.array(self.typecode, [1+2j, 3+4j, 5+6j])
original = a.tobytes()
a.byteswap()
expected = bytearray()
for i in range(0, len(original), 16):
item = original[i:i + 16]
expected += item[7::-1] + item[15:7:-1]
self.assertEqual(a.tobytes(), bytes(expected))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to do this in a more generic way:

  1. Move to CFPTest
  2. use self.examples
  3. support all possible itemsize's

@skirpichev skirpichev added the needs backport to 3.15 pre-release feature fixes, bugs and security fixes label Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting review needs backport to 3.15 pre-release feature fixes, bugs and security fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

array.byteswap() corrupts data for 'Zd' (complex double) arrays with more than one element

2 participants