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.
(cherry picked from commit 84bc6a4)

Co-authored-by: Eric Wieser <[email protected]>
  • Loading branch information
eric-wieser authored and miss-islington committed Dec 23, 2022
1 parent 1fa4c6b commit af7a12d
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 8 deletions.
2 changes: 2 additions & 0 deletions Lib/ctypes/test/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 @@ -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;

Expand All @@ -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;
Expand Down

0 comments on commit af7a12d

Please sign in to comment.