/* Retrive the (optional) _pack_ attribute from a type, the _fields_ attribute, and create an StgDictObject. Used for Structure and Union subclasses. */ int StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct) { StgDictObject *stgdict, *basedict; Py_ssize_t len, offset, size, align, i; Py_ssize_t union_size, total_align; Py_ssize_t field_size = 0; int bitofs; PyObject *isPacked; int pack = 0; Py_ssize_t ffi_ofs; int big_endian; /* HACK Alert: I cannot be bothered to fix ctypes.com, so there has to be a way to use the old, broken sematics: _fields_ are not extended but replaced in subclasses. XXX Remove this in ctypes 1.0! */ int use_broken_old_ctypes_semantics; if (fields == NULL) return 0; #ifdef WORDS_BIGENDIAN big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 0 : 1; #else big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 1 : 0; #endif use_broken_old_ctypes_semantics = \ PyObject_HasAttrString(type, "_use_broken_old_ctypes_structure_semantics_"); isPacked = PyObject_GetAttrString(type, "_pack_"); if (isPacked) { pack = PyInt_AsLong(isPacked); if (pack < 0 || PyErr_Occurred()) { Py_XDECREF(isPacked); PyErr_SetString(PyExc_ValueError, "_pack_ must be a non-negative integer"); return -1; } Py_DECREF(isPacked); } else PyErr_Clear(); len = PySequence_Length(fields); if (len == -1) { PyErr_SetString(PyExc_TypeError, "'_fields_' must be a sequence of pairs"); return -1; } stgdict = PyType_stgdict(type); if (!stgdict) return -1; /* If this structure/union is already marked final we cannot assign _fields_ anymore. */ if (stgdict->flags & DICTFLAG_FINAL) {/* is final ? */ PyErr_SetString(PyExc_AttributeError, "_fields_ is final"); return -1; } if (stgdict->format) { PyMem_Free(stgdict->format); stgdict->format = NULL; } if (stgdict->ffi_type_pointer.elements) PyMem_Free(stgdict->ffi_type_pointer.elements); basedict = PyType_stgdict((PyObject *)((PyTypeObject *)type)->tp_base); if (basedict && !use_broken_old_ctypes_semantics) { size = offset = basedict->size; align = basedict->align; union_size = 0; total_align = align ? align : 1; stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (basedict->length + len + 1)); if (stgdict->ffi_type_pointer.elements == NULL) { PyErr_NoMemory(); return -1; } memset(stgdict->ffi_type_pointer.elements, 0, sizeof(ffi_type *) * (basedict->length + len + 1)); memcpy(stgdict->ffi_type_pointer.elements, basedict->ffi_type_pointer.elements, sizeof(ffi_type *) * (basedict->length)); ffi_ofs = basedict->length; } else { offset = 0; size = 0; align = 0; union_size = 0; total_align = 1; stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (len + 1)); if (stgdict->ffi_type_pointer.elements == NULL) { PyErr_NoMemory(); return -1; } memset(stgdict->ffi_type_pointer.elements, 0, sizeof(ffi_type *) * (len + 1)); ffi_ofs = 0; } assert(stgdict->format == NULL); if (isStruct && !isPacked) { stgdict->format = alloc_format_string(NULL, "T{"); } else { /* PEP3118 doesn't support union, or packed structures (well, only standard packing, but we dont support the pep for that). Use 'B' for bytes. */ stgdict->format = alloc_format_string(NULL, "B"); } #define realdict ((PyObject *)&stgdict->dict) for (i = 0; i < len; ++i) { PyObject *name = NULL, *desc = NULL; PyObject *pair = PySequence_GetItem(fields, i); PyObject *prop; StgDictObject *dict; int bitsize = 0; if (!pair || !PyArg_ParseTuple(pair, "OO|i", &name, &desc, &bitsize)) { PyErr_SetString(PyExc_AttributeError, "'_fields_' must be a sequence of pairs"); Py_XDECREF(pair); return -1; } dict = PyType_stgdict(desc); if (dict == NULL) { Py_DECREF(pair); PyErr_Format(PyExc_TypeError, #if (PY_VERSION_HEX < 0x02050000) "second item in _fields_ tuple (index %d) must be a C type", #else "second item in _fields_ tuple (index %zd) must be a C type", #endif i); return -1; } stgdict->ffi_type_pointer.elements[ffi_ofs + i] = &dict->ffi_type_pointer; if (dict->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER)) stgdict->flags |= TYPEFLAG_HASPOINTER; dict->flags |= DICTFLAG_FINAL; /* mark field type final */ if (PyTuple_Size(pair) == 3) { /* bits specified */ switch(dict->ffi_type_pointer.type) { case FFI_TYPE_UINT8: case FFI_TYPE_UINT16: case FFI_TYPE_UINT32: case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: break; case FFI_TYPE_SINT8: case FFI_TYPE_SINT16: case FFI_TYPE_SINT32: if (dict->getfunc != getentry("c")->getfunc #ifdef CTYPES_UNICODE && dict->getfunc != getentry("u")->getfunc #endif ) break; /* else fall through */ default: PyErr_Format(PyExc_TypeError, "bit fields not allowed for type %s", ((PyTypeObject *)desc)->tp_name); Py_DECREF(pair); return -1; } if (bitsize <= 0 || bitsize > dict->size * 8) { PyErr_SetString(PyExc_ValueError, "number of bits invalid for bit field"); Py_DECREF(pair); return -1; } } else bitsize = 0; if (isStruct && !isPacked) { char *fieldfmt = dict->format ? dict->format : "B"; char *fieldname = PyString_AsString(name); char *ptr; Py_ssize_t len = strlen(fieldname) + strlen(fieldfmt); char *buf = alloca(len + 2 + 1); sprintf(buf, "%s:%s:", fieldfmt, fieldname); ptr = stgdict->format; stgdict->format = alloc_format_string(stgdict->format, buf); PyMem_Free(ptr); if (stgdict->format == NULL) { Py_DECREF(pair); return -1; } } if (isStruct) { prop = CField_FromDesc(desc, i, &field_size, bitsize, &bitofs, &size, &offset, &align, pack, big_endian); } else /* union */ { size = 0; offset = 0; align = 0; prop = CField_FromDesc(desc, i, &field_size, bitsize, &bitofs, &size, &offset, &align, pack, big_endian); union_size = max(size, union_size); } total_align = max(align, total_align); if (!prop) { Py_DECREF(pair); return -1; } if (-1 == PyObject_SetAttr(type, name, prop)) { Py_DECREF(prop); Py_DECREF(pair); return -1; } Py_DECREF(pair); Py_DECREF(prop); } #undef realdict if (isStruct && !isPacked) { char *ptr = stgdict->format; stgdict->format = alloc_format_string(stgdict->format, "}"); PyMem_Free(ptr); if (stgdict->format == NULL) return -1; } if (!isStruct) size = union_size; /* Adjust the size according to the alignment requirements */ size = ((size + total_align - 1) / total_align) * total_align; stgdict->ffi_type_pointer.alignment = Py_SAFE_DOWNCAST(total_align, Py_ssize_t, unsigned short); stgdict->ffi_type_pointer.size = size; stgdict->size = size; stgdict->align = total_align; stgdict->length = len; /* ADD ffi_ofs? */ /* We did check that this flag was NOT set above, it must not have been set until now. */ if (stgdict->flags & DICTFLAG_FINAL) { PyErr_SetString(PyExc_AttributeError, "Structure or union cannot contain itself"); return -1; } stgdict->flags |= DICTFLAG_FINAL; return MakeAnonFields(type); }
/* * bitfields extension: * bitsize != 0: this is a bit field. * pbitofs points to the current bit offset, this will be updated. * prev_desc points to the type of the previous bitfield, if any. */ PyObject * PyCField_FromDesc(PyObject *desc, Py_ssize_t index, Py_ssize_t *pfield_size, int bitsize, int *pbitofs, Py_ssize_t *psize, Py_ssize_t *poffset, Py_ssize_t *palign, int pack, int big_endian) { CFieldObject *self; PyObject *proto; Py_ssize_t size, align; SETFUNC setfunc = NULL; GETFUNC getfunc = NULL; StgDictObject *dict; int fieldtype; #define NO_BITFIELD 0 #define NEW_BITFIELD 1 #define CONT_BITFIELD 2 #define EXPAND_BITFIELD 3 self = (CFieldObject *)PyObject_CallObject((PyObject *)&PyCField_Type, NULL); if (self == NULL) return NULL; dict = PyType_stgdict(desc); if (!dict) { PyErr_SetString(PyExc_TypeError, "has no _stginfo_"); Py_DECREF(self); return NULL; } if (bitsize /* this is a bitfield request */ && *pfield_size /* we have a bitfield open */ #ifdef MS_WIN32 /* MSVC, GCC with -mms-bitfields */ && dict->size * 8 == *pfield_size #else /* GCC */ && dict->size * 8 <= *pfield_size #endif && (*pbitofs + bitsize) <= *pfield_size) { /* continue bit field */ fieldtype = CONT_BITFIELD; #ifndef MS_WIN32 } else if (bitsize /* this is a bitfield request */ && *pfield_size /* we have a bitfield open */ && dict->size * 8 >= *pfield_size && (*pbitofs + bitsize) <= dict->size * 8) { /* expand bit field */ fieldtype = EXPAND_BITFIELD; #endif } else if (bitsize) { /* start new bitfield */ fieldtype = NEW_BITFIELD; *pbitofs = 0; *pfield_size = dict->size * 8; } else { /* not a bit field */ fieldtype = NO_BITFIELD; *pbitofs = 0; *pfield_size = 0; } size = dict->size; proto = desc; /* Field descriptors for 'c_char * n' are be scpecial cased to return a Python string instead of an Array object instance... */ if (PyCArrayTypeObject_Check(proto)) { StgDictObject *adict = PyType_stgdict(proto); StgDictObject *idict; if (adict && adict->proto) { idict = PyType_stgdict(adict->proto); if (!idict) { PyErr_SetString(PyExc_TypeError, "has no _stginfo_"); Py_DECREF(self); return NULL; } if (idict->getfunc == _ctypes_get_fielddesc("c")->getfunc) { struct fielddesc *fd = _ctypes_get_fielddesc("s"); getfunc = fd->getfunc; setfunc = fd->setfunc; } #ifdef CTYPES_UNICODE if (idict->getfunc == _ctypes_get_fielddesc("u")->getfunc) { struct fielddesc *fd = _ctypes_get_fielddesc("U"); getfunc = fd->getfunc; setfunc = fd->setfunc; } #endif } } self->setfunc = setfunc; self->getfunc = getfunc; self->index = index; Py_INCREF(proto); self->proto = proto; switch (fieldtype) { case NEW_BITFIELD: if (big_endian) self->size = (bitsize << 16) + *pfield_size - *pbitofs - bitsize; else self->size = (bitsize << 16) + *pbitofs; *pbitofs = bitsize; /* fall through */ case NO_BITFIELD: if (pack) align = min(pack, dict->align); else align = dict->align; if (align && *poffset % align) { Py_ssize_t delta = align - (*poffset % align); *psize += delta; *poffset += delta; } if (bitsize == 0) self->size = size; *psize += size; self->offset = *poffset; *poffset += size; *palign = align; break; case EXPAND_BITFIELD: *poffset += dict->size - *pfield_size/8; *psize += dict->size - *pfield_size/8; *pfield_size = dict->size * 8; if (big_endian) self->size = (bitsize << 16) + *pfield_size - *pbitofs - bitsize; else self->size = (bitsize << 16) + *pbitofs; self->offset = *poffset - size; /* poffset is already updated for the NEXT field */ *pbitofs += bitsize; break; case CONT_BITFIELD: if (big_endian) self->size = (bitsize << 16) + *pfield_size - *pbitofs - bitsize; else self->size = (bitsize << 16) + *pbitofs; self->offset = *poffset - size; /* poffset is already updated for the NEXT field */ *pbitofs += bitsize; break; } return (PyObject *)self; }
/****************************************************************************** * * Call the python object with all arguments * */ static void _CallPythonObject(void *mem, ffi_type *restype, SETFUNC setfunc, PyObject *callable, PyObject *converters, int flags, void **pArgs) { Py_ssize_t i; PyObject *result; PyObject *arglist = NULL; Py_ssize_t nArgs; PyObject *error_object = NULL; int *space; #ifdef WITH_THREAD PyGILState_STATE state = PyGILState_Ensure(); #endif nArgs = PySequence_Length(converters); /* Hm. What to return in case of error? For COM, 0xFFFFFFFF seems better than 0. */ if (nArgs < 0) { PrintError("BUG: PySequence_Length"); goto Done; } arglist = PyTuple_New(nArgs); if (!arglist) { PrintError("PyTuple_New()"); goto Done; } for (i = 0; i < nArgs; ++i) { /* Note: new reference! */ PyObject *cnv = PySequence_GetItem(converters, i); StgDictObject *dict; if (cnv) dict = PyType_stgdict(cnv); else { PrintError("Getting argument converter %d\n", i); goto Done; } if (dict && dict->getfunc && !_ctypes_simple_instance(cnv)) { PyObject *v = dict->getfunc(*pArgs, dict->size); if (!v) { PrintError("create argument %d:\n", i); Py_DECREF(cnv); goto Done; } PyTuple_SET_ITEM(arglist, i, v); /* XXX XXX XX We have the problem that c_byte or c_short have dict->size of 1 resp. 4, but these parameters are pushed as sizeof(int) bytes. BTW, the same problem occurrs when they are pushed as parameters */ } else if (dict) { /* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */ CDataObject *obj = (CDataObject *)PyObject_CallFunctionObjArgs(cnv, NULL); if (!obj) { PrintError("create argument %d:\n", i); Py_DECREF(cnv); goto Done; } if (!CDataObject_Check(obj)) { Py_DECREF(obj); Py_DECREF(cnv); PrintError("unexpected result of create argument %d:\n", i); goto Done; } memcpy(obj->b_ptr, *pArgs, dict->size); PyTuple_SET_ITEM(arglist, i, (PyObject *)obj); #ifdef MS_WIN32 TryAddRef(dict, obj); #endif } else { PyErr_SetString(PyExc_TypeError, "cannot build parameter"); PrintError("Parsing argument %d\n", i); Py_DECREF(cnv); goto Done; } Py_DECREF(cnv); /* XXX error handling! */ pArgs++; } #define CHECK(what, x) \ if (x == NULL) _ctypes_add_traceback(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print() if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) { error_object = _ctypes_get_errobj(&space); if (error_object == NULL) goto Done; if (flags & FUNCFLAG_USE_ERRNO) { int temp = space[0]; space[0] = errno; errno = temp; } #ifdef MS_WIN32 if (flags & FUNCFLAG_USE_LASTERROR) { int temp = space[1]; space[1] = GetLastError(); SetLastError(temp); } #endif } result = PyObject_CallObject(callable, arglist); CHECK("'calling callback function'", result); #ifdef MS_WIN32 if (flags & FUNCFLAG_USE_LASTERROR) { int temp = space[1]; space[1] = GetLastError(); SetLastError(temp); } #endif if (flags & FUNCFLAG_USE_ERRNO) { int temp = space[0]; space[0] = errno; errno = temp; } Py_XDECREF(error_object); if ((restype != &ffi_type_void) && result) { PyObject *keep; assert(setfunc); #ifdef WORDS_BIGENDIAN /* See the corresponding code in callproc.c, around line 961 */ if (restype->type != FFI_TYPE_FLOAT && restype->size < sizeof(ffi_arg)) mem = (char *)mem + sizeof(ffi_arg) - restype->size; #endif keep = setfunc(mem, result, 0); CHECK("'converting callback result'", keep); /* keep is an object we have to keep alive so that the result stays valid. If there is no such object, the setfunc will have returned Py_None. If there is such an object, we have no choice than to keep it alive forever - but a refcount and/or memory leak will be the result. EXCEPT when restype is py_object - Python itself knows how to manage the refcount of these objects. */ if (keep == NULL) /* Could not convert callback result. */ PyErr_WriteUnraisable(callable); else if (keep == Py_None) /* Nothing to keep */ Py_DECREF(keep); else if (setfunc != _ctypes_get_fielddesc("O")->setfunc) { if (-1 == PyErr_WarnEx(PyExc_RuntimeWarning, "memory leak in callback function.", 1)) PyErr_WriteUnraisable(callable); } } Py_XDECREF(result); Done: Py_XDECREF(arglist); #ifdef WITH_THREAD PyGILState_Release(state); #endif }
CThunkObject *_ctypes_alloc_callback(PyObject *callable, PyObject *converters, PyObject *restype, int flags) { int result; CThunkObject *p; Py_ssize_t nArgs, i; ffi_abi cc; nArgs = PySequence_Size(converters); p = CThunkObject_new(nArgs); if (p == NULL) return NULL; assert(CThunk_CheckExact((PyObject *)p)); p->pcl = _ctypes_alloc_closure(); if (p->pcl == NULL) { PyErr_NoMemory(); goto error; } p->flags = flags; for (i = 0; i < nArgs; ++i) { PyObject *cnv = PySequence_GetItem(converters, i); if (cnv == NULL) goto error; p->atypes[i] = _ctypes_get_ffi_type(cnv); Py_DECREF(cnv); } p->atypes[i] = NULL; Py_INCREF(restype); p->restype = restype; if (restype == Py_None) { p->setfunc = NULL; p->ffi_restype = &ffi_type_void; } else { StgDictObject *dict = PyType_stgdict(restype); if (dict == NULL || dict->setfunc == NULL) { PyErr_SetString(PyExc_TypeError, "invalid result type for callback function"); goto error; } p->setfunc = dict->setfunc; p->ffi_restype = &dict->ffi_type_pointer; } cc = FFI_DEFAULT_ABI; #if defined(MS_WIN32) && !defined(_WIN32_WCE) && !defined(MS_WIN64) if ((flags & FUNCFLAG_CDECL) == 0) cc = FFI_STDCALL; #endif result = ffi_prep_cif(&p->cif, cc, Py_SAFE_DOWNCAST(nArgs, Py_ssize_t, int), _ctypes_get_ffi_type(restype), &p->atypes[0]); if (result != FFI_OK) { PyErr_Format(PyExc_RuntimeError, "ffi_prep_cif failed with %d", result); goto error; } result = ffi_prep_closure(p->pcl, &p->cif, closure_fcn, p); if (result != FFI_OK) { PyErr_Format(PyExc_RuntimeError, "ffi_prep_closure failed with %d", result); goto error; } Py_INCREF(converters); p->converters = converters; Py_INCREF(callable); p->callable = callable; return p; error: Py_XDECREF(p); return NULL; }
ffi_info *AllocFunctionCallback(PyObject *callable, PyObject *converters, PyObject *restype, int is_cdecl) { int result; ffi_info *p; int nArgs, i; ffi_abi cc; nArgs = PySequence_Size(converters); p = (ffi_info *)PyMem_Malloc(sizeof(ffi_info) + sizeof(ffi_type) * (nArgs + 1)); if (p == NULL) { PyErr_NoMemory(); return NULL; } p->pcl = MallocClosure(); if (p->pcl == NULL) { PyErr_NoMemory(); goto error; } for (i = 0; i < nArgs; ++i) { PyObject *cnv = PySequence_GetItem(converters, i); if (cnv == NULL) goto error; p->atypes[i] = GetType(cnv); Py_DECREF(cnv); } p->atypes[i] = NULL; if (restype == Py_None) { p->setfunc = NULL; p->restype = &ffi_type_void; } else { StgDictObject *dict = PyType_stgdict(restype); if (dict == NULL || dict->setfunc == NULL) { PyErr_SetString(PyExc_TypeError, "invalid result type for callback function"); goto error; } p->setfunc = dict->setfunc; p->restype = &dict->ffi_type_pointer; } cc = FFI_DEFAULT_ABI; #if defined(MS_WIN32) && !defined(_WIN32_WCE) if (is_cdecl == 0) cc = FFI_STDCALL; #endif result = ffi_prep_cif(&p->cif, cc, nArgs, GetType(restype), &p->atypes[0]); if (result != FFI_OK) { PyErr_Format(PyExc_RuntimeError, "ffi_prep_cif failed with %d", result); goto error; } result = ffi_prep_closure(p->pcl, &p->cif, closure_fcn, p); if (result != FFI_OK) { PyErr_Format(PyExc_RuntimeError, "ffi_prep_closure failed with %d", result); goto error; } p->converters = converters; p->callable = callable; return p; error: if (p) { if (p->pcl) FreeClosure(p->pcl); PyMem_Free(p); } return NULL; }