[pygobject] Fix GLib.Source ref leak upon destruction



commit 6f6c0ceff00fea83bc85756b10694f7c96039abc
Author: Martin Pitt <martinpitt gnome org>
Date:   Fri Mar 1 11:10:01 2013 +0100

    Fix GLib.Source ref leak upon destruction
    
    In GLib.Source.__del__(), manually unref the source if we are a custom Source.
    As we use a static binding to create it, the GI part won't unref it for us,
    leading to finalize() method not being called and the GSource object leaking.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=510511

 gi/overrides/GLib.py |    4 ++++
 tests/test_source.py |   31 +++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 0 deletions(-)
---
diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py
index b3f1563..3e660d1 100644
--- a/gi/overrides/GLib.py
+++ b/gi/overrides/GLib.py
@@ -539,6 +539,10 @@ class Source(GLib.Source):
         setattr(source, '__pygi_custom_source', True)
         return source
 
+    def __del__(self):
+        if hasattr(self, '__pygi_custom_source'):
+            self.unref()
+
     # Backwards compatible API for optional arguments
     def attach(self, context=None):
         id = super(Source, self).attach(context)
diff --git a/tests/test_source.py b/tests/test_source.py
index dda492a..5b3b51b 100644
--- a/tests/test_source.py
+++ b/tests/test_source.py
@@ -183,6 +183,37 @@ class TestSource(unittest.TestCase):
         GLib.Timeout(20)
         GLib.Idle()
 
+    def test_finalize(self):
+        self.dispatched = False
+        self.finalized = False
+
+        class S(GLib.Source):
+            def prepare(s):
+                return (True, 1)
+
+            def dispatch(s, callback, args):
+                self.dispatched = True
+                return False
+
+            def finalize(s):
+                self.finalized = True
+
+        source = S()
+        id = source.attach()
+        print('source id:', id)
+        self.assertFalse(self.finalized)
+        self.assertFalse(source.is_destroyed())
+
+        while source.get_context().iteration(False):
+            pass
+
+        source.destroy()
+        self.assertTrue(self.dispatched)
+        self.assertFalse(self.finalized)
+        self.assertTrue(source.is_destroyed())
+        del source
+        self.assertTrue(self.finalized)
+
 
 class TestUserData(unittest.TestCase):
     def test_idle_no_data(self):


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]