[PATCH 10/10] cms-colord: Fix crash at compositor shutdown.

Derek Foreman derekf at osg.samsung.com
Fri Jul 17 14:53:31 PDT 2015


On 21/06/15 02:25 PM, Mario Kleiner wrote:
> cms-colord used the weston_compositor destroy signal to
> trigger its final colord_module_destroy cleanup, and the
> wl_output destroy signal to trigger per output cleanup.
> 
> The problem is that the compositor destroy signal gets
> emitted before the output destroy signals at compositor
> shutdown, colord_module_destroy would free all its
> shared data structures and then later on the output
> destroy callback would try to access those shared
> data structures when handling output destruction
> -> Use after free -> Crash, usually with VT switching
> dead and thereby an unuseable system requiring a reboot.
> 
> Solve this by moving the output destruction handling into
> the colord_cms_output_destroy() cleanup function for
> colord-cms own hash dictionary of all active outputs.
> 
> The output destroy callback just removes the corresponding
> output from the dictionary and triggers proper cleanup if
> an output is unplugged during runtime. During compositor
> shutdown, the dictionary as a whole is released before
> releasing all other shared data structures, thereby
> triggering cleanup of all remaining outputs.
> 
> Tested to fix crashes on x11 and drm backends.

Tricky. :)

I like the solution, looks good to me...  However there are some > 80
column lines that should probably be wrapped.

That done,
Reviewed-By: Derek Foreman <derekf at osg.samsung.com>

> 
> Signed-off-by: Mario Kleiner <mario.kleiner.de at gmail.com>
> Cc: Richard Hughes <richard at hughsie.com>
> ---
>  src/cms-colord.c | 53 +++++++++++++++++++++++++++++++++--------------------
>  1 file changed, 33 insertions(+), 20 deletions(-)
> 
> diff --git a/src/cms-colord.c b/src/cms-colord.c
> index 2adc886..b0dbb7b 100644
> --- a/src/cms-colord.c
> +++ b/src/cms-colord.c
> @@ -220,26 +220,9 @@ colord_notifier_output_destroy(struct wl_listener *listener, void *data)
>  		container_of(listener, struct cms_output, destroy_listener);
>  	struct weston_output *o = (struct weston_output *) data;
>  	struct cms_colord *cms = ocms->cms;
> -
> -	gboolean ret;
>  	gchar *device_id;
> -	GError *error = NULL;
>  
> -	colord_idle_cancel_for_output(cms, o);
>  	device_id = get_output_id(cms, o);
> -	weston_log("colord: output removed %s\n", device_id);
> -	g_signal_handlers_disconnect_by_data(ocms->device, ocms);
> -	ret = cd_client_delete_device_sync (cms->client,
> -					    ocms->device,
> -					    NULL,
> -					    &error);
> -
> -	if (!ret) {
> -		weston_log("colord: failed to delete device: %s\n", error->message);
> -		g_error_free(error);
> -		goto out;
> -	}
> -out:
>  	g_hash_table_remove (cms->devices, device_id);
>  	g_free (device_id);
>  }
> @@ -445,15 +428,17 @@ colord_load_pnp_ids(struct cms_colord *cms)
>  static void
>  colord_module_destroy(struct cms_colord *cms)
>  {
> -	g_free(cms->pnp_ids_data);
> -	g_hash_table_unref(cms->pnp_ids);
> -
>  	if (cms->loop) {
>  		g_main_loop_quit(cms->loop);
>  		g_main_loop_unref(cms->loop);
>  	}
>  	if (cms->thread)
>  		g_thread_join(cms->thread);
> +
> +	/* cms->devices must be destroyed before other resources, as
> +	 * the other resources are needed during output cleanup in
> +	 * cms->devices unref.
> +	 */
>  	if (cms->devices)
>  		g_hash_table_unref(cms->devices);
>  	if (cms->client)
> @@ -462,6 +447,10 @@ colord_module_destroy(struct cms_colord *cms)
>  		close(cms->readfd);
>  	if (cms->writefd)
>  		close(cms->writefd);
> +
> +	g_free(cms->pnp_ids_data);
> +	g_hash_table_unref(cms->pnp_ids);
> +
>  	free(cms);
>  }
>  
> @@ -477,8 +466,32 @@ static void
>  colord_cms_output_destroy(gpointer data)
>  {
>  	struct cms_output *ocms = (struct cms_output *) data;
> +	struct cms_colord *cms = ocms->cms;
> +	struct weston_output *o = ocms->o;
> +	gboolean ret;
> +	gchar *device_id;
> +	GError *error = NULL;
> +
> +	colord_idle_cancel_for_output(cms, o);
> +	device_id = get_output_id(cms, o);
> +	weston_log("colord: output unplugged %s\n", device_id);
> +
> +	wl_list_remove(&ocms->destroy_listener.link);
> +	g_signal_handlers_disconnect_by_data(ocms->device, ocms);
> +
> +	ret = cd_client_delete_device_sync (cms->client,
> +					    ocms->device,
> +					    NULL,
> +					    &error);
> +
> +	if (!ret) {
> +		weston_log("colord: failed to delete device: %s\n", error->message);
> +		g_error_free(error);
> +	}
> +
>  	g_object_unref(ocms->device);
>  	g_slice_free(struct cms_output, ocms);
> +	g_free (device_id);
>  }
>  
>  WL_EXPORT int
> 



More information about the wayland-devel mailing list