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