Python - Save and restore exception state before calling destroy.

PyObject_CallFunction has the potential to silently drop the active
exception.  In cases where the user just finished iterating a
generator, StopIteration will be active.  Most of the time this
is fine because destroy() won't raise an exception.  On Python 3
however, and with a debug interpreter, you will get an assertion
failure inside of Python.  And in the worst case scenario, if
destroy() does throw an exception, the intepreter probably won't
be able to correctly detect the end of the iteration.
This commit is contained in:
Zachary Turner 2015-11-13 21:07:44 -08:00
commit 2fa9454c9f

View file

@ -537,14 +537,21 @@ SwigPyObject_dealloc(PyObject *v)
/* destroy is always a VARARGS method */
PyObject *res;
if (data->delargs) {
/* we need to create a temporary object to carry the destroy operation */
PyObject *tmp = SwigPyObject_New(sobj->ptr, ty, 0);
res = SWIG_Python_CallFunctor(destroy, tmp);
Py_DECREF(tmp);
/* we need to create a temporary object to carry the destroy operation */
PyObject *tmp = SwigPyObject_New(sobj->ptr, ty, 0);
/* PyObject_CallFunction() has the potential to silently drop the active
active exception. In cases where we just finished iterating over a
generator StopIteration will be active right now, and this needs to
remain true upon return from SwigPyObject_dealloc. So save and restore. */
PyObject *val = NULL, *type = NULL, *tb = NULL;
PyErr_Fetch(&val, &type, &tb);
res = SWIG_Python_CallFunctor(destroy, tmp);
PyErr_Restore(val, type, tb);
Py_DECREF(tmp);
} else {
PyCFunction meth = PyCFunction_GET_FUNCTION(destroy);
PyObject *mself = PyCFunction_GET_SELF(destroy);
res = ((*meth)(mself, v));
PyCFunction meth = PyCFunction_GET_FUNCTION(destroy);
PyObject *mself = PyCFunction_GET_SELF(destroy);
res = ((*meth)(mself, v));
}
Py_XDECREF(res);
}