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 <kl@kl.wtf>
This commit is contained in:
Kenny Levinsen 2026-04-20 19:08:55 +02:00
parent 70d99eefef
commit 6183b374dd

View file

@ -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);