fix use-after-free: detach reparented children before tree destroy
When destroying a frame_buf tree, any other frame_bufs whose trees were reparented into it (e.g. fake_leaders) would have their tree_destroy_handler fire on already-freed memory during cascade. Detach their listeners and NULL their tree pointers before destroying the parent tree.
This commit is contained in:
parent
01904fdb39
commit
a6f43cdbe1
|
|
@ -28,6 +28,12 @@ extern void *W_GetViewBacking(unsigned long id);
|
|||
void frame_buf_destroy(struct wlr_buffer *wlr_buf)
|
||||
{
|
||||
struct wl_frame_buf *fb = wl_container_of(wlr_buf, fb, base);
|
||||
/* Unlink destroy listeners before freeing so cascade signals
|
||||
* from parent tree destruction can't reach this freed struct. */
|
||||
if (fb->tree_destroy.link.next)
|
||||
wl_list_remove(&fb->tree_destroy.link);
|
||||
if (fb->scene_buf_destroy.link.next)
|
||||
wl_list_remove(&fb->scene_buf_destroy.link);
|
||||
if (fb->bg_pixmap)
|
||||
pixman_image_unref(fb->bg_pixmap);
|
||||
if (fb->image)
|
||||
|
|
@ -472,11 +478,26 @@ wl_frame_destroy(WScreen *scr, WNativeWindow win)
|
|||
}
|
||||
}
|
||||
|
||||
W_UnregisterBacking(fb->id);
|
||||
/* Destroy the scene_buf and (if any) the tree. Without destroying
|
||||
* the tree, leaked tree nodes accumulate in the scene graph and
|
||||
* can cause stale rendering or hit-testing issues (e.g. ghost
|
||||
* titlebars after a menu is closed). */
|
||||
/* Before destroying the tree, detach any other frame_bufs whose
|
||||
* trees are descendants of ours (e.g. reparented fake_leaders) so
|
||||
* their tree_destroy_handler doesn't fire on freed memory. */
|
||||
if (fb->tree) {
|
||||
struct wl_frame_buf *other, *otmp;
|
||||
wl_list_for_each_safe(other, otmp, &wl_state.frame_list, link) {
|
||||
if (other == fb || !other->tree) continue;
|
||||
struct wlr_scene_tree *p = other->tree->node.parent;
|
||||
while (p) {
|
||||
if (p == fb->tree) {
|
||||
wl_list_remove(&other->tree_destroy.link);
|
||||
wl_list_init(&other->tree_destroy.link);
|
||||
other->tree = NULL;
|
||||
break;
|
||||
}
|
||||
p = p->node.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fb->scene_buf)
|
||||
wlr_scene_node_destroy(&fb->scene_buf->node);
|
||||
if (fb->tree)
|
||||
|
|
|
|||
Loading…
Reference in New Issue