From 54f21a61464757ff58b659be453806c969157114 Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Thu, 19 Feb 2026 22:57:48 +0000 Subject: [PATCH] gh-144725: Relax over-strict alignment test on arrays The alignment test introduced in gh-140557 guards against empty-allocation optimisations handing out oddly-aligned pointers, as had been observed for the empty `bytearray` used by pickle protocol 5. It compared every array buffer against the maximum alignment of any array element type, which over-specifies the requirement: an allocation only needs to be aligned for the type stored in it. This failed on 32-bit platforms using mimalloc for single-byte element types such as 'B', where the tiny allocation region only guarantees 4-byte alignment rather than the 8-byte alignment of `double`. Check instead that each array's buffer, empty or allocated, is aligned to at least the alignment of its element type. The alignment is derived from `struct` rather than from `itemsize`, since the two differ for types such as `Zf` and `Zd`. Co-authored-by: Jake Lishman --- Lib/test/test_buffer.py | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 579e680448e94e3..c6bcd88b9dc9891 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -4519,24 +4519,16 @@ def test_bytearray_alignment(self): @support.cpython_only @unittest.skipIf(_testcapi is None, "requires _testcapi") def test_array_alignment(self): - # gh-140557: pointer alignment of buffers including empty allocation - # should match the maximum array alignment. - formats = [fmt for fmt in ARRAY - if struct.calcsize(fmt) <= struct.calcsize('P')] - align = max(struct.calcsize(fmt) for fmt in formats) - cases = [array.array(fmt) for fmt in formats] - # Empty arrays - self.assertEqual( - [_testcapi.buffer_pointer_as_int(case) % align for case in cases], - [0] * len(cases), - ) - for case in cases: - case.append(0) - # Allocated arrays - self.assertEqual( - [_testcapi.buffer_pointer_as_int(case) % align for case in cases], - [0] * len(cases), - ) + # gh-140557: buffer pointers, including for empty arrays, must be + # aligned to at least the alignment of the element type. + for fmt in ARRAY: + with self.subTest(fmt=fmt): + # A zero repeat count pads to the alignment of the type, so + # this is the native alignment of `fmt`. + align = struct.calcsize(f"B0{fmt}") + for case in (array.array(fmt), array.array(fmt, [0])): + ptr = _testcapi.buffer_pointer_as_int(case) + self.assertEqual(ptr % align, 0) @support.cpython_only def test_pybuffer_size_from_format(self):