After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 725950 - GApplication: call dbus_unregister only once, and before destruction
GApplication: call dbus_unregister only once, and before destruction
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: gapplication
unspecified
Other All
: Normal normal
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2014-03-08 18:33 UTC by Giovanni Campagna
Modified: 2020-02-27 14:56 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
GApplication: destroy the implementation in dispose, not finalize (2.01 KB, patch)
2014-03-08 18:33 UTC, Giovanni Campagna
none Details | Review
GApplication: Don't call dbus_unregister multiple times (1.60 KB, patch)
2017-06-08 18:17 UTC, Debarshi Ray
none Details | Review
GApplication: Assert that dbus_unregister was called before destruction (2.40 KB, patch)
2017-06-19 14:25 UTC, Debarshi Ray
committed Details | Review
GApplication: Don't call dbus_unregister multiple times (1.59 KB, patch)
2017-07-20 16:47 UTC, Debarshi Ray
committed Details | Review
GApplication: Use a WARNING if dbus_unregister is called by destructor (2.73 KB, patch)
2017-07-21 13:13 UTC, Debarshi Ray
committed Details | Review

Description Giovanni Campagna 2014-03-08 18:33:07 UTC
Shutting down the application calls out to user code through
dbus_unregister(), and is therefore unsafe to do in finalize().
Do it in dispose instead.
Comment 1 Giovanni Campagna 2014-03-08 18:33:12 UTC
Created attachment 271329 [details] [review]
GApplication: destroy the implementation in dispose, not finalize
Comment 2 Allison Karlitskaya (desrt) 2014-03-08 20:44:29 UTC
Why is this unsafe?
Comment 3 Giovanni Campagna 2014-03-08 22:23:45 UTC
If the vfunc is implemented in JS you risk calling JS code while finalizing, which is not allowed. I suspect python has a similar problem.
Comment 4 Allison Karlitskaya (desrt) 2014-03-08 22:45:30 UTC
(In reply to comment #3)
> If the vfunc is implemented in JS you risk calling JS code while finalizing,
> which is not allowed. I suspect python has a similar problem.

Makes sense -- except that we'd have the same risk from dispose, wouldn't we?  By the time dispose is running, the last ref was already dropped...

fwiw, I think we ought to be calling dbus_unregister() from shutdown() only.  If it doesn't happen by then then it should just never happen.  That's probably the correct spot to free the impl as well...
Comment 5 Giovanni Campagna 2014-03-08 23:03:59 UTC
Yes, but if the unsafe code runs in dispose(), I can call run_dispose() beforehand. 

I thought of shutdown, but I assumed existing code wants to call run() multiple times, or do something with the app between run() and unref
Comment 6 Matthias Clasen 2015-03-29 18:36:54 UTC
Is this still something we want ?
Comment 7 Giovanni Campagna 2015-03-30 00:19:05 UTC
This is still something that creates problems if a JS class wants to override dbus_unregister, but it's not an urgent issue because in practice there is no need to free resources as the process is exiting anyway.
Comment 8 Debarshi Ray 2017-06-08 18:07:52 UTC
This commit for bug 757372 has changed things a bit:
https://git.gnome.org/browse/glib/commit/?id=21b1c390a3ce1f7e2816c6309f161c4b92470c46

Right now, the first invocation of dbus_unregister always happens before finalize. But it is not just JS. It was pretty weird for C code too.

If the dbus_register vfunc is called from finalize, then, in terms of C, that's after the GApplication sub-class' dispose and finalize implementations have been run. People usually drop the references to their instance objects by then, and the exported objects are usually just that. So it is surprising to have the D-Bus unexport code called after that.

Secondly, do we expect people to guard against dbus_unregister being called multiple times?

It can happen if you tried to spawn a second instance of an application while the primary is still around. It is due to a g_application_impl_stop_primary call followed by g_application_impl_destroy. The exact call chain depends on whether the second instance had G_APPLICATION_IS_SERVICE set or not. See bug 783548 for an example. Every application has to deal with this oddity in one way or the other.

Maybe we should avoid that? I am struggling to find a good way to justify the current behaviour in the documentation.
Comment 9 Debarshi Ray 2017-06-08 18:17:09 UTC
Created attachment 353421 [details] [review]
GApplication: Don't call dbus_unregister multiple times

Sorry for digressing from the original intent of the bug. On the other hand, it is somewhat related.
Comment 10 Debarshi Ray 2017-06-19 14:25:28 UTC
Created attachment 354044 [details] [review]
GApplication: Assert that dbus_unregister was called before destruction
Comment 11 Christian Persch 2017-06-19 15:17:31 UTC
(In reply to Debarshi Ray from comment #8)
> Secondly, do we expect people to guard against dbus_unregister being called
> multiple times?

When I added the dbus hooks (bug 675509), it was certainly my intention that they would be called only once.
Comment 12 Philip Withnall 2017-07-04 10:37:41 UTC
Rishi, what was the outcome of your chat with Matthias about this?
Comment 13 Debarshi Ray 2017-07-04 10:44:33 UTC
(In reply to Philip Withnall from comment #12)
> Rishi, what was the outcome of your chat with Matthias about this?

I think he was in agreement, but he didn't formally codify it, so I might be mistaken.
Comment 14 Matthias Clasen 2017-07-19 15:42:19 UTC
Review of attachment 353421 [details] [review]:

Looks good to me with that change

::: gio/gapplicationimpl-dbus.c
@@ +458,3 @@
   GApplicationClass *app_class = G_APPLICATION_GET_CLASS (impl->app);
 
+  if (!impl->unregistered)

This looks double-negative to me. Should we have a registered boolean instead ?
Comment 15 Matthias Clasen 2017-07-19 15:44:00 UTC
Review of attachment 354044 [details] [review]:

looks ok to me
Comment 16 Debarshi Ray 2017-07-20 13:46:29 UTC
Comment on attachment 354044 [details] [review]
GApplication: Assert that dbus_unregister was called before destruction

Pushed to master.
Comment 17 Debarshi Ray 2017-07-20 16:47:00 UTC
Created attachment 356058 [details] [review]
GApplication: Don't call dbus_unregister multiple times

unregistered -> registered
Comment 18 Debarshi Ray 2017-07-20 17:48:06 UTC
Review of attachment 354044 [details] [review]:

::: gio/gapplication.c
@@ +1248,3 @@
+  GApplication *application = G_APPLICATION (object);
+
+  g_assert_null (application->priv->impl);

We need to express this differently because it doesn't work for those (eg., evolution --quit) that use GApplication but not g_application_run.

Thanks to Hussam for catching this.
Comment 19 Debarshi Ray 2017-07-21 13:13:55 UTC
Created attachment 356117 [details] [review]
GApplication: Use a WARNING if dbus_unregister is called by destructor

Here's another way to express it.
Comment 20 Matthias Clasen 2017-07-24 17:44:36 UTC
Review of attachment 356117 [details] [review]:

ok
Comment 21 Matthias Clasen 2017-07-24 17:45:16 UTC
Review of attachment 356058 [details] [review]:

ok
Comment 22 Debarshi Ray 2017-07-24 17:53:40 UTC
Pushed to master. Thanks for the reviews!
Comment 23 Milan Crha 2020-02-27 14:56:39 UTC
The warning brings "regression" [1] (well, it relaxes a crash, but otherwise is useless) and the commit message is inaccurate, missing the case when the application doesn't run, because it's the second running instance of it. There's no way to call g_application_run() when the application wants to quit and pass the "action" to an already running process (like described in [1]).

[1] https://gitlab.gnome.org/GNOME/glib/issues/1857