• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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