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