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

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


https://github.com/python/cpython/commit/f6fe4bb75cb1c7423cfd08d0bf10f9843761c2ac
commit: f6fe4bb75cb1c7423cfd08d0bf10f9843761c2ac
branch: 3.11
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: mdickinson <dickinsm at gmail.com>
date: 2022-12-23T08:56:20Z
summary:

[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 84bc6a4f25fcf467813ee12b74118f7b1b54e285)

Co-authored-by: Eric Wieser <wieser.eric at gmail.com>

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

diff --git a/Lib/ctypes/test/test_pep3118.py b/Lib/ctypes/test/test_pep3118.py
index 81e8ca7638fd..efffc80a66fc 100644
--- a/Lib/ctypes/test/test_pep3118.py
+++ b/Lib/ctypes/test/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 d6fa11d34813..b5eafe49e4ee 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -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;
 
@@ -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;



More information about the Python-checkins mailing list