Skip to content

Commit b036215

Browse files
committed
Add alignment tests with _testcapi helper
1 parent ad966dc commit b036215

2 files changed

Lines changed: 61 additions & 0 deletions

File tree

Lib/test/test_buffer.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4447,6 +4447,43 @@ def test_bytearray_release_buffer_read_flag(self):
44474447
with self.assertRaises(SystemError):
44484448
obj.__buffer__(inspect.BufferFlags.WRITE)
44494449

4450+
@support.cpython_only
4451+
@unittest.skipIf(_testcapi is None, "requires _testcapi")
4452+
@unittest.skipIf(ctypes is None, "requires ctypes")
4453+
def test_bytearray_alignment(self):
4454+
# gh-140557: pointer alignment of buffers including empty allocation
4455+
max_align = ctypes.alignment(ctypes.c_longdouble)
4456+
cases = [
4457+
bytearray(),
4458+
bytearray(1),
4459+
bytearray(b"0123456789abcdef"),
4460+
bytearray(16),
4461+
]
4462+
ptrs = [_testcapi.buffer_pointer_as_int(array) for array in cases]
4463+
self.assertEqual([ptr % max_align for ptr in ptrs], [0]*len(ptrs))
4464+
4465+
@support.cpython_only
4466+
@unittest.skipIf(_testcapi is None, "requires _testcapi")
4467+
@unittest.skipIf(ctypes is None, "requires ctypes")
4468+
def test_array_alignment(self):
4469+
# gh-140557: pointer alignment of buffers including empty allocation
4470+
max_align = ctypes.alignment(ctypes.c_longdouble)
4471+
cases = [array.array(fmt) for fmt in ARRAY]
4472+
# Empty arrays
4473+
self.assertEqual(
4474+
[_testcapi.buffer_pointer_as_int(case) % max_align
4475+
for case in cases],
4476+
[0] * len(cases),
4477+
)
4478+
for case in cases:
4479+
case.append(0)
4480+
# Allocated arrays
4481+
self.assertEqual(
4482+
[_testcapi.buffer_pointer_as_int(case) % max_align
4483+
for case in cases],
4484+
[0] * len(cases),
4485+
)
4486+
44504487
@support.cpython_only
44514488
def test_pybuffer_size_from_format(self):
44524489
# basic tests

Modules/_testcapi/buffer.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,27 @@ static PyTypeObject testBufType = {
9898
.tp_members = testbuf_members
9999
};
100100

101+
/* Get the pointer from a buffer-supporting object as a PyLong.
102+
*
103+
* Used to test alignment properties.*/
104+
static PyObject *
105+
buffer_pointer_as_int(PyObject *Py_UNUSED(module), PyObject *obj)
106+
{
107+
PyObject *out;
108+
Py_buffer view;
109+
if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0) {
110+
return NULL;
111+
}
112+
out = PyLong_FromVoidPtr(view.buf);
113+
PyBuffer_Release(&view);
114+
return out;
115+
}
116+
117+
static PyMethodDef test_methods[] = {
118+
{"buffer_pointer_as_int", buffer_pointer_as_int, METH_O},
119+
{NULL},
120+
};
121+
101122
int
102123
_PyTestCapi_Init_Buffer(PyObject *m) {
103124
if (PyType_Ready(&testBufType) < 0) {
@@ -106,6 +127,9 @@ _PyTestCapi_Init_Buffer(PyObject *m) {
106127
if (PyModule_AddObjectRef(m, "testBuf", (PyObject *)&testBufType)) {
107128
return -1;
108129
}
130+
if (PyModule_AddFunctions(m, test_methods) < 0) {
131+
return -1;
132+
}
109133

110134
return 0;
111135
}

0 commit comments

Comments
 (0)