I am trying to \"monkey patch\" a class derived from Python ctypes \"Union\", but I am unable to do so - getting weird errors and sometimes seg-faults. The same thing works
I think there's an actual CPython bug here. The __setattr__ implementation for type objects for struct types uses PyType_Type.tp_setattro
:
static int
PyCStructType_setattro(PyObject *self, PyObject *key, PyObject *value)
{
/* XXX Should we disallow deleting _fields_? */
if (-1 == PyType_Type.tp_setattro(self, key, value))
return -1;
if (value && PyUnicode_Check(key) &&
_PyUnicode_EqualToASCIIString(key, "_fields_"))
return PyCStructUnionType_update_stgdict(self, value, 1);
return 0;
}
but the one for type objects for union types uses PyObject_GenericSetAttr
:
static int
UnionType_setattro(PyObject *self, PyObject *key, PyObject *value)
{
/* XXX Should we disallow deleting _fields_? */
if (-1 == PyObject_GenericSetAttr(self, key, value))
return -1;
if (PyUnicode_Check(key) &&
_PyUnicode_EqualToASCIIString(key, "_fields_"))
return PyCStructUnionType_update_stgdict(self, value, 0);
return 0;
}
The use of PyType_Type.tp_setattro
is necessary to update type slots and invalidate the internal type attribute cache. PyObject_GenericSetAttr
doesn't know it should do either of those things, causing potential memory corruption due to "zombie" cached attributes. It looks like the same bug was fixed in early 2008 for structs, but they forgot to handle unions.