LCOV - code coverage report
Current view: | top level - Modules/_ctypes - stgdict.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 26 | 447 | 5.8 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 4 | 11 | 36.4 %
|  |  | Branches: | 10 | 231 | 4.3 %

               Branch data     Line data    Source code
           1                 :            : #ifndef Py_BUILD_CORE_BUILTIN
           2                 :            : #  define Py_BUILD_CORE_MODULE 1
           3                 :            : #endif
           4                 :            :
           5                 :            : #include "Python.h"
           6                 :            : // windows.h must be included before pycore internal headers
           7                 :            : #ifdef MS_WIN32
           8                 :            : #  include <windows.h>
           9                 :            : #endif
          10                 :            :
          11                 :            : #include "pycore_call.h"          // _PyObject_CallNoArgs()
          12                 :            : #include <ffi.h>
          13                 :            : #ifdef MS_WIN32
          14                 :            : #  include <malloc.h>
          15                 :            : #endif
          16                 :            : #include "ctypes.h"
          17                 :            :
          18                 :            : /******************************************************************/
          19                 :            : /*
          20                 :            :   StdDict - a dictionary subclass, containing additional C accessible fields
          21                 :            :
          22                 :            :   XXX blabla more
          23                 :            : */
          24                 :            :
          25                 :            : /* Seems we need this, otherwise we get problems when calling
          26                 :            :  * PyDict_SetItem() (ma_lookup is NULL)
          27                 :            :  */
          28                 :            : static int
          29                 :         38 : PyCStgDict_init(StgDictObject *self, PyObject *args, PyObject *kwds)
          30                 :            : {
          31         [ -  + ]:         38 :     if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
          32                 :          0 :         return -1;
          33                 :         38 :     self->format = NULL;
          34                 :         38 :     self->ndim = 0;
          35                 :         38 :     self->shape = NULL;
          36                 :         38 :     return 0;
          37                 :            : }
          38                 :            :
          39                 :            : static int
          40                 :          2 : PyCStgDict_clear(StgDictObject *self)
          41                 :            : {
          42         [ -  + ]:          2 :     Py_CLEAR(self->proto);
          43         [ -  + ]:          2 :     Py_CLEAR(self->argtypes);
          44         [ -  + ]:          2 :     Py_CLEAR(self->converters);
          45         [ -  + ]:          2 :     Py_CLEAR(self->restype);
          46         [ -  + ]:          2 :     Py_CLEAR(self->checker);
          47                 :          2 :     return 0;
          48                 :            : }
          49                 :            :
          50                 :            : static void
          51                 :          2 : PyCStgDict_dealloc(StgDictObject *self)
          52                 :            : {
          53                 :          2 :     PyCStgDict_clear(self);
          54                 :          2 :     PyMem_Free(self->format);
          55                 :          2 :     PyMem_Free(self->shape);
          56                 :          2 :     PyMem_Free(self->ffi_type_pointer.elements);
          57                 :          2 :     PyDict_Type.tp_dealloc((PyObject *)self);
          58                 :          2 : }
          59                 :            :
          60                 :            : static PyObject *
          61                 :          0 : PyCStgDict_sizeof(StgDictObject *self, void *unused)
          62                 :            : {
          63                 :            :     Py_ssize_t res;
          64                 :            :
          65                 :          0 :     res = _PyDict_SizeOf((PyDictObject *)self);
          66                 :          0 :     res += sizeof(StgDictObject) - sizeof(PyDictObject);
          67         [ #  # ]:          0 :     if (self->format)
          68                 :          0 :         res += strlen(self->format) + 1;
          69                 :          0 :     res += self->ndim * sizeof(Py_ssize_t);
          70         [ #  # ]:          0 :     if (self->ffi_type_pointer.elements)
          71                 :          0 :         res += (self->length + 1) * sizeof(ffi_type *);
          72                 :          0 :     return PyLong_FromSsize_t(res);
          73                 :            : }
          74                 :            :
          75                 :            : int
          76                 :          0 : PyCStgDict_clone(StgDictObject *dst, StgDictObject *src)
          77                 :            : {
          78                 :            :     char *d, *s;
          79                 :            :     Py_ssize_t size;
          80                 :            :
          81                 :          0 :     PyCStgDict_clear(dst);
          82                 :          0 :     PyMem_Free(dst->ffi_type_pointer.elements);
          83                 :          0 :     PyMem_Free(dst->format);
          84                 :          0 :     dst->format = NULL;
          85                 :          0 :     PyMem_Free(dst->shape);
          86                 :          0 :     dst->shape = NULL;
          87                 :          0 :     dst->ffi_type_pointer.elements = NULL;
          88                 :            :
          89                 :          0 :     d = (char *)dst;
          90                 :          0 :     s = (char *)src;
          91                 :          0 :     memcpy(d + sizeof(PyDictObject),
          92                 :          0 :            s + sizeof(PyDictObject),
          93                 :            :            sizeof(StgDictObject) - sizeof(PyDictObject));
          94                 :            :
          95                 :          0 :     Py_XINCREF(dst->proto);
          96                 :          0 :     Py_XINCREF(dst->argtypes);
          97                 :          0 :     Py_XINCREF(dst->converters);
          98                 :          0 :     Py_XINCREF(dst->restype);
          99                 :          0 :     Py_XINCREF(dst->checker);
         100                 :            :
         101         [ #  # ]:          0 :     if (src->format) {
         102                 :          0 :         dst->format = PyMem_Malloc(strlen(src->format) + 1);
         103         [ #  # ]:          0 :         if (dst->format == NULL) {
         104                 :          0 :             PyErr_NoMemory();
         105                 :          0 :             return -1;
         106                 :            :         }
         107                 :          0 :         strcpy(dst->format, src->format);
         108                 :            :     }
         109         [ #  # ]:          0 :     if (src->shape) {
         110                 :          0 :         dst->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src->ndim);
         111         [ #  # ]:          0 :         if (dst->shape == NULL) {
         112                 :          0 :             PyErr_NoMemory();
         113                 :          0 :             return -1;
         114                 :            :         }
         115                 :          0 :         memcpy(dst->shape, src->shape,
         116                 :          0 :                sizeof(Py_ssize_t) * src->ndim);
         117                 :            :     }
         118                 :            :
         119         [ #  # ]:          0 :     if (src->ffi_type_pointer.elements == NULL)
         120                 :          0 :         return 0;
         121                 :          0 :     size = sizeof(ffi_type *) * (src->length + 1);
         122                 :          0 :     dst->ffi_type_pointer.elements = PyMem_Malloc(size);
         123         [ #  # ]:          0 :     if (dst->ffi_type_pointer.elements == NULL) {
         124                 :          0 :         PyErr_NoMemory();
         125                 :          0 :         return -1;
         126                 :            :     }
         127                 :          0 :     memcpy(dst->ffi_type_pointer.elements,
         128                 :          0 :            src->ffi_type_pointer.elements,
         129                 :            :            size);
         130                 :          0 :     return 0;
         131                 :            : }
         132                 :            :
         133                 :            : static struct PyMethodDef PyCStgDict_methods[] = {
         134                 :            :     {"__sizeof__", (PyCFunction)PyCStgDict_sizeof, METH_NOARGS},
         135                 :            :     {NULL, NULL}                /* sentinel */
         136                 :            : };
         137                 :            :
         138                 :            : PyTypeObject PyCStgDict_Type = {
         139                 :            :     PyVarObject_HEAD_INIT(NULL, 0)
         140                 :            :     "StgDict",
         141                 :            :     sizeof(StgDictObject),
         142                 :            :     0,
         143                 :            :     (destructor)PyCStgDict_dealloc,             /* tp_dealloc */
         144                 :            :     0,                                          /* tp_vectorcall_offset */
         145                 :            :     0,                                          /* tp_getattr */
         146                 :            :     0,                                          /* tp_setattr */
         147                 :            :     0,                                          /* tp_as_async */
         148                 :            :     0,                                          /* tp_repr */
         149                 :            :     0,                                          /* tp_as_number */
         150                 :            :     0,                                          /* tp_as_sequence */
         151                 :            :     0,                                          /* tp_as_mapping */
         152                 :            :     0,                                          /* tp_hash */
         153                 :            :     0,                                          /* tp_call */
         154                 :            :     0,                                          /* tp_str */
         155                 :            :     0,                                          /* tp_getattro */
         156                 :            :     0,                                          /* tp_setattro */
         157                 :            :     0,                                          /* tp_as_buffer */
         158                 :            :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
         159                 :            :     0,                                          /* tp_doc */
         160                 :            :     0,                                          /* tp_traverse */
         161                 :            :     0,                                          /* tp_clear */
         162                 :            :     0,                                          /* tp_richcompare */
         163                 :            :     0,                                          /* tp_weaklistoffset */
         164                 :            :     0,                                          /* tp_iter */
         165                 :            :     0,                                          /* tp_iternext */
         166                 :            :     PyCStgDict_methods,                         /* tp_methods */
         167                 :            :     0,                                          /* tp_members */
         168                 :            :     0,                                          /* tp_getset */
         169                 :            :     0,                                          /* tp_base */
         170                 :            :     0,                                          /* tp_dict */
         171                 :            :     0,                                          /* tp_descr_get */
         172                 :            :     0,                                          /* tp_descr_set */
         173                 :            :     0,                                          /* tp_dictoffset */
         174                 :            :     (initproc)PyCStgDict_init,                          /* tp_init */
         175                 :            :     0,                                          /* tp_alloc */
         176                 :            :     0,                                          /* tp_new */
         177                 :            :     0,                                          /* tp_free */
         178                 :            : };
         179                 :            :
         180                 :            : /* May return NULL, but does not set an exception! */
         181                 :            : StgDictObject *
         182                 :        433 : PyType_stgdict(PyObject *obj)
         183                 :            : {
         184                 :            :     PyTypeObject *type;
         185                 :            :
         186         [ -  + ]:        433 :     if (!PyType_Check(obj))
         187                 :          0 :         return NULL;
         188                 :        433 :     type = (PyTypeObject *)obj;
         189   [ +  -  +  + ]:        433 :     if (!type->tp_dict || !PyCStgDict_CheckExact(type->tp_dict))
         190                 :          2 :         return NULL;
         191                 :        431 :     return (StgDictObject *)type->tp_dict;
         192                 :            : }
         193                 :            :
         194                 :            : /* May return NULL, but does not set an exception! */
         195                 :            : /*
         196                 :            :   This function should be as fast as possible, so we don't call PyType_stgdict
         197                 :            :   above but inline the code, and avoid the PyType_Check().
         198                 :            : */
         199                 :            : StgDictObject *
         200                 :          0 : PyObject_stgdict(PyObject *self)
         201                 :            : {
         202                 :          0 :     PyTypeObject *type = Py_TYPE(self);
         203   [ #  #  #  # ]:          0 :     if (!type->tp_dict || !PyCStgDict_CheckExact(type->tp_dict))
         204                 :          0 :         return NULL;
         205                 :          0 :     return (StgDictObject *)type->tp_dict;
         206                 :            : }
         207                 :            :
         208                 :            : /* descr is the descriptor for a field marked as anonymous.  Get all the
         209                 :            :  _fields_ descriptors from descr->proto, create new descriptors with offset
         210                 :            :  and index adjusted, and stuff them into type.
         211                 :            :  */
         212                 :            : static int
         213                 :          0 : MakeFields(PyObject *type, CFieldObject *descr,
         214                 :            :            Py_ssize_t index, Py_ssize_t offset)
         215                 :            : {
         216                 :            :     Py_ssize_t i;
         217                 :            :     PyObject *fields;
         218                 :            :     PyObject *fieldlist;
         219                 :            :
         220                 :          0 :     fields = PyObject_GetAttrString(descr->proto, "_fields_");
         221         [ #  # ]:          0 :     if (fields == NULL)
         222                 :          0 :         return -1;
         223                 :          0 :     fieldlist = PySequence_Fast(fields, "_fields_ must be a sequence");
         224                 :          0 :     Py_DECREF(fields);
         225         [ #  # ]:          0 :     if (fieldlist == NULL)
         226                 :          0 :         return -1;
         227                 :            :
         228   [ #  #  #  # ]:          0 :     for (i = 0; i < PySequence_Fast_GET_SIZE(fieldlist); ++i) {
         229         [ #  # ]:          0 :         PyObject *pair = PySequence_Fast_GET_ITEM(fieldlist, i); /* borrowed */
         230                 :            :         PyObject *fname, *ftype, *bits;
         231                 :            :         CFieldObject *fdescr;
         232                 :            :         CFieldObject *new_descr;
         233                 :            :         /* Convert to PyArg_UnpackTuple... */
         234         [ #  # ]:          0 :         if (!PyArg_ParseTuple(pair, "OO|O", &fname, &ftype, &bits)) {
         235                 :          0 :             Py_DECREF(fieldlist);
         236                 :          0 :             return -1;
         237                 :            :         }
         238                 :          0 :         fdescr = (CFieldObject *)PyObject_GetAttr(descr->proto, fname);
         239         [ #  # ]:          0 :         if (fdescr == NULL) {
         240                 :          0 :             Py_DECREF(fieldlist);
         241                 :          0 :             return -1;
         242                 :            :         }
         243         [ #  # ]:          0 :         if (!Py_IS_TYPE(fdescr, &PyCField_Type)) {
         244                 :          0 :             PyErr_SetString(PyExc_TypeError, "unexpected type");
         245                 :          0 :             Py_DECREF(fdescr);
         246                 :          0 :             Py_DECREF(fieldlist);
         247                 :          0 :             return -1;
         248                 :            :         }
         249         [ #  # ]:          0 :         if (fdescr->anonymous) {
         250                 :          0 :             int rc = MakeFields(type, fdescr,
         251                 :          0 :                                 index + fdescr->index,
         252                 :          0 :                                 offset + fdescr->offset);
         253                 :          0 :             Py_DECREF(fdescr);
         254         [ #  # ]:          0 :             if (rc == -1) {
         255                 :          0 :                 Py_DECREF(fieldlist);
         256                 :          0 :                 return -1;
         257                 :            :             }
         258                 :          0 :             continue;
         259                 :            :         }
         260                 :          0 :         new_descr = (CFieldObject *)PyCField_Type.tp_alloc((PyTypeObject *)&PyCField_Type, 0);
         261         [ #  # ]:          0 :         if (new_descr == NULL) {
         262                 :          0 :             Py_DECREF(fdescr);
         263                 :          0 :             Py_DECREF(fieldlist);
         264                 :          0 :             return -1;
         265                 :            :         }
         266                 :            :         assert(Py_IS_TYPE(new_descr, &PyCField_Type));
         267                 :          0 :         new_descr->size = fdescr->size;
         268                 :          0 :         new_descr->offset = fdescr->offset + offset;
         269                 :          0 :         new_descr->index = fdescr->index + index;
         270                 :          0 :         new_descr->proto = Py_XNewRef(fdescr->proto);
         271                 :          0 :         new_descr->getfunc = fdescr->getfunc;
         272                 :          0 :         new_descr->setfunc = fdescr->setfunc;
         273                 :            :
         274                 :          0 :         Py_DECREF(fdescr);
         275                 :            :
         276         [ #  # ]:          0 :         if (-1 == PyObject_SetAttr(type, fname, (PyObject *)new_descr)) {
         277                 :          0 :             Py_DECREF(fieldlist);
         278                 :          0 :             Py_DECREF(new_descr);
         279                 :          0 :             return -1;
         280                 :            :         }
         281                 :          0 :         Py_DECREF(new_descr);
         282                 :            :     }
         283                 :          0 :     Py_DECREF(fieldlist);
         284                 :          0 :     return 0;
         285                 :            : }
         286                 :            :
         287                 :            : /* Iterate over the names in the type's _anonymous_ attribute, if present,
         288                 :            :  */
         289                 :            : static int
         290                 :          0 : MakeAnonFields(PyObject *type)
         291                 :            : {
         292                 :            :     PyObject *anon;
         293                 :            :     PyObject *anon_names;
         294                 :            :     Py_ssize_t i;
         295                 :            :
         296         [ #  # ]:          0 :     if (_PyObject_LookupAttr(type, &_Py_ID(_anonymous_), &anon) < 0) {
         297                 :          0 :         return -1;
         298                 :            :     }
         299         [ #  # ]:          0 :     if (anon == NULL) {
         300                 :          0 :         return 0;
         301                 :            :     }
         302                 :          0 :     anon_names = PySequence_Fast(anon, "_anonymous_ must be a sequence");
         303                 :          0 :     Py_DECREF(anon);
         304         [ #  # ]:          0 :     if (anon_names == NULL)
         305                 :          0 :         return -1;
         306                 :            :
         307   [ #  #  #  # ]:          0 :     for (i = 0; i < PySequence_Fast_GET_SIZE(anon_names); ++i) {
         308         [ #  # ]:          0 :         PyObject *fname = PySequence_Fast_GET_ITEM(anon_names, i); /* borrowed */
         309                 :          0 :         CFieldObject *descr = (CFieldObject *)PyObject_GetAttr(type, fname);
         310         [ #  # ]:          0 :         if (descr == NULL) {
         311                 :          0 :             Py_DECREF(anon_names);
         312                 :          0 :             return -1;
         313                 :            :         }
         314         [ #  # ]:          0 :         if (!Py_IS_TYPE(descr, &PyCField_Type)) {
         315                 :          0 :             PyErr_Format(PyExc_AttributeError,
         316                 :            :                          "'%U' is specified in _anonymous_ but not in "
         317                 :            :                          "_fields_",
         318                 :            :                          fname);
         319                 :          0 :             Py_DECREF(anon_names);
         320                 :          0 :             Py_DECREF(descr);
         321                 :          0 :             return -1;
         322                 :            :         }
         323                 :          0 :         descr->anonymous = 1;
         324                 :            :
         325                 :            :         /* descr is in the field descriptor. */
         326         [ #  # ]:          0 :         if (-1 == MakeFields(type, (CFieldObject *)descr,
         327                 :            :                              ((CFieldObject *)descr)->index,
         328                 :            :                              ((CFieldObject *)descr)->offset)) {
         329                 :          0 :             Py_DECREF(descr);
         330                 :          0 :             Py_DECREF(anon_names);
         331                 :          0 :             return -1;
         332                 :            :         }
         333                 :          0 :         Py_DECREF(descr);
         334                 :            :     }
         335                 :            :
         336                 :          0 :     Py_DECREF(anon_names);
         337                 :          0 :     return 0;
         338                 :            : }
         339                 :            :
         340                 :            : /*
         341                 :            :   Allocate a memory block for a pep3118 format string, copy prefix (if
         342                 :            :   non-null) into it and append `{padding}x` to the end.
         343                 :            :   Returns NULL on failure, with the error indicator set.
         344                 :            : */
         345                 :            : char *
         346                 :          0 : _ctypes_alloc_format_padding(const char *prefix, Py_ssize_t padding)
         347                 :            : {
         348                 :            :     /* int64 decimal characters + x + null */
         349                 :            :     char buf[19 + 1 + 1];
         350                 :            :
         351                 :            :     assert(padding > 0);
         352                 :            :
         353         [ #  # ]:          0 :     if (padding == 1) {
         354                 :            :         /* Use x instead of 1x, for brevity */
         355                 :          0 :         return _ctypes_alloc_format_string(prefix, "x");
         356                 :            :     }
         357                 :            :
         358                 :          0 :     int ret = PyOS_snprintf(buf, sizeof(buf), "%zdx", padding); (void)ret;
         359                 :            :     assert(0 <= ret && ret < (Py_ssize_t)sizeof(buf));
         360                 :          0 :     return _ctypes_alloc_format_string(prefix, buf);
         361                 :            : }
         362                 :            :
         363                 :            : /*
         364                 :            :   Retrieve the (optional) _pack_ attribute from a type, the _fields_ attribute,
         365                 :            :   and create an StgDictObject.  Used for Structure and Union subclasses.
         366                 :            : */
         367                 :            : int
         368                 :          0 : PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
         369                 :            : {
         370                 :            :     StgDictObject *stgdict, *basedict;
         371                 :            :     Py_ssize_t len, offset, size, align, i;
         372                 :            :     Py_ssize_t union_size, total_align, aligned_size;
         373                 :          0 :     Py_ssize_t field_size = 0;
         374                 :            :     int bitofs;
         375                 :            :     PyObject *tmp;
         376                 :            :     int pack;
         377                 :            :     Py_ssize_t ffi_ofs;
         378                 :            :     int big_endian;
         379                 :          0 :     int arrays_seen = 0;
         380                 :            :
         381         [ #  # ]:          0 :     if (fields == NULL)
         382                 :          0 :         return 0;
         383                 :            :
         384         [ #  # ]:          0 :     if (_PyObject_LookupAttr(type, &_Py_ID(_swappedbytes_), &tmp) < 0) {
         385                 :          0 :         return -1;
         386                 :            :     }
         387         [ #  # ]:          0 :     if (tmp) {
         388                 :          0 :         Py_DECREF(tmp);
         389                 :          0 :         big_endian = !PY_BIG_ENDIAN;
         390                 :            :     }
         391                 :            :     else {
         392                 :          0 :         big_endian = PY_BIG_ENDIAN;
         393                 :            :     }
         394                 :            :
         395         [ #  # ]:          0 :     if (_PyObject_LookupAttr(type, &_Py_ID(_pack_), &tmp) < 0) {
         396                 :          0 :         return -1;
         397                 :            :     }
         398         [ #  # ]:          0 :     if (tmp) {
         399                 :          0 :         pack = _PyLong_AsInt(tmp);
         400                 :          0 :         Py_DECREF(tmp);
         401         [ #  # ]:          0 :         if (pack < 0) {
         402   [ #  #  #  # ]:          0 :             if (!PyErr_Occurred() ||
         403         [ #  # ]:          0 :                 PyErr_ExceptionMatches(PyExc_TypeError) ||
         404                 :          0 :                 PyErr_ExceptionMatches(PyExc_OverflowError))
         405                 :            :             {
         406                 :          0 :                 PyErr_SetString(PyExc_ValueError,
         407                 :            :                                 "_pack_ must be a non-negative integer");
         408                 :            :             }
         409                 :          0 :             return -1;
         410                 :            :         }
         411                 :            :     }
         412                 :            :     else {
         413                 :            :         /* Setting `_pack_ = 0` amounts to using the default alignment */
         414                 :          0 :         pack = 0;
         415                 :            :     }
         416                 :            :
         417                 :          0 :     len = PySequence_Size(fields);
         418         [ #  # ]:          0 :     if (len == -1) {
         419         [ #  # ]:          0 :         if (PyErr_ExceptionMatches(PyExc_TypeError)) {
         420                 :          0 :             PyErr_SetString(PyExc_TypeError,
         421                 :            :                             "'_fields_' must be a sequence of pairs");
         422                 :            :         }
         423                 :          0 :         return -1;
         424                 :            :     }
         425                 :            :
         426                 :          0 :     stgdict = PyType_stgdict(type);
         427         [ #  # ]:          0 :     if (!stgdict) {
         428                 :          0 :         PyErr_SetString(PyExc_TypeError,
         429                 :            :                         "ctypes state is not initialized");
         430                 :          0 :         return -1;
         431                 :            :     }
         432                 :            :     /* If this structure/union is already marked final we cannot assign
         433                 :            :        _fields_ anymore. */
         434                 :            :
         435         [ #  # ]:          0 :     if (stgdict->flags & DICTFLAG_FINAL) {/* is final ? */
         436                 :          0 :         PyErr_SetString(PyExc_AttributeError,
         437                 :            :                         "_fields_ is final");
         438                 :          0 :         return -1;
         439                 :            :     }
         440                 :            :
         441         [ #  # ]:          0 :     if (stgdict->format) {
         442                 :          0 :         PyMem_Free(stgdict->format);
         443                 :          0 :         stgdict->format = NULL;
         444                 :            :     }
         445                 :            :
         446         [ #  # ]:          0 :     if (stgdict->ffi_type_pointer.elements)
         447                 :          0 :         PyMem_Free(stgdict->ffi_type_pointer.elements);
         448                 :            :
         449                 :          0 :     basedict = PyType_stgdict((PyObject *)((PyTypeObject *)type)->tp_base);
         450         [ #  # ]:          0 :     if (basedict) {
         451                 :          0 :         stgdict->flags |= (basedict->flags &
         452                 :            :                            (TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD));
         453                 :            :     }
         454         [ #  # ]:          0 :     if (!isStruct) {
         455                 :          0 :         stgdict->flags |= TYPEFLAG_HASUNION;
         456                 :            :     }
         457         [ #  # ]:          0 :     if (basedict) {
         458                 :          0 :         size = offset = basedict->size;
         459                 :          0 :         align = basedict->align;
         460                 :          0 :         union_size = 0;
         461         [ #  # ]:          0 :         total_align = align ? align : 1;
         462                 :          0 :         stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT;
         463         [ #  # ]:          0 :         stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, basedict->length + len + 1);
         464         [ #  # ]:          0 :         if (stgdict->ffi_type_pointer.elements == NULL) {
         465                 :          0 :             PyErr_NoMemory();
         466                 :          0 :             return -1;
         467                 :            :         }
         468                 :          0 :         memset(stgdict->ffi_type_pointer.elements, 0,
         469                 :          0 :                sizeof(ffi_type *) * (basedict->length + len + 1));
         470         [ #  # ]:          0 :         if (basedict->length > 0) {
         471                 :          0 :             memcpy(stgdict->ffi_type_pointer.elements,
         472                 :          0 :                    basedict->ffi_type_pointer.elements,
         473                 :          0 :                    sizeof(ffi_type *) * (basedict->length));
         474                 :            :         }
         475                 :          0 :         ffi_ofs = basedict->length;
         476                 :            :     } else {
         477                 :          0 :         offset = 0;
         478                 :          0 :         size = 0;
         479                 :          0 :         align = 0;
         480                 :          0 :         union_size = 0;
         481                 :          0 :         total_align = 1;
         482                 :          0 :         stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT;
         483         [ #  # ]:          0 :         stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1);
         484         [ #  # ]:          0 :         if (stgdict->ffi_type_pointer.elements == NULL) {
         485                 :          0 :             PyErr_NoMemory();
         486                 :          0 :             return -1;
         487                 :            :         }
         488                 :          0 :         memset(stgdict->ffi_type_pointer.elements, 0,
         489                 :          0 :                sizeof(ffi_type *) * (len + 1));
         490                 :          0 :         ffi_ofs = 0;
         491                 :            :     }
         492                 :            :
         493                 :            :     assert(stgdict->format == NULL);
         494         [ #  # ]:          0 :     if (isStruct) {
         495                 :          0 :         stgdict->format = _ctypes_alloc_format_string(NULL, "T{");
         496                 :            :     } else {
         497                 :            :         /* PEP3118 doesn't support union. Use 'B' for bytes. */
         498                 :          0 :         stgdict->format = _ctypes_alloc_format_string(NULL, "B");
         499                 :            :     }
         500         [ #  # ]:          0 :     if (stgdict->format == NULL)
         501                 :          0 :         return -1;
         502                 :            :
         503         [ #  # ]:          0 :     for (i = 0; i < len; ++i) {
         504                 :          0 :         PyObject *name = NULL, *desc = NULL;
         505                 :          0 :         PyObject *pair = PySequence_GetItem(fields, i);
         506                 :            :         PyObject *prop;
         507                 :            :         StgDictObject *dict;
         508                 :          0 :         int bitsize = 0;
         509                 :            :
         510   [ #  #  #  # ]:          0 :         if (!pair || !PyArg_ParseTuple(pair, "UO|i", &name, &desc, &bitsize)) {
         511                 :          0 :             PyErr_SetString(PyExc_TypeError,
         512                 :            :                             "'_fields_' must be a sequence of (name, C type) pairs");
         513                 :          0 :             Py_XDECREF(pair);
         514                 :          0 :             return -1;
         515                 :            :         }
         516         [ #  # ]:          0 :         if (PyCArrayTypeObject_Check(desc))
         517                 :          0 :             arrays_seen = 1;
         518                 :          0 :         dict = PyType_stgdict(desc);
         519         [ #  # ]:          0 :         if (dict == NULL) {
         520                 :          0 :             Py_DECREF(pair);
         521                 :          0 :             PyErr_Format(PyExc_TypeError,
         522                 :            :                          "second item in _fields_ tuple (index %zd) must be a C type",
         523                 :            :                          i);
         524                 :          0 :             return -1;
         525                 :            :         }
         526                 :          0 :         stgdict->ffi_type_pointer.elements[ffi_ofs + i] = &dict->ffi_type_pointer;
         527         [ #  # ]:          0 :         if (dict->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER))
         528                 :          0 :             stgdict->flags |= TYPEFLAG_HASPOINTER;
         529                 :          0 :         stgdict->flags |= dict->flags & (TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD);
         530                 :          0 :         dict->flags |= DICTFLAG_FINAL; /* mark field type final */
         531         [ #  # ]:          0 :         if (PyTuple_Size(pair) == 3) { /* bits specified */
         532                 :          0 :             stgdict->flags |= TYPEFLAG_HASBITFIELD;
         533      [ #  #  # ]:          0 :             switch(dict->ffi_type_pointer.type) {
         534                 :          0 :             case FFI_TYPE_UINT8:
         535                 :            :             case FFI_TYPE_UINT16:
         536                 :            :             case FFI_TYPE_UINT32:
         537                 :            :             case FFI_TYPE_SINT64:
         538                 :            :             case FFI_TYPE_UINT64:
         539                 :          0 :                 break;
         540                 :            :
         541                 :          0 :             case FFI_TYPE_SINT8:
         542                 :            :             case FFI_TYPE_SINT16:
         543                 :            :             case FFI_TYPE_SINT32:
         544         [ #  # ]:          0 :                 if (dict->getfunc != _ctypes_get_fielddesc("c")->getfunc
         545         [ #  # ]:          0 :                     && dict->getfunc != _ctypes_get_fielddesc("u")->getfunc
         546                 :            :                     )
         547                 :          0 :                     break;
         548                 :            :                 /* else fall through */
         549                 :            :             default:
         550                 :          0 :                 PyErr_Format(PyExc_TypeError,
         551                 :            :                              "bit fields not allowed for type %s",
         552                 :          0 :                              ((PyTypeObject *)desc)->tp_name);
         553                 :          0 :                 Py_DECREF(pair);
         554                 :          0 :                 return -1;
         555                 :            :             }
         556   [ #  #  #  # ]:          0 :             if (bitsize <= 0 || bitsize > dict->size * 8) {
         557                 :          0 :                 PyErr_SetString(PyExc_ValueError,
         558                 :            :                                 "number of bits invalid for bit field");
         559                 :          0 :                 Py_DECREF(pair);
         560                 :          0 :                 return -1;
         561                 :            :             }
         562                 :            :         } else
         563                 :          0 :             bitsize = 0;
         564                 :            :
         565         [ #  # ]:          0 :         if (isStruct) {
         566         [ #  # ]:          0 :             const char *fieldfmt = dict->format ? dict->format : "B";
         567                 :          0 :             const char *fieldname = PyUnicode_AsUTF8(name);
         568                 :            :             char *ptr;
         569                 :            :             Py_ssize_t len;
         570                 :            :             char *buf;
         571                 :          0 :             Py_ssize_t last_size = size;
         572                 :            :             Py_ssize_t padding;
         573                 :            :
         574         [ #  # ]:          0 :             if (fieldname == NULL)
         575                 :            :             {
         576                 :          0 :                 Py_DECREF(pair);
         577                 :          0 :                 return -1;
         578                 :            :             }
         579                 :            :
         580                 :            :             /* construct the field now, as `prop->offset` is `offset` with
         581                 :            :                corrected alignment */
         582                 :          0 :             prop = PyCField_FromDesc(desc, i,
         583                 :            :                                    &field_size, bitsize, &bitofs,
         584                 :            :                                    &size, &offset, &align,
         585                 :            :                                    pack, big_endian);
         586         [ #  # ]:          0 :             if (prop == NULL) {
         587                 :          0 :                 Py_DECREF(pair);
         588                 :          0 :                 return -1;
         589                 :            :             }
         590                 :            :
         591                 :            :             /* number of bytes between the end of the last field and the start
         592                 :            :                of this one */
         593                 :          0 :             padding = ((CFieldObject *)prop)->offset - last_size;
         594                 :            :
         595         [ #  # ]:          0 :             if (padding > 0) {
         596                 :          0 :                 ptr = stgdict->format;
         597                 :          0 :                 stgdict->format = _ctypes_alloc_format_padding(ptr, padding);
         598                 :          0 :                 PyMem_Free(ptr);
         599         [ #  # ]:          0 :                 if (stgdict->format == NULL) {
         600                 :          0 :                     Py_DECREF(pair);
         601                 :          0 :                     Py_DECREF(prop);
         602                 :          0 :                     return -1;
         603                 :            :                 }
         604                 :            :             }
         605                 :            :
         606                 :          0 :             len = strlen(fieldname) + strlen(fieldfmt);
         607                 :            :
         608                 :          0 :             buf = PyMem_Malloc(len + 2 + 1);
         609         [ #  # ]:          0 :             if (buf == NULL) {
         610                 :          0 :                 Py_DECREF(pair);
         611                 :          0 :                 Py_DECREF(prop);
         612                 :          0 :                 PyErr_NoMemory();
         613                 :          0 :                 return -1;
         614                 :            :             }
         615                 :          0 :             sprintf(buf, "%s:%s:", fieldfmt, fieldname);
         616                 :            :
         617                 :          0 :             ptr = stgdict->format;
         618         [ #  # ]:          0 :             if (dict->shape != NULL) {
         619                 :          0 :                 stgdict->format = _ctypes_alloc_format_string_with_shape(
         620                 :          0 :                     dict->ndim, dict->shape, stgdict->format, buf);
         621                 :            :             } else {
         622                 :          0 :                 stgdict->format = _ctypes_alloc_format_string(stgdict->format, buf);
         623                 :            :             }
         624                 :          0 :             PyMem_Free(ptr);
         625                 :          0 :             PyMem_Free(buf);
         626                 :            :
         627         [ #  # ]:          0 :             if (stgdict->format == NULL) {
         628                 :          0 :                 Py_DECREF(pair);
         629                 :          0 :                 Py_DECREF(prop);
         630                 :          0 :                 return -1;
         631                 :            :             }
         632                 :            :         } else /* union */ {
         633                 :          0 :             size = 0;
         634                 :          0 :             offset = 0;
         635                 :          0 :             align = 0;
         636                 :          0 :             prop = PyCField_FromDesc(desc, i,
         637                 :            :                                    &field_size, bitsize, &bitofs,
         638                 :            :                                    &size, &offset, &align,
         639                 :            :                                    pack, big_endian);
         640         [ #  # ]:          0 :             if (prop == NULL) {
         641                 :          0 :                 Py_DECREF(pair);
         642                 :          0 :                 return -1;
         643                 :            :             }
         644                 :          0 :             union_size = max(size, union_size);
         645                 :            :         }
         646                 :          0 :         total_align = max(align, total_align);
         647                 :            :
         648         [ #  # ]:          0 :         if (-1 == PyObject_SetAttr(type, name, prop)) {
         649                 :          0 :             Py_DECREF(prop);
         650                 :          0 :             Py_DECREF(pair);
         651                 :          0 :             return -1;
         652                 :            :         }
         653                 :          0 :         Py_DECREF(pair);
         654                 :          0 :         Py_DECREF(prop);
         655                 :            :     }
         656                 :            :
         657         [ #  # ]:          0 :     if (!isStruct) {
         658                 :          0 :         size = union_size;
         659                 :            :     }
         660                 :            :
         661                 :            :     /* Adjust the size according to the alignment requirements */
         662                 :          0 :     aligned_size = ((size + total_align - 1) / total_align) * total_align;
         663                 :            :
         664         [ #  # ]:          0 :     if (isStruct) {
         665                 :            :         char *ptr;
         666                 :            :         Py_ssize_t padding;
         667                 :            :
         668                 :            :         /* Pad up to the full size of the struct */
         669                 :          0 :         padding = aligned_size - size;
         670         [ #  # ]:          0 :         if (padding > 0) {
         671                 :          0 :             ptr = stgdict->format;
         672                 :          0 :             stgdict->format = _ctypes_alloc_format_padding(ptr, padding);
         673                 :          0 :             PyMem_Free(ptr);
         674         [ #  # ]:          0 :             if (stgdict->format == NULL) {
         675                 :          0 :                 return -1;
         676                 :            :             }
         677                 :            :         }
         678                 :            :
         679                 :          0 :         ptr = stgdict->format;
         680                 :          0 :         stgdict->format = _ctypes_alloc_format_string(stgdict->format, "}");
         681                 :          0 :         PyMem_Free(ptr);
         682         [ #  # ]:          0 :         if (stgdict->format == NULL)
         683                 :          0 :             return -1;
         684                 :            :     }
         685                 :            :
         686                 :          0 :     stgdict->ffi_type_pointer.alignment = Py_SAFE_DOWNCAST(total_align,
         687                 :            :                                                            Py_ssize_t,
         688                 :            :                                                            unsigned short);
         689                 :          0 :     stgdict->ffi_type_pointer.size = aligned_size;
         690                 :            :
         691                 :          0 :     stgdict->size = aligned_size;
         692                 :          0 :     stgdict->align = total_align;
         693                 :          0 :     stgdict->length = len;      /* ADD ffi_ofs? */
         694                 :            :
         695                 :            : #define MAX_STRUCT_SIZE 16
         696                 :            :
         697   [ #  #  #  # ]:          0 :     if (arrays_seen && (size <= MAX_STRUCT_SIZE)) {
         698                 :            :         /*
         699                 :            :          * See bpo-22273. Arrays are normally treated as pointers, which is
         700                 :            :          * fine when an array name is being passed as parameter, but not when
         701                 :            :          * passing structures by value that contain arrays. On 64-bit Linux,
         702                 :            :          * small structures passed by value are passed in registers, and in
         703                 :            :          * order to do this, libffi needs to know the true type of the array
         704                 :            :          * members of structs. Treating them as pointers breaks things.
         705                 :            :          *
         706                 :            :          * By small structures, we mean ones that are 16 bytes or less. In that
         707                 :            :          * case, there can't be more than 16 elements after unrolling arrays,
         708                 :            :          * as we (will) disallow bitfields. So we can collect the true ffi_type
         709                 :            :          * values in a fixed-size local array on the stack and, if any arrays
         710                 :            :          * were seen, replace the ffi_type_pointer.elements with a more
         711                 :            :          * accurate set, to allow libffi to marshal them into registers
         712                 :            :          * correctly. It means one more loop over the fields, but if we got
         713                 :            :          * here, the structure is small, so there aren't too many of those.
         714                 :            :          *
         715                 :            :          * Although the passing in registers is specific to 64-bit Linux, the
         716                 :            :          * array-in-struct vs. pointer problem is general. But we restrict the
         717                 :            :          * type transformation to small structs nonetheless.
         718                 :            :          *
         719                 :            :          * Note that although a union may be small in terms of memory usage, it
         720                 :            :          * could contain many overlapping declarations of arrays, e.g.
         721                 :            :          *
         722                 :            :          * union {
         723                 :            :          *     unsigned int_8 foo [16];
         724                 :            :          *     unsigned uint_8 bar [16];
         725                 :            :          *     unsigned int_16 baz[8];
         726                 :            :          *     unsigned uint_16 bozz[8];
         727                 :            :          *     unsigned int_32 fizz[4];
         728                 :            :          *     unsigned uint_32 buzz[4];
         729                 :            :          * }
         730                 :            :          *
         731                 :            :          * which is still only 16 bytes in size. We need to convert this into
         732                 :            :          * the following equivalent for libffi:
         733                 :            :          *
         734                 :            :          * union {
         735                 :            :          *     struct { int_8 e1; int_8 e2; ... int_8 e_16; } f1;
         736                 :            :          *     struct { uint_8 e1; uint_8 e2; ... uint_8 e_16; } f2;
         737                 :            :          *     struct { int_16 e1; int_16 e2; ... int_16 e_8; } f3;
         738                 :            :          *     struct { uint_16 e1; uint_16 e2; ... uint_16 e_8; } f4;
         739                 :            :          *     struct { int_32 e1; int_32 e2; ... int_32 e_4; } f5;
         740                 :            :          *     struct { uint_32 e1; uint_32 e2; ... uint_32 e_4; } f6;
         741                 :            :          * }
         742                 :            :          *
         743                 :            :          * So the struct/union needs setting up as follows: all non-array
         744                 :            :          * elements copied across as is, and all array elements replaced with
         745                 :            :          * an equivalent struct which has as many fields as the array has
         746                 :            :          * elements, plus one NULL pointer.
         747                 :            :          */
         748                 :            :
         749                 :          0 :         Py_ssize_t num_ffi_type_pointers = 0;  /* for the dummy fields */
         750                 :          0 :         Py_ssize_t num_ffi_types = 0;  /* for the dummy structures */
         751                 :            :         size_t alloc_size;  /* total bytes to allocate */
         752                 :            :         void *type_block;  /* to hold all the type information needed */
         753                 :            :         ffi_type **element_types;  /* of this struct/union */
         754                 :            :         ffi_type **dummy_types;  /* of the dummy struct elements */
         755                 :            :         ffi_type *structs;  /* point to struct aliases of arrays */
         756                 :            :         Py_ssize_t element_index;  /* index into element_types for this */
         757                 :          0 :         Py_ssize_t dummy_index = 0; /* index into dummy field pointers */
         758                 :          0 :         Py_ssize_t struct_index = 0; /* index into dummy structs */
         759                 :            :
         760                 :            :         /* first pass to see how much memory to allocate */
         761         [ #  # ]:          0 :         for (i = 0; i < len; ++i) {
         762                 :            :             PyObject *name, *desc;
         763                 :          0 :             PyObject *pair = PySequence_GetItem(fields, i);
         764                 :            :             StgDictObject *dict;
         765                 :          0 :             int bitsize = 0;
         766                 :            :
         767         [ #  # ]:          0 :             if (pair == NULL) {
         768                 :          0 :                 return -1;
         769                 :            :             }
         770         [ #  # ]:          0 :             if (!PyArg_ParseTuple(pair, "UO|i", &name, &desc, &bitsize)) {
         771                 :          0 :                 PyErr_SetString(PyExc_TypeError,
         772                 :            :                     "'_fields_' must be a sequence of (name, C type) pairs");
         773                 :          0 :                 Py_DECREF(pair);
         774                 :          0 :                 return -1;
         775                 :            :             }
         776                 :          0 :             dict = PyType_stgdict(desc);
         777         [ #  # ]:          0 :             if (dict == NULL) {
         778                 :          0 :                 Py_DECREF(pair);
         779                 :          0 :                 PyErr_Format(PyExc_TypeError,
         780                 :            :                     "second item in _fields_ tuple (index %zd) must be a C type",
         781                 :            :                     i);
         782                 :          0 :                 return -1;
         783                 :            :             }
         784         [ #  # ]:          0 :             if (!PyCArrayTypeObject_Check(desc)) {
         785                 :            :                 /* Not an array. Just need an ffi_type pointer. */
         786                 :          0 :                 num_ffi_type_pointers++;
         787                 :            :             }
         788                 :            :             else {
         789                 :            :                 /* It's an array. */
         790                 :          0 :                 Py_ssize_t length = dict->length;
         791                 :            :                 StgDictObject *edict;
         792                 :            :
         793                 :          0 :                 edict = PyType_stgdict(dict->proto);
         794         [ #  # ]:          0 :                 if (edict == NULL) {
         795                 :          0 :                     Py_DECREF(pair);
         796                 :          0 :                     PyErr_Format(PyExc_TypeError,
         797                 :            :                         "second item in _fields_ tuple (index %zd) must be a C type",
         798                 :            :                         i);
         799                 :          0 :                     return -1;
         800                 :            :                 }
         801                 :            :                 /*
         802                 :            :                  * We need one extra ffi_type to hold the struct, and one
         803                 :            :                  * ffi_type pointer per array element + one for a NULL to
         804                 :            :                  * mark the end.
         805                 :            :                  */
         806                 :          0 :                 num_ffi_types++;
         807                 :          0 :                 num_ffi_type_pointers += length + 1;
         808                 :            :             }
         809                 :          0 :             Py_DECREF(pair);
         810                 :            :         }
         811                 :            :
         812                 :            :         /*
         813                 :            :          * At this point, we know we need storage for some ffi_types and some
         814                 :            :          * ffi_type pointers. We'll allocate these in one block.
         815                 :            :          * There are three sub-blocks of information: the ffi_type pointers to
         816                 :            :          * this structure/union's elements, the ffi_type_pointers to the
         817                 :            :          * dummy fields standing in for array elements, and the
         818                 :            :          * ffi_types representing the dummy structures.
         819                 :            :          */
         820                 :          0 :         alloc_size = (ffi_ofs + 1 + len + num_ffi_type_pointers) * sizeof(ffi_type *) +
         821                 :            :                         num_ffi_types * sizeof(ffi_type);
         822                 :          0 :         type_block = PyMem_Malloc(alloc_size);
         823                 :            :
         824         [ #  # ]:          0 :         if (type_block == NULL) {
         825                 :          0 :             PyErr_NoMemory();
         826                 :          0 :             return -1;
         827                 :            :         }
         828                 :            :         /*
         829                 :            :          * the first block takes up ffi_ofs + len + 1 which is the pointers *
         830                 :            :          * for this struct/union. The second block takes up
         831                 :            :          * num_ffi_type_pointers, so the sum of these is ffi_ofs + len + 1 +
         832                 :            :          * num_ffi_type_pointers as allocated above. The last bit is the
         833                 :            :          * num_ffi_types structs.
         834                 :            :          */
         835                 :          0 :         element_types = (ffi_type **) type_block;
         836                 :          0 :         dummy_types = &element_types[ffi_ofs + len + 1];
         837                 :          0 :         structs = (ffi_type *) &dummy_types[num_ffi_type_pointers];
         838                 :            :
         839         [ #  # ]:          0 :         if (num_ffi_types > 0) {
         840                 :          0 :             memset(structs, 0, num_ffi_types * sizeof(ffi_type));
         841                 :            :         }
         842   [ #  #  #  # ]:          0 :         if (ffi_ofs && (basedict != NULL)) {
         843                 :          0 :             memcpy(element_types,
         844                 :          0 :                 basedict->ffi_type_pointer.elements,
         845                 :            :                 ffi_ofs * sizeof(ffi_type *));
         846                 :            :         }
         847                 :          0 :         element_index = ffi_ofs;
         848                 :            :
         849                 :            :         /* second pass to actually set the type pointers */
         850         [ #  # ]:          0 :         for (i = 0; i < len; ++i) {
         851                 :            :             PyObject *name, *desc;
         852                 :          0 :             PyObject *pair = PySequence_GetItem(fields, i);
         853                 :            :             StgDictObject *dict;
         854                 :          0 :             int bitsize = 0;
         855                 :            :
         856         [ #  # ]:          0 :             if (pair == NULL) {
         857                 :          0 :                 PyMem_Free(type_block);
         858                 :          0 :                 return -1;
         859                 :            :             }
         860                 :            :             /* In theory, we made this call in the first pass, so it *shouldn't*
         861                 :            :              * fail. However, you never know, and the code above might change
         862                 :            :              * later - keeping the check in here is a tad defensive but it
         863                 :            :              * will affect program size only slightly and performance hardly at
         864                 :            :              * all.
         865                 :            :              */
         866         [ #  # ]:          0 :             if (!PyArg_ParseTuple(pair, "UO|i", &name, &desc, &bitsize)) {
         867                 :          0 :                 PyErr_SetString(PyExc_TypeError,
         868                 :            :                                 "'_fields_' must be a sequence of (name, C type) pairs");
         869                 :          0 :                 Py_DECREF(pair);
         870                 :          0 :                 PyMem_Free(type_block);
         871                 :          0 :                 return -1;
         872                 :            :             }
         873                 :          0 :             dict = PyType_stgdict(desc);
         874                 :            :             /* Possibly this check could be avoided, but see above comment. */
         875         [ #  # ]:          0 :             if (dict == NULL) {
         876                 :          0 :                 Py_DECREF(pair);
         877                 :          0 :                 PyMem_Free(type_block);
         878                 :          0 :                 PyErr_Format(PyExc_TypeError,
         879                 :            :                              "second item in _fields_ tuple (index %zd) must be a C type",
         880                 :            :                              i);
         881                 :          0 :                 return -1;
         882                 :            :             }
         883                 :            :             assert(element_index < (ffi_ofs + len)); /* will be used below */
         884         [ #  # ]:          0 :             if (!PyCArrayTypeObject_Check(desc)) {
         885                 :            :                 /* Not an array. Just copy over the element ffi_type. */
         886                 :          0 :                 element_types[element_index++] = &dict->ffi_type_pointer;
         887                 :            :             }
         888                 :            :             else {
         889                 :          0 :                 Py_ssize_t length = dict->length;
         890                 :            :                 StgDictObject *edict;
         891                 :            :
         892                 :          0 :                 edict = PyType_stgdict(dict->proto);
         893         [ #  # ]:          0 :                 if (edict == NULL) {
         894                 :          0 :                     Py_DECREF(pair);
         895                 :          0 :                     PyMem_Free(type_block);
         896                 :          0 :                     PyErr_Format(PyExc_TypeError,
         897                 :            :                                  "second item in _fields_ tuple (index %zd) must be a C type",
         898                 :            :                                  i);
         899                 :          0 :                     return -1;
         900                 :            :                 }
         901                 :          0 :                 element_types[element_index++] = &structs[struct_index];
         902                 :          0 :                 structs[struct_index].size = length * edict->ffi_type_pointer.size;
         903                 :          0 :                 structs[struct_index].alignment = edict->ffi_type_pointer.alignment;
         904                 :          0 :                 structs[struct_index].type = FFI_TYPE_STRUCT;
         905                 :          0 :                 structs[struct_index].elements = &dummy_types[dummy_index];
         906                 :          0 :                 ++struct_index;
         907                 :            :                 /* Copy over the element's type, length times. */
         908         [ #  # ]:          0 :                 while (length > 0) {
         909                 :            :                     assert(dummy_index < (num_ffi_type_pointers));
         910                 :          0 :                     dummy_types[dummy_index++] = &edict->ffi_type_pointer;
         911                 :          0 :                     length--;
         912                 :            :                 }
         913                 :            :                 assert(dummy_index < (num_ffi_type_pointers));
         914                 :          0 :                 dummy_types[dummy_index++] = NULL;
         915                 :            :             }
         916                 :          0 :             Py_DECREF(pair);
         917                 :            :         }
         918                 :            :
         919                 :          0 :         element_types[element_index] = NULL;
         920                 :            :         /*
         921                 :            :          * Replace the old elements with the new, taking into account
         922                 :            :          * base class elements where necessary.
         923                 :            :          */
         924                 :            :         assert(stgdict->ffi_type_pointer.elements);
         925                 :          0 :         PyMem_Free(stgdict->ffi_type_pointer.elements);
         926                 :          0 :         stgdict->ffi_type_pointer.elements = element_types;
         927                 :            :     }
         928                 :            :
         929                 :            :     /* We did check that this flag was NOT set above, it must not
         930                 :            :        have been set until now. */
         931         [ #  # ]:          0 :     if (stgdict->flags & DICTFLAG_FINAL) {
         932                 :          0 :         PyErr_SetString(PyExc_AttributeError,
         933                 :            :                         "Structure or union cannot contain itself");
         934                 :          0 :         return -1;
         935                 :            :     }
         936                 :          0 :     stgdict->flags |= DICTFLAG_FINAL;
         937                 :            :
         938                 :          0 :     return MakeAnonFields(type);
         939                 :            : }

Generated by: LCOV version 1.14