You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
array.byteswap() corrupts data for 'Zd' (complex double) arrays with more than one element #154566
array.array('Zd', ...).byteswap() produces incorrect data for arrays
with more than one element. The 16-byte-item loop in array_array_byteswap_impl
(Modules/arraymodule.c) advances the buffer pointer by only 8 bytes per
iteration even though each iteration manually swaps a full 16-byte item
(two independent 8-byte halves, for the real/imaginary double components).
This causes every item after the first to overlap the previous iteration's
byte window and come out scrambled.
Reproducer:
import array
a = array.array('Zd', [1+2j, 3+4j])
raw_before = a.tobytes()
a.byteswap()
raw_after = a.tobytes()
expected = bytearray()
for i in range(0, len(raw_before), 8):
expected += raw_before[i:i+8][::-1]
print(bytes(expected) == raw_after) # False -- should be True
A single byteswap() call gives the wrong bytes for the second item
onward. Calling byteswap() twice happens to round-trip back to the
original value (the corruption is self-canceling under double
application), which is why the existing test suite (test_byteswap in Lib/test/test_array.py, which only checks a double-call round-trip)
doesn't catch it.
The sibling cases in the same switch statement (case 4:, case 8:)
correctly advance the pointer by the item's own size (4, 8 bytes); the case 16: block is the only one where the increment doesn't match the
16 bytes actually touched in the loop body.
Activity
Merge branch 'main' into pythongh-154566-byteswap-zd-fix
gh-154566: Fix array.byteswap() corrupting 'Zd' arrays with more than…
[3.15] gh-154566: Fix array.byteswap() corrupting 'Zd' arrays with mo…
pythongh-154566: Fix array.byteswap() corrupting 'Zd' arrays with mor…