Skip to content

Commit 84bc6a4

Browse files
authored
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.
1 parent 73c08ee commit 84bc6a4

File tree

3 files changed

+30
-8
lines changed

3 files changed

+30
-8
lines changed

Lib/test/test_ctypes/test_pep3118.py

+2
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,9 @@ class Complete(Structure):
176176
## arrays and pointers
177177

178178
(c_double * 4, "<d", (4,), c_double),
179+
(c_double * 0, "<d", (0,), c_double),
179180
(c_float * 4 * 3 * 2, "<f", (2,3,4), c_float),
181+
(c_float * 4 * 0 * 2, "<f", (2,0,4), c_float),
180182
(POINTER(c_short) * 2, "&<" + s_short, (2,), POINTER(c_short)),
181183
(POINTER(c_short) * 2 * 3, "&<" + s_short, (3,2,), POINTER(c_short)),
182184
(POINTER(c_short * 2), "&(2)<" + s_short, (), POINTER(c_short)),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
``ctypes`` arrays of length 0 now report a correct itemsize when a
2+
``memoryview`` is constructed from them, rather than always giving a value
3+
of 0.

Modules/_ctypes/_ctypes.c

+25-8
Original file line numberDiff line numberDiff line change
@@ -2731,11 +2731,33 @@ static PyMemberDef PyCData_members[] = {
27312731
{ NULL },
27322732
};
27332733

2734-
static int PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
2734+
/* Find the innermost type of an array type, returning a borrowed reference */
2735+
static PyObject *
2736+
PyCData_item_type(PyObject *type)
2737+
{
2738+
if (PyCArrayTypeObject_Check(type)) {
2739+
StgDictObject *stg_dict;
2740+
PyObject *elem_type;
2741+
2742+
/* asserts used here as these are all guaranteed by construction */
2743+
stg_dict = PyType_stgdict(type);
2744+
assert(stg_dict);
2745+
elem_type = stg_dict->proto;
2746+
assert(elem_type);
2747+
return PyCData_item_type(elem_type);
2748+
}
2749+
else {
2750+
return type;
2751+
}
2752+
}
2753+
2754+
static int
2755+
PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
27352756
{
27362757
CDataObject *self = (CDataObject *)myself;
27372758
StgDictObject *dict = PyObject_stgdict(myself);
2738-
Py_ssize_t i;
2759+
PyObject *item_type = PyCData_item_type((PyObject*)Py_TYPE(myself));
2760+
StgDictObject *item_dict = PyType_stgdict(item_type);
27392761

27402762
if (view == NULL) return 0;
27412763

@@ -2747,12 +2769,7 @@ static int PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
27472769
view->format = dict->format ? dict->format : "B";
27482770
view->ndim = dict->ndim;
27492771
view->shape = dict->shape;
2750-
view->itemsize = self->b_size;
2751-
if (view->itemsize) {
2752-
for (i = 0; i < view->ndim; ++i) {
2753-
view->itemsize /= dict->shape[i];
2754-
}
2755-
}
2772+
view->itemsize = item_dict->size;
27562773
view->strides = NULL;
27572774
view->suboffsets = NULL;
27582775
view->internal = NULL;

0 commit comments

Comments
 (0)