stgdict.c revision 25d208bd464aa6b1bde8a30cc71327133edaeeb3
1/*****************************************************************
2  This file should be kept compatible with Python 2.3, see PEP 291.
3 *****************************************************************/
4
5#include "Python.h"
6#include <ffi.h>
7#ifdef MS_WIN32
8#include <windows.h>
9#endif
10#include "ctypes.h"
11
12/******************************************************************/
13/*
14  StdDict - a dictionary subclass, containing additional C accessible fields
15
16  XXX blabla more
17*/
18
19/* Seems we need this, otherwise we get problems when calling
20 * PyDict_SetItem() (ma_lookup is NULL)
21 */
22static int
23StgDict_init(StgDictObject *self, PyObject *args, PyObject *kwds)
24{
25	if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
26		return -1;
27	return 0;
28}
29
30static int
31StgDict_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
41static void
42StgDict_dealloc(StgDictObject *self)
43{
44	StgDict_clear(self);
45	PyMem_Free(self->ffi_type_pointer.elements);
46	PyDict_Type.tp_dealloc((PyObject *)self);
47}
48
49int
50StgDict_clone(StgDictObject *dst, StgDictObject *src)
51{
52	char *d, *s;
53	int size;
54
55	StgDict_clear(dst);
56	PyMem_Free(dst->ffi_type_pointer.elements);
57	dst->ffi_type_pointer.elements = NULL;
58
59	d = (char *)dst;
60	s = (char *)src;
61	memcpy(d + sizeof(PyDictObject),
62	       s + sizeof(PyDictObject),
63	       sizeof(StgDictObject) - sizeof(PyDictObject));
64
65	Py_XINCREF(dst->proto);
66	Py_XINCREF(dst->argtypes);
67	Py_XINCREF(dst->converters);
68	Py_XINCREF(dst->restype);
69	Py_XINCREF(dst->checker);
70
71	if (src->ffi_type_pointer.elements == NULL)
72		return 0;
73	size = sizeof(ffi_type *) * (src->length + 1);
74	dst->ffi_type_pointer.elements = PyMem_Malloc(size);
75	if (dst->ffi_type_pointer.elements == NULL)
76		return -1;
77	memcpy(dst->ffi_type_pointer.elements,
78	       src->ffi_type_pointer.elements,
79	       size);
80	return 0;
81}
82
83PyTypeObject StgDict_Type = {
84	PyObject_HEAD_INIT(NULL)
85	0,
86	"StgDict",
87	sizeof(StgDictObject),
88	0,
89	(destructor)StgDict_dealloc,		/* tp_dealloc */
90	0,					/* tp_print */
91	0,					/* tp_getattr */
92	0,					/* tp_setattr */
93	0,					/* tp_compare */
94	0,					/* tp_repr */
95	0,					/* tp_as_number */
96	0,					/* tp_as_sequence */
97	0,					/* tp_as_mapping */
98	0,					/* tp_hash */
99	0,					/* tp_call */
100	0,					/* tp_str */
101	0,					/* tp_getattro */
102	0,					/* tp_setattro */
103	0,					/* tp_as_buffer */
104	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
105	0,					/* tp_doc */
106	0,					/* tp_traverse */
107	0,					/* tp_clear */
108	0,					/* tp_richcompare */
109	0,					/* tp_weaklistoffset */
110	0,					/* tp_iter */
111	0,					/* tp_iternext */
112	0,					/* tp_methods */
113	0,					/* tp_members */
114	0,					/* tp_getset */
115	0,					/* tp_base */
116	0,					/* tp_dict */
117	0,					/* tp_descr_get */
118	0,					/* tp_descr_set */
119	0,					/* tp_dictoffset */
120	(initproc)StgDict_init,			/* tp_init */
121	0,					/* tp_alloc */
122	0,					/* tp_new */
123	0,					/* tp_free */
124};
125
126/* May return NULL, but does not set an exception! */
127StgDictObject *
128PyType_stgdict(PyObject *obj)
129{
130	PyTypeObject *type;
131
132	if (!PyType_Check(obj))
133		return NULL;
134	type = (PyTypeObject *)obj;
135	if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS))
136		return NULL;
137	if (!type->tp_dict || !StgDict_CheckExact(type->tp_dict))
138		return NULL;
139	return (StgDictObject *)type->tp_dict;
140}
141
142/* May return NULL, but does not set an exception! */
143/*
144  This function should be as fast as possible, so we don't call PyType_stgdict
145  above but inline the code, and avoid the PyType_Check().
146*/
147StgDictObject *
148PyObject_stgdict(PyObject *self)
149{
150	PyTypeObject *type = self->ob_type;
151	if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS))
152		return NULL;
153	if (!type->tp_dict || !StgDict_CheckExact(type->tp_dict))
154		return NULL;
155	return (StgDictObject *)type->tp_dict;
156}
157
158/* descr is the descriptor for a field marked as anonymous.  Get all the
159 _fields_ descriptors from descr->proto, create new descriptors with offset
160 and index adjusted, and stuff them into type.
161 */
162static int
163MakeFields(PyObject *type, CFieldObject *descr,
164	   Py_ssize_t index, Py_ssize_t offset)
165{
166	Py_ssize_t i;
167	PyObject *fields;
168	PyObject *fieldlist;
169
170	fields = PyObject_GetAttrString(descr->proto, "_fields_");
171	if (fields == NULL)
172		return -1;
173	fieldlist = PySequence_Fast(fields, "_fields_ must be a sequence");
174	Py_DECREF(fields);
175	if (fieldlist == NULL)
176		return -1;
177
178	for (i = 0; i < PySequence_Fast_GET_SIZE(fieldlist); ++i) {
179		PyObject *pair = PySequence_Fast_GET_ITEM(fieldlist, i); /* borrowed */
180		PyObject *fname, *ftype, *bits;
181		CFieldObject *fdescr;
182		CFieldObject *new_descr;
183		/* Convert to PyArg_UnpackTuple... */
184		if (!PyArg_ParseTuple(pair, "OO|O", &fname, &ftype, &bits)) {
185			Py_DECREF(fieldlist);
186			return -1;
187		}
188		fdescr = (CFieldObject *)PyObject_GetAttr(descr->proto, fname);
189		if (fdescr == NULL) {
190			Py_DECREF(fieldlist);
191			return -1;
192		}
193		if (fdescr->ob_type != &CField_Type) {
194			PyErr_SetString(PyExc_TypeError, "unexpected type");
195			Py_DECREF(fdescr);
196			Py_DECREF(fieldlist);
197			return -1;
198		}
199		if (fdescr->anonymous) {
200			int rc = MakeFields(type, fdescr,
201					    index + fdescr->index,
202					    offset + fdescr->offset);
203			Py_DECREF(fdescr);
204			if (rc == -1) {
205				Py_DECREF(fieldlist);
206				return -1;
207			}
208			continue;
209		}
210 		new_descr = (CFieldObject *)PyObject_CallObject((PyObject *)&CField_Type, NULL);
211		if (new_descr == NULL) {
212			Py_DECREF(fdescr);
213			Py_DECREF(fieldlist);
214			return -1;
215		}
216		assert(new_descr->ob_type == &CField_Type);
217 		new_descr->size = fdescr->size;
218 		new_descr->offset = fdescr->offset + offset;
219 		new_descr->index = fdescr->index + index;
220 		new_descr->proto = fdescr->proto;
221 		Py_XINCREF(new_descr->proto);
222 		new_descr->getfunc = fdescr->getfunc;
223 		new_descr->setfunc = fdescr->setfunc;
224
225  		Py_DECREF(fdescr);
226
227		if (-1 == PyObject_SetAttr(type, fname, (PyObject *)new_descr)) {
228			Py_DECREF(fieldlist);
229			Py_DECREF(new_descr);
230			return -1;
231		}
232		Py_DECREF(new_descr);
233	}
234	Py_DECREF(fieldlist);
235	return 0;
236}
237
238/* Iterate over the names in the type's _anonymous_ attribute, if present,
239 */
240static int
241MakeAnonFields(PyObject *type)
242{
243	PyObject *anon;
244	PyObject *anon_names;
245	Py_ssize_t i;
246
247	anon = PyObject_GetAttrString(type, "_anonymous_");
248	if (anon == NULL) {
249		PyErr_Clear();
250		return 0;
251	}
252	anon_names = PySequence_Fast(anon, "_anonymous_ must be a sequence");
253	Py_DECREF(anon);
254	if (anon_names == NULL)
255		return -1;
256
257	for (i = 0; i < PySequence_Fast_GET_SIZE(anon_names); ++i) {
258		PyObject *fname = PySequence_Fast_GET_ITEM(anon_names, i); /* borrowed */
259		CFieldObject *descr = (CFieldObject *)PyObject_GetAttr(type, fname);
260		if (descr == NULL) {
261			Py_DECREF(anon_names);
262			return -1;
263		}
264		assert(descr->ob_type == &CField_Type);
265		descr->anonymous = 1;
266
267		/* descr is in the field descriptor. */
268		if (-1 == MakeFields(type, (CFieldObject *)descr,
269				     ((CFieldObject *)descr)->index,
270				     ((CFieldObject *)descr)->offset)) {
271			Py_DECREF(descr);
272			Py_DECREF(anon_names);
273			return -1;
274		}
275		Py_DECREF(descr);
276	}
277
278	Py_DECREF(anon_names);
279	return 0;
280}
281
282/*
283  Retrive the (optional) _pack_ attribute from a type, the _fields_ attribute,
284  and create an StgDictObject.  Used for Structure and Union subclasses.
285*/
286int
287StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
288{
289	StgDictObject *stgdict, *basedict;
290	int len, offset, size, align, i;
291	int union_size, total_align;
292	int field_size = 0;
293	int bitofs;
294	PyObject *isPacked;
295	int pack = 0;
296	int ffi_ofs;
297	int big_endian;
298
299	/* HACK Alert: I cannot be bothered to fix ctypes.com, so there has to
300	   be a way to use the old, broken sematics: _fields_ are not extended
301	   but replaced in subclasses.
302
303	   XXX Remove this in ctypes 1.0!
304	*/
305	int use_broken_old_ctypes_semantics;
306
307	if (fields == NULL)
308		return 0;
309
310#ifdef WORDS_BIGENDIAN
311	big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 0 : 1;
312#else
313	big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 1 : 0;
314#endif
315
316	use_broken_old_ctypes_semantics = \
317		PyObject_HasAttrString(type, "_use_broken_old_ctypes_structure_semantics_");
318
319	isPacked = PyObject_GetAttrString(type, "_pack_");
320	if (isPacked) {
321		pack = PyInt_AsLong(isPacked);
322		if (pack < 0 || PyErr_Occurred()) {
323			Py_XDECREF(isPacked);
324			PyErr_SetString(PyExc_ValueError,
325					"_pack_ must be a non-negative integer");
326			return -1;
327		}
328		Py_DECREF(isPacked);
329	} else
330		PyErr_Clear();
331
332	len = PySequence_Length(fields);
333	if (len == -1) {
334		PyErr_SetString(PyExc_TypeError,
335				"'_fields_' must be a sequence of pairs");
336		return -1;
337	}
338
339	stgdict = PyType_stgdict(type);
340	if (!stgdict)
341		return -1;
342	/* If this structure/union is already marked final we cannot assign
343	   _fields_ anymore. */
344
345	if (stgdict->flags & DICTFLAG_FINAL) {/* is final ? */
346		PyErr_SetString(PyExc_AttributeError,
347				"_fields_ is final");
348		return -1;
349	}
350
351	if (stgdict->ffi_type_pointer.elements)
352		PyMem_Free(stgdict->ffi_type_pointer.elements);
353
354	basedict = PyType_stgdict((PyObject *)((PyTypeObject *)type)->tp_base);
355	if (basedict && !use_broken_old_ctypes_semantics) {
356		size = offset = basedict->size;
357		align = basedict->align;
358		union_size = 0;
359		total_align = align ? align : 1;
360		stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT;
361		stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (basedict->length + len + 1));
362		memset(stgdict->ffi_type_pointer.elements, 0,
363		       sizeof(ffi_type *) * (basedict->length + len + 1));
364		memcpy(stgdict->ffi_type_pointer.elements,
365		       basedict->ffi_type_pointer.elements,
366		       sizeof(ffi_type *) * (basedict->length));
367		ffi_ofs = basedict->length;
368	} else {
369		offset = 0;
370		size = 0;
371		align = 0;
372		union_size = 0;
373		total_align = 1;
374		stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT;
375		stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (len + 1));
376		memset(stgdict->ffi_type_pointer.elements, 0,
377		       sizeof(ffi_type *) * (len + 1));
378		ffi_ofs = 0;
379	}
380
381#define realdict ((PyObject *)&stgdict->dict)
382	for (i = 0; i < len; ++i) {
383		PyObject *name = NULL, *desc = NULL;
384		PyObject *pair = PySequence_GetItem(fields, i);
385		PyObject *prop;
386		StgDictObject *dict;
387		int bitsize = 0;
388
389		if (!pair || !PyArg_ParseTuple(pair, "OO|i", &name, &desc, &bitsize)) {
390			PyErr_SetString(PyExc_AttributeError,
391					"'_fields_' must be a sequence of pairs");
392			Py_XDECREF(pair);
393			return -1;
394		}
395		dict = PyType_stgdict(desc);
396		if (dict == NULL) {
397			Py_DECREF(pair);
398			PyErr_Format(PyExc_TypeError,
399				     "second item in _fields_ tuple (index %d) must be a C type",
400				     i);
401			return -1;
402		}
403		stgdict->ffi_type_pointer.elements[ffi_ofs + i] = &dict->ffi_type_pointer;
404		dict->flags |= DICTFLAG_FINAL; /* mark field type final */
405		if (PyTuple_Size(pair) == 3) { /* bits specified */
406			switch(dict->ffi_type_pointer.type) {
407			case FFI_TYPE_UINT8:
408			case FFI_TYPE_UINT16:
409			case FFI_TYPE_UINT32:
410			case FFI_TYPE_SINT64:
411			case FFI_TYPE_UINT64:
412				break;
413
414			case FFI_TYPE_SINT8:
415			case FFI_TYPE_SINT16:
416			case FFI_TYPE_SINT32:
417				if (dict->getfunc != getentry("c")->getfunc
418#ifdef CTYPES_UNICODE
419				    && dict->getfunc != getentry("u")->getfunc
420#endif
421					)
422					break;
423				/* else fall through */
424			default:
425				PyErr_Format(PyExc_TypeError,
426					     "bit fields not allowed for type %s",
427					     ((PyTypeObject *)desc)->tp_name);
428				Py_DECREF(pair);
429				return -1;
430			}
431			if (bitsize <= 0 || bitsize > dict->size * 8) {
432				PyErr_SetString(PyExc_ValueError,
433						"number of bits invalid for bit field");
434				Py_DECREF(pair);
435				return -1;
436			}
437		} else
438			bitsize = 0;
439		if (isStruct) {
440			prop = CField_FromDesc(desc, i,
441					       &field_size, bitsize, &bitofs,
442					       &size, &offset, &align,
443					       pack, big_endian);
444		} else /* union */ {
445			size = 0;
446			offset = 0;
447			align = 0;
448			prop = CField_FromDesc(desc, i,
449					       &field_size, bitsize, &bitofs,
450					       &size, &offset, &align,
451					       pack, big_endian);
452			union_size = max(size, union_size);
453		}
454		total_align = max(align, total_align);
455
456		if (!prop) {
457			Py_DECREF(pair);
458			Py_DECREF((PyObject *)stgdict);
459			return -1;
460		}
461		if (-1 == PyDict_SetItem(realdict, name, prop)) {
462			Py_DECREF(prop);
463			Py_DECREF(pair);
464			Py_DECREF((PyObject *)stgdict);
465			return -1;
466		}
467		Py_DECREF(pair);
468		Py_DECREF(prop);
469	}
470#undef realdict
471	if (!isStruct)
472		size = union_size;
473
474	/* Adjust the size according to the alignment requirements */
475	size = ((size + total_align - 1) / total_align) * total_align;
476
477	stgdict->ffi_type_pointer.alignment = total_align;
478	stgdict->ffi_type_pointer.size = size;
479
480	stgdict->size = size;
481	stgdict->align = total_align;
482	stgdict->length = len;	/* ADD ffi_ofs? */
483
484	/* We did check that this flag was NOT set above, it must not
485	   have been set until now. */
486	if (stgdict->flags & DICTFLAG_FINAL) {
487		PyErr_SetString(PyExc_AttributeError,
488				"Structure or union cannot contain itself");
489		return -1;
490	}
491	stgdict->flags |= DICTFLAG_FINAL;
492
493	return MakeAnonFields(type);
494}
495