[gjs/gnome-40: 5/30] object: Switch back to normal references on disposal




commit a34823b9250877322c4d927515d155b3d5f081b5
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Thu Mar 25 20:03:41 2021 +0100

    object: Switch back to normal references on disposal
    
    When an object is disposed we already remove the toggle reference on it
    and we avoid that nothing will unref it again, however this can lead to
    troubles when something else owns the last reference at garbage
    collecting point if we didn't release the object earlier because in
    ~ObjectInstance we still expect to have a reference.
    
    To avoid this, let's just keep it simpler and switch back to normal
    reference again at dispose notify.
    
    The ordering here is important though, as referencing the object may
    cause a toggle-up event to happen, but we need to do it before removing
    the toggle reference (as that could be the only one we have), however
    after that we're still forcing a toggle-down event to happen, so we'll
    still be unrooted afterwards.
    
    Fixes: #399
    
    (cherry-picked from commit 627ea90f)

 gi/object.cpp                  |  6 +++---
 installed-tests/js/testGtk3.js | 20 ++++++++++++++------
 2 files changed, 17 insertions(+), 9 deletions(-)
---
diff --git a/gi/object.cpp b/gi/object.cpp
index 75b29be3..f42fb0c8 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -1090,8 +1090,10 @@ ObjectInstance::gobj_dispose_notify(void)
     m_gobj_disposed = true;
 
     if (m_uses_toggle_ref) {
+        g_object_ref(m_ptr.get());
         g_object_remove_toggle_ref(m_ptr, wrapped_gobj_toggle_notify, this);
         wrapped_gobj_toggle_notify(this, m_ptr, TRUE);
+        m_uses_toggle_ref = false;
     }
 }
 
@@ -1305,9 +1307,7 @@ void
 ObjectInstance::release_native_object(void)
 {
     discard_wrapper();
-    if (m_uses_toggle_ref && m_gobj_disposed)
-        m_ptr.release();
-    else if (m_uses_toggle_ref)
+    if (m_uses_toggle_ref && !m_gobj_disposed)
         g_object_remove_toggle_ref(m_ptr.release(), wrapped_gobj_toggle_notify,
                                    this);
     else
diff --git a/installed-tests/js/testGtk3.js b/installed-tests/js/testGtk3.js
index fd0608d1..8d08481f 100644
--- a/installed-tests/js/testGtk3.js
+++ b/installed-tests/js/testGtk3.js
@@ -191,19 +191,27 @@ describe('Gtk overrides', function () {
             'Gtk overrides avoid crashing and print a stack trace');
     });
 
-    it('GTK vfuncs can be explicitly called during disposition', function () {
-        let called;
-        const GoodLabel = GObject.registerClass(class GoodLabel extends Gtk.Label {
+    it('GTK vfuncs are not called if the object is disposed', function () {
+        const spy = jasmine.createSpy('vfunc_destroy');
+        const NotSoGoodLabel = GObject.registerClass(class NotSoGoodLabel extends Gtk.Label {
             vfunc_destroy() {
-                called = true;
+                spy();
             }
         });
 
-        let label = new GoodLabel();
+        let label = new NotSoGoodLabel();
+
         label.destroy();
-        expect(called).toBeTruthy();
+        expect(spy).toHaveBeenCalledTimes(1);
+
+        GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL,
+            '*during garbage collection*');
+        GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL,
+            '*destroy*');
         label = null;
         System.gc();
+        GLib.test_assert_expected_messages_internal('Gjs', 'testGtk3.js', 0,
+            'GTK vfuncs are not called if the object is disposed');
     });
 
     it('accepts string in place of GdkAtom', function () {


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