gapplication: don't rely on cmdline being finalized immediately

The GApplicationCommandLine DBus implementation currently calls
g_dbus_method_invocation_return_value() in its finalize() implementation
only, relying on the object being destroyed after g_object_unref() is
called on it inside g_application_impl_method_call().

While this is usually fine for C applications, when overriding the
command_line vfunc from language bindings, the binding might add extra
references to the object, which might not be released immediately - e.g.
because they're garbage collected, or possibly even leaked. The same
scenario could happen in a C application that decides to keep a
reference to the passed-in GApplicationCommandLine object.

To ensure the CommandLine DBus method always gets a reply after the
invocation of command_line in the primary instance, explicitly send the
message back before dropping our reference to the object.

https://bugzilla.gnome.org/show_bug.cgi?id=708042
This commit is contained in:
Cosimo Cecchi 2013-09-13 11:38:47 -07:00 committed by Matthias Clasen
parent be2656f139
commit c5748328be

View File

@ -129,6 +129,9 @@ struct _GApplicationImpl
static GApplicationCommandLine * static GApplicationCommandLine *
g_dbus_command_line_new (GDBusMethodInvocation *invocation); g_dbus_command_line_new (GDBusMethodInvocation *invocation);
static void
g_dbus_command_line_return (GApplicationCommandLine *cmdline);
static GVariant * static GVariant *
g_application_impl_get_property (GDBusConnection *connection, g_application_impl_get_property (GDBusConnection *connection,
const gchar *sender, const gchar *sender,
@ -259,6 +262,8 @@ g_application_impl_method_call (GDBusConnection *connection,
g_application_command_line_set_exit_status (cmdline, status); g_application_command_line_set_exit_status (cmdline, status);
class->after_emit (impl->app, platform_data); class->after_emit (impl->app, platform_data);
g_variant_unref (platform_data); g_variant_unref (platform_data);
g_dbus_command_line_return (cmdline);
g_object_unref (cmdline); g_object_unref (cmdline);
} }
else if (g_str_equal (method_name, "ActivateAction")) else if (g_str_equal (method_name, "ActivateAction"))
@ -787,6 +792,8 @@ typedef struct
GDBusConnection *connection; GDBusConnection *connection;
const gchar *bus_name; const gchar *bus_name;
const gchar *object_path; const gchar *object_path;
gboolean returned;
} GDBusCommandLine; } GDBusCommandLine;
@ -852,16 +859,29 @@ g_dbus_command_line_get_stdin (GApplicationCommandLine *cmdline)
} }
static void static void
g_dbus_command_line_finalize (GObject *object) g_dbus_command_line_return (GApplicationCommandLine *cmdline)
{ {
GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object); GDBusCommandLine *gdbcl = (GDBusCommandLine *) cmdline;
GDBusCommandLine *gdbcl = (GDBusCommandLine *) object;
gint status; gint status;
if (gdbcl->returned)
return;
gdbcl->returned = TRUE;
status = g_application_command_line_get_exit_status (cmdline); status = g_application_command_line_get_exit_status (cmdline);
g_dbus_method_invocation_return_value (gdbcl->invocation, g_dbus_method_invocation_return_value (gdbcl->invocation,
g_variant_new ("(i)", status)); g_variant_new ("(i)", status));
}
static void
g_dbus_command_line_finalize (GObject *object)
{
GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
GDBusCommandLine *gdbcl = (GDBusCommandLine *) object;
g_dbus_command_line_return (cmdline);
g_object_unref (gdbcl->invocation); g_object_unref (gdbcl->invocation);
G_OBJECT_CLASS (g_dbus_command_line_parent_class) G_OBJECT_CLASS (g_dbus_command_line_parent_class)