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
PyCStgDict_init(StgDictObject * self,PyObject * args,PyObject * kwds)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
PyCStgDict_clear(StgDictObject * self)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
PyCStgDict_dealloc(StgDictObject * self)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 int
PyCStgDict_clone(StgDictObject * dst,StgDictObject * src)52 PyCStgDict_clone(StgDictObject *dst, StgDictObject *src)
53 {
54 char *d, *s;
55 Py_ssize_t size;
56
57 PyCStgDict_clear(dst);
58 PyMem_Free(dst->ffi_type_pointer.elements);
59 PyMem_Free(dst->format);
60 dst->format = NULL;
61 PyMem_Free(dst->shape);
62 dst->shape = NULL;
63 dst->ffi_type_pointer.elements = NULL;
64
65 d = (char *)dst;
66 s = (char *)src;
67 memcpy(d + sizeof(PyDictObject),
68 s + sizeof(PyDictObject),
69 sizeof(StgDictObject) - sizeof(PyDictObject));
70
71 Py_XINCREF(dst->proto);
72 Py_XINCREF(dst->argtypes);
73 Py_XINCREF(dst->converters);
74 Py_XINCREF(dst->restype);
75 Py_XINCREF(dst->checker);
76
77 if (src->format) {
78 dst->format = PyMem_Malloc(strlen(src->format) + 1);
79 if (dst->format == NULL) {
80 PyErr_NoMemory();
81 return -1;
82 }
83 strcpy(dst->format, src->format);
84 }
85 if (src->shape) {
86 dst->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src->ndim);
87 if (dst->shape == NULL) {
88 PyErr_NoMemory();
89 return -1;
90 }
91 memcpy(dst->shape, src->shape,
92 sizeof(Py_ssize_t) * src->ndim);
93 }
94
95 if (src->ffi_type_pointer.elements == NULL)
96 return 0;
97 size = sizeof(ffi_type *) * (src->length + 1);
98 dst->ffi_type_pointer.elements = PyMem_Malloc(size);
99 if (dst->ffi_type_pointer.elements == NULL) {
100 PyErr_NoMemory();
101 return -1;
102 }
103 memcpy(dst->ffi_type_pointer.elements,
104 src->ffi_type_pointer.elements,
105 size);
106 return 0;
107 }
108
109 PyTypeObject PyCStgDict_Type = {
110 PyVarObject_HEAD_INIT(NULL, 0)
111 "StgDict",
112 sizeof(StgDictObject),
113 0,
114 (destructor)PyCStgDict_dealloc, /* tp_dealloc */
115 0, /* tp_print */
116 0, /* tp_getattr */
117 0, /* tp_setattr */
118 0, /* tp_compare */
119 0, /* tp_repr */
120 0, /* tp_as_number */
121 0, /* tp_as_sequence */
122 0, /* tp_as_mapping */
123 0, /* tp_hash */
124 0, /* tp_call */
125 0, /* tp_str */
126 0, /* tp_getattro */
127 0, /* tp_setattro */
128 0, /* tp_as_buffer */
129 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
130 0, /* tp_doc */
131 0, /* tp_traverse */
132 0, /* tp_clear */
133 0, /* tp_richcompare */
134 0, /* tp_weaklistoffset */
135 0, /* tp_iter */
136 0, /* tp_iternext */
137 0, /* tp_methods */
138 0, /* tp_members */
139 0, /* tp_getset */
140 0, /* tp_base */
141 0, /* tp_dict */
142 0, /* tp_descr_get */
143 0, /* tp_descr_set */
144 0, /* tp_dictoffset */
145 (initproc)PyCStgDict_init, /* tp_init */
146 0, /* tp_alloc */
147 0, /* tp_new */
148 0, /* tp_free */
149 };
150
151 /* May return NULL, but does not set an exception! */
152 StgDictObject *
PyType_stgdict(PyObject * obj)153 PyType_stgdict(PyObject *obj)
154 {
155 PyTypeObject *type;
156
157 if (!PyType_Check(obj))
158 return NULL;
159 type = (PyTypeObject *)obj;
160 if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS))
161 return NULL;
162 if (!type->tp_dict || !PyCStgDict_CheckExact(type->tp_dict))
163 return NULL;
164 return (StgDictObject *)type->tp_dict;
165 }
166
167 /* May return NULL, but does not set an exception! */
168 /*
169 This function should be as fast as possible, so we don't call PyType_stgdict
170 above but inline the code, and avoid the PyType_Check().
171 */
172 StgDictObject *
PyObject_stgdict(PyObject * self)173 PyObject_stgdict(PyObject *self)
174 {
175 PyTypeObject *type = self->ob_type;
176 if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS))
177 return NULL;
178 if (!type->tp_dict || !PyCStgDict_CheckExact(type->tp_dict))
179 return NULL;
180 return (StgDictObject *)type->tp_dict;
181 }
182
183 /* descr is the descriptor for a field marked as anonymous. Get all the
184 _fields_ descriptors from descr->proto, create new descriptors with offset
185 and index adjusted, and stuff them into type.
186 */
187 static int
MakeFields(PyObject * type,CFieldObject * descr,Py_ssize_t index,Py_ssize_t offset)188 MakeFields(PyObject *type, CFieldObject *descr,
189 Py_ssize_t index, Py_ssize_t offset)
190 {
191 Py_ssize_t i;
192 PyObject *fields;
193 PyObject *fieldlist;
194
195 fields = PyObject_GetAttrString(descr->proto, "_fields_");
196 if (fields == NULL)
197 return -1;
198 fieldlist = PySequence_Fast(fields, "_fields_ must be a sequence");
199 Py_DECREF(fields);
200 if (fieldlist == NULL)
201 return -1;
202
203 for (i = 0; i < PySequence_Fast_GET_SIZE(fieldlist); ++i) {
204 PyObject *pair = PySequence_Fast_GET_ITEM(fieldlist, i); /* borrowed */
205 PyObject *fname, *ftype, *bits;
206 CFieldObject *fdescr;
207 CFieldObject *new_descr;
208 /* Convert to PyArg_UnpackTuple... */
209 if (!PyArg_ParseTuple(pair, "OO|O", &fname, &ftype, &bits)) {
210 Py_DECREF(fieldlist);
211 return -1;
212 }
213 fdescr = (CFieldObject *)PyObject_GetAttr(descr->proto, fname);
214 if (fdescr == NULL) {
215 Py_DECREF(fieldlist);
216 return -1;
217 }
218 if (Py_TYPE(fdescr) != &PyCField_Type) {
219 PyErr_SetString(PyExc_TypeError, "unexpected type");
220 Py_DECREF(fdescr);
221 Py_DECREF(fieldlist);
222 return -1;
223 }
224 if (fdescr->anonymous) {
225 int rc = MakeFields(type, fdescr,
226 index + fdescr->index,
227 offset + fdescr->offset);
228 Py_DECREF(fdescr);
229 if (rc == -1) {
230 Py_DECREF(fieldlist);
231 return -1;
232 }
233 continue;
234 }
235 new_descr = (CFieldObject *)PyObject_CallObject((PyObject *)&PyCField_Type, NULL);
236 if (new_descr == NULL) {
237 Py_DECREF(fdescr);
238 Py_DECREF(fieldlist);
239 return -1;
240 }
241 assert(Py_TYPE(new_descr) == &PyCField_Type);
242 new_descr->size = fdescr->size;
243 new_descr->offset = fdescr->offset + offset;
244 new_descr->index = fdescr->index + index;
245 new_descr->proto = fdescr->proto;
246 Py_XINCREF(new_descr->proto);
247 new_descr->getfunc = fdescr->getfunc;
248 new_descr->setfunc = fdescr->setfunc;
249
250 Py_DECREF(fdescr);
251
252 if (-1 == PyObject_SetAttr(type, fname, (PyObject *)new_descr)) {
253 Py_DECREF(fieldlist);
254 Py_DECREF(new_descr);
255 return -1;
256 }
257 Py_DECREF(new_descr);
258 }
259 Py_DECREF(fieldlist);
260 return 0;
261 }
262
263 /* Iterate over the names in the type's _anonymous_ attribute, if present,
264 */
265 static int
MakeAnonFields(PyObject * type)266 MakeAnonFields(PyObject *type)
267 {
268 PyObject *anon;
269 PyObject *anon_names;
270 Py_ssize_t i;
271
272 anon = PyObject_GetAttrString(type, "_anonymous_");
273 if (anon == NULL) {
274 PyErr_Clear();
275 return 0;
276 }
277 anon_names = PySequence_Fast(anon, "_anonymous_ must be a sequence");
278 Py_DECREF(anon);
279 if (anon_names == NULL)
280 return -1;
281
282 for (i = 0; i < PySequence_Fast_GET_SIZE(anon_names); ++i) {
283 PyObject *fname = PySequence_Fast_GET_ITEM(anon_names, i); /* borrowed */
284 CFieldObject *descr = (CFieldObject *)PyObject_GetAttr(type, fname);
285 if (descr == NULL) {
286 Py_DECREF(anon_names);
287 return -1;
288 }
289 assert(Py_TYPE(descr) == &PyCField_Type);
290 descr->anonymous = 1;
291
292 /* descr is in the field descriptor. */
293 if (-1 == MakeFields(type, (CFieldObject *)descr,
294 ((CFieldObject *)descr)->index,
295 ((CFieldObject *)descr)->offset)) {
296 Py_DECREF(descr);
297 Py_DECREF(anon_names);
298 return -1;
299 }
300 Py_DECREF(descr);
301 }
302
303 Py_DECREF(anon_names);
304 return 0;
305 }
306
307 /*
308 Retrive the (optional) _pack_ attribute from a type, the _fields_ attribute,
309 and create an StgDictObject. Used for Structure and Union subclasses.
310 */
311 int
PyCStructUnionType_update_stgdict(PyObject * type,PyObject * fields,int isStruct)312 PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
313 {
314 StgDictObject *stgdict, *basedict;
315 Py_ssize_t len, offset, size, align, i;
316 Py_ssize_t union_size, total_align;
317 Py_ssize_t field_size = 0;
318 int bitofs;
319 PyObject *isPacked;
320 int pack = 0;
321 Py_ssize_t ffi_ofs;
322 int big_endian;
323
324 /* HACK Alert: I cannot be bothered to fix ctypes.com, so there has to
325 be a way to use the old, broken sematics: _fields_ are not extended
326 but replaced in subclasses.
327
328 XXX Remove this in ctypes 1.0!
329 */
330 int use_broken_old_ctypes_semantics;
331
332 if (fields == NULL)
333 return 0;
334
335 #ifdef WORDS_BIGENDIAN
336 big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 0 : 1;
337 #else
338 big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 1 : 0;
339 #endif
340
341 use_broken_old_ctypes_semantics = \
342 PyObject_HasAttrString(type, "_use_broken_old_ctypes_structure_semantics_");
343
344 isPacked = PyObject_GetAttrString(type, "_pack_");
345 if (isPacked) {
346 pack = _PyInt_AsInt(isPacked);
347 if (pack < 0 || PyErr_Occurred()) {
348 Py_XDECREF(isPacked);
349 PyErr_SetString(PyExc_ValueError,
350 "_pack_ must be a non-negative integer");
351 return -1;
352 }
353 Py_DECREF(isPacked);
354 } else
355 PyErr_Clear();
356
357 len = PySequence_Length(fields);
358 if (len == -1) {
359 PyErr_SetString(PyExc_TypeError,
360 "'_fields_' must be a sequence of pairs");
361 return -1;
362 }
363
364 stgdict = PyType_stgdict(type);
365 if (!stgdict)
366 return -1;
367 /* If this structure/union is already marked final we cannot assign
368 _fields_ anymore. */
369
370 if (stgdict->flags & DICTFLAG_FINAL) {/* is final ? */
371 PyErr_SetString(PyExc_AttributeError,
372 "_fields_ is final");
373 return -1;
374 }
375
376 if (stgdict->format) {
377 PyMem_Free(stgdict->format);
378 stgdict->format = NULL;
379 }
380
381 if (stgdict->ffi_type_pointer.elements)
382 PyMem_Free(stgdict->ffi_type_pointer.elements);
383
384 basedict = PyType_stgdict((PyObject *)((PyTypeObject *)type)->tp_base);
385 if (basedict && !use_broken_old_ctypes_semantics) {
386 size = offset = basedict->size;
387 align = basedict->align;
388 union_size = 0;
389 total_align = align ? align : 1;
390 stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT;
391 stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, basedict->length + len + 1);
392 if (stgdict->ffi_type_pointer.elements == NULL) {
393 PyErr_NoMemory();
394 return -1;
395 }
396 memset(stgdict->ffi_type_pointer.elements, 0,
397 sizeof(ffi_type *) * (basedict->length + len + 1));
398 if (basedict->length > 0) {
399 memcpy(stgdict->ffi_type_pointer.elements,
400 basedict->ffi_type_pointer.elements,
401 sizeof(ffi_type *) * (basedict->length));
402 }
403 ffi_ofs = basedict->length;
404 } else {
405 offset = 0;
406 size = 0;
407 align = 0;
408 union_size = 0;
409 total_align = 1;
410 stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT;
411 stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1);
412 if (stgdict->ffi_type_pointer.elements == NULL) {
413 PyErr_NoMemory();
414 return -1;
415 }
416 memset(stgdict->ffi_type_pointer.elements, 0,
417 sizeof(ffi_type *) * (len + 1));
418 ffi_ofs = 0;
419 }
420
421 assert(stgdict->format == NULL);
422 if (isStruct && !isPacked) {
423 stgdict->format = _ctypes_alloc_format_string(NULL, "T{");
424 } else {
425 /* PEP3118 doesn't support union, or packed structures (well,
426 only standard packing, but we dont support the pep for
427 that). Use 'B' for bytes. */
428 stgdict->format = _ctypes_alloc_format_string(NULL, "B");
429 }
430
431 #define realdict ((PyObject *)&stgdict->dict)
432 for (i = 0; i < len; ++i) {
433 PyObject *name = NULL, *desc = NULL;
434 PyObject *pair = PySequence_GetItem(fields, i);
435 PyObject *prop;
436 StgDictObject *dict;
437 int bitsize = 0;
438
439 if (!pair || !PyArg_ParseTuple(pair, "OO|i", &name, &desc, &bitsize)) {
440 PyErr_SetString(PyExc_AttributeError,
441 "'_fields_' must be a sequence of pairs");
442 Py_XDECREF(pair);
443 return -1;
444 }
445 dict = PyType_stgdict(desc);
446 if (dict == NULL) {
447 Py_DECREF(pair);
448 PyErr_Format(PyExc_TypeError,
449 #if (PY_VERSION_HEX < 0x02050000)
450 /* Compatibility no longer strictly required */
451 "second item in _fields_ tuple (index %d) must be a C type",
452 #else
453 "second item in _fields_ tuple (index %zd) must be a C type",
454 #endif
455 i);
456 return -1;
457 }
458 stgdict->ffi_type_pointer.elements[ffi_ofs + i] = &dict->ffi_type_pointer;
459 if (dict->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER))
460 stgdict->flags |= TYPEFLAG_HASPOINTER;
461 dict->flags |= DICTFLAG_FINAL; /* mark field type final */
462 if (PyTuple_Size(pair) == 3) { /* bits specified */
463 switch(dict->ffi_type_pointer.type) {
464 case FFI_TYPE_UINT8:
465 case FFI_TYPE_UINT16:
466 case FFI_TYPE_UINT32:
467 case FFI_TYPE_SINT64:
468 case FFI_TYPE_UINT64:
469 break;
470
471 case FFI_TYPE_SINT8:
472 case FFI_TYPE_SINT16:
473 case FFI_TYPE_SINT32:
474 if (dict->getfunc != _ctypes_get_fielddesc("c")->getfunc
475 #ifdef CTYPES_UNICODE
476 && dict->getfunc != _ctypes_get_fielddesc("u")->getfunc
477 #endif
478 )
479 break;
480 /* else fall through */
481 default:
482 PyErr_Format(PyExc_TypeError,
483 "bit fields not allowed for type %s",
484 ((PyTypeObject *)desc)->tp_name);
485 Py_DECREF(pair);
486 return -1;
487 }
488 if (bitsize <= 0 || bitsize > dict->size * 8) {
489 PyErr_SetString(PyExc_ValueError,
490 "number of bits invalid for bit field");
491 Py_DECREF(pair);
492 return -1;
493 }
494 } else
495 bitsize = 0;
496 if (isStruct && !isPacked) {
497 char *fieldfmt = dict->format ? dict->format : "B";
498 char *fieldname = PyString_AsString(name);
499 char *ptr;
500 Py_ssize_t len;
501 char *buf;
502
503 if (fieldname == NULL)
504 {
505 PyErr_Format(PyExc_TypeError,
506 "structure field name must be string not %s",
507 name->ob_type->tp_name);
508
509 Py_DECREF(pair);
510 return -1;
511 }
512
513 len = strlen(fieldname) + strlen(fieldfmt);
514
515 buf = PyMem_Malloc(len + 2 + 1);
516 if (buf == NULL) {
517 Py_DECREF(pair);
518 PyErr_NoMemory();
519 return -1;
520 }
521 sprintf(buf, "%s:%s:", fieldfmt, fieldname);
522
523 ptr = stgdict->format;
524 if (dict->shape != NULL) {
525 stgdict->format = _ctypes_alloc_format_string_with_shape(
526 dict->ndim, dict->shape, stgdict->format, buf);
527 } else {
528 stgdict->format = _ctypes_alloc_format_string(stgdict->format, buf);
529 }
530 PyMem_Free(ptr);
531 PyMem_Free(buf);
532
533 if (stgdict->format == NULL) {
534 Py_DECREF(pair);
535 return -1;
536 }
537 }
538 if (isStruct) {
539 prop = PyCField_FromDesc(desc, i,
540 &field_size, bitsize, &bitofs,
541 &size, &offset, &align,
542 pack, big_endian);
543 } else /* union */ {
544 size = 0;
545 offset = 0;
546 align = 0;
547 prop = PyCField_FromDesc(desc, i,
548 &field_size, bitsize, &bitofs,
549 &size, &offset, &align,
550 pack, big_endian);
551 union_size = max(size, union_size);
552 }
553 total_align = max(align, total_align);
554
555 if (!prop) {
556 Py_DECREF(pair);
557 return -1;
558 }
559 if (-1 == PyObject_SetAttr(type, name, prop)) {
560 Py_DECREF(prop);
561 Py_DECREF(pair);
562 return -1;
563 }
564 Py_DECREF(pair);
565 Py_DECREF(prop);
566 }
567 #undef realdict
568
569 if (isStruct && !isPacked) {
570 char *ptr = stgdict->format;
571 stgdict->format = _ctypes_alloc_format_string(stgdict->format, "}");
572 PyMem_Free(ptr);
573 if (stgdict->format == NULL)
574 return -1;
575 }
576
577 if (!isStruct)
578 size = union_size;
579
580 /* Adjust the size according to the alignment requirements */
581 size = ((size + total_align - 1) / total_align) * total_align;
582
583 stgdict->ffi_type_pointer.alignment = Py_SAFE_DOWNCAST(total_align,
584 Py_ssize_t,
585 unsigned short);
586 stgdict->ffi_type_pointer.size = size;
587
588 stgdict->size = size;
589 stgdict->align = total_align;
590 stgdict->length = len; /* ADD ffi_ofs? */
591
592 /* We did check that this flag was NOT set above, it must not
593 have been set until now. */
594 if (stgdict->flags & DICTFLAG_FINAL) {
595 PyErr_SetString(PyExc_AttributeError,
596 "Structure or union cannot contain itself");
597 return -1;
598 }
599 stgdict->flags |= DICTFLAG_FINAL;
600
601 return MakeAnonFields(type);
602 }
603