From ebfe2300c33a3bad311e9ac1530e6c92636a08a4 Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Fri, 27 May 2016 12:25:59 +0200 Subject: python: Fix object deallocation. Handing a reference to the wrapper object created a non-trivial circular reference that Pythons garbage collector is unable to break. Explicitly break it by using a weak reference. * lang/python/helpers.c (pygpgme_stash_callback_exception): Retrieve object from weak reference. * lang/python/pyme/core.py (Context.__del__): Free status callback. (Context.set_passphrase_cb): Use a weak reference. (Context.set_progress_cb): Likewise. (Context.set_status_cb): Likewise. (Context.op_edit): Likewise. Signed-off-by: Justus Winter --- lang/python/helpers.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'lang/python/helpers.c') diff --git a/lang/python/helpers.c b/lang/python/helpers.c index ec7264aa..9fe81c9f 100644 --- a/lang/python/helpers.c +++ b/lang/python/helpers.c @@ -64,9 +64,9 @@ void pygpgme_clear_generic_cb(PyObject **cb) { /* Exception support for callbacks. */ #define EXCINFO "_callback_excinfo" -static void pygpgme_stash_callback_exception(PyObject *self) +static void pygpgme_stash_callback_exception(PyObject *weak_self) { - PyObject *ptype, *pvalue, *ptraceback, *excinfo; + PyObject *self, *ptype, *pvalue, *ptraceback, *excinfo; PyErr_Fetch(&ptype, &pvalue, &ptraceback); excinfo = PyTuple_New(3); @@ -86,7 +86,23 @@ static void pygpgme_stash_callback_exception(PyObject *self) PyTuple_SetItem(excinfo, 2, Py_None); } - PyObject_SetAttrString(self, EXCINFO, excinfo); + self = PyWeakref_GetObject(weak_self); + /* self only has a borrowed reference. */ + if (self == Py_None) { + /* This should not happen, as even if we're called from the data + release callback triggered from the wrappers destructor, the + object is still alive and hence the weak reference still refers + to the object. However, in case this ever changes, not seeing + any exceptions is worse than having a little extra code, so + here we go. */ + fprintf(stderr, + "Error occurred in callback, but the wrapper object " + "has been deallocated.\n"); + PyErr_Restore(ptype, pvalue, ptraceback); + PyErr_Print(); + } + else + PyObject_SetAttrString(self, EXCINFO, excinfo); } PyObject *pygpgme_raise_callback_exception(PyObject *self) -- cgit v1.2.3