]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.10] gh-76963: PEP3118 itemsize of an empty ctypes array should not be 0 (GH-5576...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Fri, 23 Dec 2022 08:55:55 +0000 (00:55 -0800)
committerGitHub <noreply@github.com>
Fri, 23 Dec 2022 08:55:55 +0000 (08:55 +0000)
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@gmail.com>
Lib/ctypes/test/test_pep3118.py
Misc/NEWS.d/next/Core and Builtins/2018-02-06-23-21-13.bpo-32782.EJVSfR.rst [new file with mode: 0644]
Modules/_ctypes/_ctypes.c

index 81e8ca7638fdeba2e4ed9d5ef4a7586cdf4b0b2c..efffc80a66fcb8c3849d5759f49f3b25657d043a 100644 (file)
@@ -176,7 +176,9 @@ native_types = [
     ## 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 (file)
index 0000000..8417401
--- /dev/null
@@ -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.
index 84378c40357b07bc90ab9cc7cc0ad404dd362759..a534a828d1ee794af0554bf60fa91c1b56f76743 100644 (file)
@@ -2795,11 +2795,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;
 
@@ -2812,12 +2834,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;