mirror of
https://github.com/python/cpython
synced 2024-09-05 00:05:39 +00:00
gh-114314: ctypes: remove stgdict and switch to heap types (GH-116458)
Before this change, ctypes classes used a custom dict subclass, `StgDict`, as their `tp_dict`. This acts like a regular dict but also includes extra information about the type. This replaces stgdict by `StgInfo`, a C struct on the type, accessed by `PyObject_GetTypeData()` (PEP-697). All usage of `StgDict` (mainly variables named `stgdict`, `dict`, `edict` etc.) is converted to `StgInfo` (named `stginfo`, `info`, `einfo`, etc.). Where the dict is actually used for class attributes (as a regular PyDict), it's now called `attrdict`. This change -- not overriding `tp_dict` -- is made to make me comfortable with the next part of this PR: moving the initialization logic from `tp_new` to `tp_init`. The `StgInfo` is set up in `__init__` of each class, with a guard that prevents calling `__init__` more than once. Note that abstract classes (like `Array` or `Structure`) are created using `PyType_FromMetaclass` and do not have `__init__` called. Previously, this was done in `__new__`, which also wasn't called for abstract classes. Since `__init__` can be called from Python code or skipped, there is a tested guard to ensure `StgInfo` is initialized exactly once before it's used. Co-authored-by: neonene <53406459+neonene@users.noreply.github.com> Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
This commit is contained in:
parent
44fbab43d8
commit
dcaf33a41d
|
@ -37,6 +37,22 @@ def test_type_flags(self):
|
|||
self.assertTrue(cls.__flags__ & Py_TPFLAGS_IMMUTABLETYPE)
|
||||
self.assertFalse(cls.__flags__ & Py_TPFLAGS_DISALLOW_INSTANTIATION)
|
||||
|
||||
def test_metaclass_details(self):
|
||||
# Abstract classes (whose metaclass __init__ was not called) can't be
|
||||
# instantiated directly
|
||||
NewArray = PyCArrayType.__new__(PyCArrayType, 'NewArray', (Array,), {})
|
||||
for cls in Array, NewArray:
|
||||
with self.subTest(cls=cls):
|
||||
with self.assertRaisesRegex(TypeError, "abstract class"):
|
||||
obj = cls()
|
||||
|
||||
# Cannot call the metaclass __init__ more than once
|
||||
class T(Array):
|
||||
_type_ = c_int
|
||||
_length_ = 13
|
||||
with self.assertRaisesRegex(SystemError, "already initialized"):
|
||||
PyCArrayType.__init__(T, 'ptr', (), {})
|
||||
|
||||
def test_simple(self):
|
||||
# create classes holding simple numeric types, and check
|
||||
# various properties.
|
||||
|
|
|
@ -106,7 +106,7 @@ def test_pyobject(self):
|
|||
|
||||
def test_unsupported_restype_1(self):
|
||||
# Only "fundamental" result types are supported for callback
|
||||
# functions, the type must have a non-NULL stgdict->setfunc.
|
||||
# functions, the type must have a non-NULL stginfo->setfunc.
|
||||
# POINTER(c_double), for example, is not supported.
|
||||
|
||||
prototype = self.functype.__func__(POINTER(c_double))
|
||||
|
|
|
@ -29,6 +29,12 @@ def test_type_flags(self):
|
|||
self.assertTrue(_CFuncPtr.__flags__ & Py_TPFLAGS_IMMUTABLETYPE)
|
||||
self.assertFalse(_CFuncPtr.__flags__ & Py_TPFLAGS_DISALLOW_INSTANTIATION)
|
||||
|
||||
def test_metaclass_details(self):
|
||||
# Cannot call the metaclass __init__ more than once
|
||||
CdeclCallback = CFUNCTYPE(c_int, c_int, c_int)
|
||||
with self.assertRaisesRegex(SystemError, "already initialized"):
|
||||
PyCFuncPtrType.__init__(CdeclCallback, 'ptr', (), {})
|
||||
|
||||
def test_basic(self):
|
||||
X = WINFUNCTYPE(c_int, c_int, c_int)
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ def test_type_flags(self):
|
|||
self.assertTrue(_Pointer.__flags__ & Py_TPFLAGS_IMMUTABLETYPE)
|
||||
self.assertFalse(_Pointer.__flags__ & Py_TPFLAGS_DISALLOW_INSTANTIATION)
|
||||
|
||||
def test_metaclass_details(self):
|
||||
# Cannot call the metaclass __init__ more than once
|
||||
with self.assertRaisesRegex(SystemError, "already initialized"):
|
||||
PyCPointerType.__init__(POINTER(c_byte), 'ptr', (), {})
|
||||
|
||||
def test_pointer_crash(self):
|
||||
|
||||
class A(POINTER(c_ulong)):
|
||||
|
|
|
@ -26,6 +26,29 @@ def test_type_flags(self):
|
|||
self.assertTrue(_SimpleCData.__flags__ & Py_TPFLAGS_IMMUTABLETYPE)
|
||||
self.assertFalse(_SimpleCData.__flags__ & Py_TPFLAGS_DISALLOW_INSTANTIATION)
|
||||
|
||||
def test_metaclass_details(self):
|
||||
# Abstract classes (whose metaclass __init__ was not called) can't be
|
||||
# instantiated directly
|
||||
NewT = PyCSimpleType.__new__(PyCSimpleType, 'NewT', (_SimpleCData,), {})
|
||||
for cls in _SimpleCData, NewT:
|
||||
with self.subTest(cls=cls):
|
||||
with self.assertRaisesRegex(TypeError, "abstract class"):
|
||||
obj = cls()
|
||||
|
||||
# Cannot call the metaclass __init__ more than once
|
||||
class T(_SimpleCData):
|
||||
_type_ = "i"
|
||||
with self.assertRaisesRegex(SystemError, "already initialized"):
|
||||
PyCSimpleType.__init__(T, 'ptr', (), {})
|
||||
|
||||
def test_swapped_type_creation(self):
|
||||
cls = PyCSimpleType.__new__(PyCSimpleType, '', (), {'_type_': 'i'})
|
||||
with self.assertRaises(TypeError):
|
||||
PyCSimpleType.__init__(cls)
|
||||
PyCSimpleType.__init__(cls, '', (), {'_type_': 'i'})
|
||||
self.assertEqual(cls.__ctype_le__.__dict__.get('_type_'), 'i')
|
||||
self.assertEqual(cls.__ctype_be__.__dict__.get('_type_'), 'i')
|
||||
|
||||
def test_compare(self):
|
||||
self.assertEqual(MyInt(3), MyInt(3))
|
||||
self.assertNotEqual(MyInt(42), MyInt(43))
|
||||
|
|
|
@ -69,7 +69,7 @@ def test_cfield_inheritance_hierarchy(self):
|
|||
def test_gh99275(self):
|
||||
class BrokenStructure(Structure):
|
||||
def __init_subclass__(cls, **kwargs):
|
||||
cls._fields_ = [] # This line will fail, `stgdict` is not ready
|
||||
cls._fields_ = [] # This line will fail, `stginfo` is not ready
|
||||
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'ctypes state is not initialized'):
|
||||
|
|
|
@ -85,6 +85,23 @@ def test_type_flags(self):
|
|||
self.assertTrue(Structure.__flags__ & Py_TPFLAGS_IMMUTABLETYPE)
|
||||
self.assertFalse(Structure.__flags__ & Py_TPFLAGS_DISALLOW_INSTANTIATION)
|
||||
|
||||
def test_metaclass_details(self):
|
||||
# Abstract classes (whose metaclass __init__ was not called) can't be
|
||||
# instantiated directly
|
||||
NewStructure = PyCStructType.__new__(PyCStructType, 'NewStructure',
|
||||
(Structure,), {})
|
||||
for cls in Structure, NewStructure:
|
||||
with self.subTest(cls=cls):
|
||||
with self.assertRaisesRegex(TypeError, "abstract class"):
|
||||
obj = cls()
|
||||
|
||||
# Cannot call the metaclass __init__ more than once
|
||||
class T(Structure):
|
||||
_fields_ = [("x", c_char),
|
||||
("y", c_char)]
|
||||
with self.assertRaisesRegex(SystemError, "already initialized"):
|
||||
PyCStructType.__init__(T, 'ptr', (), {})
|
||||
|
||||
def test_simple_structs(self):
|
||||
for code, tp in self.formats.items():
|
||||
class X(Structure):
|
||||
|
@ -507,8 +524,8 @@ def _test_issue18060(self, Vector):
|
|||
@unittest.skipUnless(sys.byteorder == 'little', "can't test on this platform")
|
||||
def test_issue18060_a(self):
|
||||
# This test case calls
|
||||
# PyCStructUnionType_update_stgdict() for each
|
||||
# _fields_ assignment, and PyCStgDict_clone()
|
||||
# PyCStructUnionType_update_stginfo() for each
|
||||
# _fields_ assignment, and PyCStgInfo_clone()
|
||||
# for the Mid and Vector class definitions.
|
||||
class Base(Structure):
|
||||
_fields_ = [('y', c_double),
|
||||
|
@ -523,7 +540,7 @@ class Vector(Mid): pass
|
|||
@unittest.skipUnless(sys.byteorder == 'little', "can't test on this platform")
|
||||
def test_issue18060_b(self):
|
||||
# This test case calls
|
||||
# PyCStructUnionType_update_stgdict() for each
|
||||
# PyCStructUnionType_update_stginfo() for each
|
||||
# _fields_ assignment.
|
||||
class Base(Structure):
|
||||
_fields_ = [('y', c_double),
|
||||
|
@ -538,7 +555,7 @@ class Vector(Mid):
|
|||
@unittest.skipUnless(sys.byteorder == 'little', "can't test on this platform")
|
||||
def test_issue18060_c(self):
|
||||
# This test case calls
|
||||
# PyCStructUnionType_update_stgdict() for each
|
||||
# PyCStructUnionType_update_stginfo() for each
|
||||
# _fields_ assignment.
|
||||
class Base(Structure):
|
||||
_fields_ = [('y', c_double)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import unittest
|
||||
from ctypes import Union
|
||||
from ctypes import Union, c_char
|
||||
from ._support import (_CData, UnionType, Py_TPFLAGS_DISALLOW_INSTANTIATION,
|
||||
Py_TPFLAGS_IMMUTABLETYPE)
|
||||
|
||||
|
@ -16,3 +16,20 @@ def test_type_flags(self):
|
|||
with self.subTest(cls=Union):
|
||||
self.assertTrue(Union.__flags__ & Py_TPFLAGS_IMMUTABLETYPE)
|
||||
self.assertFalse(Union.__flags__ & Py_TPFLAGS_DISALLOW_INSTANTIATION)
|
||||
|
||||
def test_metaclass_details(self):
|
||||
# Abstract classes (whose metaclass __init__ was not called) can't be
|
||||
# instantiated directly
|
||||
NewUnion = UnionType.__new__(UnionType, 'NewUnion',
|
||||
(Union,), {})
|
||||
for cls in Union, NewUnion:
|
||||
with self.subTest(cls=cls):
|
||||
with self.assertRaisesRegex(TypeError, "abstract class"):
|
||||
obj = cls()
|
||||
|
||||
# Cannot call the metaclass __init__ more than once
|
||||
class T(Union):
|
||||
_fields_ = [("x", c_char),
|
||||
("y", c_char)]
|
||||
with self.assertRaisesRegex(SystemError, "already initialized"):
|
||||
UnionType.__init__(T, 'ptr', (), {})
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
In :mod:`ctypes`, ctype data is now stored in type objects directly rather
|
||||
than in a dict subclass. This is an internal change that should not affect
|
||||
usage.
|
File diff suppressed because it is too large
Load diff
|
@ -109,10 +109,14 @@ PrintError(const char *msg, ...)
|
|||
* slower.
|
||||
*/
|
||||
static void
|
||||
TryAddRef(StgDictObject *dict, CDataObject *obj)
|
||||
TryAddRef(PyObject *cnv, CDataObject *obj)
|
||||
{
|
||||
IUnknown *punk;
|
||||
int r = PyDict_Contains((PyObject *)dict, &_Py_ID(_needs_com_addref_));
|
||||
PyObject *attrdict = _PyType_GetDict((PyTypeObject *)cnv);
|
||||
if (!attrdict) {
|
||||
return;
|
||||
}
|
||||
int r = PyDict_Contains(attrdict, &_Py_ID(_needs_com_addref_));
|
||||
if (r <= 0) {
|
||||
if (r < 0) {
|
||||
PrintError("getting _needs_com_addref_");
|
||||
|
@ -154,22 +158,26 @@ static void _CallPythonObject(void *mem,
|
|||
ctypes_state *st = GLOBAL_STATE();
|
||||
for (i = 0; i < nargs; i++) {
|
||||
PyObject *cnv = cnvs[i]; // borrowed ref
|
||||
StgDictObject *dict;
|
||||
dict = PyType_stgdict(cnv);
|
||||
|
||||
if (dict && dict->getfunc && !_ctypes_simple_instance(cnv)) {
|
||||
PyObject *v = dict->getfunc(*pArgs, dict->size);
|
||||
StgInfo *info;
|
||||
if (PyStgInfo_FromType(st, cnv, &info) < 0) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (info && info->getfunc && !_ctypes_simple_instance(cnv)) {
|
||||
PyObject *v = info->getfunc(*pArgs, info->size);
|
||||
if (!v) {
|
||||
PrintError("create argument %zd:\n", i);
|
||||
goto Done;
|
||||
}
|
||||
args[i] = v;
|
||||
/* XXX XXX XX
|
||||
We have the problem that c_byte or c_short have dict->size of
|
||||
We have the problem that c_byte or c_short have info->size of
|
||||
1 resp. 4, but these parameters are pushed as sizeof(int) bytes.
|
||||
BTW, the same problem occurs when they are pushed as parameters
|
||||
*/
|
||||
} else if (dict) {
|
||||
}
|
||||
else if (info) {
|
||||
/* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */
|
||||
CDataObject *obj = (CDataObject *)_PyObject_CallNoArgs(cnv);
|
||||
if (!obj) {
|
||||
|
@ -181,10 +189,10 @@ static void _CallPythonObject(void *mem,
|
|||
PrintError("unexpected result of create argument %zd:\n", i);
|
||||
goto Done;
|
||||
}
|
||||
memcpy(obj->b_ptr, *pArgs, dict->size);
|
||||
memcpy(obj->b_ptr, *pArgs, info->size);
|
||||
args[i] = (PyObject *)obj;
|
||||
#ifdef MS_WIN32
|
||||
TryAddRef(dict, obj);
|
||||
TryAddRef(cnv, obj);
|
||||
#endif
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
|
@ -348,10 +356,8 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
|
|||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
#ifdef Py_DEBUG
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
assert(CThunk_CheckExact(st, (PyObject *)p));
|
||||
#endif
|
||||
|
||||
p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec);
|
||||
if (p->pcl_write == NULL) {
|
||||
|
@ -372,14 +378,18 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
|
|||
p->setfunc = NULL;
|
||||
p->ffi_restype = &ffi_type_void;
|
||||
} else {
|
||||
StgDictObject *dict = PyType_stgdict(restype);
|
||||
if (dict == NULL || dict->setfunc == NULL) {
|
||||
StgInfo *info;
|
||||
if (PyStgInfo_FromType(st, restype, &info) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (info == NULL || info->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;
|
||||
p->setfunc = info->setfunc;
|
||||
p->ffi_restype = &info->ffi_type_pointer;
|
||||
}
|
||||
|
||||
cc = FFI_DEFAULT_ABI;
|
||||
|
|
|
@ -664,15 +664,20 @@ struct argument {
|
|||
*/
|
||||
static int ConvParam(PyObject *obj, Py_ssize_t index, struct argument *pa)
|
||||
{
|
||||
StgDictObject *dict;
|
||||
pa->keep = NULL; /* so we cannot forget it later */
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
|
||||
dict = PyObject_stgdict(obj);
|
||||
if (dict) {
|
||||
StgInfo *info;
|
||||
int result = PyStgInfo_FromObject(st, obj, &info);
|
||||
if (result < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (info) {
|
||||
assert(info);
|
||||
PyCArgObject *carg;
|
||||
assert(dict->paramfunc);
|
||||
/* If it has an stgdict, it is a CDataObject */
|
||||
carg = dict->paramfunc((CDataObject *)obj);
|
||||
assert(info->paramfunc);
|
||||
/* If it has an stginfo, it is a CDataObject */
|
||||
carg = info->paramfunc((CDataObject *)obj);
|
||||
if (carg == NULL)
|
||||
return -1;
|
||||
pa->ffi_type = carg->pffi_type;
|
||||
|
@ -681,7 +686,6 @@ static int ConvParam(PyObject *obj, Py_ssize_t index, struct argument *pa)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
if (PyCArg_CheckExact(st, obj)) {
|
||||
PyCArgObject *carg = (PyCArgObject *)obj;
|
||||
pa->ffi_type = carg->pffi_type;
|
||||
|
@ -778,26 +782,34 @@ int can_return_struct_as_sint64(size_t s)
|
|||
#endif
|
||||
|
||||
|
||||
// returns NULL with exception set on error
|
||||
ffi_type *_ctypes_get_ffi_type(PyObject *obj)
|
||||
{
|
||||
StgDictObject *dict;
|
||||
if (obj == NULL)
|
||||
if (obj == NULL) {
|
||||
return &ffi_type_sint;
|
||||
dict = PyType_stgdict(obj);
|
||||
if (dict == NULL)
|
||||
}
|
||||
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
StgInfo *info;
|
||||
if (PyStgInfo_FromType(st, obj, &info) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (info == NULL) {
|
||||
return &ffi_type_sint;
|
||||
}
|
||||
#if defined(MS_WIN32) && !defined(_WIN32_WCE)
|
||||
/* This little trick works correctly with MSVC.
|
||||
It returns small structures in registers
|
||||
*/
|
||||
if (dict->ffi_type_pointer.type == FFI_TYPE_STRUCT) {
|
||||
if (can_return_struct_as_int(dict->ffi_type_pointer.size))
|
||||
if (info->ffi_type_pointer.type == FFI_TYPE_STRUCT) {
|
||||
if (can_return_struct_as_int(info->ffi_type_pointer.size))
|
||||
return &ffi_type_sint32;
|
||||
else if (can_return_struct_as_sint64 (dict->ffi_type_pointer.size))
|
||||
else if (can_return_struct_as_sint64 (info->ffi_type_pointer.size))
|
||||
return &ffi_type_sint64;
|
||||
}
|
||||
#endif
|
||||
return &dict->ffi_type_pointer;
|
||||
return &info->ffi_type_pointer;
|
||||
}
|
||||
|
||||
|
||||
|
@ -983,7 +995,6 @@ static int _call_function_pointer(int flags,
|
|||
*/
|
||||
static PyObject *GetResult(PyObject *restype, void *result, PyObject *checker)
|
||||
{
|
||||
StgDictObject *dict;
|
||||
PyObject *retval, *v;
|
||||
|
||||
if (restype == NULL)
|
||||
|
@ -993,17 +1004,22 @@ static PyObject *GetResult(PyObject *restype, void *result, PyObject *checker)
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
dict = PyType_stgdict(restype);
|
||||
if (dict == NULL)
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
StgInfo *info;
|
||||
if (PyStgInfo_FromType(st, restype, &info) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (info == NULL) {
|
||||
return PyObject_CallFunction(restype, "i", *(int *)result);
|
||||
}
|
||||
|
||||
if (dict->getfunc && !_ctypes_simple_instance(restype)) {
|
||||
retval = dict->getfunc(result, dict->size);
|
||||
if (info->getfunc && !_ctypes_simple_instance(restype)) {
|
||||
retval = info->getfunc(result, info->size);
|
||||
/* If restype is py_object (detected by comparing getfunc with
|
||||
O_get), we have to call Py_DECREF because O_get has already
|
||||
called Py_INCREF.
|
||||
*/
|
||||
if (dict->getfunc == _ctypes_get_fielddesc("O")->getfunc) {
|
||||
if (info->getfunc == _ctypes_get_fielddesc("O")->getfunc) {
|
||||
Py_DECREF(retval);
|
||||
}
|
||||
} else
|
||||
|
@ -1240,6 +1256,9 @@ PyObject *_ctypes_callproc(PPROC pProc,
|
|||
} else {
|
||||
rtype = _ctypes_get_ffi_type(restype);
|
||||
}
|
||||
if (!rtype) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
resbuf = alloca(max(rtype->size, sizeof(ffi_arg)));
|
||||
|
||||
|
@ -1683,13 +1702,16 @@ PyDoc_STRVAR(sizeof_doc,
|
|||
static PyObject *
|
||||
sizeof_func(PyObject *self, PyObject *obj)
|
||||
{
|
||||
StgDictObject *dict;
|
||||
|
||||
dict = PyType_stgdict(obj);
|
||||
if (dict) {
|
||||
return PyLong_FromSsize_t(dict->size);
|
||||
}
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
|
||||
StgInfo *info;
|
||||
if (PyStgInfo_FromType(st, obj, &info) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (info) {
|
||||
return PyLong_FromSsize_t(info->size);
|
||||
}
|
||||
|
||||
if (CDataObject_Check(st, obj)) {
|
||||
return PyLong_FromSsize_t(((CDataObject *)obj)->b_size);
|
||||
}
|
||||
|
@ -1706,16 +1728,14 @@ PyDoc_STRVAR(alignment_doc,
|
|||
static PyObject *
|
||||
align_func(PyObject *self, PyObject *obj)
|
||||
{
|
||||
StgDictObject *dict;
|
||||
|
||||
dict = PyType_stgdict(obj);
|
||||
if (dict)
|
||||
return PyLong_FromSsize_t(dict->align);
|
||||
|
||||
dict = PyObject_stgdict(obj);
|
||||
if (dict)
|
||||
return PyLong_FromSsize_t(dict->align);
|
||||
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
StgInfo *info;
|
||||
if (PyStgInfo_FromAny(st, obj, &info) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (info) {
|
||||
return PyLong_FromSsize_t(info->align);
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"no alignment info");
|
||||
return NULL;
|
||||
|
@ -1824,7 +1844,6 @@ static PyObject *
|
|||
resize(PyObject *self, PyObject *args)
|
||||
{
|
||||
CDataObject *obj;
|
||||
StgDictObject *dict;
|
||||
Py_ssize_t size;
|
||||
|
||||
if (!PyArg_ParseTuple(args,
|
||||
|
@ -1832,16 +1851,21 @@ resize(PyObject *self, PyObject *args)
|
|||
&obj, &size))
|
||||
return NULL;
|
||||
|
||||
dict = PyObject_stgdict((PyObject *)obj);
|
||||
if (dict == NULL) {
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
StgInfo *info;
|
||||
int result = PyStgInfo_FromObject(st, (PyObject *)obj, &info);
|
||||
if (result < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (info == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"expected ctypes instance");
|
||||
return NULL;
|
||||
}
|
||||
if (size < dict->size) {
|
||||
if (size < info->size) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"minimum size is %zd",
|
||||
dict->size);
|
||||
info->size);
|
||||
return NULL;
|
||||
}
|
||||
if (obj->b_needsfree == 0) {
|
||||
|
@ -2004,28 +2028,30 @@ create_pointer_inst(PyObject *module, PyObject *arg)
|
|||
static PyObject *
|
||||
buffer_info(PyObject *self, PyObject *arg)
|
||||
{
|
||||
StgDictObject *dict = PyType_stgdict(arg);
|
||||
PyObject *shape;
|
||||
Py_ssize_t i;
|
||||
|
||||
if (dict == NULL)
|
||||
dict = PyObject_stgdict(arg);
|
||||
if (dict == NULL) {
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
StgInfo *info;
|
||||
if (PyStgInfo_FromAny(st, arg, &info) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (info == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"not a ctypes type or object");
|
||||
return NULL;
|
||||
}
|
||||
shape = PyTuple_New(dict->ndim);
|
||||
shape = PyTuple_New(info->ndim);
|
||||
if (shape == NULL)
|
||||
return NULL;
|
||||
for (i = 0; i < (int)dict->ndim; ++i)
|
||||
PyTuple_SET_ITEM(shape, i, PyLong_FromSsize_t(dict->shape[i]));
|
||||
for (i = 0; i < (int)info->ndim; ++i)
|
||||
PyTuple_SET_ITEM(shape, i, PyLong_FromSsize_t(info->shape[i]));
|
||||
|
||||
if (PyErr_Occurred()) {
|
||||
Py_DECREF(shape);
|
||||
return NULL;
|
||||
}
|
||||
return Py_BuildValue("siN", dict->format, dict->ndim, shape);
|
||||
return Py_BuildValue("siN", info->format, info->ndim, shape);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -54,7 +54,6 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
|
|||
Py_ssize_t size, align;
|
||||
SETFUNC setfunc = NULL;
|
||||
GETFUNC getfunc = NULL;
|
||||
StgDictObject *dict;
|
||||
int fieldtype;
|
||||
#define NO_BITFIELD 0
|
||||
#define NEW_BITFIELD 1
|
||||
|
@ -66,21 +65,27 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
|
|||
self = (CFieldObject *)tp->tp_alloc(tp, 0);
|
||||
if (self == NULL)
|
||||
return NULL;
|
||||
dict = PyType_stgdict(desc);
|
||||
if (!dict) {
|
||||
|
||||
StgInfo *info;
|
||||
if (PyStgInfo_FromType(st, desc, &info) < 0) {
|
||||
Py_DECREF(self);
|
||||
return NULL;
|
||||
}
|
||||
if (!info) {
|
||||
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
|
||||
&& info->size * 8 == *pfield_size
|
||||
#else
|
||||
/* GCC */
|
||||
&& dict->size * 8 <= *pfield_size
|
||||
&& info->size * 8 <= *pfield_size
|
||||
#endif
|
||||
&& (*pbitofs + bitsize) <= *pfield_size) {
|
||||
/* continue bit field */
|
||||
|
@ -88,8 +93,8 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
|
|||
#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) {
|
||||
&& info->size * 8 >= *pfield_size
|
||||
&& (*pbitofs + bitsize) <= info->size * 8) {
|
||||
/* expand bit field */
|
||||
fieldtype = EXPAND_BITFIELD;
|
||||
#endif
|
||||
|
@ -97,7 +102,7 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
|
|||
/* start new bitfield */
|
||||
fieldtype = NEW_BITFIELD;
|
||||
*pbitofs = 0;
|
||||
*pfield_size = dict->size * 8;
|
||||
*pfield_size = info->size * 8;
|
||||
} else {
|
||||
/* not a bit field */
|
||||
fieldtype = NO_BITFIELD;
|
||||
|
@ -105,29 +110,37 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
|
|||
*pfield_size = 0;
|
||||
}
|
||||
|
||||
size = dict->size;
|
||||
size = info->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(st, proto)) {
|
||||
StgDictObject *adict = PyType_stgdict(proto);
|
||||
StgDictObject *idict;
|
||||
if (adict && adict->proto) {
|
||||
idict = PyType_stgdict(adict->proto);
|
||||
if (!idict) {
|
||||
StgInfo *ainfo;
|
||||
if (PyStgInfo_FromType(st, proto, &ainfo) < 0) {
|
||||
Py_DECREF(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ainfo && ainfo->proto) {
|
||||
StgInfo *iinfo;
|
||||
if (PyStgInfo_FromType(st, ainfo->proto, &iinfo) < 0) {
|
||||
Py_DECREF(self);
|
||||
return NULL;
|
||||
}
|
||||
if (!iinfo) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"has no _stginfo_");
|
||||
Py_DECREF(self);
|
||||
return NULL;
|
||||
}
|
||||
if (idict->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
|
||||
if (iinfo->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
|
||||
struct fielddesc *fd = _ctypes_get_fielddesc("s");
|
||||
getfunc = fd->getfunc;
|
||||
setfunc = fd->setfunc;
|
||||
}
|
||||
if (idict->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
|
||||
if (iinfo->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
|
||||
struct fielddesc *fd = _ctypes_get_fielddesc("U");
|
||||
getfunc = fd->getfunc;
|
||||
setfunc = fd->setfunc;
|
||||
|
@ -151,9 +164,9 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
|
|||
/* fall through */
|
||||
case NO_BITFIELD:
|
||||
if (pack)
|
||||
align = min(pack, dict->align);
|
||||
align = min(pack, info->align);
|
||||
else
|
||||
align = dict->align;
|
||||
align = info->align;
|
||||
if (align && *poffset % align) {
|
||||
Py_ssize_t delta = align - (*poffset % align);
|
||||
*psize += delta;
|
||||
|
@ -171,10 +184,10 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
|
|||
break;
|
||||
|
||||
case EXPAND_BITFIELD:
|
||||
*poffset += dict->size - *pfield_size/8;
|
||||
*psize += dict->size - *pfield_size/8;
|
||||
*poffset += info->size - *pfield_size/8;
|
||||
*psize += info->size - *pfield_size/8;
|
||||
|
||||
*pfield_size = dict->size * 8;
|
||||
*pfield_size = info->size * 8;
|
||||
|
||||
if (big_endian)
|
||||
self->size = (bitsize << 16) + *pfield_size - *pbitofs - bitsize;
|
||||
|
|
|
@ -41,7 +41,6 @@ typedef struct {
|
|||
PyTypeObject *PyCArg_Type;
|
||||
PyTypeObject *PyCField_Type;
|
||||
PyTypeObject *PyCThunk_Type;
|
||||
PyTypeObject *PyCStgDict_Type;
|
||||
PyTypeObject *StructParam_Type;
|
||||
PyTypeObject *PyCStructType_Type;
|
||||
PyTypeObject *UnionType_Type;
|
||||
|
@ -59,6 +58,7 @@ typedef struct {
|
|||
#ifdef MS_WIN32
|
||||
PyTypeObject *PyComError_Type;
|
||||
#endif
|
||||
PyTypeObject *PyCType_Type;
|
||||
} ctypes_state;
|
||||
|
||||
extern ctypes_state global_state;
|
||||
|
@ -144,7 +144,7 @@ typedef struct {
|
|||
CThunkObject *thunk;
|
||||
PyObject *callable;
|
||||
|
||||
/* These two fields will override the ones in the type's stgdict if
|
||||
/* These two fields will override the ones in the type's stginfo if
|
||||
they are set */
|
||||
PyObject *converters;
|
||||
PyObject *argtypes;
|
||||
|
@ -158,17 +158,12 @@ typedef struct {
|
|||
PyObject *paramflags;
|
||||
} PyCFuncPtrObject;
|
||||
|
||||
extern PyTypeObject PyCStgDict_Type;
|
||||
#define PyCStgDict_CheckExact(st, v) Py_IS_TYPE((v), (st)->PyCStgDict_Type)
|
||||
#define PyCStgDict_Check(st, v) PyObject_TypeCheck((v), (st)->PyCStgDict_Type)
|
||||
|
||||
extern int PyCStructUnionType_update_stgdict(PyObject *fields, PyObject *type, int isStruct);
|
||||
extern int PyCStructUnionType_update_stginfo(PyObject *fields, PyObject *type, int isStruct);
|
||||
extern int PyType_stginfo(PyTypeObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength);
|
||||
extern int PyObject_stginfo(PyObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength);
|
||||
|
||||
|
||||
|
||||
extern PyTypeObject PyCData_Type;
|
||||
#define CDataObject_CheckExact(st, v) Py_IS_TYPE((v), (st)->PyCData_Type)
|
||||
#define CDataObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCData_Type)
|
||||
#define _CDataObject_HasExternalBuffer(v) ((v)->b_ptr != (char *)&(v)->b_value)
|
||||
|
@ -188,10 +183,6 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
|
|||
extern PyObject *PyCData_AtAddress(PyObject *type, void *buf);
|
||||
extern PyObject *PyCData_FromBytes(PyObject *type, char *data, Py_ssize_t length);
|
||||
|
||||
extern PyTypeObject PyCArray_Type;
|
||||
extern PyTypeObject PyCPointer_Type;
|
||||
extern PyTypeObject PyCFuncPtr_Type;
|
||||
|
||||
#define PyCArrayTypeObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCArrayType_Type)
|
||||
#define ArrayObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCArray_Type)
|
||||
#define PointerObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCPointer_Type)
|
||||
|
@ -231,45 +222,22 @@ typedef struct {
|
|||
int anonymous;
|
||||
} CFieldObject;
|
||||
|
||||
/* A subclass of PyDictObject, used as the instance dictionary of ctypes
|
||||
metatypes */
|
||||
typedef struct {
|
||||
PyDictObject dict; /* first part identical to PyDictObject */
|
||||
/* The size and align fields are unneeded, they are in ffi_type as well. As
|
||||
an experiment shows, it's trivial to get rid of them, the only thing to
|
||||
remember is that in PyCArrayType_new the ffi_type fields must be filled in -
|
||||
so far it was unneeded because libffi doesn't support arrays at all
|
||||
(because they are passed as pointers to function calls anyway). But it's
|
||||
too much risk to change that now, and there are other fields which doesn't
|
||||
belong into this structure anyway. Maybe in ctypes 2.0... (ctypes 2000?)
|
||||
*/
|
||||
Py_ssize_t size; /* number of bytes */
|
||||
Py_ssize_t align; /* alignment requirements */
|
||||
Py_ssize_t length; /* number of fields */
|
||||
ffi_type ffi_type_pointer;
|
||||
PyObject *proto; /* Only for Pointer/ArrayObject */
|
||||
SETFUNC setfunc; /* Only for simple objects */
|
||||
GETFUNC getfunc; /* Only for simple objects */
|
||||
PARAMFUNC paramfunc;
|
||||
|
||||
/* Following fields only used by PyCFuncPtrType_Type instances */
|
||||
PyObject *argtypes; /* tuple of CDataObjects */
|
||||
PyObject *converters; /* tuple([t.from_param for t in argtypes]) */
|
||||
PyObject *restype; /* CDataObject or NULL */
|
||||
PyObject *checker;
|
||||
int flags; /* calling convention and such */
|
||||
|
||||
/* pep3118 fields, pointers need PyMem_Free */
|
||||
char *format;
|
||||
int ndim;
|
||||
Py_ssize_t *shape;
|
||||
/* Py_ssize_t *strides; */ /* unused in ctypes */
|
||||
/* Py_ssize_t *suboffsets; */ /* unused in ctypes */
|
||||
|
||||
} StgDictObject;
|
||||
|
||||
/****************************************************************
|
||||
StgDictObject fields
|
||||
StgInfo
|
||||
|
||||
Since Python 3.13, ctypes-specific type information is stored in the
|
||||
corresponding type object, in a `StgInfo` struct accessed by the helpers
|
||||
below.
|
||||
Before that, each type's `tp_dict` was set to a dict *subclass* that included
|
||||
the fields that are now in StgInfo. The mechanism was called "StgDict"; a few
|
||||
references to that name might remain.
|
||||
|
||||
Functions for accessing StgInfo are `static inline` for performance;
|
||||
see later in this file.
|
||||
|
||||
****************************************************************
|
||||
|
||||
StgInfo fields
|
||||
|
||||
setfunc and getfunc is only set for simple data types, it is copied from the
|
||||
corresponding fielddesc entry. These are functions to set and get the value
|
||||
|
@ -280,11 +248,11 @@ typedef struct {
|
|||
object.
|
||||
|
||||
Probably all the magic ctypes methods (like from_param) should have C
|
||||
callable wrappers in the StgDictObject. For simple data type, for example,
|
||||
callable wrappers in the StgInfo. For simple data type, for example,
|
||||
the fielddesc table could have entries for C codec from_param functions or
|
||||
other methods as well, if a subtype overrides this method in Python at
|
||||
construction time, or assigns to it later, tp_setattro should update the
|
||||
StgDictObject function to a generic one.
|
||||
StgInfo function to a generic one.
|
||||
|
||||
Currently, PyCFuncPtr types have 'converters' and 'checker' entries in their
|
||||
type dict. They are only used to cache attributes from other entries, which
|
||||
|
@ -308,13 +276,33 @@ typedef struct {
|
|||
|
||||
*****************************************************************/
|
||||
|
||||
/* May return NULL, but does not set an exception! */
|
||||
extern StgDictObject *PyType_stgdict(PyObject *obj);
|
||||
typedef struct {
|
||||
int initialized;
|
||||
Py_ssize_t size; /* number of bytes */
|
||||
Py_ssize_t align; /* alignment requirements */
|
||||
Py_ssize_t length; /* number of fields */
|
||||
ffi_type ffi_type_pointer;
|
||||
PyObject *proto; /* Only for Pointer/ArrayObject */
|
||||
SETFUNC setfunc; /* Only for simple objects */
|
||||
GETFUNC getfunc; /* Only for simple objects */
|
||||
PARAMFUNC paramfunc;
|
||||
|
||||
/* May return NULL, but does not set an exception! */
|
||||
extern StgDictObject *PyObject_stgdict(PyObject *self);
|
||||
/* Following fields only used by PyCFuncPtrType_Type instances */
|
||||
PyObject *argtypes; /* tuple of CDataObjects */
|
||||
PyObject *converters; /* tuple([t.from_param for t in argtypes]) */
|
||||
PyObject *restype; /* CDataObject or NULL */
|
||||
PyObject *checker;
|
||||
int flags; /* calling convention and such */
|
||||
|
||||
extern int PyCStgDict_clone(StgDictObject *src, StgDictObject *dst);
|
||||
/* pep3118 fields, pointers need PyMem_Free */
|
||||
char *format;
|
||||
int ndim;
|
||||
Py_ssize_t *shape;
|
||||
/* Py_ssize_t *strides; */ /* unused in ctypes */
|
||||
/* Py_ssize_t *suboffsets; */ /* unused in ctypes */
|
||||
} StgInfo;
|
||||
|
||||
extern int PyCStgInfo_clone(StgInfo *dst_info, StgInfo *src_info);
|
||||
|
||||
typedef int(* PPROC)(void);
|
||||
|
||||
|
@ -416,8 +404,74 @@ void *Py_ffi_closure_alloc(size_t size, void** codeloc);
|
|||
#define Py_ffi_closure_alloc ffi_closure_alloc
|
||||
#endif
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
compile-command: "python setup.py -q build install --home ~"
|
||||
End:
|
||||
*/
|
||||
|
||||
/****************************************************************
|
||||
* Accessing StgInfo -- these are inlined for performance reasons.
|
||||
*/
|
||||
|
||||
// `PyStgInfo_From**` functions get a PyCTypeDataObject.
|
||||
// These return -1 on error, 0 if "not found", 1 on OK.
|
||||
// (Currently, these do not return -1 in practice. This might change
|
||||
// in the future.)
|
||||
|
||||
//
|
||||
// Common helper:
|
||||
static inline int
|
||||
_stginfo_from_type(ctypes_state *state, PyTypeObject *type, StgInfo **result)
|
||||
{
|
||||
*result = NULL;
|
||||
if (!PyObject_IsInstance((PyObject *)type, (PyObject *)state->PyCType_Type)) {
|
||||
// not a ctypes class.
|
||||
return 0;
|
||||
}
|
||||
StgInfo *info = PyObject_GetTypeData((PyObject *)type, state->PyCType_Type);
|
||||
assert(info != NULL);
|
||||
if (!info->initialized) {
|
||||
// StgInfo is not initialized. This happens in abstract classes.
|
||||
return 0;
|
||||
}
|
||||
*result = info;
|
||||
return 1;
|
||||
}
|
||||
// from a type:
|
||||
static inline int
|
||||
PyStgInfo_FromType(ctypes_state *state, PyObject *type, StgInfo **result)
|
||||
{
|
||||
return _stginfo_from_type(state, (PyTypeObject *)type, result);
|
||||
}
|
||||
// from an instance:
|
||||
static inline int
|
||||
PyStgInfo_FromObject(ctypes_state *state, PyObject *obj, StgInfo **result)
|
||||
{
|
||||
return _stginfo_from_type(state, Py_TYPE(obj), result);
|
||||
}
|
||||
// from either a type or an instance:
|
||||
static inline int
|
||||
PyStgInfo_FromAny(ctypes_state *state, PyObject *obj, StgInfo **result)
|
||||
{
|
||||
if (PyType_Check(obj)) {
|
||||
return _stginfo_from_type(state, (PyTypeObject *)obj, result);
|
||||
}
|
||||
return _stginfo_from_type(state, Py_TYPE(obj), result);
|
||||
}
|
||||
|
||||
// Initialize StgInfo on a newly created type
|
||||
static inline StgInfo *
|
||||
PyStgInfo_Init(ctypes_state *state, PyTypeObject *type)
|
||||
{
|
||||
if (!PyObject_IsInstance((PyObject *)type, (PyObject *)state->PyCType_Type)) {
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"'%s' is not a ctypes class.",
|
||||
type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
StgInfo *info = PyObject_GetTypeData((PyObject *)type, state->PyCType_Type);
|
||||
if (info->initialized) {
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"StgInfo of '%s' is already initialized.",
|
||||
type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
info->initialized = 1;
|
||||
return info;
|
||||
}
|
||||
|
|
|
@ -16,201 +16,62 @@
|
|||
#endif
|
||||
#include "ctypes.h"
|
||||
|
||||
/******************************************************************/
|
||||
/*
|
||||
StdDict - a dictionary subclass, containing additional C accessible fields
|
||||
|
||||
XXX blabla more
|
||||
*/
|
||||
|
||||
/* Seems we need this, otherwise we get problems when calling
|
||||
* PyDict_SetItem() (ma_lookup is NULL)
|
||||
/* This file relates to StgInfo -- type-specific information for ctypes.
|
||||
* See ctypes.h for details.
|
||||
*/
|
||||
static int
|
||||
PyCStgDict_init(StgDictObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
|
||||
return -1;
|
||||
self->format = NULL;
|
||||
self->ndim = 0;
|
||||
self->shape = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
PyCStgDict_clear(StgDictObject *self)
|
||||
{
|
||||
Py_CLEAR(self->proto);
|
||||
Py_CLEAR(self->argtypes);
|
||||
Py_CLEAR(self->converters);
|
||||
Py_CLEAR(self->restype);
|
||||
Py_CLEAR(self->checker);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
PyCStgDict_dealloc(StgDictObject *self)
|
||||
{
|
||||
PyCStgDict_clear(self);
|
||||
PyMem_Free(self->format);
|
||||
PyMem_Free(self->shape);
|
||||
PyMem_Free(self->ffi_type_pointer.elements);
|
||||
PyDict_Type.tp_dealloc((PyObject *)self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PyCStgDict_sizeof(StgDictObject *self, void *unused)
|
||||
{
|
||||
Py_ssize_t res;
|
||||
|
||||
res = _PyDict_SizeOf((PyDictObject *)self);
|
||||
res += sizeof(StgDictObject) - sizeof(PyDictObject);
|
||||
if (self->format)
|
||||
res += strlen(self->format) + 1;
|
||||
res += self->ndim * sizeof(Py_ssize_t);
|
||||
if (self->ffi_type_pointer.elements)
|
||||
res += (self->length + 1) * sizeof(ffi_type *);
|
||||
return PyLong_FromSsize_t(res);
|
||||
}
|
||||
|
||||
int
|
||||
PyCStgDict_clone(StgDictObject *dst, StgDictObject *src)
|
||||
PyCStgInfo_clone(StgInfo *dst_info, StgInfo *src_info)
|
||||
{
|
||||
char *d, *s;
|
||||
Py_ssize_t size;
|
||||
|
||||
PyCStgDict_clear(dst);
|
||||
PyMem_Free(dst->ffi_type_pointer.elements);
|
||||
PyMem_Free(dst->format);
|
||||
dst->format = NULL;
|
||||
PyMem_Free(dst->shape);
|
||||
dst->shape = NULL;
|
||||
dst->ffi_type_pointer.elements = NULL;
|
||||
PyMem_Free(dst_info->ffi_type_pointer.elements);
|
||||
PyMem_Free(dst_info->format);
|
||||
dst_info->format = NULL;
|
||||
PyMem_Free(dst_info->shape);
|
||||
dst_info->shape = NULL;
|
||||
dst_info->ffi_type_pointer.elements = NULL;
|
||||
|
||||
d = (char *)dst;
|
||||
s = (char *)src;
|
||||
memcpy(d + sizeof(PyDictObject),
|
||||
s + sizeof(PyDictObject),
|
||||
sizeof(StgDictObject) - sizeof(PyDictObject));
|
||||
memcpy(dst_info, src_info, sizeof(StgInfo));
|
||||
|
||||
Py_XINCREF(dst->proto);
|
||||
Py_XINCREF(dst->argtypes);
|
||||
Py_XINCREF(dst->converters);
|
||||
Py_XINCREF(dst->restype);
|
||||
Py_XINCREF(dst->checker);
|
||||
Py_XINCREF(dst_info->proto);
|
||||
Py_XINCREF(dst_info->argtypes);
|
||||
Py_XINCREF(dst_info->converters);
|
||||
Py_XINCREF(dst_info->restype);
|
||||
Py_XINCREF(dst_info->checker);
|
||||
|
||||
if (src->format) {
|
||||
dst->format = PyMem_Malloc(strlen(src->format) + 1);
|
||||
if (dst->format == NULL) {
|
||||
if (src_info->format) {
|
||||
dst_info->format = PyMem_Malloc(strlen(src_info->format) + 1);
|
||||
if (dst_info->format == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
strcpy(dst->format, src->format);
|
||||
strcpy(dst_info->format, src_info->format);
|
||||
}
|
||||
if (src->shape) {
|
||||
dst->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src->ndim);
|
||||
if (dst->shape == NULL) {
|
||||
if (src_info->shape) {
|
||||
dst_info->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src_info->ndim);
|
||||
if (dst_info->shape == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
memcpy(dst->shape, src->shape,
|
||||
sizeof(Py_ssize_t) * src->ndim);
|
||||
memcpy(dst_info->shape, src_info->shape,
|
||||
sizeof(Py_ssize_t) * src_info->ndim);
|
||||
}
|
||||
|
||||
if (src->ffi_type_pointer.elements == NULL)
|
||||
if (src_info->ffi_type_pointer.elements == NULL)
|
||||
return 0;
|
||||
size = sizeof(ffi_type *) * (src->length + 1);
|
||||
dst->ffi_type_pointer.elements = PyMem_Malloc(size);
|
||||
if (dst->ffi_type_pointer.elements == NULL) {
|
||||
size = sizeof(ffi_type *) * (src_info->length + 1);
|
||||
dst_info->ffi_type_pointer.elements = PyMem_Malloc(size);
|
||||
if (dst_info->ffi_type_pointer.elements == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
memcpy(dst->ffi_type_pointer.elements,
|
||||
src->ffi_type_pointer.elements,
|
||||
memcpy(dst_info->ffi_type_pointer.elements,
|
||||
src_info->ffi_type_pointer.elements,
|
||||
size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct PyMethodDef PyCStgDict_methods[] = {
|
||||
{"__sizeof__", (PyCFunction)PyCStgDict_sizeof, METH_NOARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject PyCStgDict_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"StgDict",
|
||||
sizeof(StgDictObject),
|
||||
0,
|
||||
(destructor)PyCStgDict_dealloc, /* tp_dealloc */
|
||||
0, /* tp_vectorcall_offset */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_as_async */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
PyCStgDict_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc)PyCStgDict_init, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
0, /* tp_free */
|
||||
};
|
||||
|
||||
/* May return NULL, but does not set an exception! */
|
||||
StgDictObject *
|
||||
PyType_stgdict(PyObject *obj)
|
||||
{
|
||||
PyTypeObject *type;
|
||||
|
||||
if (!PyType_Check(obj)) {
|
||||
return NULL;
|
||||
}
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
type = (PyTypeObject *)obj;
|
||||
if (!type->tp_dict || !PyCStgDict_CheckExact(st, type->tp_dict)) {
|
||||
return NULL;
|
||||
}
|
||||
return (StgDictObject *)type->tp_dict;
|
||||
}
|
||||
|
||||
/* May return NULL, but does not set an exception! */
|
||||
/*
|
||||
This function should be as fast as possible, so we don't call PyType_stgdict
|
||||
above but inline the code, and avoid the PyType_Check().
|
||||
*/
|
||||
StgDictObject *
|
||||
PyObject_stgdict(PyObject *self)
|
||||
{
|
||||
PyTypeObject *type = Py_TYPE(self);
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
if (!type->tp_dict || !PyCStgDict_CheckExact(st, type->tp_dict)) {
|
||||
return NULL;
|
||||
}
|
||||
return (StgDictObject *)type->tp_dict;
|
||||
}
|
||||
|
||||
/* descr is the descriptor for a field marked as anonymous. Get all the
|
||||
_fields_ descriptors from descr->proto, create new descriptors with offset
|
||||
and index adjusted, and stuff them into type.
|
||||
|
@ -372,12 +233,11 @@ _ctypes_alloc_format_padding(const char *prefix, Py_ssize_t padding)
|
|||
|
||||
/*
|
||||
Retrieve the (optional) _pack_ attribute from a type, the _fields_ attribute,
|
||||
and create an StgDictObject. Used for Structure and Union subclasses.
|
||||
and initialize StgInfo. Used for Structure and Union subclasses.
|
||||
*/
|
||||
int
|
||||
PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
|
||||
PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct)
|
||||
{
|
||||
StgDictObject *stgdict, *basedict;
|
||||
Py_ssize_t len, offset, size, align, i;
|
||||
Py_ssize_t union_size, total_align, aligned_size;
|
||||
Py_ssize_t field_size = 0;
|
||||
|
@ -456,90 +316,97 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
return -1;
|
||||
}
|
||||
|
||||
stgdict = PyType_stgdict(type);
|
||||
if (!stgdict) {
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
StgInfo *stginfo;
|
||||
if (PyStgInfo_FromType(st, type, &stginfo) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (!stginfo) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"ctypes state is not initialized");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If this structure/union is already marked final we cannot assign
|
||||
_fields_ anymore. */
|
||||
|
||||
if (stgdict->flags & DICTFLAG_FINAL) {/* is final ? */
|
||||
if (stginfo->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 (stginfo->format) {
|
||||
PyMem_Free(stginfo->format);
|
||||
stginfo->format = NULL;
|
||||
}
|
||||
|
||||
if (stgdict->ffi_type_pointer.elements)
|
||||
PyMem_Free(stgdict->ffi_type_pointer.elements);
|
||||
if (stginfo->ffi_type_pointer.elements)
|
||||
PyMem_Free(stginfo->ffi_type_pointer.elements);
|
||||
|
||||
basedict = PyType_stgdict((PyObject *)((PyTypeObject *)type)->tp_base);
|
||||
if (basedict) {
|
||||
stgdict->flags |= (basedict->flags &
|
||||
StgInfo *baseinfo;
|
||||
if (PyStgInfo_FromType(st, (PyObject *)((PyTypeObject *)type)->tp_base,
|
||||
&baseinfo) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (baseinfo) {
|
||||
stginfo->flags |= (baseinfo->flags &
|
||||
(TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD));
|
||||
}
|
||||
if (!isStruct) {
|
||||
stgdict->flags |= TYPEFLAG_HASUNION;
|
||||
stginfo->flags |= TYPEFLAG_HASUNION;
|
||||
}
|
||||
if (basedict) {
|
||||
size = offset = basedict->size;
|
||||
align = basedict->align;
|
||||
if (baseinfo) {
|
||||
size = offset = baseinfo->size;
|
||||
align = baseinfo->align;
|
||||
union_size = 0;
|
||||
total_align = align ? align : 1;
|
||||
total_align = max(total_align, forced_alignment);
|
||||
stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT;
|
||||
stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, basedict->length + len + 1);
|
||||
if (stgdict->ffi_type_pointer.elements == NULL) {
|
||||
stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT;
|
||||
stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, baseinfo->length + len + 1);
|
||||
if (stginfo->ffi_type_pointer.elements == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
memset(stgdict->ffi_type_pointer.elements, 0,
|
||||
sizeof(ffi_type *) * (basedict->length + len + 1));
|
||||
if (basedict->length > 0) {
|
||||
memcpy(stgdict->ffi_type_pointer.elements,
|
||||
basedict->ffi_type_pointer.elements,
|
||||
sizeof(ffi_type *) * (basedict->length));
|
||||
memset(stginfo->ffi_type_pointer.elements, 0,
|
||||
sizeof(ffi_type *) * (baseinfo->length + len + 1));
|
||||
if (baseinfo->length > 0) {
|
||||
memcpy(stginfo->ffi_type_pointer.elements,
|
||||
baseinfo->ffi_type_pointer.elements,
|
||||
sizeof(ffi_type *) * (baseinfo->length));
|
||||
}
|
||||
ffi_ofs = basedict->length;
|
||||
ffi_ofs = baseinfo->length;
|
||||
} else {
|
||||
offset = 0;
|
||||
size = 0;
|
||||
align = 0;
|
||||
union_size = 0;
|
||||
total_align = forced_alignment;
|
||||
stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT;
|
||||
stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1);
|
||||
if (stgdict->ffi_type_pointer.elements == NULL) {
|
||||
stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT;
|
||||
stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1);
|
||||
if (stginfo->ffi_type_pointer.elements == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
memset(stgdict->ffi_type_pointer.elements, 0,
|
||||
memset(stginfo->ffi_type_pointer.elements, 0,
|
||||
sizeof(ffi_type *) * (len + 1));
|
||||
ffi_ofs = 0;
|
||||
}
|
||||
|
||||
assert(stgdict->format == NULL);
|
||||
assert(stginfo->format == NULL);
|
||||
if (isStruct) {
|
||||
stgdict->format = _ctypes_alloc_format_string(NULL, "T{");
|
||||
stginfo->format = _ctypes_alloc_format_string(NULL, "T{");
|
||||
} else {
|
||||
/* PEP3118 doesn't support union. Use 'B' for bytes. */
|
||||
stgdict->format = _ctypes_alloc_format_string(NULL, "B");
|
||||
stginfo->format = _ctypes_alloc_format_string(NULL, "B");
|
||||
}
|
||||
if (stgdict->format == NULL)
|
||||
if (stginfo->format == NULL)
|
||||
return -1;
|
||||
|
||||
ctypes_state *st = GLOBAL_STATE();
|
||||
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, "UO|i", &name, &desc, &bitsize)) {
|
||||
|
@ -551,22 +418,28 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
if (PyCArrayTypeObject_Check(st, desc)) {
|
||||
arrays_seen = 1;
|
||||
}
|
||||
dict = PyType_stgdict(desc);
|
||||
if (dict == NULL) {
|
||||
|
||||
StgInfo *info;
|
||||
if (PyStgInfo_FromType(st, desc, &info) < 0) {
|
||||
Py_DECREF(pair);
|
||||
return -1;
|
||||
}
|
||||
if (info == NULL) {
|
||||
Py_DECREF(pair);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"second item in _fields_ tuple (index %zd) must be a C type",
|
||||
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;
|
||||
stgdict->flags |= dict->flags & (TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD);
|
||||
dict->flags |= DICTFLAG_FINAL; /* mark field type final */
|
||||
|
||||
stginfo->ffi_type_pointer.elements[ffi_ofs + i] = &info->ffi_type_pointer;
|
||||
if (info->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER))
|
||||
stginfo->flags |= TYPEFLAG_HASPOINTER;
|
||||
stginfo->flags |= info->flags & (TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD);
|
||||
info->flags |= DICTFLAG_FINAL; /* mark field type final */
|
||||
if (PyTuple_Size(pair) == 3) { /* bits specified */
|
||||
stgdict->flags |= TYPEFLAG_HASBITFIELD;
|
||||
switch(dict->ffi_type_pointer.type) {
|
||||
stginfo->flags |= TYPEFLAG_HASBITFIELD;
|
||||
switch(info->ffi_type_pointer.type) {
|
||||
case FFI_TYPE_UINT8:
|
||||
case FFI_TYPE_UINT16:
|
||||
case FFI_TYPE_UINT32:
|
||||
|
@ -577,8 +450,8 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
case FFI_TYPE_SINT8:
|
||||
case FFI_TYPE_SINT16:
|
||||
case FFI_TYPE_SINT32:
|
||||
if (dict->getfunc != _ctypes_get_fielddesc("c")->getfunc
|
||||
&& dict->getfunc != _ctypes_get_fielddesc("u")->getfunc
|
||||
if (info->getfunc != _ctypes_get_fielddesc("c")->getfunc
|
||||
&& info->getfunc != _ctypes_get_fielddesc("u")->getfunc
|
||||
)
|
||||
break;
|
||||
/* else fall through */
|
||||
|
@ -589,7 +462,7 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
Py_DECREF(pair);
|
||||
return -1;
|
||||
}
|
||||
if (bitsize <= 0 || bitsize > dict->size * 8) {
|
||||
if (bitsize <= 0 || bitsize > info->size * 8) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"number of bits invalid for bit field");
|
||||
Py_DECREF(pair);
|
||||
|
@ -599,7 +472,7 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
bitsize = 0;
|
||||
|
||||
if (isStruct) {
|
||||
const char *fieldfmt = dict->format ? dict->format : "B";
|
||||
const char *fieldfmt = info->format ? info->format : "B";
|
||||
const char *fieldname = PyUnicode_AsUTF8(name);
|
||||
char *ptr;
|
||||
Py_ssize_t len;
|
||||
|
@ -629,10 +502,10 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
padding = ((CFieldObject *)prop)->offset - last_size;
|
||||
|
||||
if (padding > 0) {
|
||||
ptr = stgdict->format;
|
||||
stgdict->format = _ctypes_alloc_format_padding(ptr, padding);
|
||||
ptr = stginfo->format;
|
||||
stginfo->format = _ctypes_alloc_format_padding(ptr, padding);
|
||||
PyMem_Free(ptr);
|
||||
if (stgdict->format == NULL) {
|
||||
if (stginfo->format == NULL) {
|
||||
Py_DECREF(pair);
|
||||
Py_DECREF(prop);
|
||||
return -1;
|
||||
|
@ -650,17 +523,17 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
}
|
||||
sprintf(buf, "%s:%s:", fieldfmt, fieldname);
|
||||
|
||||
ptr = stgdict->format;
|
||||
if (dict->shape != NULL) {
|
||||
stgdict->format = _ctypes_alloc_format_string_with_shape(
|
||||
dict->ndim, dict->shape, stgdict->format, buf);
|
||||
ptr = stginfo->format;
|
||||
if (info->shape != NULL) {
|
||||
stginfo->format = _ctypes_alloc_format_string_with_shape(
|
||||
info->ndim, info->shape, stginfo->format, buf);
|
||||
} else {
|
||||
stgdict->format = _ctypes_alloc_format_string(stgdict->format, buf);
|
||||
stginfo->format = _ctypes_alloc_format_string(stginfo->format, buf);
|
||||
}
|
||||
PyMem_Free(ptr);
|
||||
PyMem_Free(buf);
|
||||
|
||||
if (stgdict->format == NULL) {
|
||||
if (stginfo->format == NULL) {
|
||||
Py_DECREF(pair);
|
||||
Py_DECREF(prop);
|
||||
return -1;
|
||||
|
@ -704,29 +577,29 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
/* Pad up to the full size of the struct */
|
||||
padding = aligned_size - size;
|
||||
if (padding > 0) {
|
||||
ptr = stgdict->format;
|
||||
stgdict->format = _ctypes_alloc_format_padding(ptr, padding);
|
||||
ptr = stginfo->format;
|
||||
stginfo->format = _ctypes_alloc_format_padding(ptr, padding);
|
||||
PyMem_Free(ptr);
|
||||
if (stgdict->format == NULL) {
|
||||
if (stginfo->format == NULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ptr = stgdict->format;
|
||||
stgdict->format = _ctypes_alloc_format_string(stgdict->format, "}");
|
||||
ptr = stginfo->format;
|
||||
stginfo->format = _ctypes_alloc_format_string(stginfo->format, "}");
|
||||
PyMem_Free(ptr);
|
||||
if (stgdict->format == NULL)
|
||||
if (stginfo->format == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
stgdict->ffi_type_pointer.alignment = Py_SAFE_DOWNCAST(total_align,
|
||||
stginfo->ffi_type_pointer.alignment = Py_SAFE_DOWNCAST(total_align,
|
||||
Py_ssize_t,
|
||||
unsigned short);
|
||||
stgdict->ffi_type_pointer.size = aligned_size;
|
||||
stginfo->ffi_type_pointer.size = aligned_size;
|
||||
|
||||
stgdict->size = aligned_size;
|
||||
stgdict->align = total_align;
|
||||
stgdict->length = ffi_ofs + len;
|
||||
stginfo->size = aligned_size;
|
||||
stginfo->align = total_align;
|
||||
stginfo->length = ffi_ofs + len;
|
||||
|
||||
/*
|
||||
* The value of MAX_STRUCT_SIZE depends on the platform Python is running on.
|
||||
|
@ -817,7 +690,6 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
for (i = 0; i < len; ++i) {
|
||||
PyObject *name, *desc;
|
||||
PyObject *pair = PySequence_GetItem(fields, i);
|
||||
StgDictObject *dict;
|
||||
int bitsize = 0;
|
||||
|
||||
if (pair == NULL) {
|
||||
|
@ -829,25 +701,34 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
Py_DECREF(pair);
|
||||
return -1;
|
||||
}
|
||||
dict = PyType_stgdict(desc);
|
||||
if (dict == NULL) {
|
||||
|
||||
StgInfo *info;
|
||||
if (PyStgInfo_FromType(st, desc, &info) < 0) {
|
||||
Py_DECREF(pair);
|
||||
return -1;
|
||||
}
|
||||
if (info == NULL) {
|
||||
Py_DECREF(pair);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"second item in _fields_ tuple (index %zd) must be a C type",
|
||||
i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!PyCArrayTypeObject_Check(st, desc)) {
|
||||
/* Not an array. Just need an ffi_type pointer. */
|
||||
num_ffi_type_pointers++;
|
||||
}
|
||||
else {
|
||||
/* It's an array. */
|
||||
Py_ssize_t length = dict->length;
|
||||
StgDictObject *edict;
|
||||
Py_ssize_t length = info->length;
|
||||
|
||||
edict = PyType_stgdict(dict->proto);
|
||||
if (edict == NULL) {
|
||||
StgInfo *einfo;
|
||||
if (PyStgInfo_FromType(st, info->proto, &einfo) < 0) {
|
||||
Py_DECREF(pair);
|
||||
return -1;
|
||||
}
|
||||
if (einfo == NULL) {
|
||||
Py_DECREF(pair);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"second item in _fields_ tuple (index %zd) must be a C type",
|
||||
|
@ -895,9 +776,9 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
if (num_ffi_types > 0) {
|
||||
memset(structs, 0, num_ffi_types * sizeof(ffi_type));
|
||||
}
|
||||
if (ffi_ofs && (basedict != NULL)) {
|
||||
if (ffi_ofs && (baseinfo != NULL)) {
|
||||
memcpy(element_types,
|
||||
basedict->ffi_type_pointer.elements,
|
||||
baseinfo->ffi_type_pointer.elements,
|
||||
ffi_ofs * sizeof(ffi_type *));
|
||||
}
|
||||
element_index = ffi_ofs;
|
||||
|
@ -906,7 +787,6 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
for (i = 0; i < len; ++i) {
|
||||
PyObject *name, *desc;
|
||||
PyObject *pair = PySequence_GetItem(fields, i);
|
||||
StgDictObject *dict;
|
||||
int bitsize = 0;
|
||||
|
||||
if (pair == NULL) {
|
||||
|
@ -926,9 +806,16 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
PyMem_Free(type_block);
|
||||
return -1;
|
||||
}
|
||||
dict = PyType_stgdict(desc);
|
||||
|
||||
StgInfo *info;
|
||||
if (PyStgInfo_FromType(st, desc, &info) < 0) {
|
||||
Py_DECREF(pair);
|
||||
PyMem_Free(type_block);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Possibly this check could be avoided, but see above comment. */
|
||||
if (dict == NULL) {
|
||||
if (info == NULL) {
|
||||
Py_DECREF(pair);
|
||||
PyMem_Free(type_block);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
|
@ -936,17 +823,21 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(element_index < (ffi_ofs + len)); /* will be used below */
|
||||
if (!PyCArrayTypeObject_Check(st, desc)) {
|
||||
/* Not an array. Just copy over the element ffi_type. */
|
||||
element_types[element_index++] = &dict->ffi_type_pointer;
|
||||
element_types[element_index++] = &info->ffi_type_pointer;
|
||||
}
|
||||
else {
|
||||
Py_ssize_t length = dict->length;
|
||||
StgDictObject *edict;
|
||||
|
||||
edict = PyType_stgdict(dict->proto);
|
||||
if (edict == NULL) {
|
||||
Py_ssize_t length = info->length;
|
||||
StgInfo *einfo;
|
||||
if (PyStgInfo_FromType(st, info->proto, &einfo) < 0) {
|
||||
Py_DECREF(pair);
|
||||
PyMem_Free(type_block);
|
||||
return -1;
|
||||
}
|
||||
if (einfo == NULL) {
|
||||
Py_DECREF(pair);
|
||||
PyMem_Free(type_block);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
|
@ -955,15 +846,15 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
return -1;
|
||||
}
|
||||
element_types[element_index++] = &structs[struct_index];
|
||||
structs[struct_index].size = length * edict->ffi_type_pointer.size;
|
||||
structs[struct_index].alignment = edict->ffi_type_pointer.alignment;
|
||||
structs[struct_index].size = length * einfo->ffi_type_pointer.size;
|
||||
structs[struct_index].alignment = einfo->ffi_type_pointer.alignment;
|
||||
structs[struct_index].type = FFI_TYPE_STRUCT;
|
||||
structs[struct_index].elements = &dummy_types[dummy_index];
|
||||
++struct_index;
|
||||
/* Copy over the element's type, length times. */
|
||||
while (length > 0) {
|
||||
assert(dummy_index < (num_ffi_type_pointers));
|
||||
dummy_types[dummy_index++] = &edict->ffi_type_pointer;
|
||||
dummy_types[dummy_index++] = &einfo->ffi_type_pointer;
|
||||
length--;
|
||||
}
|
||||
assert(dummy_index < (num_ffi_type_pointers));
|
||||
|
@ -977,19 +868,19 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
* Replace the old elements with the new, taking into account
|
||||
* base class elements where necessary.
|
||||
*/
|
||||
assert(stgdict->ffi_type_pointer.elements);
|
||||
PyMem_Free(stgdict->ffi_type_pointer.elements);
|
||||
stgdict->ffi_type_pointer.elements = element_types;
|
||||
assert(stginfo->ffi_type_pointer.elements);
|
||||
PyMem_Free(stginfo->ffi_type_pointer.elements);
|
||||
stginfo->ffi_type_pointer.elements = element_types;
|
||||
}
|
||||
|
||||
/* We did check that this flag was NOT set above, it must not
|
||||
have been set until now. */
|
||||
if (stgdict->flags & DICTFLAG_FINAL) {
|
||||
if (stginfo->flags & DICTFLAG_FINAL) {
|
||||
PyErr_SetString(PyExc_AttributeError,
|
||||
"Structure or union cannot contain itself");
|
||||
return -1;
|
||||
}
|
||||
stgdict->flags |= DICTFLAG_FINAL;
|
||||
stginfo->flags |= DICTFLAG_FINAL;
|
||||
|
||||
return MakeAnonFields(type);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue