Skip to content

Commit

Permalink
pythongh-76963: PEP3118 itemsize of an empty ctypes array should not …
Browse files Browse the repository at this point in the history
…be 0 (pythonGH-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.
  • Loading branch information
eric-wieser authored Dec 23, 2022
1 parent 73c08ee commit 84bc6a4
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 8 deletions.
2 changes: 2 additions & 0 deletions Lib/test/test_ctypes/test_pep3118.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,9 @@ class Complete(Structure):
## 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)),
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
33 changes: 25 additions & 8 deletions Modules/_ctypes/_ctypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2731,11 +2731,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;

Expand All @@ -2747,12 +2769,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;
Expand Down

0 comments on commit 84bc6a4

Please sign in to comment.