Skip to content

Commit 95c55a6

Browse files
[3.10] gh-76963: PEP3118 itemsize of an empty ctypes array should not be 0 (GH-5576) (#100451)
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 86cdfaa commit 95c55a6

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
@@ -2795,11 +2795,33 @@ static PyMemberDef PyCData_members[] = {
27952795
{ NULL },
27962796
};
27972797

2798-
static int PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
2798+
/* Find the innermost type of an array type, returning a borrowed reference */
2799+
static PyObject *
2800+
PyCData_item_type(PyObject *type)
2801+
{
2802+
if (PyCArrayTypeObject_Check(type)) {
2803+
StgDictObject *stg_dict;
2804+
PyObject *elem_type;
2805+
2806+
/* asserts used here as these are all guaranteed by construction */
2807+
stg_dict = PyType_stgdict(type);
2808+
assert(stg_dict);
2809+
elem_type = stg_dict->proto;
2810+
assert(elem_type);
2811+
return PyCData_item_type(elem_type);
2812+
}
2813+
else {
2814+
return type;
2815+
}
2816+
}
2817+
2818+
static int
2819+
PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
27992820
{
28002821
CDataObject *self = (CDataObject *)myself;
28012822
StgDictObject *dict = PyObject_stgdict(myself);
2802-
Py_ssize_t i;
2823+
PyObject *item_type = PyCData_item_type((PyObject*)Py_TYPE(myself));
2824+
StgDictObject *item_dict = PyType_stgdict(item_type);
28032825

28042826
if (view == NULL) return 0;
28052827

@@ -2812,12 +2834,7 @@ static int PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
28122834
view->format = dict->format ? dict->format : "B";
28132835
view->ndim = dict->ndim;
28142836
view->shape = dict->shape;
2815-
view->itemsize = self->b_size;
2816-
if (view->itemsize) {
2817-
for (i = 0; i < view->ndim; ++i) {
2818-
view->itemsize /= dict->shape[i];
2819-
}
2820-
}
2837+
view->itemsize = item_dict->size;
28212838
view->strides = NULL;
28222839
view->suboffsets = NULL;
28232840
view->internal = NULL;

0 commit comments

Comments
 (0)