From 9ba2f52e4df38e8a2d1406de4b2a1e1b408c056a Mon Sep 17 00:00:00 2001 From: llyyr Date: Thu, 26 Mar 2026 22:47:53 +0530 Subject: [PATCH] tree/node: add and use node_finish in destroy functions We set node as dirty in {output,workspace,container}_begin_destroy functions but this leaves destroyed pointers in server.dirty_nodes while destroying. This can cause crashes when waking up the screen after being turned off for a while, because we request modeset on a 10ms timer when starting to destroy outputs. This timer could fire while we're in the middle of destroying the output and make us try to modeset an already freed output. See backtrace in https://github.com/swaywm/sway/pull/8969 --- include/sway/tree/node.h | 2 ++ sway/tree/container.c | 1 + sway/tree/node.c | 7 +++++++ sway/tree/output.c | 1 + sway/tree/workspace.c | 1 + 5 files changed, 12 insertions(+) diff --git a/include/sway/tree/node.h b/include/sway/tree/node.h index e2dbcdf05..b41bca42d 100644 --- a/include/sway/tree/node.h +++ b/include/sway/tree/node.h @@ -60,6 +60,8 @@ const char *node_type_to_str(enum sway_node_type type); */ void node_set_dirty(struct sway_node *node); +void node_finish(struct sway_node *node); + bool node_is_view(struct sway_node *node); char *node_get_name(struct sway_node *node); diff --git a/sway/tree/container.c b/sway/tree/container.c index fd9abadc6..a31434313 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -530,6 +530,7 @@ void container_destroy(struct sway_container *con) { scene_node_disown_children(con->content_tree); wlr_scene_node_destroy(&con->scene_tree->node); + node_finish(&con->node); free(con); } diff --git a/sway/tree/node.c b/sway/tree/node.c index 48ae325e4..abd7dbf0b 100644 --- a/sway/tree/node.c +++ b/sway/tree/node.c @@ -36,6 +36,13 @@ void node_set_dirty(struct sway_node *node) { list_add(server.dirty_nodes, node); } +void node_finish(struct sway_node *node) { + int dirty_idx = list_find(server.dirty_nodes, node); + if (dirty_idx >= 0) { + list_del(server.dirty_nodes, dirty_idx); + } +} + bool node_is_view(struct sway_node *node) { return node->type == N_CONTAINER && node->sway_container->view; } diff --git a/sway/tree/output.c b/sway/tree/output.c index c401d0f1d..2bbc6c273 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -273,6 +273,7 @@ void output_destroy(struct sway_output *output) { list_free(output->workspaces); list_free(output->current.workspaces); wlr_color_transform_unref(output->color_transform); + node_finish(&output->node); free(output); } diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index d366d19aa..c1b96052f 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -292,6 +292,7 @@ void workspace_destroy(struct sway_workspace *workspace) { list_free(workspace->tiling); list_free(workspace->current.floating); list_free(workspace->current.tiling); + node_finish(&workspace->node); free(workspace); }