[gjs: 21/22] testGObjectDestructionAccess: Ensure that disposed wrappers are unbound




commit f897012f9075733b530aa07f9f40a24f724f311b
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Thu Apr 22 22:35:49 2021 +0200

    testGObjectDestructionAccess: Ensure that disposed wrappers are unbound
    
    When an object is disposed we discard its wrapper, if a new wrapper for
    such objects is created it will stay connected to the object till the
    wrapper is alive or the object is finalized.
    
    However, we need to make sure that also the "disposed" wrapper object is
    always unbound from its wrapped or we'll crash as in issue #395.
    
    To test this, we can just repeatedly get from a C function a disposed
    object so that we're going it to rewrap it over and over.

 .../js/libgjstesttools/gjs-test-tools.cpp          | 11 ++++
 .../js/libgjstesttools/gjs-test-tools.h            |  2 +
 installed-tests/js/testGObjectDestructionAccess.js | 59 ++++++++++++++--------
 3 files changed, 52 insertions(+), 20 deletions(-)
---
diff --git a/installed-tests/js/libgjstesttools/gjs-test-tools.cpp 
b/installed-tests/js/libgjstesttools/gjs-test-tools.cpp
index 54c457bc..276303af 100644
--- a/installed-tests/js/libgjstesttools/gjs-test-tools.cpp
+++ b/installed-tests/js/libgjstesttools/gjs-test-tools.cpp
@@ -212,6 +212,17 @@ void gjs_test_tools_save_weak(GObject* object) {
     g_weak_ref_set(&m_tmp_weak, object);
 }
 
+/**
+ * gjs_test_tools_peek_saved:
+ * Returns: (transfer none)
+ */
+GObject* gjs_test_tools_peek_saved() {
+    if (FinalizedObjectsLocked()->count(m_tmp_object))
+        return nullptr;
+
+    return m_tmp_object;
+}
+
 /**
  * gjs_test_tools_get_weak:
  * Returns: (transfer full)
diff --git a/installed-tests/js/libgjstesttools/gjs-test-tools.h 
b/installed-tests/js/libgjstesttools/gjs-test-tools.h
index 9ba75df1..9f692941 100644
--- a/installed-tests/js/libgjstesttools/gjs-test-tools.h
+++ b/installed-tests/js/libgjstesttools/gjs-test-tools.h
@@ -41,6 +41,8 @@ GObject* gjs_test_tools_get_saved();
 
 GObject* gjs_test_tools_steal_saved();
 
+GObject* gjs_test_tools_peek_saved();
+
 void gjs_test_tools_save_weak(GObject* object);
 
 GObject* gjs_test_tools_get_weak();
diff --git a/installed-tests/js/testGObjectDestructionAccess.js 
b/installed-tests/js/testGObjectDestructionAccess.js
index 63819f5e..1ec25c14 100644
--- a/installed-tests/js/testGObjectDestructionAccess.js
+++ b/installed-tests/js/testGObjectDestructionAccess.js
@@ -172,18 +172,29 @@ describe('Disposed or finalized GObject', function () {
         GjsTestTools.reset();
     });
 
-    it('is marked as disposed when it is a manually disposed property', function () {
-        const emblem = new Gio.EmblemedIcon({
-            gicon: new Gio.ThemedIcon({name: 'alarm'}),
+    [true, false].forEach(gc => {
+        it(`is marked as disposed when it is a manually disposed property ${gc ? '' : 'not '}garbage 
collected`, function () {
+            const emblem = new Gio.EmblemedIcon({
+                gicon: new Gio.ThemedIcon({name: 'alarm'}),
+            });
+
+            let {gicon} = emblem;
+            gicon.run_dispose();
+            gicon = null;
+            System.gc();
+
+            Array(10).fill().forEach(() => {
+                // We need to repeat the test to ensure that we disassociate
+                // wrappers from disposed objects on destruction.
+                gicon = emblem.gicon;
+                expect(gicon.toString()).toMatch(
+                    /\[object \(DISPOSED\) instance wrapper .* jsobj@0x[a-f0-9]+ native@0x[a-f0-9]+\]/);
+
+                gicon = null;
+                if (gc)
+                    System.gc();
+            });
         });
-
-        let {gicon} = emblem;
-        gicon.run_dispose();
-        gicon = null;
-        System.gc();
-
-        expect(emblem.gicon.toString()).toMatch(
-            /\[object \(DISPOSED\) instance wrapper .* jsobj@0x[a-f0-9]+ native@0x[a-f0-9]+\]/);
     });
 
     it('calls dispose vfunc on explicit disposal only', function () {
@@ -258,15 +269,23 @@ describe('Disposed or finalized GObject', function () {
             'generates a warn if already disposed at garbage collection');
     });
 
-    it('created from other function is marked as disposed', function () {
-        let file = Gio.File.new_for_path('/');
-        GjsTestTools.save_object(file);
-        file.run_dispose();
-        file = null;
-        System.gc();
-
-        expect(GjsTestTools.get_saved()).toMatch(
-            /\[object \(DISPOSED\) instance wrapper GType:GLocalFile jsobj@0x[a-f0-9]+ 
native@0x[a-f0-9]+\]/);
+    [true, false].forEach(gc => {
+        it(`created from other function is marked as disposed and ${gc ? '' : 'not '}garbage collected`, 
function () {
+            let file = Gio.File.new_for_path('/');
+            GjsTestTools.save_object(file);
+            file.run_dispose();
+            file = null;
+            System.gc();
+
+            Array(10).fill().forEach(() => {
+                // We need to repeat the test to ensure that we disassociate
+                // wrappers from disposed objects on destruction.
+                expect(GjsTestTools.peek_saved()).toMatch(
+                    /\[object \(DISPOSED\) instance wrapper GType:GLocalFile jsobj@0x[a-f0-9]+ 
native@0x[a-f0-9]+\]/);
+                if (gc)
+                    System.gc();
+            });
+        });
     });
 
     it('returned from function is marked as disposed', function () {


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