[3.11] gh-76963: PEP3118 itemsize of an empty ctypes array should not be 0 (GH-5576) (GH-100452)

gh-76963: PEP3118 itemsize of an empty ctypes array should not be 0 (GH-5576)

The itemsize returned in a memoryview of a ctypes array is now computed from the item type, instead of dividing the total size by the length and assuming that the length is not zero.
(cherry picked from commit 84bc6a4f25)

Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
This commit is contained in:
Miss Islington (bot) 2022-12-23 00:56:20 -08:00 committed by GitHub
parent 1fa4c6bd1f
commit f6fe4bb75c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 8 deletions

View file

@ -176,7 +176,9 @@ native_types = [
## arrays and pointers
(c_double * 4, "<d", (4,), c_double),
(c_double * 0, "<d", (0,), c_double),
(c_float * 4 * 3 * 2, "<f", (2,3,4), c_float),
(c_float * 4 * 0 * 2, "<f", (2,0,4), c_float),
(POINTER(c_short) * 2, "&<" + s_short, (2,), POINTER(c_short)),
(POINTER(c_short) * 2 * 3, "&<" + s_short, (3,2,), POINTER(c_short)),
(POINTER(c_short * 2), "&(2)<" + s_short, (), POINTER(c_short)),

View file

@ -0,0 +1,3 @@
``ctypes`` arrays of length 0 now report a correct itemsize when a
``memoryview`` is constructed from them, rather than always giving a value
of 0.

View file

@ -2775,11 +2775,33 @@ static PyMemberDef PyCData_members[] = {
{ NULL },
};
static int PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
/* Find the innermost type of an array type, returning a borrowed reference */
static PyObject *
PyCData_item_type(PyObject *type)
{
if (PyCArrayTypeObject_Check(type)) {
StgDictObject *stg_dict;
PyObject *elem_type;
/* asserts used here as these are all guaranteed by construction */
stg_dict = PyType_stgdict(type);
assert(stg_dict);
elem_type = stg_dict->proto;
assert(elem_type);
return PyCData_item_type(elem_type);
}
else {
return type;
}
}
static int
PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
{
CDataObject *self = (CDataObject *)myself;
StgDictObject *dict = PyObject_stgdict(myself);
Py_ssize_t i;
PyObject *item_type = PyCData_item_type((PyObject*)Py_TYPE(myself));
StgDictObject *item_dict = PyType_stgdict(item_type);
if (view == NULL) return 0;
@ -2792,12 +2814,7 @@ static int PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
view->format = dict->format ? dict->format : "B";
view->ndim = dict->ndim;
view->shape = dict->shape;
view->itemsize = self->b_size;
if (view->itemsize) {
for (i = 0; i < view->ndim; ++i) {
view->itemsize /= dict->shape[i];
}
}
view->itemsize = item_dict->size;
view->strides = NULL;
view->suboffsets = NULL;
view->internal = NULL;