• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
PyCStgDict_init(StgDictObject * self,PyObject * args,PyObject * kwds)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
PyCStgDict_clear(StgDictObject * self)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
PyCStgDict_dealloc(StgDictObject * self)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 *
PyCStgDict_sizeof(StgDictObject * self,void * unused)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
PyCStgDict_clone(StgDictObject * dst,StgDictObject * src)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 *
PyType_stgdict(PyObject * obj)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 *
PyObject_stgdict(PyObject * self)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
MakeFields(PyObject * type,CFieldObject * descr,Py_ssize_t index,Py_ssize_t offset)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
MakeAnonFields(PyObject * type)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
PyCStructUnionType_update_stgdict(PyObject * type,PyObject * fields,int isStruct)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 }
910