desktop-shell: Don't crash if the output is removed in startup

If the output is destroyed between setting the panel and committing the
panel, or between setting the background and committing the background,
we have a use after free crash.

Handle this by clearing the surface private pointers on output destroy
so we can skip the useless commits.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
This commit is contained in:
Derek Foreman 2024-11-05 11:29:39 -06:00
parent fe35be5013
commit 1ee1b93bac

View file

@ -2777,7 +2777,13 @@ background_committed(struct weston_surface *es,
struct weston_coord_surface new_origin)
{
struct shell_output *sh_output = es->committed_private;
struct desktop_shell *shell = sh_output->shell;
struct desktop_shell *shell;
/* The output was destroyed before the background was committed */
if (!sh_output)
return;
shell = sh_output->shell;
if (!weston_surface_has_content(es))
return;
@ -2866,9 +2872,17 @@ panel_committed(struct weston_surface *es,
struct weston_coord_surface new_origin)
{
struct shell_output *sh_output = es->committed_private;
struct weston_output *output = sh_output->output;
struct weston_coord_global pos = output->pos;
struct desktop_shell *shell = sh_output->shell;
struct weston_output *output;
struct weston_coord_global pos;
struct desktop_shell *shell;
/* The output was destroyed before the panel was committed */
if (!sh_output)
return;
output = sh_output->output;
pos = output->pos;
shell = sh_output->shell;
if (!weston_surface_has_content(es))
return;
@ -4550,10 +4564,14 @@ shell_output_destroy(struct shell_output *shell_output)
shell_for_each_layer(shell, shell_output_changed_move_layer, NULL);
if (shell_output->panel_surface)
if (shell_output->panel_surface) {
wl_list_remove(&shell_output->panel_surface_listener.link);
if (shell_output->background_surface)
shell_output->panel_surface->committed_private = NULL;
}
if (shell_output->background_surface) {
wl_list_remove(&shell_output->background_surface_listener.link);
shell_output->background_surface->committed_private = NULL;
}
wl_list_remove(&shell_output->destroy_listener.link);
wl_list_remove(&shell_output->link);
free(shell_output);