Clamp dimensions to non-negative before wlr_scene_rect_set_size

During cross-output tiling drags, computed box dimensions can become
negative due to coordinate transforms and thickness subtractions. This
triggers the assertion in wlr_scene_rect_set_size() which requires
width >= 0 && height >= 0, crashing the compositor.

Clamp dimensions to zero in three locations:
- resize_box() in seatop_move_tiling.c for the WLR_EDGE_NONE case
- update_indicator() in seatop_move_tiling.c as a safety net
- arrange_container() in transaction.c for border width (matching the
  existing vert_border_height clamping from 62fd8c4d)
- update_rect_list() in container.c for pixman region boxes

This is the same class of bug fixed by 62fd8c4d (height clamping) and
partially addressed by c2d6aff6 (too-many-containers guards).
This commit is contained in:
James N. Hart 2026-03-18 21:46:22 -06:00
parent 4d0c805f2a
commit 24243f9c38
3 changed files with 14 additions and 5 deletions

View file

@ -435,9 +435,10 @@ static void arrange_container(struct sway_container *con,
int border_left = con->current.border_left ? border_width : 0; int border_left = con->current.border_left ? border_width : 0;
int border_right = con->current.border_right ? border_width : 0; int border_right = con->current.border_right ? border_width : 0;
int vert_border_height = MAX(0, height - border_top - border_bottom); int vert_border_height = MAX(0, height - border_top - border_bottom);
int horiz_border_width = MAX(0, width);
wlr_scene_rect_set_size(con->border.top, width, border_top); wlr_scene_rect_set_size(con->border.top, horiz_border_width, border_top);
wlr_scene_rect_set_size(con->border.bottom, width, border_bottom); wlr_scene_rect_set_size(con->border.bottom, horiz_border_width, border_bottom);
wlr_scene_rect_set_size(con->border.left, wlr_scene_rect_set_size(con->border.left,
border_left, vert_border_height); border_left, vert_border_height);
wlr_scene_rect_set_size(con->border.right, wlr_scene_rect_set_size(con->border.right,
@ -449,7 +450,7 @@ static void arrange_container(struct sway_container *con,
wlr_scene_node_set_position(&con->border.left->node, wlr_scene_node_set_position(&con->border.left->node,
0, border_top); 0, border_top);
wlr_scene_node_set_position(&con->border.right->node, wlr_scene_node_set_position(&con->border.right->node,
width - border_right, border_top); horiz_border_width - border_right, border_top);
// make sure to reparent, it's possible that the client just came out of // make sure to reparent, it's possible that the client just came out of
// fullscreen mode where the parent of the surface is not the container // fullscreen mode where the parent of the surface is not the container

View file

@ -81,6 +81,8 @@ static void resize_box(struct wlr_box *box, enum wlr_edges edge,
box->y += thickness; box->y += thickness;
box->width -= thickness * 2; box->width -= thickness * 2;
box->height -= thickness * 2; box->height -= thickness * 2;
if (box->width < 0) box->width = 0;
if (box->height < 0) box->height = 0;
break; break;
} }
} }
@ -154,7 +156,9 @@ static bool split_titlebar(struct sway_node *node, struct sway_container *avoid,
static void update_indicator(struct seatop_move_tiling_event *e, struct wlr_box *box) { static void update_indicator(struct seatop_move_tiling_event *e, struct wlr_box *box) {
wlr_scene_node_set_position(&e->indicator_rect->node, box->x, box->y); wlr_scene_node_set_position(&e->indicator_rect->node, box->x, box->y);
wlr_scene_rect_set_size(e->indicator_rect, box->width, box->height); wlr_scene_rect_set_size(e->indicator_rect,
box->width > 0 ? box->width : 0,
box->height > 0 ? box->height : 0);
} }
static void handle_motion_postthreshold(struct sway_seat *seat) { static void handle_motion_postthreshold(struct sway_seat *seat) {

View file

@ -335,7 +335,11 @@ static void update_rect_list(struct wlr_scene_tree *tree, pixman_region32_t *reg
if (i < len) { if (i < len) {
const pixman_box32_t *box = &rects[i++]; const pixman_box32_t *box = &rects[i++];
wlr_scene_node_set_position(&rect->node, box->x1, box->y1); wlr_scene_node_set_position(&rect->node, box->x1, box->y1);
wlr_scene_rect_set_size(rect, box->x2 - box->x1, box->y2 - box->y1); int rect_width = box->x2 - box->x1;
int rect_height = box->y2 - box->y1;
wlr_scene_rect_set_size(rect,
rect_width > 0 ? rect_width : 0,
rect_height > 0 ? rect_height : 0);
} }
} }
} }