diff options
author | Eric Wieser <wieser.eric@gmail.com> | 2022-12-23 08:23:19 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-23 08:23:19 (GMT) |
commit | 84bc6a4f25fcf467813ee12b74118f7b1b54e285 (patch) | |
tree | d5ec734fae7968f0073f5769d3575b7173038096 | |
parent | 73c08eeaffadb73184808e462792b6793ce9f82d (diff) | |
download | cpython-84bc6a4f25fcf467813ee12b74118f7b1b54e285.zip cpython-84bc6a4f25fcf467813ee12b74118f7b1b54e285.tar.gz cpython-84bc6a4f25fcf467813ee12b74118f7b1b54e285.tar.bz2 |
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.
-rw-r--r-- | Lib/test/test_ctypes/test_pep3118.py | 2 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2018-02-06-23-21-13.bpo-32782.EJVSfR.rst | 3 | ||||
-rw-r--r-- | Modules/_ctypes/_ctypes.c | 33 |
3 files changed, 30 insertions, 8 deletions
diff --git a/Lib/test/test_ctypes/test_pep3118.py b/Lib/test/test_ctypes/test_pep3118.py index 81e8ca7..efffc80 100644 --- a/Lib/test/test_ctypes/test_pep3118.py +++ b/Lib/test/test_ctypes/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 0000000..8417401 --- /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 b9092d3..f69a377 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; |