[Python-checkins] gh-76963: PEP3118 itemsize of an empty ctypes array should not be 0 (GH-5576)

mdickinson webhook-mailer at python.org
Fri Dec 23 03:23:44 EST 2022


https://github.com/python/cpython/commit/84bc6a4f25fcf467813ee12b74118f7b1b54e285
commit: 84bc6a4f25fcf467813ee12b74118f7b1b54e285
branch: main
author: Eric Wieser <wieser.eric at gmail.com>
committer: mdickinson <dickinsm at gmail.com>
date: 2022-12-23T08:23:19Z
summary:

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.

files:
A Misc/NEWS.d/next/Core and Builtins/2018-02-06-23-21-13.bpo-32782.EJVSfR.rst
M Lib/test/test_ctypes/test_pep3118.py
M Modules/_ctypes/_ctypes.c

diff --git a/Lib/test/test_ctypes/test_pep3118.py b/Lib/test/test_ctypes/test_pep3118.py
index 81e8ca7638fd..efffc80a66fc 100644
--- a/Lib/test/test_ctypes/test_pep3118.py
+++ b/Lib/test/test_ctypes/test_pep3118.py
@@ -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)),
diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-02-06-23-21-13.bpo-32782.EJVSfR.rst b/Misc/NEWS.d/next/Core and Builtins/2018-02-06-23-21-13.bpo-32782.EJVSfR.rst
new file mode 100644
index 000000000000..841740130bd1
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2018-02-06-23-21-13.bpo-32782.EJVSfR.rst	
@@ -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.
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index b9092d3981f3..f69a37709963 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -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;
 
@@ -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;



More information about the Python-checkins mailing list