Skip to content

Commit a3fdab5

Browse files
committed
Add tests of buffer pointer alignment
1 parent 6b37e66 commit a3fdab5

File tree

3 files changed

+61
-0
lines changed

3 files changed

+61
-0
lines changed

Lib/test/support/__init__.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import annotationlib
77
import contextlib
8+
import ctypes
89
import functools
910
import inspect
1011
import logging
@@ -69,6 +70,7 @@
6970
"in_systemd_nspawn_sync_suppressed",
7071
"run_no_yield_async_fn", "run_yielding_async_fn", "async_yield",
7172
"reset_code",
73+
"ctypes_py_buffer",
7274
]
7375

7476

@@ -3183,3 +3185,37 @@ def linked_to_musl():
31833185
return _linked_to_musl
31843186
_linked_to_musl = tuple(map(int, version.split('.')))
31853187
return _linked_to_musl
3188+
3189+
3190+
class _py_buffer(ctypes.Structure):
3191+
_fields_ = [
3192+
("buf", ctypes.c_void_p),
3193+
("obj", ctypes.py_object),
3194+
("len", ctypes.c_ssize_t),
3195+
("itemsize", ctypes.c_ssize_t),
3196+
("readonly", ctypes.c_int),
3197+
("ndim", ctypes.c_int),
3198+
("format", ctypes.c_char_p),
3199+
("shape", ctypes.POINTER(ctypes.c_ssize_t)),
3200+
("strides", ctypes.POINTER(ctypes.c_ssize_t)),
3201+
("suboffsets", ctypes.POINTER(ctypes.c_ssize_t)),
3202+
("internal", ctypes.c_void_p),
3203+
]
3204+
3205+
3206+
@contextlib.contextmanager
3207+
def ctypes_py_buffer(ob, flags=inspect.BufferFlags.SIMPLE):
3208+
"""
3209+
Safely acquire a `Py_buffer` as a ctypes struct.
3210+
3211+
`ob` must implement the buffer protocol, and the retrieved buffer is
3212+
released on exit of the context manager.
3213+
"""
3214+
buf = _py_buffer()
3215+
ctypes.pythonapi.PyObject_GetBuffer(ctypes.py_object(ob),
3216+
ctypes.byref(buf),
3217+
ctypes.c_int(flags))
3218+
try:
3219+
yield buf
3220+
finally:
3221+
ctypes.pythonapi.PyBuffer_Release(ctypes.byref(buf))

Lib/test/test_array.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from test.support import import_helper
99
from test.support import os_helper
1010
from test.support import _2G
11+
from test.support import ctypes_py_buffer
12+
import ctypes
1113
import weakref
1214
import pickle
1315
import operator
@@ -67,6 +69,20 @@ def test_empty(self):
6769
a += a
6870
self.assertEqual(len(a), 0)
6971

72+
def test_empty_alignment(self):
73+
# gh-140557: pointer alignment of empty allocation
74+
self.enterContext(warnings.catch_warnings())
75+
warnings.filterwarnings(
76+
"ignore",
77+
message="The 'u' type code is deprecated and "
78+
"will be removed in Python 3.16",
79+
category=DeprecationWarning)
80+
max_align = ctypes.alignment(ctypes.c_longdouble)
81+
for typecode in typecodes:
82+
a = array.array(typecode)
83+
with ctypes_py_buffer(a) as buf:
84+
self.assertEqual(buf.buf % max_align, 0)
85+
7086

7187
# Machine format codes.
7288
#

Lib/test/test_builtin.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import builtins
55
import collections
66
import contextlib
7+
import ctypes
78
import decimal
89
import fractions
910
import gc
@@ -38,6 +39,7 @@
3839
from test.support.testcase import ComplexesAreIdenticalMixin
3940
from test.support.warnings_helper import check_warnings
4041
from test.support import requires_IEEE_754
42+
from test.support import ctypes_py_buffer
4143
from unittest.mock import MagicMock, patch
4244
try:
4345
import pty, signal
@@ -2404,6 +2406,13 @@ def iterator():
24042406
yield b'B'
24052407
self.assertEqual(bytearray(b'A,B'), array.join(iterator()))
24062408

2409+
def test_bytearray_empty_alignment(self):
2410+
# gh-140557: alignment of pointer in empty allocation
2411+
max_align = ctypes.alignment(ctypes.c_longdouble)
2412+
array = bytearray()
2413+
with ctypes_py_buffer(array) as buf:
2414+
self.assertEqual(buf.buf % max_align, 0)
2415+
24072416
def test_construct_singletons(self):
24082417
for const in None, Ellipsis, NotImplemented:
24092418
tp = type(const)

0 commit comments

Comments
 (0)