From 6183b374dd97206e1d51bff46ab0929a0e5ed0e6 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 20 Apr 2026 19:08:55 +0200 Subject: [PATCH] wlr_compositor: Kill the client if we cannot accept the buffer When the client commits a new buffer, we may need to instantiate a new wlr_client_buffer which may cause us to import the buffer into our active renderer, which may fail. If the import fails, we leave the old buffer behind but otherwise proceed as normal. If the client is resizing its window and we fail to apply a buffer of a new size, while the client is also applying a suitable viewport src_box for the new buffer size, we will end up with an inconsistent surface state that will later lead to assert. Rather than have an inconsistent surface state that can cause the entire display server to crash on asserts later, sacrifice the client. We might be able to do something smarter in the future. Fixes: https://gitlab.freedesktop.org/wlroots/wlroots/-/work_items/4079 Signed-off-by: Kenny Levinsen --- types/wlr_compositor.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 6b31ab857..fd1a99346 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -404,7 +404,7 @@ static void surface_state_move(struct wlr_surface_state *state, next->cached_state_locks = 0; } -static void surface_apply_damage(struct wlr_surface *surface) { +static bool surface_apply_damage(struct wlr_surface *surface) { if (surface->current.buffer == NULL) { // NULL commit if (surface->buffer != NULL) { @@ -412,7 +412,7 @@ static void surface_apply_damage(struct wlr_surface *surface) { } surface->buffer = NULL; surface->opaque = false; - return; + return true; } surface->opaque = wlr_buffer_is_opaque(surface->current.buffer); @@ -422,12 +422,12 @@ static void surface_apply_damage(struct wlr_surface *surface) { surface->current.buffer, &surface->buffer_damage)) { wlr_buffer_unlock(surface->current.buffer); surface->current.buffer = NULL; - return; + return true; } } if (surface->compositor->renderer == NULL) { - return; + return true; } struct wlr_client_buffer *buffer = wlr_client_buffer_create( @@ -435,13 +435,14 @@ static void surface_apply_damage(struct wlr_surface *surface) { if (buffer == NULL) { wlr_log(WLR_ERROR, "Failed to upload buffer"); - return; + return false; } if (surface->buffer != NULL) { wlr_buffer_unlock(&surface->buffer->base); } surface->buffer = buffer; + return true; } static void surface_update_opaque_region(struct wlr_surface *surface) { @@ -532,8 +533,12 @@ static void surface_commit_state(struct wlr_surface *surface, surface_state_move(&surface->current, next, surface); - if (invalid_buffer) { - surface_apply_damage(surface); + if (invalid_buffer && !surface_apply_damage(surface)) { + // We could not update the buffer, which means inconsistent surface + // state. If we keep going we risk hitting asserts, so let's play it + // safe and kill the client for now. + wl_resource_post_no_memory(surface->resource); + return; } surface_update_opaque_region(surface); surface_update_input_region(surface);