4 Commits
Author SHA1 Message Date
save196 babccfe6dc Preserve asleep disabled outputs in output config 2026-09-08 11:39:37 +02:00
klim 4847f97678 Clear surface->data on unmap to fix idle-inhibitor use-after-free
mapnotify() stores the client's scene tree in client_surface(c)->data;
checkidleinhibitor() later reads it back as a wlr_scene_tree and calls
wlr_scene_node_coords() on it. unmapnotify() frees the scene tree with
wlr_scene_node_destroy() but leaves surface->data dangling, so the next
arrange() -> checkidleinhibitor() dereferences freed memory and crashes
(SIGSEGV) whenever an idle inhibitor outlives the unmap.

Reset the pointer to NULL on unmap so the existing !tree guard handles it.
2026-09-08 09:30:56 +02:00
Alex Denes 04279f28e0 Remove decoration event listeners on destroynotify
When destroynotify doesn't clean up these listeners it causes a crash once the cleanup of the decoration is triggered

Thanks to kennylevinsen - https://codeberg.org/dwl/dwl/issues/1205#issuecomment-22424401
2026-09-06 13:52:31 +00:00
Alex Denes f4dfdabd0b NULL out decoration on destroy 2026-09-06 13:52:31 +00:00
+10 -1
View File
@@ -1242,6 +1242,7 @@ void
destroydecoration(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, destroy_decoration);
c->decoration = NULL;
wl_list_remove(&c->destroy_decoration.link);
wl_list_remove(&c->set_decoration_mode.link);
@@ -1347,6 +1348,10 @@ destroynotify(struct wl_listener *listener, void *data)
wl_list_remove(&c->map.link);
wl_list_remove(&c->unmap.link);
wl_list_remove(&c->maximize.link);
if (c->decoration) {
wl_list_remove(&c->set_decoration_mode.link);
wl_list_remove(&c->destroy_decoration.link);
}
}
free(c);
}
@@ -2834,6 +2839,7 @@ unmapnotify(struct wl_listener *listener, void *data)
}
wlr_scene_node_destroy(&c->scene->node);
client_surface(c)->data = NULL;
printstatus();
motionnotify(0, NULL, 0, 0, 0, 0);
}
@@ -2856,10 +2862,13 @@ updatemons(struct wl_listener *listener, void *data)
/* First remove from the layout the disabled monitors */
wl_list_for_each(m, &mons, link) {
if (m->wlr_output->enabled || m->asleep)
if (m->wlr_output->enabled)
continue;
config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
config_head->state.enabled = 0;
if (m->asleep)
continue;
/* Remove this output from the layout to avoid cursor enter inside it */
wlr_output_layout_remove(output_layout, m->wlr_output);
closemon(m);