PyObject_IsInstance is not safe when used to check if the object is an instance of specified builtin type. Typical code:
rc = PyObject_IsInstance(obj, &Someting_Type); if (rc < 0) return NULL; if (rc) { SometingObject *something = (SometingObject *)obj; something->some_field ... }
The __class__ attribute can be modified and PyObject_IsInstance() can return true if the object has not layout compatible with specified structure. And even worse, __class__ can be dynamic property and PyObject_IsInstance() can execute arbitrary Python code, that can invalidate cached values of pointers and sizes in C code.
More safe way would be to use PyObject_IsSubclass().
rc = PyObject_IsSubclass((Py_Object *)obj->ob_type, &Someting_Type); if (rc < 0) return NULL; if (rc) { SometingObject *something = (SometingObject *)obj; something->some_field ... }
For example see issue24102 [1], issue24091 [2] and many other issues opened by pkt.
[1] http://bugs.python.org/issue24102 [2] http://bugs.python.org/issue24091
Serhiy Storchaka wrote:
PyObject_IsInstance is not safe when used to check if the object is an instance of specified builtin type.
The __class__ attribute can be modified and PyObject_IsInstance() can return true if the object has not layout compatible with specified structure.
Code that requires a particular C layout should be using PyObject_TypeCheck, not PyObject_IsInstance.
On 18.05.15 15:14, Greg Ewing wrote:
Serhiy Storchaka wrote:
PyObject_IsInstance is not safe when used to check if the object is an instance of specified builtin type.
The __class__ attribute can be modified and PyObject_IsInstance() can return true if the object has not layout compatible with specified structure.
Code that requires a particular C layout should be using PyObject_TypeCheck, not PyObject_IsInstance.
Thank you. I didn't know about this helper.
Looks as most (if not all) usages of PyObject_IsInstance are not correct. May be modify PyObject_IsInstance so that it will never return true if layouts are not compatible?
Serhiy Storchaka wrote:
May be modify PyObject_IsInstance so that it will never return true if layouts are not compatible?
That wouldn't be a good idea, since PyObject_IsInstance is meant to reflect the behaviour of python's isinstance() function, which doesn't care about C layouts.