[PATCH v2] gdi32: Skip edge processing on overflow.

Gabriel Ivăncescu gabrielopcode at gmail.com
Thu Jun 4 09:15:59 CDT 2020


Fixes a regression introduced by 9bc6f004ceccf3963584a4f7f4681b5c0578c214,
which broke when REGION_CreateEdgeTable overflowed.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

Supersedes 185732.

The patch just indents the code to skip it if nb_points is zero, which can
be from overflow.

 dlls/gdi32/region.c         | 181 ++++++++++++++++++------------------
 dlls/gdi32/tests/clipping.c |   9 ++
 2 files changed, 101 insertions(+), 89 deletions(-)

diff --git a/dlls/gdi32/region.c b/dlls/gdi32/region.c
index 93238b5..3a3138a 100644
--- a/dlls/gdi32/region.c
+++ b/dlls/gdi32/region.c
@@ -2631,79 +2631,28 @@ HRGN create_polypolygon_region( const POINT *Pts, const INT *Count, INT nbpolygo
     if (!(obj = alloc_region( nb_points / 2 )))
         goto done;
 
-    if (clip_rect) ET.ymax = min( ET.ymax, clip_rect->bottom );
-    list_init( &AET );
-    pSLL = ET.scanlines.next;
-    if (mode != WINDING) {
-        /*
-         *  for each scanline
-         */
-        for (y = ET.ymin; y < ET.ymax; y++) {
+    if (nb_points)
+    {
+        if (clip_rect) ET.ymax = min( ET.ymax, clip_rect->bottom );
+        list_init( &AET );
+        pSLL = ET.scanlines.next;
+        if (mode != WINDING) {
             /*
-             *  Add a new edge to the active edge table when we
-             *  get to the next edge.
+             *  for each scanline
              */
-            if (pSLL != NULL && y == pSLL->scanline) {
-                REGION_loadAET(&AET, &pSLL->edgelist);
-                pSLL = pSLL->next;
-            }
-
-            if (!clip_rect || y >= clip_rect->top)
-            {
-                LIST_FOR_EACH_ENTRY( active, &AET, struct edge_table_entry, entry )
-                {
-                    if (first)
-                    {
-                        obj->rects[obj->numRects].left = active->bres.minor_axis;
-                        obj->rects[obj->numRects].top = y;
-                    }
-                    else if (obj->rects[obj->numRects].left != active->bres.minor_axis)
-                    {
-                        obj->rects[obj->numRects].right = active->bres.minor_axis;
-                        obj->rects[obj->numRects].bottom = y + 1;
-                        obj->numRects++;
-                    }
-                    first = !first;
+            for (y = ET.ymin; y < ET.ymax; y++) {
+                /*
+                 *  Add a new edge to the active edge table when we
+                 *  get to the next edge.
+                 */
+                if (pSLL != NULL && y == pSLL->scanline) {
+                    REGION_loadAET(&AET, &pSLL->edgelist);
+                    pSLL = pSLL->next;
                 }
-            }
-
-            next_scanline( &AET, y );
 
-            if (obj->numRects)
-            {
-                prev_band = REGION_Coalesce( obj, prev_band, cur_band );
-                cur_band = obj->numRects;
-            }
-        }
-    }
-    else {
-        /*
-         *  for each scanline
-         */
-        for (y = ET.ymin; y < ET.ymax; y++) {
-            /*
-             *  Add a new edge to the active edge table when we
-             *  get to the next edge.
-             */
-            if (pSLL != NULL && y == pSLL->scanline) {
-                REGION_loadAET(&AET, &pSLL->edgelist);
-                REGION_computeWAET( &AET, &WETE );
-                pSLL = pSLL->next;
-            }
-            pWETE = list_head( &WETE );
-
-            /*
-             *  for each active edge
-             */
-            if (!clip_rect || y >= clip_rect->top)
-            {
-                LIST_FOR_EACH_ENTRY( active, &AET, struct edge_table_entry, entry )
+                if (!clip_rect || y >= clip_rect->top)
                 {
-                    /*
-                     *  add to the buffer only those edges that
-                     *  are in the Winding active edge table.
-                     */
-                    if (pWETE == &active->winding_entry)
+                    LIST_FOR_EACH_ENTRY( active, &AET, struct edge_table_entry, entry )
                     {
                         if (first)
                         {
@@ -2717,40 +2666,94 @@ HRGN create_polypolygon_region( const POINT *Pts, const INT *Count, INT nbpolygo
                             obj->numRects++;
                         }
                         first = !first;
-                        pWETE = list_next( &WETE, pWETE );
                     }
                 }
-            }
 
+                next_scanline( &AET, y );
+
+                if (obj->numRects)
+                {
+                    prev_band = REGION_Coalesce( obj, prev_band, cur_band );
+                    cur_band = obj->numRects;
+                }
+            }
+        }
+        else {
             /*
-             *  recompute the winding active edge table if
-             *  we just resorted or have exited an edge.
+             *  for each scanline
              */
-            if (next_scanline( &AET, y )) REGION_computeWAET( &AET, &WETE );
+            for (y = ET.ymin; y < ET.ymax; y++) {
+                /*
+                 *  Add a new edge to the active edge table when we
+                 *  get to the next edge.
+                 */
+                if (pSLL != NULL && y == pSLL->scanline) {
+                    REGION_loadAET(&AET, &pSLL->edgelist);
+                    REGION_computeWAET( &AET, &WETE );
+                    pSLL = pSLL->next;
+                }
+                pWETE = list_head( &WETE );
 
-            if (obj->numRects)
-            {
-                prev_band = REGION_Coalesce( obj, prev_band, cur_band );
-                cur_band = obj->numRects;
+                /*
+                 *  for each active edge
+                 */
+                if (!clip_rect || y >= clip_rect->top)
+                {
+                    LIST_FOR_EACH_ENTRY( active, &AET, struct edge_table_entry, entry )
+                    {
+                        /*
+                         *  add to the buffer only those edges that
+                         *  are in the Winding active edge table.
+                         */
+                        if (pWETE == &active->winding_entry)
+                        {
+                            if (first)
+                            {
+                                obj->rects[obj->numRects].left = active->bres.minor_axis;
+                                obj->rects[obj->numRects].top = y;
+                            }
+                            else if (obj->rects[obj->numRects].left != active->bres.minor_axis)
+                            {
+                                obj->rects[obj->numRects].right = active->bres.minor_axis;
+                                obj->rects[obj->numRects].bottom = y + 1;
+                                obj->numRects++;
+                            }
+                            first = !first;
+                            pWETE = list_next( &WETE, pWETE );
+                        }
+                    }
+                }
+
+                /*
+                 *  recompute the winding active edge table if
+                 *  we just resorted or have exited an edge.
+                 */
+                if (next_scanline( &AET, y )) REGION_computeWAET( &AET, &WETE );
+
+                if (obj->numRects)
+                {
+                    prev_band = REGION_Coalesce( obj, prev_band, cur_band );
+                    cur_band = obj->numRects;
+                }
             }
         }
-    }
 
-    assert( obj->numRects <= nb_points / 2 );
+        assert( obj->numRects <= nb_points / 2 );
 
-    if (obj->numRects)
-    {
-        obj->extents.left = INT_MAX;
-        obj->extents.right = INT_MIN;
-        obj->extents.top = obj->rects[0].top;
-        obj->extents.bottom = obj->rects[obj->numRects-1].bottom;
-        for (i = 0; i < obj->numRects; i++)
+        if (obj->numRects)
         {
-            obj->extents.left = min( obj->extents.left, obj->rects[i].left );
-            obj->extents.right = max( obj->extents.right, obj->rects[i].right );
+            obj->extents.left = INT_MAX;
+            obj->extents.right = INT_MIN;
+            obj->extents.top = obj->rects[0].top;
+            obj->extents.bottom = obj->rects[obj->numRects-1].bottom;
+            for (i = 0; i < obj->numRects; i++)
+            {
+                obj->extents.left = min( obj->extents.left, obj->rects[i].left );
+                obj->extents.right = max( obj->extents.right, obj->rects[i].right );
+            }
         }
+        REGION_compact( obj );
     }
-    REGION_compact( obj );
 
     if (!(hrgn = alloc_gdi_handle( obj, OBJ_REGION, &region_funcs )))
         free_region( obj );
diff --git a/dlls/gdi32/tests/clipping.c b/dlls/gdi32/tests/clipping.c
index 0151575..484430b 100644
--- a/dlls/gdi32/tests/clipping.c
+++ b/dlls/gdi32/tests/clipping.c
@@ -513,8 +513,10 @@ static void test_CreatePolyPolygonRgn(void)
     POINT points_mixed[] = { {0, 0}, {0, 0}, {0, 0}, {6, 6}, {6, 6}, {6, 6} };
     POINT points_six[] = { {6, 6}, {6, 6}, {6, 6} };
     POINT points_line[] = { {1, 0}, {11, 0}, {21, 0}};
+    POINT points_overflow[] = { {0, 0}, {1, 0}, {0, 0x80000000} };
     INT counts_single_poly[] = { 3 };
     INT counts_two_poly[] = { 3, 3 };
+    INT counts_overflow[] = { ARRAY_SIZE(points_overflow) };
     int ret;
     RECT rect;
 
@@ -543,6 +545,13 @@ static void test_CreatePolyPolygonRgn(void)
     ret = GetRgnBox(region, &rect);
     ok (ret == NULLREGION, "Expected NULLREGION, got %d\n", ret);
     DeleteObject(region);
+
+    /* Test with points that overflow the edge table */
+    region = CreatePolyPolygonRgn(points_overflow, counts_overflow, ARRAY_SIZE(counts_overflow), ALTERNATE);
+    ok (region != NULL, "region must not be NULL\n");
+    ret = GetRgnBox(region, &rect);
+    ok (ret == NULLREGION, "Expected NULLREGION, got %d\n", ret);
+    DeleteObject(region);
 }
 
 START_TEST(clipping)
-- 
2.21.0




More information about the wine-devel mailing list