summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Wieser <wieser.eric@gmail.com>2022-12-23 08:23:19 (GMT)
committerGitHub <noreply@github.com>2022-12-23 08:23:19 (GMT)
commit84bc6a4f25fcf467813ee12b74118f7b1b54e285 (patch)
treed5ec734fae7968f0073f5769d3575b7173038096
parent73c08eeaffadb73184808e462792b6793ce9f82d (diff)
downloadcpython-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.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/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;