wayland: Don't crash if wl_output resource is destroyed after being removed

Previously a MetaWaylandOutput could be removed from the current outputs
table (by being unplugged for example). This would result in the global
object being removed and the MetaWaylandOutput instance freed, but the
wl_resource destructor would still try to remove itself from the list of
resources. Trying to do this, it'd try to access its user data pointer
which would point to the freed MetaWaylandOutput instance, and as a
result crash when trying to manipulate the freed data.

https://bugzilla.gnome.org/show_bug.cgi?id=744453
This commit is contained in:
Jonas Ådahl 2015-07-01 13:18:45 +08:00
parent eb023ff2c9
commit f295349e26

View File

@ -47,6 +47,9 @@ output_resource_destroy (struct wl_resource *res)
MetaWaylandOutput *wayland_output; MetaWaylandOutput *wayland_output;
wayland_output = wl_resource_get_user_data (res); wayland_output = wl_resource_get_user_data (res);
if (!wayland_output)
return;
wayland_output->resources = g_list_remove (wayland_output->resources, res); wayland_output->resources = g_list_remove (wayland_output->resources, res);
} }
@ -234,14 +237,21 @@ static void
meta_wayland_output_finalize (GObject *object) meta_wayland_output_finalize (GObject *object)
{ {
MetaWaylandOutput *wayland_output = META_WAYLAND_OUTPUT (object); MetaWaylandOutput *wayland_output = META_WAYLAND_OUTPUT (object);
GList *resources; GList *l;
/* Make sure the destructors don't mess with the list */
resources = wayland_output->resources;
wayland_output->resources = NULL;
wl_global_destroy (wayland_output->global); wl_global_destroy (wayland_output->global);
g_list_free (resources);
/* Make sure the wl_output destructor doesn't try to access MetaWaylandOutput
* after we have freed it.
*/
for (l = wayland_output->resources; l; l = l->next)
{
struct wl_resource *output_resource = l->data;
wl_resource_set_user_data (output_resource, NULL);
}
g_list_free (wayland_output->resources);
G_OBJECT_CLASS (meta_wayland_output_parent_class)->finalize (object); G_OBJECT_CLASS (meta_wayland_output_parent_class)->finalize (object);
} }