Skip to content

Commit f6fe4bb

Browse files
[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 84bc6a4) Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
1 parent 1fa4c6b commit f6fe4bb

File tree

3 files changed

+30
-8
lines changed

3 files changed

+30
-8
lines changed

Lib/ctypes/test/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
@@ -2775,11 +2775,33 @@ static PyMemberDef PyCData_members[] = {
27752775
{ NULL },
27762776
};
27772777

2778-
static int PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
2778+
/* Find the innermost type of an array type, returning a borrowed reference */
2779+
static PyObject *
2780+
PyCData_item_type(PyObject *type)
2781+
{
2782+
if (PyCArrayTypeObject_Check(type)) {
2783+
StgDictObject *stg_dict;
2784+
PyObject *elem_type;
2785+
2786+
/* asserts used here as these are all guaranteed by construction */
2787+
stg_dict = PyType_stgdict(type);
2788+
assert(stg_dict);
2789+
elem_type = stg_dict->proto;
2790+
assert(elem_type);
2791+
return PyCData_item_type(elem_type);
2792+
}
2793+
else {
2794+
return type;
2795+
}
2796+
}
2797+
2798+
static int
2799+
PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
27792800
{
27802801
CDataObject *self = (CDataObject *)myself;
27812802
StgDictObject *dict = PyObject_stgdict(myself);
2782-
Py_ssize_t i;
2803+
PyObject *item_type = PyCData_item_type((PyObject*)Py_TYPE(myself));
2804+
StgDictObject *item_dict = PyType_stgdict(item_type);
27832805

27842806
if (view == NULL) return 0;
27852807

@@ -2792,12 +2814,7 @@ static int PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
27922814
view->format = dict->format ? dict->format : "B";
27932815
view->ndim = dict->ndim;
27942816
view->shape = dict->shape;
2795-
view->itemsize = self->b_size;
2796-
if (view->itemsize) {
2797-
for (i = 0; i < view->ndim; ++i) {
2798-
view->itemsize /= dict->shape[i];
2799-
}
2800-
}
2817+
view->itemsize = item_dict->size;
28012818
view->strides = NULL;
28022819
view->suboffsets = NULL;
28032820
view->internal = NULL;

0 commit comments

Comments
 (0)