mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-28 13:12:10 +01:00
GDBusConnection: Do not dispatch calls to unregistered objects or subtrees
There was a slight race where we ended up calling into user code if the user managed to unregister an object (or subtree) in the window between - processing the remote call on the worker thread; and - continuing handling it on the user code thread (via an idle handler) This patch fixes the problem. Signed-off-by: David Zeuthen <davidz@redhat.com>
This commit is contained in:
parent
ed7f59770e
commit
db0c55608f
@ -3018,15 +3018,52 @@ exported_interface_free (ExportedInterface *ei)
|
|||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Convenience function to check if @registration_id (if not zero) or
|
||||||
|
* @subtree_registration_id (if not zero) has been unregistered. If
|
||||||
|
* so, returns %TRUE.
|
||||||
|
*
|
||||||
|
* Caller must *not* hold lock.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
has_object_been_unregistered (GDBusConnection *connection,
|
||||||
|
guint registration_id,
|
||||||
|
guint subtree_registration_id)
|
||||||
|
{
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
|
||||||
|
|
||||||
|
ret = FALSE;
|
||||||
|
|
||||||
|
CONNECTION_LOCK (connection);
|
||||||
|
if (registration_id != 0 && g_hash_table_lookup (connection->priv->map_id_to_ei,
|
||||||
|
GUINT_TO_POINTER (registration_id)) == NULL)
|
||||||
|
{
|
||||||
|
ret = TRUE;
|
||||||
|
}
|
||||||
|
else if (subtree_registration_id != 0 && g_hash_table_lookup (connection->priv->map_id_to_es,
|
||||||
|
GUINT_TO_POINTER (subtree_registration_id)) == NULL)
|
||||||
|
{
|
||||||
|
ret = TRUE;
|
||||||
|
}
|
||||||
|
CONNECTION_UNLOCK (connection);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
GDBusConnection *connection;
|
GDBusConnection *connection;
|
||||||
GDBusMessage *message;
|
GDBusMessage *message;
|
||||||
gpointer user_data;
|
gpointer user_data;
|
||||||
const char *property_name;
|
const gchar *property_name;
|
||||||
const GDBusInterfaceVTable *vtable;
|
const GDBusInterfaceVTable *vtable;
|
||||||
const GDBusInterfaceInfo *interface_info;
|
const GDBusInterfaceInfo *interface_info;
|
||||||
const GDBusPropertyInfo *property_info;
|
const GDBusPropertyInfo *property_info;
|
||||||
|
guint registration_id;
|
||||||
|
guint subtree_registration_id;
|
||||||
} PropertyData;
|
} PropertyData;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -3046,6 +3083,19 @@ invoke_get_property_in_idle_cb (gpointer _data)
|
|||||||
GError *error;
|
GError *error;
|
||||||
GDBusMessage *reply;
|
GDBusMessage *reply;
|
||||||
|
|
||||||
|
if (has_object_been_unregistered (data->connection,
|
||||||
|
data->registration_id,
|
||||||
|
data->subtree_registration_id))
|
||||||
|
{
|
||||||
|
reply = g_dbus_message_new_method_error (data->message,
|
||||||
|
"org.freedesktop.DBus.Error.UnknownMethod",
|
||||||
|
_("No such interface `org.freedesktop.DBus.Properties' on object at path %s"),
|
||||||
|
g_dbus_message_get_path (data->message));
|
||||||
|
g_dbus_connection_send_message (data->connection, reply, NULL, NULL);
|
||||||
|
g_object_unref (reply);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
error = NULL;
|
error = NULL;
|
||||||
value = data->vtable->get_property (data->connection,
|
value = data->vtable->get_property (data->connection,
|
||||||
g_dbus_message_get_sender (data->message),
|
g_dbus_message_get_sender (data->message),
|
||||||
@ -3070,9 +3120,7 @@ invoke_get_property_in_idle_cb (gpointer _data)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
gchar *dbus_error_name;
|
gchar *dbus_error_name;
|
||||||
|
|
||||||
g_assert (error != NULL);
|
g_assert (error != NULL);
|
||||||
|
|
||||||
dbus_error_name = g_dbus_error_encode_gerror (error);
|
dbus_error_name = g_dbus_error_encode_gerror (error);
|
||||||
reply = g_dbus_message_new_method_error_literal (data->message,
|
reply = g_dbus_message_new_method_error_literal (data->message,
|
||||||
dbus_error_name,
|
dbus_error_name,
|
||||||
@ -3083,6 +3131,7 @@ invoke_get_property_in_idle_cb (gpointer _data)
|
|||||||
g_object_unref (reply);
|
g_object_unref (reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3153,6 +3202,8 @@ invoke_set_property_in_idle_cb (gpointer _data)
|
|||||||
static gboolean
|
static gboolean
|
||||||
validate_and_maybe_schedule_property_getset (GDBusConnection *connection,
|
validate_and_maybe_schedule_property_getset (GDBusConnection *connection,
|
||||||
GDBusMessage *message,
|
GDBusMessage *message,
|
||||||
|
guint registration_id,
|
||||||
|
guint subtree_registration_id,
|
||||||
gboolean is_get,
|
gboolean is_get,
|
||||||
const GDBusInterfaceInfo *introspection_data,
|
const GDBusInterfaceInfo *introspection_data,
|
||||||
const GDBusInterfaceVTable *vtable,
|
const GDBusInterfaceVTable *vtable,
|
||||||
@ -3243,6 +3294,8 @@ validate_and_maybe_schedule_property_getset (GDBusConnection *connect
|
|||||||
property_data->vtable = vtable;
|
property_data->vtable = vtable;
|
||||||
property_data->interface_info = introspection_data;
|
property_data->interface_info = introspection_data;
|
||||||
property_data->property_info = property_info;
|
property_data->property_info = property_info;
|
||||||
|
property_data->registration_id = registration_id;
|
||||||
|
property_data->subtree_registration_id = subtree_registration_id;
|
||||||
|
|
||||||
idle_source = g_idle_source_new ();
|
idle_source = g_idle_source_new ();
|
||||||
g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
|
g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
|
||||||
@ -3304,6 +3357,8 @@ handle_getset_property (GDBusConnection *connection,
|
|||||||
|
|
||||||
handled = validate_and_maybe_schedule_property_getset (eo->connection,
|
handled = validate_and_maybe_schedule_property_getset (eo->connection,
|
||||||
message,
|
message,
|
||||||
|
ei->id,
|
||||||
|
0,
|
||||||
is_get,
|
is_get,
|
||||||
ei->introspection_data,
|
ei->introspection_data,
|
||||||
ei->vtable,
|
ei->vtable,
|
||||||
@ -3322,6 +3377,8 @@ typedef struct
|
|||||||
gpointer user_data;
|
gpointer user_data;
|
||||||
const GDBusInterfaceVTable *vtable;
|
const GDBusInterfaceVTable *vtable;
|
||||||
const GDBusInterfaceInfo *interface_info;
|
const GDBusInterfaceInfo *interface_info;
|
||||||
|
guint registration_id;
|
||||||
|
guint subtree_registration_id;
|
||||||
} PropertyGetAllData;
|
} PropertyGetAllData;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -3342,6 +3399,19 @@ invoke_get_all_properties_in_idle_cb (gpointer _data)
|
|||||||
GDBusMessage *reply;
|
GDBusMessage *reply;
|
||||||
guint n;
|
guint n;
|
||||||
|
|
||||||
|
if (has_object_been_unregistered (data->connection,
|
||||||
|
data->registration_id,
|
||||||
|
data->subtree_registration_id))
|
||||||
|
{
|
||||||
|
reply = g_dbus_message_new_method_error (data->message,
|
||||||
|
"org.freedesktop.DBus.Error.UnknownMethod",
|
||||||
|
_("No such interface `org.freedesktop.DBus.Properties' on object at path %s"),
|
||||||
|
g_dbus_message_get_path (data->message));
|
||||||
|
g_dbus_connection_send_message (data->connection, reply, NULL, NULL);
|
||||||
|
g_object_unref (reply);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
error = NULL;
|
error = NULL;
|
||||||
|
|
||||||
/* TODO: Right now we never fail this call - we just omit values if
|
/* TODO: Right now we never fail this call - we just omit values if
|
||||||
@ -3383,6 +3453,7 @@ invoke_get_all_properties_in_idle_cb (gpointer _data)
|
|||||||
g_dbus_connection_send_message (data->connection, reply, NULL, NULL);
|
g_dbus_connection_send_message (data->connection, reply, NULL, NULL);
|
||||||
g_object_unref (reply);
|
g_object_unref (reply);
|
||||||
|
|
||||||
|
out:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3390,6 +3461,8 @@ invoke_get_all_properties_in_idle_cb (gpointer _data)
|
|||||||
static gboolean
|
static gboolean
|
||||||
validate_and_maybe_schedule_property_get_all (GDBusConnection *connection,
|
validate_and_maybe_schedule_property_get_all (GDBusConnection *connection,
|
||||||
GDBusMessage *message,
|
GDBusMessage *message,
|
||||||
|
guint registration_id,
|
||||||
|
guint subtree_registration_id,
|
||||||
const GDBusInterfaceInfo *introspection_data,
|
const GDBusInterfaceInfo *introspection_data,
|
||||||
const GDBusInterfaceVTable *vtable,
|
const GDBusInterfaceVTable *vtable,
|
||||||
GMainContext *main_context,
|
GMainContext *main_context,
|
||||||
@ -3416,6 +3489,8 @@ validate_and_maybe_schedule_property_get_all (GDBusConnection *connec
|
|||||||
property_get_all_data->user_data = user_data;
|
property_get_all_data->user_data = user_data;
|
||||||
property_get_all_data->vtable = vtable;
|
property_get_all_data->vtable = vtable;
|
||||||
property_get_all_data->interface_info = introspection_data;
|
property_get_all_data->interface_info = introspection_data;
|
||||||
|
property_get_all_data->registration_id = registration_id;
|
||||||
|
property_get_all_data->subtree_registration_id = subtree_registration_id;
|
||||||
|
|
||||||
idle_source = g_idle_source_new ();
|
idle_source = g_idle_source_new ();
|
||||||
g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
|
g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
|
||||||
@ -3467,6 +3542,8 @@ handle_get_all_properties (GDBusConnection *connection,
|
|||||||
|
|
||||||
handled = validate_and_maybe_schedule_property_get_all (eo->connection,
|
handled = validate_and_maybe_schedule_property_get_all (eo->connection,
|
||||||
message,
|
message,
|
||||||
|
ei->id,
|
||||||
|
0,
|
||||||
ei->introspection_data,
|
ei->introspection_data,
|
||||||
ei->vtable,
|
ei->vtable,
|
||||||
ei->context,
|
ei->context,
|
||||||
@ -3656,10 +3733,30 @@ call_in_idle_cb (gpointer user_data)
|
|||||||
{
|
{
|
||||||
GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (user_data);
|
GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (user_data);
|
||||||
GDBusInterfaceVTable *vtable;
|
GDBusInterfaceVTable *vtable;
|
||||||
|
guint registration_id;
|
||||||
|
guint subtree_registration_id;
|
||||||
|
|
||||||
vtable = g_object_get_data (G_OBJECT (invocation), "g-dbus-interface-vtable");
|
vtable = g_object_get_data (G_OBJECT (invocation), "g-dbus-interface-vtable");
|
||||||
g_assert (vtable != NULL && vtable->method_call != NULL);
|
g_assert (vtable != NULL && vtable->method_call != NULL);
|
||||||
|
|
||||||
|
registration_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (invocation), "g-dbus-registration-id"));
|
||||||
|
subtree_registration_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (invocation), "g-dbus-subtree-registration-id"));
|
||||||
|
|
||||||
|
if (has_object_been_unregistered (g_dbus_method_invocation_get_connection (invocation),
|
||||||
|
registration_id,
|
||||||
|
subtree_registration_id))
|
||||||
|
{
|
||||||
|
GDBusMessage *reply;
|
||||||
|
reply = g_dbus_message_new_method_error (g_dbus_method_invocation_get_message (invocation),
|
||||||
|
"org.freedesktop.DBus.Error.UnknownMethod",
|
||||||
|
_("No such interface `%s' on object at path %s"),
|
||||||
|
g_dbus_method_invocation_get_interface_name (invocation),
|
||||||
|
g_dbus_method_invocation_get_object_path (invocation));
|
||||||
|
g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, NULL, NULL);
|
||||||
|
g_object_unref (reply);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
vtable->method_call (g_dbus_method_invocation_get_connection (invocation),
|
vtable->method_call (g_dbus_method_invocation_get_connection (invocation),
|
||||||
g_dbus_method_invocation_get_sender (invocation),
|
g_dbus_method_invocation_get_sender (invocation),
|
||||||
g_dbus_method_invocation_get_object_path (invocation),
|
g_dbus_method_invocation_get_object_path (invocation),
|
||||||
@ -3669,6 +3766,7 @@ call_in_idle_cb (gpointer user_data)
|
|||||||
g_object_ref (invocation),
|
g_object_ref (invocation),
|
||||||
g_dbus_method_invocation_get_user_data (invocation));
|
g_dbus_method_invocation_get_user_data (invocation));
|
||||||
|
|
||||||
|
out:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3676,6 +3774,8 @@ call_in_idle_cb (gpointer user_data)
|
|||||||
static gboolean
|
static gboolean
|
||||||
validate_and_maybe_schedule_method_call (GDBusConnection *connection,
|
validate_and_maybe_schedule_method_call (GDBusConnection *connection,
|
||||||
GDBusMessage *message,
|
GDBusMessage *message,
|
||||||
|
guint registration_id,
|
||||||
|
guint subtree_registration_id,
|
||||||
const GDBusInterfaceInfo *introspection_data,
|
const GDBusInterfaceInfo *introspection_data,
|
||||||
const GDBusInterfaceVTable *vtable,
|
const GDBusInterfaceVTable *vtable,
|
||||||
GMainContext *main_context,
|
GMainContext *main_context,
|
||||||
@ -3756,9 +3856,12 @@ validate_and_maybe_schedule_method_call (GDBusConnection *connection,
|
|||||||
parameters,
|
parameters,
|
||||||
user_data);
|
user_data);
|
||||||
g_variant_unref (parameters);
|
g_variant_unref (parameters);
|
||||||
g_object_set_data (G_OBJECT (invocation),
|
|
||||||
"g-dbus-interface-vtable",
|
/* TODO: would be nicer with a real MethodData like we already
|
||||||
(gpointer) vtable);
|
* have PropertyData and PropertyGetAllData... */
|
||||||
|
g_object_set_data (G_OBJECT (invocation), "g-dbus-interface-vtable", (gpointer) vtable);
|
||||||
|
g_object_set_data (G_OBJECT (invocation), "g-dbus-registration-id", GUINT_TO_POINTER (registration_id));
|
||||||
|
g_object_set_data (G_OBJECT (invocation), "g-dbus-subtree-registration-id", GUINT_TO_POINTER (subtree_registration_id));
|
||||||
|
|
||||||
idle_source = g_idle_source_new ();
|
idle_source = g_idle_source_new ();
|
||||||
g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
|
g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
|
||||||
@ -3809,6 +3912,8 @@ obj_message_func (GDBusConnection *connection,
|
|||||||
|
|
||||||
handled = validate_and_maybe_schedule_method_call (connection,
|
handled = validate_and_maybe_schedule_method_call (connection,
|
||||||
message,
|
message,
|
||||||
|
ei->id,
|
||||||
|
0,
|
||||||
ei->introspection_data,
|
ei->introspection_data,
|
||||||
ei->vtable,
|
ei->vtable,
|
||||||
ei->context,
|
ei->context,
|
||||||
@ -4687,6 +4792,8 @@ handle_subtree_method_invocation (GDBusConnection *connection,
|
|||||||
CONNECTION_LOCK (connection);
|
CONNECTION_LOCK (connection);
|
||||||
handled = validate_and_maybe_schedule_method_call (es->connection,
|
handled = validate_and_maybe_schedule_method_call (es->connection,
|
||||||
message,
|
message,
|
||||||
|
0,
|
||||||
|
es->id,
|
||||||
introspection_data,
|
introspection_data,
|
||||||
interface_vtable,
|
interface_vtable,
|
||||||
es->context,
|
es->context,
|
||||||
@ -4746,6 +4853,8 @@ handle_subtree_method_invocation (GDBusConnection *connection,
|
|||||||
CONNECTION_LOCK (connection);
|
CONNECTION_LOCK (connection);
|
||||||
handled = validate_and_maybe_schedule_property_getset (es->connection,
|
handled = validate_and_maybe_schedule_property_getset (es->connection,
|
||||||
message,
|
message,
|
||||||
|
0,
|
||||||
|
es->id,
|
||||||
is_property_get,
|
is_property_get,
|
||||||
introspection_data,
|
introspection_data,
|
||||||
interface_vtable,
|
interface_vtable,
|
||||||
@ -4758,6 +4867,8 @@ handle_subtree_method_invocation (GDBusConnection *connection,
|
|||||||
CONNECTION_LOCK (connection);
|
CONNECTION_LOCK (connection);
|
||||||
handled = validate_and_maybe_schedule_property_get_all (es->connection,
|
handled = validate_and_maybe_schedule_property_get_all (es->connection,
|
||||||
message,
|
message,
|
||||||
|
0,
|
||||||
|
es->id,
|
||||||
introspection_data,
|
introspection_data,
|
||||||
interface_vtable,
|
interface_vtable,
|
||||||
es->context,
|
es->context,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user