gdiplus: Prevent infinite loops due to floating point inaccuracy.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52492
This commit is contained in:
Fabian Maurer 2023-07-24 17:23:44 +02:00 committed by Alexandre Julliard
parent 57f692aef5
commit 36c3a51d6a
2 changed files with 44 additions and 5 deletions

View file

@ -183,14 +183,16 @@ static BOOL flatten_bezier(path_list_node_t *start, REAL x2, REAL y2, REAL x3, R
mp[2].X = (mp[1].X + mp[3].X) / 2.0;
mp[2].Y = (mp[1].Y + mp[3].Y) / 2.0;
/* Is one pair of the new control points equal to the old control points? */
if ((x2 == mp[0].X && y2 == mp[0].Y && x3 == mp[1].X && y3 == mp[1].Y) ||
(x2 == mp[3].X && y2 == mp[3].Y && x3 == mp[4].X && y3 == mp[4].Y))
continue;
pt = end->pt;
pt_st = start->pt;
/* Test for closely spaced points that don't need to be flattened
* Also avoids limited-precision errors in flatness check
*/
if((fabs(pt.X - mp[2].X) + fabs(pt.Y - mp[2].Y) +
fabs(pt_st.X - mp[2].X) + fabs(pt_st.Y - mp[2].Y) ) <= flatness * 0.5)
continue;
/* check flatness as a half of distance between middle point and a linearized path
* formula for distance point from line for point (x0, y0) and line (x1, y1) (x2, y2)
* is defined as (area_triangle / distance_start_end):

View file

@ -1253,6 +1253,42 @@ static void test_flatten(void)
GdipDeletePath(path);
}
static void test_flatten2(void)
{
GpStatus status;
GpPath *path;
status = GdipCreatePath(0, &path);
expect(Ok, status);
status = GdipStartPathFigure(path);
expect(Ok, status);
/* path seen in the wild that caused a stack overflow */
status = GdipAddPathArc(path, -136.33, 20.00, 786.00, 786.00, -105.00, 30.00);
expect(Ok, status);
status = GdipAddPathArc(path, 256.67, 413.00, 0.00, 0.00, -75.00, -30.00);
expect(Ok, status);
status = GdipClosePathFigure(path);
expect(Ok, status);
status = GdipFlattenPath(path, NULL, 1.0);
expect(Ok, status);
/* path seen in the wild that caused a stack overflow */
/* same path but redo with the manual points that caused a crash */
status = GdipResetPath(path);
expect(Ok, status);
status = GdipAddPathBezier(path, 154.950806, 33.391144, 221.586075, 15.536285, 291.747314, 15.536285, 358.382568, 33.391144);
expect(Ok, status);
status = GdipAddPathBezier(path, 256.666809, 412.999512, 256.666718, 412.999481, 256.666656, 412.999481, 256.666565, 412.999512);
expect(Ok, status);
status = GdipClosePathFigure(path);
expect(Ok, status);
status = GdipFlattenPath(path, NULL, 1.0);
GdipDeletePath(path);
}
static path_test_t widenline_path[] = {
{5.0, 5.0, PathPointTypeStart, 0, 0}, /*0*/
{50.0, 5.0, PathPointTypeLine, 0, 0}, /*1*/
@ -1935,6 +1971,7 @@ START_TEST(graphicspath)
test_widen_cap();
test_isvisible();
test_empty_rect();
test_flatten2();
GdiplusShutdown(gdiplusToken);
}