summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2022-12-23 00:55:55 -0800
committerGitHub <noreply@github.com>2022-12-23 08:55:55 +0000
commit95c55a69b3935e36108059ea89efd372d0902c6e (patch)
treec3f6a0985ce1e6d2458da472ca28da3c8eebf5da
parent86cdfaa885eedefe3a33fccc0bbccd0b6a388260 (diff)
downloadcpython-git-95c55a69b3935e36108059ea89efd372d0902c6e.tar.gz
[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 84bc6a4f25fcf467813ee12b74118f7b1b54e285) Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
-rw-r--r--Lib/ctypes/test/test_pep3118.py2
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2018-02-06-23-21-13.bpo-32782.EJVSfR.rst3
-rw-r--r--Modules/_ctypes/_ctypes.c33
3 files changed, 30 insertions, 8 deletions
diff --git a/Lib/ctypes/test/test_pep3118.py b/Lib/ctypes/test/test_pep3118.py
index 81e8ca7638..efffc80a66 100644
--- a/Lib/ctypes/test/test_pep3118.py
+++ b/Lib/ctypes/test/test_pep3118.py
@@ -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
index 0000000000..841740130b
--- /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 84378c4035..a534a828d1 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -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;