Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Lib/test/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -1611,6 +1611,20 @@ class ComplexDoubleTest(CFPTest, unittest.TestCase):
typecode = 'Zd'
minitemsize = 16

def test_byteswap_single_call_result(self):
# A single byteswap() must swap each 16-byte item's two 8-byte
# 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.
Comment on lines +1616 to +1618

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.

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))
Comment on lines +1619 to +1626

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



class LargeArrayTest(unittest.TestCase):
typecode = 'b'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,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.
Comment on lines +1 to +6

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.

2 changes: 1 addition & 1 deletion Modules/arraymodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1617,7 +1617,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];
Expand Down
Loading