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