diff --git a/include/util/rect_union.h b/include/util/rect_union.h index c4b378888..297c64d43 100644 --- a/include/util/rect_union.h +++ b/include/util/rect_union.h @@ -63,8 +63,10 @@ void rect_union_add(struct rect_union *r, const pixman_box32_t *box); /** * Compute an exact cover of the rectangles added so far, and return * a pointer to a pixman_region32_t giving that cover. The pointer will - * remain valid until the next time *r is modified. If there was an allocation - * failure, this function may return a single-rectangle bounding box instead. + * remain valid until the next time *r is modified. + * + * An internal complexity limit is enforced by rect_union. If exceeded, this + * function will instead return a single-rectangle bounding box. * * This may be called multiple times and interleaved with rect_union_add(). * diff --git a/util/rect_union.c b/util/rect_union.c index 8d29798de..f113fe43e 100644 --- a/util/rect_union.c +++ b/util/rect_union.c @@ -44,13 +44,21 @@ void rect_union_add(struct rect_union *ru, const pixman_box32_t *box) { box_union(&ru->bounding_box, box); - if (!ru->alloc_failure) { - pixman_box32_t *entry = wl_array_add(&ru->unsorted, sizeof(*entry)); - if (entry) { - *entry = *box; - } else { - handle_alloc_failure(ru); - } + if (ru->alloc_failure) { + return; + } + + int nrects = (int)(ru->unsorted.size / sizeof(pixman_box32_t)); + if (nrects >= 1024) { + handle_alloc_failure(ru); + return; + } + + pixman_box32_t *entry = wl_array_add(&ru->unsorted, sizeof(*entry)); + if (entry) { + *entry = *box; + } else { + handle_alloc_failure(ru); } }