diff --git a/gi/object.cpp b/gi/object.cpp index 4ad951fc45d5d830d8c169bdb2c7e89d05868a09..b6d6557a25484e654f2d494cb3e68541824a3a82 100644 --- a/gi/object.cpp +++ b/gi/object.cpp @@ -974,8 +974,11 @@ wrapped_gobj_dispose_notify(gpointer data, priv->g_object_finalized = true; - priv->keep_alive.reset(); - dissociate_list_remove(priv); + if (priv->keep_alive.rooted()) { + priv->keep_alive.reset(); + dissociate_list_remove(priv); + } + weak_pointer_list.erase(priv); #if DEBUG_DISPOSE gjs_debug(GJS_DEBUG_GOBJECT, "Wrapped GObject %p disposed", where_the_object_was); @@ -1681,6 +1684,16 @@ real_connect_func(JSContext *context, priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype)); return false; } + if (priv->g_object_finalized) { + g_critical("Object %s.%s (%p), has been already deallocated - impossible to connect to signal. " + "This might be caused by the fact that the object has been destroyed from C " + "code using something such as destroy(), dispose(), or remove() vfuncs", + priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "", + priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype), + priv->gobj); + gjs_dumpstack(); + return true; + } if (argc != 2 || !argv[0].isString() || !JS::IsCallable(&argv[1].toObject())) { gjs_throw(context, "connect() takes two args, the signal name and the callback"); @@ -1768,6 +1781,17 @@ emit_func(JSContext *context, return false; } + if (priv->g_object_finalized) { + g_critical("Object %s.%s (%p), has been already deallocated - impossible to emit signal. " + "This might be caused by the fact that the object has been destroyed from C " + "code using something such as destroy(), dispose(), or remove() vfuncs", + priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "", + priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype), + priv->gobj); + gjs_dumpstack(); + return true; + } + if (argc < 1 || !argv[0].isString()) { gjs_throw(context, "emit() first arg is the signal name"); return false; @@ -1856,7 +1880,9 @@ to_string_func(JSContext *context, return false; /* wrong class passed in */ } - return _gjs_proxy_to_string_func(context, obj, "object", + return _gjs_proxy_to_string_func(context, obj, + (priv->g_object_finalized) ? + "object (FINALIZED)" : "object", (GIBaseInfo*)priv->info, priv->gtype, priv->gobj, rec.rval()); } diff --git a/installed-tests/js/testGObjectDestructionAccess.js b/installed-tests/js/testGObjectDestructionAccess.js index 3e30e6e484038d282289de223c5836cfd6bbcce7..c4eb307dc628625c981613680c898df6bc0a0cd5 100644 --- a/installed-tests/js/testGObjectDestructionAccess.js +++ b/installed-tests/js/testGObjectDestructionAccess.js @@ -55,4 +55,38 @@ describe('Access to destroyed GObject', () => { GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectMethodSet'); }); + + it('Proto function connect', () => { + GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + 'Object Gtk.Window (0x*'); + + destroyedWindow.connect('foo-signal', () => {}); + + GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + 'testExceptionInDestroyedObjectConnect'); + }); + + it('Proto function connect_after', () => { + GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + 'Object Gtk.Window (0x*'); + + destroyedWindow.connect_after('foo-signal', () => {}); + + GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + 'testExceptionInDestroyedObjectConnectAfter'); + }); + + it('Proto function emit', () => { + GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + 'Object Gtk.Window (0x*'); + + destroyedWindow.emit('foo-signal'); + + GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + 'testExceptionInDestroyedObjectEmit'); + }); + + it('Proto function toString', () => { + expect(destroyedWindow.toString()).toMatch(/\[object \(FINALIZED\) instance proxy GIName:Gtk.Window jsobj@0x[a-f0-9]+ native@0x[a-f0-9]+\]/); + }); });