render: don't try to set a NULL xcursor image

render_xcursor_update() is called when we've loaded a new xcursor
image, and needs to display it. The reason it's not pushed to the
compositor immediately is to ensure we don't flood the Wayland socket
with xcursor updates.

Normally, it's only called when we *succeed* to load a new xcursor
image. I.e. if we try to load a non-existing xcursor image, we never
schedule an update.

However, we _can_ still end up in render_xcursor_update() without a
valid xcursor image. For example, we have loaded a valid xcursor
image, and scheduled an update. But before the update runs, the user
moves the cursor, and we try to load a new xcursor image. If it fails,
we crash when the previously scheduled update finally runs.

Closes #1624
This commit is contained in:
Daniel Eklöf 2024-02-29 07:49:08 +01:00
parent 4bb3b5383f
commit 6fd533ce13
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 19 additions and 2 deletions

View file

@ -122,12 +122,14 @@
affect emojis.
* Pressing a modifier key while the kitty keyboard protocol is enabled
no longer resets the viewport, or clears the selection.
* Crash when failing to load an xcursor image ([#1624][1624]).
[1531]: https://codeberg.org/dnkl/foot/issues/1531
[1573]: https://codeberg.org/dnkl/foot/issues/1573
[1568]: https://codeberg.org/dnkl/foot/issues/1568
[1552]: https://codeberg.org/dnkl/foot/issues/1552
[1610]: https://codeberg.org/dnkl/foot/issues/1610
[1624]: https://codeberg.org/dnkl/foot/issues/1624
### Security

View file

@ -4363,8 +4363,6 @@ render_xcursor_update(struct seat *seat)
return;
}
xassert(seat->pointer.cursor != NULL);
const enum cursor_shape shape = seat->pointer.shape;
const char *const xcursor = seat->pointer.last_custom_xcursor;
@ -4398,6 +4396,23 @@ render_xcursor_update(struct seat *seat)
LOG_DBG("setting %scursor shape using a client-side cursor surface",
seat->pointer.shape == CURSOR_SHAPE_CUSTOM ? "custom " : "");
if (seat->pointer.cursor == NULL) {
/*
* Normally, we never get here with a NULL-cursor, because we
* only schedule a cursor update when we succeed to load the
* cursor image.
*
* However, it is possible that we did succeed to load an
* image, and scheduled an update. But, *before* the scheduled
* update triggers, the user mvoes the pointer, and we try to
* load a new cursor image. This time failing.
*
* In this case, we have a NULL cursor, but the scheduled
* update is still scheduled.
*/
return;
}
const float scale = seat->pointer.scale;
struct wl_cursor_image *image = seat->pointer.cursor->images[0];
struct wl_buffer *buf = wl_cursor_image_get_buffer(image);