fix: three startup/session crashers exposed by eager hosts and real use

tabs/mru lists init before host_init (sync configure walked garbage); EGL init keeps configured host size (swapchain desync abort); overlay sentinel bump snapshots size (shrank 1px/call to zero, then aborted). Adds motion-burst regression test.
This commit is contained in:
Andrew Hamilton 2026-09-12 07:53:02 +10:00
parent 5be0db56f6
commit a2b7802ec1
2 changed files with 53 additions and 10 deletions

37
kick.c
View file

@ -8706,8 +8706,14 @@ static void standalone_overlay_damage(void) {
to re-damage that whole region; restore the z-order immediately so the
always-enabled transparent rect never intercepts pointer hit-testing. */
wlr_scene_node_raise_to_top(&r->node);
wlr_scene_rect_set_size(r, r->width, r->height - 1);
wlr_scene_rect_set_size(r, r->width, r->height);
/* Snapshot the size: set_size updates the struct in place, so re-reading
r->height for the restore would keep the decremented value and shrink
the rect one pixel per call -- after output_height calls the height
reaches zero and the next bump aborts in wlr_scene_rect_set_size.
Every pointer motion calls here, so any real session got there. */
int w = r->width, h = r->height;
wlr_scene_rect_set_size(r, w, h > 0 ? h - 1 : h);
wlr_scene_rect_set_size(r, w, h);
wlr_scene_node_lower_to_bottom(&r->node);
}
@ -10945,8 +10951,15 @@ static bool host_init(void) {
return true;
}
host.width = 1280;
host.height = 800;
/* An eager host (kick-in-kick) may have configured the window inside
the startup roundtrip already; keep that real size. Otherwise install
the default until the first (async) configure overwrites it.
Resetting unconditionally desyncs the swapchain (sized from the
configure) from the host size and trips wlroots' build_state assert. */
if (!host.configured) {
host.width = 1280;
host.height = 800;
}
host.egl_window = wl_egl_window_create(host.surface, host.width, host.height);
host.egl_surface = eglCreateWindowSurface(host.egl_display, host.egl_config,
(EGLNativeWindowType)host.egl_window, NULL);
@ -12709,6 +12722,14 @@ int main(int argc, char *argv[]) {
return 1;
}
/* The tab/MRU lists must exist before host_init(): a host that sends
its first configure synchronously inside the startup roundtrip drives
the resize path (which walks server.tabs) before any tab exists. */
wl_list_init(&server.tabs);
wl_list_init(&server.mru);
server.mru_alt_anchor = NULL;
server.mru_alt_navigated = false;
/* Standalone mode presents onto the native output directly; nested mode
connects to the host compositor and presents inside it. */
if (!server.standalone && !host_init()) {
@ -12723,12 +12744,8 @@ int main(int argc, char *argv[]) {
order, each carrying a still-black pending window the command's client
claims when it connects (the process-group match in
handle_new_toplevel puts each client on its own slot no matter which
connects first). */
wl_list_init(&server.tabs);
wl_list_init(&server.mru);
server.mru_alt_anchor = NULL;
server.mru_alt_navigated = false;
connects first). The lists themselves were initialized before
host_init above. */
int focus_idx = start_cmd_index >= 0 ? start_cmd_index : total_apps - 1;
struct kick_tab *focus_tab = NULL;
for (int i = 0; i < total_apps; i++) {