Skip to content

Commit 523676b

Browse files
committed
Adapt array module declarations Python 3.15 changes
In python/cpython#148676 the format of the `arraydescr` struct get changed, which meant that our representation was outdated and crashed. It isn't easy to adapt it perfectly for both (if users are manually using the `arraydescr` type anyway) but we can make our `array.array.__getbuffer__` function not crash by hiding some of the details in C code.
1 parent 87f82b7 commit 523676b

2 files changed

Lines changed: 30 additions & 5 deletions

File tree

Cython/Includes/cpython/array.pxd

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,14 @@ cdef extern from *: # Hard-coded utility code hack.
7070
ctypedef object GETF(array a, Py_ssize_t ix)
7171
ctypedef object SETF(array a, Py_ssize_t ix, object o)
7272
ctypedef struct arraydescr: # [object arraydescr]:
73-
char typecode
73+
char typecode # This is untrue in Python 3.15+ but it isn't easy to expose both
7474
int itemsize
7575
GETF getitem # PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
7676
SETF setitem # int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
7777

78+
Py_ssize_t _typecode_length "__Pyx_PyArrayDescr_typecode_length"(arraydescr *descr)
79+
void _copy_typecode "__Pyx_PyArrayDescr_copy_typecode"(arraydescr *descr, char *dst)
80+
7881
ctypedef union __data_union "__Pyx_data_union":
7982
# views of ob_item:
8083
float* as_floats # direct float pointer access to buffer
@@ -118,15 +121,14 @@ cdef extern from *: # Hard-coded utility code hack.
118121
info.itemsize = self.ob_descr.itemsize # e.g. sizeof(float)
119122
info.len = info.itemsize * item_count
120123

121-
info.shape = <Py_ssize_t*> PyObject_Malloc(sizeof(Py_ssize_t) + 2)
124+
info.shape = <Py_ssize_t*> PyObject_Malloc(sizeof(Py_ssize_t) + _typecode_length(self.ob_descr) + 1)
122125
if not info.shape:
123126
raise MemoryError()
124127
info.shape[0] = item_count # constant regardless of resizing
125128
info.strides = &info.itemsize
126129

127130
info.format = <char*> (info.shape + 1)
128-
info.format[0] = self.ob_descr.typecode
129-
info.format[1] = 0
131+
_copy_typecode(self.ob_descr, info.format)
130132
info.obj = self
131133

132134
def __releasebuffer__(self, Py_buffer* info):

Cython/Utility/arrayarray.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,36 @@
2323
// below. That's defined later because the appropriate get and set
2424
// functions aren't visible yet.
2525
typedef struct arraydescr {
26-
int typecode;
26+
#if PY_VERSION_HEX <= 0x030F00a8
27+
const char* typecode;
28+
#else
29+
char typecode;
30+
#endif
2731
int itemsize;
2832
PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
2933
int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
34+
#if PY_VERSION_HEX <= 0x030F00a8
3035
char *formats;
36+
#endif
3137
} arraydescr;
3238

39+
static CYTHON_INLINE Py_ssize_t __Pyx_PyArrayDescr_typecode_length(arraydescr *desc) {
40+
#if PY_VERSION_HEX <= 0x030F00a8
41+
return strlen(desc->typecode);
42+
#else
43+
return 1;
44+
#endif
45+
}
46+
47+
static CYTHON_INLINE void __Pyx_PyArrayDescr_copy_typecode(arraydescr *desc, char *dst) {
48+
#if PY_VERSION_HEX <= 0x030F00a8
49+
strcpy(dst, desc->typecode);
50+
#else
51+
dst[0] = arrayarray->typecode;
52+
dst[1] = '\0';
53+
#endif
54+
}
55+
3356
typedef union {
3457
char *ob_item;
3558
float *as_floats;

0 commit comments

Comments
 (0)