LCOV - code coverage report
Current view: top level - Modules/_ctypes - stgdict.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 333 422 78.9 %
Date: 2022-07-20 13:12:14 Functions: 9 10 90.0 %
Branches: 169 233 72.5 %

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

Generated by: LCOV version 1.14