summaryrefslogtreecommitdiffstats
path: root/Modules/_ctypes
diff options
context:
space:
mode:
authorPetr Viktorin <encukou@gmail.com>2024-09-05 09:20:07 (GMT)
committerGitHub <noreply@github.com>2024-09-05 09:20:07 (GMT)
commitce9f84a47bfbafedd09a25d0f6f0c8209550fb6c (patch)
tree05fded014eb7d5684b8a12c9b70574f4eda4d872 /Modules/_ctypes
parent1fdfce9452706a8a12ccdacff6d02c9231dc48ce (diff)
downloadcpython-ce9f84a47bfbafedd09a25d0f6f0c8209550fb6c.zip
cpython-ce9f84a47bfbafedd09a25d0f6f0c8209550fb6c.tar.gz
cpython-ce9f84a47bfbafedd09a25d0f6f0c8209550fb6c.tar.bz2
gh-97588: Move ctypes struct/union layout logic to Python (GH-123352)
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Diffstat (limited to 'Modules/_ctypes')
-rw-r--r--Modules/_ctypes/_ctypes.c13
-rw-r--r--Modules/_ctypes/cfield.c302
-rw-r--r--Modules/_ctypes/clinic/cfield.c.h113
-rw-r--r--Modules/_ctypes/ctypes.h24
-rw-r--r--Modules/_ctypes/stgdict.c579
5 files changed, 397 insertions, 634 deletions
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index b551026..2b23be7 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -320,7 +320,7 @@ _ctypes_alloc_format_string_for_type(char code, int big_endian)
indicator set. If called with a suffix of NULL the error indicator must
already be set.
*/
-char *
+static char *
_ctypes_alloc_format_string(const char *prefix, const char *suffix)
{
size_t len;
@@ -352,7 +352,7 @@ _ctypes_alloc_format_string(const char *prefix, const char *suffix)
Returns NULL on failure, with the error indicator set. If called with
a suffix of NULL the error indicator must already be set.
*/
-char *
+static char *
_ctypes_alloc_format_string_with_shape(int ndim, const Py_ssize_t *shape,
const char *prefix, const char *suffix)
{
@@ -664,9 +664,6 @@ StructUnionType_init(PyObject *self, PyObject *args, PyObject *kwds, int isStruc
Py_DECREF(attrdict);
return -1;
}
- if (!isStruct) {
- info->flags |= TYPEFLAG_HASUNION;
- }
info->format = _ctypes_alloc_format_string(NULL, "B");
if (info->format == NULL) {
@@ -2534,6 +2531,10 @@ converters_from_argtypes(ctypes_state *st, PyObject *ob)
return -1;
}
+ // TYPEFLAG_HASUNION and TYPEFLAG_HASBITFIELD used to be set
+ // if there were any unions/bitfields;
+ // if the check is re-enabled we either need to loop here or
+ // restore the flag
if (stginfo != NULL) {
if (stginfo->flags & TYPEFLAG_HASUNION) {
Py_DECREF(converters);
@@ -5780,7 +5781,7 @@ _ctypes_add_types(PyObject *mod)
* Simple classes
*/
- CREATE_TYPE(st->PyCField_Type, &cfield_spec, NULL, NULL);
+ MOD_ADD_TYPE(st->PyCField_Type, &cfield_spec, NULL, NULL);
/*************************************************
*
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c
index 2c1fb9b..abcab65 100644
--- a/Modules/_ctypes/cfield.c
+++ b/Modules/_ctypes/cfield.c
@@ -20,6 +20,13 @@
#define CTYPES_CFIELD_CAPSULE_NAME_PYMEM "_ctypes/cfield.c pymem"
+/*[clinic input]
+module _ctypes
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=476a19c49b31a75c]*/
+
+#include "clinic/cfield.c.h"
+
static void pymem_destructor(PyObject *ptr)
{
void *p = PyCapsule_GetPointer(ptr, CTYPES_CFIELD_CAPSULE_NAME_PYMEM);
@@ -33,6 +40,10 @@ static void pymem_destructor(PyObject *ptr)
/*
PyCField_Type
*/
+/*[clinic input]
+class _ctypes.CField "PyObject *" "PyObject"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=602817ea3ffc709c]*/
static inline
Py_ssize_t round_down(Py_ssize_t numToRound, Py_ssize_t multiple)
@@ -61,238 +72,142 @@ Py_ssize_t LOW_BIT(Py_ssize_t offset);
static inline
Py_ssize_t BUILD_SIZE(Py_ssize_t bitsize, Py_ssize_t offset);
-/* PyCField_FromDesc creates and returns a struct/union field descriptor.
-
-The function expects to be called repeatedly for all fields in a struct or
-union. It uses helper functions PyCField_FromDesc_gcc and
-PyCField_FromDesc_msvc to simulate the corresponding compilers.
-
-GCC mode places fields one after another, bit by bit. But "each bit field must
-fit within a single object of its specified type" (GCC manual, section 15.8
-"Bit Field Packing"). When it doesn't, we insert a few bits of padding to
-avoid that.
-MSVC mode works similar except for bitfield packing. Adjacent bit-fields are
-packed into the same 1-, 2-, or 4-byte allocation unit if the integral types
-are the same size and if the next bit-field fits into the current allocation
-unit without crossing the boundary imposed by the common alignment requirements
-of the bit-fields.
+/*[clinic input]
+@classmethod
+_ctypes.CField.__new__ as PyCField_new
-See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mms-bitfields for details.
+ name: object(subclass_of='&PyUnicode_Type')
+ type as proto: object
+ size: Py_ssize_t
+ offset: Py_ssize_t
+ index: Py_ssize_t
+ bit_size as bit_size_obj: object = None
-We do not support zero length bitfields. In fact we use bitsize != 0 elsewhere
-to indicate a bitfield. Here, non-bitfields need bitsize set to size*8.
+[clinic start generated code]*/
-PyCField_FromDesc manages:
-- *psize: the size of the structure / union so far.
-- *poffset, *pbitofs: 8* (*poffset) + *pbitofs points to where the next field
- would start.
-- *palign: the alignment requirements of the last field we placed.
-*/
-
-static int
-PyCField_FromDesc_gcc(Py_ssize_t bitsize, Py_ssize_t *pbitofs,
- Py_ssize_t *psize, Py_ssize_t *poffset, Py_ssize_t *palign,
- CFieldObject* self, StgInfo* info,
- int is_bitfield
- )
-{
- // We don't use poffset here, so clear it, if it has been set.
- *pbitofs += *poffset * 8;
- *poffset = 0;
-
- *palign = info->align;
-
- if (bitsize > 0) {
- // Determine whether the bit field, if placed at the next free bit,
- // fits within a single object of its specified type.
- // That is: determine a "slot", sized & aligned for the specified type,
- // which contains the bitfield's beginning:
- Py_ssize_t slot_start_bit = round_down(*pbitofs, 8 * info->align);
- Py_ssize_t slot_end_bit = slot_start_bit + 8 * info->size;
- // And see if it also contains the bitfield's last bit:
- Py_ssize_t field_end_bit = *pbitofs + bitsize;
- if (field_end_bit > slot_end_bit) {
- // It doesn't: add padding (bump up to the next alignment boundary)
- *pbitofs = round_up(*pbitofs, 8*info->align);
- }
- }
- assert(*poffset == 0);
-
- self->offset = round_down(*pbitofs, 8*info->align) / 8;
- if(is_bitfield) {
- Py_ssize_t effective_bitsof = *pbitofs - 8 * self->offset;
- self->size = BUILD_SIZE(bitsize, effective_bitsof);
- assert(effective_bitsof <= info->size * 8);
- } else {
- self->size = info->size;
+static PyObject *
+PyCField_new_impl(PyTypeObject *type, PyObject *name, PyObject *proto,
+ Py_ssize_t size, Py_ssize_t offset, Py_ssize_t index,
+ PyObject *bit_size_obj)
+/*[clinic end generated code: output=43649ef9157c5f58 input=3d813f56373c4caa]*/
+{
+ CFieldObject* self = NULL;
+ if (size < 0) {
+ PyErr_Format(PyExc_ValueError,
+ "size of field %R must not be negative, got %zd",
+ name, size);
+ goto error;
}
-
- *pbitofs += bitsize;
- *psize = round_up(*pbitofs, 8) / 8;
-
- return 0;
-}
-
-static int
-PyCField_FromDesc_msvc(
- Py_ssize_t *pfield_size, Py_ssize_t bitsize,
- Py_ssize_t *pbitofs, Py_ssize_t *psize, Py_ssize_t *poffset,
- Py_ssize_t *palign, int pack,
- CFieldObject* self, StgInfo* info,
- int is_bitfield
- )
-{
- if (pack) {
- *palign = Py_MIN(pack, info->align);
- } else {
- *palign = info->align;
+ // assert: no overflow;
+ if ((unsigned long long int) size
+ >= (1ULL << (8*sizeof(Py_ssize_t)-1)) / 8) {
+ PyErr_Format(PyExc_ValueError,
+ "size of field %R is too big: %zd", name, size);
+ goto error;
}
- // *poffset points to end of current bitfield.
- // *pbitofs is generally non-positive,
- // and 8 * (*poffset) + *pbitofs points just behind
- // the end of the last field we placed.
- if (0 < *pbitofs + bitsize || 8 * info->size != *pfield_size) {
- // Close the previous bitfield (if any).
- // and start a new bitfield:
- *poffset = round_up(*poffset, *palign);
-
- *poffset += info->size;
-
- *pfield_size = info->size * 8;
- // Reminder: 8 * (*poffset) + *pbitofs points to where we would start a
- // new field. Ie just behind where we placed the last field plus an
- // allowance for alignment.
- *pbitofs = - *pfield_size;
+ PyTypeObject *tp = type;
+ ctypes_state *st = get_module_state_by_class(tp);
+ self = (CFieldObject *)tp->tp_alloc(tp, 0);
+ if (!self) {
+ return NULL;
}
-
- assert(8 * info->size == *pfield_size);
-
- self->offset = *poffset - (*pfield_size) / 8;
- if(is_bitfield) {
- assert(0 <= (*pfield_size + *pbitofs));
- assert((*pfield_size + *pbitofs) < info->size * 8);
- self->size = BUILD_SIZE(bitsize, *pfield_size + *pbitofs);
+ if (PyUnicode_CheckExact(name)) {
+ self->name = Py_NewRef(name);
} else {
- self->size = info->size;
+ self->name = PyObject_Str(name);
+ if (!self->name) {
+ goto error;
+ }
}
- assert(*pfield_size + *pbitofs <= info->size * 8);
-
- *pbitofs += bitsize;
- *psize = *poffset;
- return 0;
-}
-
-PyObject *
-PyCField_FromDesc(ctypes_state *st, PyObject *desc, Py_ssize_t index,
- Py_ssize_t *pfield_size, Py_ssize_t bitsize,
- Py_ssize_t *pbitofs, Py_ssize_t *psize, Py_ssize_t *poffset, Py_ssize_t *palign,
- int pack, int big_endian, LayoutMode layout_mode)
-{
- PyTypeObject *tp = st->PyCField_Type;
- CFieldObject* self = (CFieldObject *)tp->tp_alloc(tp, 0);
- if (self == NULL) {
- return NULL;
- }
StgInfo *info;
- if (PyStgInfo_FromType(st, desc, &info) < 0) {
- Py_DECREF(self);
- return NULL;
+ if (PyStgInfo_FromType(st, proto, &info) < 0) {
+ goto error;
}
- if (!info) {
- PyErr_SetString(PyExc_TypeError,
- "has no _stginfo_");
- Py_DECREF(self);
- return NULL;
+ if (info == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "type of field %R must be a C type", self->name);
+ goto error;
}
- PyObject* proto = desc;
+ Py_ssize_t bit_size = NUM_BITS(size);
+ if (bit_size) {
+ assert(bit_size > 0);
+ assert(bit_size <= info->size * 8);
+ switch(info->ffi_type_pointer.type) {
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ break;
+
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_SINT32:
+ if (info->getfunc != _ctypes_get_fielddesc("c")->getfunc
+ && info->getfunc != _ctypes_get_fielddesc("u")->getfunc)
+ {
+ break;
+ }
+ _Py_FALLTHROUGH; /* else fall through */
+ default:
+ PyErr_Format(PyExc_TypeError,
+ "bit fields not allowed for type %s",
+ ((PyTypeObject*)proto)->tp_name);
+ goto error;
+ }
+ }
+
+ self->proto = Py_NewRef(proto);
+ self->size = size;
+ self->offset = offset;
+
+ self->index = index;
- /* Field descriptors for 'c_char * n' are be scpecial cased to
+ /* Field descriptors for 'c_char * n' are be special cased to
return a Python string instead of an Array object instance...
*/
- SETFUNC setfunc = NULL;
- GETFUNC getfunc = NULL;
+ self->setfunc = NULL;
+ self->getfunc = NULL;
if (PyCArrayTypeObject_Check(st, proto)) {
StgInfo *ainfo;
if (PyStgInfo_FromType(st, proto, &ainfo) < 0) {
- Py_DECREF(self);
- return NULL;
+ goto error;
}
if (ainfo && ainfo->proto) {
StgInfo *iinfo;
if (PyStgInfo_FromType(st, ainfo->proto, &iinfo) < 0) {
- Py_DECREF(self);
- return NULL;
+ goto error;
}
if (!iinfo) {
PyErr_SetString(PyExc_TypeError,
"has no _stginfo_");
- Py_DECREF(self);
- return NULL;
+ goto error;
}
if (iinfo->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
struct fielddesc *fd = _ctypes_get_fielddesc("s");
- getfunc = fd->getfunc;
- setfunc = fd->setfunc;
+ self->getfunc = fd->getfunc;
+ self->setfunc = fd->setfunc;
}
if (iinfo->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
struct fielddesc *fd = _ctypes_get_fielddesc("U");
- getfunc = fd->getfunc;
- setfunc = fd->setfunc;
+ self->getfunc = fd->getfunc;
+ self->setfunc = fd->setfunc;
}
}
}
- self->setfunc = setfunc;
- self->getfunc = getfunc;
- self->index = index;
-
- self->proto = Py_NewRef(proto);
-
- int is_bitfield = !!bitsize;
- if(!is_bitfield) {
- assert(info->size >= 0);
- // assert: no overflow;
- assert((unsigned long long int) info->size
- < (1ULL << (8*sizeof(Py_ssize_t)-1)) / 8);
- bitsize = 8 * info->size;
- // Caution: bitsize might still be 0 now.
- }
- assert(bitsize <= info->size * 8);
-
- int result;
- if (layout_mode == LAYOUT_MODE_MS) {
- result = PyCField_FromDesc_msvc(
- pfield_size, bitsize, pbitofs,
- psize, poffset, palign,
- pack,
- self, info,
- is_bitfield
- );
- } else {
- assert(pack == 0);
- result = PyCField_FromDesc_gcc(
- bitsize, pbitofs,
- psize, poffset, palign,
- self, info,
- is_bitfield
- );
- }
- if (result < 0) {
- Py_DECREF(self);
- return NULL;
- }
- assert(!is_bitfield || (LOW_BIT(self->size) <= self->size * 8));
- if(big_endian && is_bitfield) {
- self->size = BUILD_SIZE(NUM_BITS(self->size), 8*info->size - LOW_BIT(self->size) - bitsize);
- }
return (PyObject *)self;
+error:
+ Py_XDECREF(self);
+ return NULL;
}
+
static int
PyCField_set(CFieldObject *self, PyObject *inst, PyObject *value)
{
@@ -371,8 +286,10 @@ PyCField_dealloc(PyObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
- (void)PyCField_clear((CFieldObject *)self);
- Py_TYPE(self)->tp_free((PyObject *)self);
+ CFieldObject *self_cf = (CFieldObject *)self;
+ (void)PyCField_clear(self_cf);
+ Py_CLEAR(self_cf->name);
+ Py_TYPE(self)->tp_free(self);
Py_DECREF(tp);
}
@@ -398,6 +315,7 @@ PyCField_repr(CFieldObject *self)
}
static PyType_Slot cfield_slots[] = {
+ {Py_tp_new, PyCField_new},
{Py_tp_dealloc, PyCField_dealloc},
{Py_tp_repr, PyCField_repr},
{Py_tp_doc, (void *)PyDoc_STR("Structure/Union member")},
@@ -413,7 +331,7 @@ PyType_Spec cfield_spec = {
.name = "_ctypes.CField",
.basicsize = sizeof(CFieldObject),
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
- Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
+ Py_TPFLAGS_IMMUTABLETYPE),
.slots = cfield_slots,
};
diff --git a/Modules/_ctypes/clinic/cfield.c.h b/Modules/_ctypes/clinic/cfield.c.h
new file mode 100644
index 0000000..df5da78
--- /dev/null
+++ b/Modules/_ctypes/clinic/cfield.c.h
@@ -0,0 +1,113 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+# include "pycore_gc.h" // PyGC_Head
+# include "pycore_runtime.h" // _Py_ID()
+#endif
+#include "pycore_abstract.h" // _PyNumber_Index()
+#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
+
+static PyObject *
+PyCField_new_impl(PyTypeObject *type, PyObject *name, PyObject *proto,
+ Py_ssize_t size, Py_ssize_t offset, Py_ssize_t index,
+ PyObject *bit_size_obj);
+
+static PyObject *
+PyCField_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 6
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_item = { &_Py_ID(name), &_Py_ID(type), &_Py_ID(size), &_Py_ID(offset), &_Py_ID(index), &_Py_ID(bit_size), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"name", "type", "size", "offset", "index", "bit_size", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "CField",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[6];
+ PyObject * const *fastargs;
+ Py_ssize_t nargs = PyTuple_GET_SIZE(args);
+ Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 5;
+ PyObject *name;
+ PyObject *proto;
+ Py_ssize_t size;
+ Py_ssize_t offset;
+ Py_ssize_t index;
+ PyObject *bit_size_obj = Py_None;
+
+ fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 5, 6, 0, argsbuf);
+ if (!fastargs) {
+ goto exit;
+ }
+ if (!PyUnicode_Check(fastargs[0])) {
+ _PyArg_BadArgument("CField", "argument 'name'", "str", fastargs[0]);
+ goto exit;
+ }
+ name = fastargs[0];
+ proto = fastargs[1];
+ {
+ Py_ssize_t ival = -1;
+ PyObject *iobj = _PyNumber_Index(fastargs[2]);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ size = ival;
+ }
+ {
+ Py_ssize_t ival = -1;
+ PyObject *iobj = _PyNumber_Index(fastargs[3]);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ offset = ival;
+ }
+ {
+ Py_ssize_t ival = -1;
+ PyObject *iobj = _PyNumber_Index(fastargs[4]);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ index = ival;
+ }
+ if (!noptargs) {
+ goto skip_optional_pos;
+ }
+ bit_size_obj = fastargs[5];
+skip_optional_pos:
+ return_value = PyCField_new_impl(type, name, proto, size, offset, index, bit_size_obj);
+
+exit:
+ return return_value;
+}
+/*[clinic end generated code: output=27c010bae9be7213 input=a9049054013a1b77]*/
diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h
index a794cfe..2eb1b6c 100644
--- a/Modules/_ctypes/ctypes.h
+++ b/Modules/_ctypes/ctypes.h
@@ -216,18 +216,6 @@ extern int PyObject_stginfo(PyObject *self, Py_ssize_t *psize, Py_ssize_t *palig
extern struct fielddesc *_ctypes_get_fielddesc(const char *fmt);
-typedef enum {
- LAYOUT_MODE_MS,
- LAYOUT_MODE_GCC_SYSV,
-} LayoutMode;
-
-extern PyObject *
-PyCField_FromDesc(ctypes_state *st, PyObject *desc, Py_ssize_t index,
- Py_ssize_t *pfield_size, Py_ssize_t bitsize,
- Py_ssize_t *pbitofs, Py_ssize_t *psize, Py_ssize_t *poffset,
- Py_ssize_t *palign,
- int pack, int is_big_endian, LayoutMode layout_mode);
-
extern PyObject *PyCData_AtAddress(ctypes_state *st, PyObject *type, void *buf);
extern PyObject *PyCData_FromBytes(ctypes_state *st, PyObject *type, char *data, Py_ssize_t length);
@@ -259,16 +247,18 @@ struct fielddesc {
GETFUNC getfunc_swapped;
};
-typedef struct {
+typedef struct CFieldObject {
PyObject_HEAD
Py_ssize_t offset;
Py_ssize_t size;
Py_ssize_t index; /* Index into CDataObject's
object array */
- PyObject *proto; /* a type or NULL */
+ PyObject *proto; /* underlying ctype; must have StgInfo */
GETFUNC getfunc; /* getter function if proto is NULL */
SETFUNC setfunc; /* setter function if proto is NULL */
int anonymous;
+
+ PyObject *name; /* exact PyUnicode */
} CFieldObject;
/****************************************************************
@@ -379,8 +369,6 @@ PyObject *_ctypes_callproc(ctypes_state *st,
#define TYPEFLAG_ISPOINTER 0x100
#define TYPEFLAG_HASPOINTER 0x200
-#define TYPEFLAG_HASUNION 0x400
-#define TYPEFLAG_HASBITFIELD 0x800
#define DICTFLAG_FINAL 0x1000
@@ -436,10 +424,6 @@ extern void *_ctypes_alloc_closure(void);
extern PyObject *PyCData_FromBaseObj(ctypes_state *st, PyObject *type,
PyObject *base, Py_ssize_t index, char *adr);
-extern char *_ctypes_alloc_format_string(const char *prefix, const char *suffix);
-extern char *_ctypes_alloc_format_string_with_shape(int ndim,
- const Py_ssize_t *shape,
- const char *prefix, const char *suffix);
extern int _ctypes_simple_instance(ctypes_state *st, PyObject *obj);
diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c
index 970f0a0..c9cd1c6 100644
--- a/Modules/_ctypes/stgdict.c
+++ b/Modules/_ctypes/stgdict.c
@@ -211,154 +211,41 @@ MakeAnonFields(PyObject *type)
}
/*
- Allocate a memory block for a pep3118 format string, copy prefix (if
- non-null) into it and append `{padding}x` to the end.
- Returns NULL on failure, with the error indicator set.
-*/
-char *
-_ctypes_alloc_format_padding(const char *prefix, Py_ssize_t padding)
-{
- /* int64 decimal characters + x + null */
- char buf[19 + 1 + 1];
-
- assert(padding > 0);
-
- if (padding == 1) {
- /* Use x instead of 1x, for brevity */
- return _ctypes_alloc_format_string(prefix, "x");
- }
-
- int ret = PyOS_snprintf(buf, sizeof(buf), "%zdx", padding); (void)ret;
- assert(0 <= ret && ret < (Py_ssize_t)sizeof(buf));
- return _ctypes_alloc_format_string(prefix, buf);
-}
-
-/*
Retrieve the (optional) _pack_ attribute from a type, the _fields_ attribute,
and initialize StgInfo. Used for Structure and Union subclasses.
*/
int
PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct)
{
- Py_ssize_t len, offset, size, align, i;
- Py_ssize_t union_size, total_align, aligned_size;
- Py_ssize_t field_size = 0;
- Py_ssize_t bitofs = 0;
PyObject *tmp;
- int pack;
- int forced_alignment = 1;
Py_ssize_t ffi_ofs;
- int big_endian;
int arrays_seen = 0;
- if (fields == NULL)
- return 0;
-
- int rc = PyObject_HasAttrWithError(type, &_Py_ID(_swappedbytes_));
- if (rc < 0) {
- return -1;
- }
- if (rc) {
- big_endian = !PY_BIG_ENDIAN;
- }
- else {
- big_endian = PY_BIG_ENDIAN;
- }
-
- if (PyObject_GetOptionalAttr(type, &_Py_ID(_pack_), &tmp) < 0) {
- return -1;
- }
- if (tmp) {
- pack = PyLong_AsInt(tmp);
- Py_DECREF(tmp);
- if (pack < 0) {
- if (!PyErr_Occurred() ||
- PyErr_ExceptionMatches(PyExc_TypeError) ||
- PyErr_ExceptionMatches(PyExc_OverflowError))
- {
- PyErr_SetString(PyExc_ValueError,
- "_pack_ must be a non-negative integer");
- }
- return -1;
- }
- }
- else {
- /* Setting `_pack_ = 0` amounts to using the default alignment */
- pack = 0;
- }
-
- #ifdef MS_WIN32
- LayoutMode layout_mode = LAYOUT_MODE_MS;
- #else
- LayoutMode layout_mode = (pack > 0) ? LAYOUT_MODE_MS : LAYOUT_MODE_GCC_SYSV;
- #endif
-
- if (PyObject_GetOptionalAttr(type, &_Py_ID(_layout_), &tmp) < 0) {
- return -1;
- }
- if (tmp) {
- if (!PyUnicode_Check(tmp)) {
- PyErr_SetString(PyExc_TypeError,
- "_layout_ must be a string");
- return -1;
- }
- if (PyUnicode_CompareWithASCIIString(tmp, "ms") == 0) {
- layout_mode = LAYOUT_MODE_MS;
- }
- else if (PyUnicode_CompareWithASCIIString(tmp, "gcc-sysv") == 0) {
- layout_mode = LAYOUT_MODE_GCC_SYSV;
- if (pack > 0) {
- PyErr_SetString(PyExc_ValueError,
- "_pack_ is not compatible with _layout_=\"gcc-sysv\"");
- return -1;
- }
- }
- else {
- PyErr_Format(PyExc_ValueError,
- "unknown _layout_ %R", tmp);
- return -1;
- }
- }
- if (PyObject_GetOptionalAttr(type, &_Py_ID(_align_), &tmp) < 0) {
- return -1;
- }
- if (tmp) {
- forced_alignment = PyLong_AsInt(tmp);
- Py_DECREF(tmp);
- if (forced_alignment < 0) {
- if (!PyErr_Occurred() ||
- PyErr_ExceptionMatches(PyExc_TypeError) ||
- PyErr_ExceptionMatches(PyExc_OverflowError))
- {
- PyErr_SetString(PyExc_ValueError,
- "_align_ must be a non-negative integer");
- }
- return -1;
- }
- }
- else {
- /* Setting `_align_ = 0` amounts to using the default alignment */
- forced_alignment = 1;
- }
+ int retval = -1;
+ // The following are NULL or hold strong references.
+ // They're cleared on error.
+ PyObject *layout_fields = NULL;
+ PyObject *layout = NULL;
+ PyObject *format_spec_obj = NULL;
- len = PySequence_Size(fields);
- if (len == -1) {
- if (PyErr_ExceptionMatches(PyExc_TypeError)) {
- PyErr_SetString(PyExc_TypeError,
- "'_fields_' must be a sequence of pairs");
- }
- return -1;
+ if (fields == NULL) {
+ return 0;
}
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
StgInfo *stginfo;
if (PyStgInfo_FromType(st, type, &stginfo) < 0) {
- return -1;
+ goto error;
}
if (!stginfo) {
PyErr_SetString(PyExc_TypeError,
"ctypes state is not initialized");
- return -1;
+ goto error;
+ }
+ PyObject *base = (PyObject *)((PyTypeObject *)type)->tp_base;
+ StgInfo *baseinfo;
+ if (PyStgInfo_FromType(st, base, &baseinfo) < 0) {
+ goto error;
}
/* If this structure/union is already marked final we cannot assign
@@ -367,40 +254,114 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
if (stginfo->flags & DICTFLAG_FINAL) {/* is final ? */
PyErr_SetString(PyExc_AttributeError,
"_fields_ is final");
- return -1;
+ goto error;
+ }
+
+ PyObject *layout_func = _PyImport_GetModuleAttrString("ctypes._layout",
+ "get_layout");
+ if (!layout_func) {
+ goto error;
+ }
+ PyObject *kwnames = PyTuple_Pack(
+ 2,
+ &_Py_ID(is_struct),
+ &_Py_ID(base));
+ if (!kwnames) {
+ goto error;
+ }
+ layout = PyObject_Vectorcall(
+ layout_func,
+ 1 + (PyObject*[]){
+ NULL,
+ /* positional args */
+ type,
+ fields,
+ /* keyword args */
+ isStruct ? Py_True : Py_False,
+ baseinfo ? base : Py_None},
+ 2 | PY_VECTORCALL_ARGUMENTS_OFFSET,
+ kwnames);
+ Py_DECREF(kwnames);
+ Py_DECREF(layout_func);
+ fields = NULL; // a borrowed reference we won't be using again
+ if (!layout) {
+ goto error;
+ }
+
+ tmp = PyObject_GetAttr(layout, &_Py_ID(align));
+ if (!tmp) {
+ goto error;
+ }
+ Py_ssize_t total_align = PyLong_AsInt(tmp);
+ Py_DECREF(tmp);
+ if (total_align < 0) {
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_ValueError,
+ "align must be a non-negative integer");
+ }
+ goto error;
+ }
+
+ tmp = PyObject_GetAttr(layout, &_Py_ID(size));
+ if (!tmp) {
+ goto error;
+ }
+ Py_ssize_t total_size = PyLong_AsInt(tmp);
+ Py_DECREF(tmp);
+ if (total_size < 0) {
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_ValueError,
+ "size must be a non-negative integer");
+ }
+ goto error;
+ }
+
+ format_spec_obj = PyObject_GetAttr(layout, &_Py_ID(format_spec));
+ if (!format_spec_obj) {
+ goto error;
+ }
+ Py_ssize_t format_spec_size;
+ const char *format_spec = PyUnicode_AsUTF8AndSize(format_spec_obj,
+ &format_spec_size);
+ if (!format_spec) {
+ goto error;
}
if (stginfo->format) {
PyMem_Free(stginfo->format);
stginfo->format = NULL;
}
+ stginfo->format = PyMem_Malloc(format_spec_size + 1);
+ if (!stginfo->format) {
+ PyErr_NoMemory();
+ goto error;
+ }
+ memcpy(stginfo->format, format_spec, format_spec_size + 1);
- if (stginfo->ffi_type_pointer.elements)
- PyMem_Free(stginfo->ffi_type_pointer.elements);
-
- StgInfo *baseinfo;
- if (PyStgInfo_FromType(st, (PyObject *)((PyTypeObject *)type)->tp_base,
- &baseinfo) < 0) {
- return -1;
+ PyObject *layout_fields_obj = PyObject_GetAttr(layout, &_Py_ID(fields));
+ if (!layout_fields_obj) {
+ goto error;
}
- if (baseinfo) {
- stginfo->flags |= (baseinfo->flags &
- (TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD));
+ layout_fields = PySequence_Tuple(layout_fields_obj);
+ Py_DECREF(layout_fields_obj);
+ if (!layout_fields) {
+ goto error;
}
- if (!isStruct) {
- stginfo->flags |= TYPEFLAG_HASUNION;
+ Py_CLEAR(layout);
+
+ Py_ssize_t len = PyTuple_GET_SIZE(layout_fields);
+
+ if (stginfo->ffi_type_pointer.elements) {
+ PyMem_Free(stginfo->ffi_type_pointer.elements);
+ stginfo->ffi_type_pointer.elements = NULL;
}
+
if (baseinfo) {
- size = offset = baseinfo->size;
- align = baseinfo->align;
- union_size = 0;
- total_align = align ? align : 1;
- total_align = max(total_align, forced_alignment);
stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT;
stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, baseinfo->length + len + 1);
if (stginfo->ffi_type_pointer.elements == NULL) {
PyErr_NoMemory();
- return -1;
+ goto error;
}
memset(stginfo->ffi_type_pointer.elements, 0,
sizeof(ffi_type *) * (baseinfo->length + len + 1));
@@ -411,231 +372,61 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
}
ffi_ofs = baseinfo->length;
} else {
- offset = 0;
- size = 0;
- align = 0;
- union_size = 0;
- total_align = forced_alignment;
stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT;
stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1);
if (stginfo->ffi_type_pointer.elements == NULL) {
PyErr_NoMemory();
- return -1;
+ goto error;
}
memset(stginfo->ffi_type_pointer.elements, 0,
sizeof(ffi_type *) * (len + 1));
ffi_ofs = 0;
}
- assert(stginfo->format == NULL);
- if (isStruct) {
- stginfo->format = _ctypes_alloc_format_string(NULL, "T{");
- } else {
- /* PEP3118 doesn't support union. Use 'B' for bytes. */
- stginfo->format = _ctypes_alloc_format_string(NULL, "B");
- }
- if (stginfo->format == NULL)
- return -1;
+ for (Py_ssize_t i = 0; i < len; ++i) {
+ PyObject *prop_obj = PyTuple_GET_ITEM(layout_fields, i);
+ assert(prop_obj);
+ if (!PyType_IsSubtype(Py_TYPE(prop_obj), st->PyCField_Type)) {
+ PyErr_Format(PyExc_TypeError,
+ "fields must be of type CField, got %T", prop_obj);
+ goto error;
- for (i = 0; i < len; ++i) {
- PyObject *name = NULL, *desc = NULL;
- PyObject *pair = PySequence_GetItem(fields, i);
- PyObject *prop;
- Py_ssize_t bitsize = 0;
+ }
+ CFieldObject *prop = (CFieldObject *)prop_obj; // borrow from prop_obj
- if (!pair || !PyArg_ParseTuple(pair, "UO|n", &name, &desc, &bitsize)) {
- PyErr_SetString(PyExc_TypeError,
- "'_fields_' must be a sequence of (name, C type) pairs");
- Py_XDECREF(pair);
- return -1;
+ if (prop->index != i) {
+ PyErr_Format(PyExc_ValueError,
+ "field %R index mismatch (expected %zd, got %zd)",
+ prop->name, i, prop->index);
+ goto error;
}
- if (PyCArrayTypeObject_Check(st, desc)) {
+
+ if (PyCArrayTypeObject_Check(st, prop->proto)) {
arrays_seen = 1;
}
StgInfo *info;
- if (PyStgInfo_FromType(st, desc, &info) < 0) {
- Py_DECREF(pair);
- return -1;
- }
- if (info == NULL) {
- Py_DECREF(pair);
- PyErr_Format(PyExc_TypeError,
- "second item in _fields_ tuple (index %zd) must be a C type",
- i);
- return -1;
+ if (PyStgInfo_FromType(st, prop->proto, &info) < 0) {
+ goto error;
}
+ assert(info);
stginfo->ffi_type_pointer.elements[ffi_ofs + i] = &info->ffi_type_pointer;
if (info->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER))
stginfo->flags |= TYPEFLAG_HASPOINTER;
- stginfo->flags |= info->flags & (TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD);
info->flags |= DICTFLAG_FINAL; /* mark field type final */
- if (PyTuple_Size(pair) == 3) { /* bits specified */
- stginfo->flags |= TYPEFLAG_HASBITFIELD;
- switch(info->ffi_type_pointer.type) {
- case FFI_TYPE_UINT8:
- case FFI_TYPE_UINT16:
- case FFI_TYPE_UINT32:
- case FFI_TYPE_SINT64:
- case FFI_TYPE_UINT64:
- break;
-
- case FFI_TYPE_SINT8:
- case FFI_TYPE_SINT16:
- case FFI_TYPE_SINT32:
- if (info->getfunc != _ctypes_get_fielddesc("c")->getfunc
- && info->getfunc != _ctypes_get_fielddesc("u")->getfunc)
- {
- break;
- }
- _Py_FALLTHROUGH; /* else fall through */
- default:
- PyErr_Format(PyExc_TypeError,
- "bit fields not allowed for type %s",
- ((PyTypeObject *)desc)->tp_name);
- Py_DECREF(pair);
- return -1;
- }
- if (bitsize <= 0 || bitsize > info->size * 8) {
- PyErr_Format(PyExc_ValueError,
- "number of bits invalid for bit field %R",
- name);
- Py_DECREF(pair);
- return -1;
- }
- } else
- bitsize = 0;
-
- if (isStruct) {
- const char *fieldfmt = info->format ? info->format : "B";
- const char *fieldname = PyUnicode_AsUTF8(name);
- char *ptr;
- Py_ssize_t len;
- char *buf;
- Py_ssize_t last_size = size;
- Py_ssize_t padding;
-
- if (fieldname == NULL)
- {
- Py_DECREF(pair);
- return -1;
- }
-
- /* construct the field now, as `prop->offset` is `offset` with
- corrected alignment */
- prop = PyCField_FromDesc(st, desc, i,
- &field_size, bitsize, &bitofs,
- &size, &offset, &align,
- pack, big_endian, layout_mode);
- if (prop == NULL) {
- Py_DECREF(pair);
- return -1;
- }
-
- /* number of bytes between the end of the last field and the start
- of this one */
- padding = ((CFieldObject *)prop)->offset - last_size;
-
- if (padding > 0) {
- ptr = stginfo->format;
- stginfo->format = _ctypes_alloc_format_padding(ptr, padding);
- PyMem_Free(ptr);
- if (stginfo->format == NULL) {
- Py_DECREF(pair);
- Py_DECREF(prop);
- return -1;
- }
- }
-
- len = strlen(fieldname) + strlen(fieldfmt);
-
- buf = PyMem_Malloc(len + 2 + 1);
- if (buf == NULL) {
- Py_DECREF(pair);
- Py_DECREF(prop);
- PyErr_NoMemory();
- return -1;
- }
- sprintf(buf, "%s:%s:", fieldfmt, fieldname);
-
- ptr = stginfo->format;
- if (info->shape != NULL) {
- stginfo->format = _ctypes_alloc_format_string_with_shape(
- info->ndim, info->shape, stginfo->format, buf);
- } else {
- stginfo->format = _ctypes_alloc_format_string(stginfo->format, buf);
- }
- PyMem_Free(ptr);
- PyMem_Free(buf);
-
- if (stginfo->format == NULL) {
- Py_DECREF(pair);
- Py_DECREF(prop);
- return -1;
- }
- } else /* union */ {
- field_size = 0;
- size = 0;
- bitofs = 0;
- offset = 0;
- align = 0;
- prop = PyCField_FromDesc(st, desc, i,
- &field_size, bitsize, &bitofs,
- &size, &offset, &align,
- pack, big_endian, layout_mode);
- if (prop == NULL) {
- Py_DECREF(pair);
- return -1;
- }
- union_size = max(size, union_size);
- }
- total_align = max(align, total_align);
- if (-1 == PyObject_SetAttr(type, name, prop)) {
- Py_DECREF(prop);
- Py_DECREF(pair);
- return -1;
+ if (-1 == PyObject_SetAttr(type, prop->name, prop_obj)) {
+ goto error;
}
- Py_DECREF(pair);
- Py_DECREF(prop);
- }
-
- if (!isStruct) {
- size = union_size;
- }
-
- /* Adjust the size according to the alignment requirements */
- aligned_size = ((size + total_align - 1) / total_align) * total_align;
-
- if (isStruct) {
- char *ptr;
- Py_ssize_t padding;
-
- /* Pad up to the full size of the struct */
- padding = aligned_size - size;
- if (padding > 0) {
- ptr = stginfo->format;
- stginfo->format = _ctypes_alloc_format_padding(ptr, padding);
- PyMem_Free(ptr);
- if (stginfo->format == NULL) {
- return -1;
- }
- }
-
- ptr = stginfo->format;
- stginfo->format = _ctypes_alloc_format_string(stginfo->format, "}");
- PyMem_Free(ptr);
- if (stginfo->format == NULL)
- return -1;
}
stginfo->ffi_type_pointer.alignment = Py_SAFE_DOWNCAST(total_align,
Py_ssize_t,
unsigned short);
- stginfo->ffi_type_pointer.size = aligned_size;
+ stginfo->ffi_type_pointer.size = total_size;
- stginfo->size = aligned_size;
+ stginfo->size = total_size;
stginfo->align = total_align;
stginfo->length = ffi_ofs + len;
@@ -650,7 +441,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
# define MAX_STRUCT_SIZE 16
#endif
- if (arrays_seen && (size <= MAX_STRUCT_SIZE)) {
+ if (arrays_seen && (total_size <= MAX_STRUCT_SIZE)) {
/*
* See bpo-22273 and gh-110190. Arrays are normally treated as
* pointers, which is fine when an array name is being passed as
@@ -725,35 +516,19 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
Py_ssize_t struct_index = 0; /* index into dummy structs */
/* first pass to see how much memory to allocate */
- for (i = 0; i < len; ++i) {
- PyObject *name, *desc;
- PyObject *pair = PySequence_GetItem(fields, i);
- int bitsize = 0;
-
- if (pair == NULL) {
- return -1;
- }
- if (!PyArg_ParseTuple(pair, "UO|i", &name, &desc, &bitsize)) {
- PyErr_SetString(PyExc_TypeError,
- "'_fields_' must be a sequence of (name, C type) pairs");
- Py_DECREF(pair);
- return -1;
- }
+ for (Py_ssize_t i = 0; i < len; ++i) {
+ PyObject *prop_obj = PyTuple_GET_ITEM(layout_fields, i); // borrowed
+ assert(prop_obj);
+ assert(PyType_IsSubtype(Py_TYPE(prop_obj), st->PyCField_Type));
+ CFieldObject *prop = (CFieldObject *)prop_obj; // borrowed
StgInfo *info;
- if (PyStgInfo_FromType(st, desc, &info) < 0) {
- Py_DECREF(pair);
- return -1;
- }
- if (info == NULL) {
- Py_DECREF(pair);
- PyErr_Format(PyExc_TypeError,
- "second item in _fields_ tuple (index %zd) must be a C type",
- i);
- return -1;
+ if (PyStgInfo_FromType(st, prop->proto, &info) < 0) {
+ goto error;
}
+ assert(info);
- if (!PyCArrayTypeObject_Check(st, desc)) {
+ if (!PyCArrayTypeObject_Check(st, prop->proto)) {
/* Not an array. Just need an ffi_type pointer. */
num_ffi_type_pointers++;
}
@@ -763,15 +538,13 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
StgInfo *einfo;
if (PyStgInfo_FromType(st, info->proto, &einfo) < 0) {
- Py_DECREF(pair);
- return -1;
+ goto error;
}
if (einfo == NULL) {
- Py_DECREF(pair);
PyErr_Format(PyExc_TypeError,
"second item in _fields_ tuple (index %zd) must be a C type",
i);
- return -1;
+ goto error;
}
/*
* We need one extra ffi_type to hold the struct, and one
@@ -781,7 +554,6 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
num_ffi_types++;
num_ffi_type_pointers += length + 1;
}
- Py_DECREF(pair);
}
/*
@@ -798,7 +570,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
if (type_block == NULL) {
PyErr_NoMemory();
- return -1;
+ goto error;
}
/*
* the first block takes up ffi_ofs + len + 1 which is the pointers *
@@ -822,48 +594,21 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
element_index = ffi_ofs;
/* second pass to actually set the type pointers */
- for (i = 0; i < len; ++i) {
- PyObject *name, *desc;
- PyObject *pair = PySequence_GetItem(fields, i);
- int bitsize = 0;
-
- if (pair == NULL) {
- PyMem_Free(type_block);
- return -1;
- }
- /* In theory, we made this call in the first pass, so it *shouldn't*
- * fail. However, you never know, and the code above might change
- * later - keeping the check in here is a tad defensive but it
- * will affect program size only slightly and performance hardly at
- * all.
- */
- if (!PyArg_ParseTuple(pair, "UO|i", &name, &desc, &bitsize)) {
- PyErr_SetString(PyExc_TypeError,
- "'_fields_' must be a sequence of (name, C type) pairs");
- Py_DECREF(pair);
- PyMem_Free(type_block);
- return -1;
- }
+ for (Py_ssize_t i = 0; i < len; ++i) {
+ PyObject *prop_obj = PyTuple_GET_ITEM(layout_fields, i); // borrowed
+ assert(prop_obj);
+ assert(PyType_IsSubtype(Py_TYPE(prop_obj), st->PyCField_Type));
+ CFieldObject *prop = (CFieldObject *)prop_obj; // borrowed
StgInfo *info;
- if (PyStgInfo_FromType(st, desc, &info) < 0) {
- Py_DECREF(pair);
- PyMem_Free(type_block);
- return -1;
- }
-
- /* Possibly this check could be avoided, but see above comment. */
- if (info == NULL) {
- Py_DECREF(pair);
+ if (PyStgInfo_FromType(st, prop->proto, &info) < 0) {
PyMem_Free(type_block);
- PyErr_Format(PyExc_TypeError,
- "second item in _fields_ tuple (index %zd) must be a C type",
- i);
- return -1;
+ goto error;
}
+ assert(info);
assert(element_index < (ffi_ofs + len)); /* will be used below */
- if (!PyCArrayTypeObject_Check(st, desc)) {
+ if (!PyCArrayTypeObject_Check(st, prop->proto)) {
/* Not an array. Just copy over the element ffi_type. */
element_types[element_index++] = &info->ffi_type_pointer;
}
@@ -871,17 +616,15 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
Py_ssize_t length = info->length;
StgInfo *einfo;
if (PyStgInfo_FromType(st, info->proto, &einfo) < 0) {
- Py_DECREF(pair);
PyMem_Free(type_block);
- return -1;
+ goto error;
}
if (einfo == NULL) {
- Py_DECREF(pair);
PyMem_Free(type_block);
PyErr_Format(PyExc_TypeError,
"second item in _fields_ tuple (index %zd) must be a C type",
i);
- return -1;
+ goto error;
}
element_types[element_index++] = &structs[struct_index];
structs[struct_index].size = length * einfo->ffi_type_pointer.size;
@@ -898,7 +641,6 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
assert(dummy_index < (num_ffi_type_pointers));
dummy_types[dummy_index++] = NULL;
}
- Py_DECREF(pair);
}
element_types[element_index] = NULL;
@@ -916,9 +658,14 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
if (stginfo->flags & DICTFLAG_FINAL) {
PyErr_SetString(PyExc_AttributeError,
"Structure or union cannot contain itself");
- return -1;
+ goto error;
}
stginfo->flags |= DICTFLAG_FINAL;
- return MakeAnonFields(type);
+ retval = MakeAnonFields(type);
+error:
+ Py_XDECREF(layout_fields);
+ Py_XDECREF(layout);
+ Py_XDECREF(format_spec_obj);
+ return retval;
}