[Pkg-gnupg-commit] [gpgme] 140/412: python: Fix object deallocation.

Daniel Kahn Gillmor dkg at fifthhorseman.net
Thu Sep 22 21:26:34 UTC 2016


This is an automated email from the git hooks/post-receive script.

dkg pushed a commit to branch master
in repository gpgme.

commit ebfe2300c33a3bad311e9ac1530e6c92636a08a4
Author: Justus Winter <justus at gnupg.org>
Date:   Fri May 27 12:25:59 2016 +0200

    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 <justus at gnupg.org>
---
 lang/python/helpers.c    | 22 +++++++++++++++++++---
 lang/python/pyme/core.py | 21 ++++++++++-----------
 2 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/lang/python/helpers.c b/lang/python/helpers.c
index ec7264a..9fe81c9 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)
diff --git a/lang/python/pyme/core.py b/lang/python/pyme/core.py
index 0c2dd60..6ef2dab 100644
--- a/lang/python/pyme/core.py
+++ b/lang/python/pyme/core.py
@@ -16,9 +16,7 @@
 #    License along with this library; if not, write to the Free Software
 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 
-# import generators for portability with python2.2
-
-
+import weakref
 from . import pygpgme
 from .errors import errorcheck, GPGMEError
 from . import errors
@@ -149,6 +147,7 @@ class Context(GpgmeWrapper):
 
         self._free_passcb()
         self._free_progresscb()
+        self._free_statuscb()
         if self.own and pygpgme.gpgme_release:
             pygpgme.gpgme_release(self.wrapped)
 
@@ -252,9 +251,9 @@ class Context(GpgmeWrapper):
         else:
             self.last_passcb = pygpgme.new_PyObject_p_p()
             if hook == None:
-                hookdata = (self, func)
+                hookdata = (weakref.ref(self), func)
             else:
-                hookdata = (self, func, hook)
+                hookdata = (weakref.ref(self), func, hook)
         pygpgme.pygpgme_set_passphrase_cb(self.wrapped, hookdata, self.last_passcb)
 
     def set_progress_cb(self, func, hook=None):
@@ -275,9 +274,9 @@ class Context(GpgmeWrapper):
         else:
             self.last_progresscb = pygpgme.new_PyObject_p_p()
             if hook == None:
-                hookdata = (self, func)
+                hookdata = (weakref.ref(self), func)
             else:
-                hookdata = (self, func, hook)
+                hookdata = (weakref.ref(self), func, hook)
         pygpgme.pygpgme_set_progress_cb(self.wrapped, hookdata, self.last_progresscb)
 
     def set_status_cb(self, func, hook=None):
@@ -297,9 +296,9 @@ class Context(GpgmeWrapper):
         else:
             self.last_statuscb = pygpgme.new_PyObject_p_p()
             if hook == None:
-                hookdata = (self, func)
+                hookdata = (weakref.ref(self), func)
             else:
-                hookdata = (self, func, hook)
+                hookdata = (weakref.ref(self), func, hook)
         pygpgme.pygpgme_set_status_cb(self.wrapped, hookdata,
                                       self.last_statuscb)
 
@@ -333,9 +332,9 @@ class Context(GpgmeWrapper):
         if key == None:
             raise ValueError("op_edit: First argument cannot be None")
         if fnc_value:
-            opaquedata = (self, func, fnc_value)
+            opaquedata = (weakref.ref(self), func, fnc_value)
         else:
-            opaquedata = (self, func)
+            opaquedata = (weakref.ref(self), func)
 
         result = pygpgme.gpgme_op_edit(self.wrapped, key, opaquedata, out)
         if self._callback_excinfo:

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/gpgme.git



More information about the Pkg-gnupg-commit mailing list