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