[cairo-commit] src/cairo-fixed-private.h src/cairo-path-stroke-boxes.c src/cairo-path-stroke.c src/cairo-path-stroke-polygon.c src/cairo-path-stroke-traps.c

Bryce Harrington bryce at kemper.freedesktop.org
Fri May 5 00:47:18 UTC 2017


 src/cairo-fixed-private.h       |   13 +++++++++++++
 src/cairo-path-stroke-boxes.c   |   25 ++++++++++++++++++++-----
 src/cairo-path-stroke-polygon.c |    1 +
 src/cairo-path-stroke-traps.c   |    1 +
 src/cairo-path-stroke.c         |    1 +
 5 files changed, 36 insertions(+), 5 deletions(-)

New commits:
commit 91b25005d62fe4ca178f45d349374e42c29a5e11
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Mar 24 12:36:41 2017 +0000

    stroker: Check for scaling overflow in computing half line widths
    
    Given a combination of a large scaling matrix and a large line, we can
    easily generate a half line width that is unrepresentable in our 24.8
    fixed-point. This leads to spurious errors later, such as generating
    negative height boxes, and so asking pixman to fill to infinity. To
    avoid this, we can check for overflow in calculating the half line with,
    though we still lack adequate range checking on the final stroke path.
    
    References: https://bugs.webkit.org/show_bug.cgi?id=16793
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
    Cc: magomez at igalia.com
    Tested-by: Bryce Harrington <bryce at osg.samsung.com>
    Acked-by: Bryce Harrington <bryce at osg.samsung.com>

diff --git a/src/cairo-fixed-private.h b/src/cairo-fixed-private.h
index 9ff8f750..8ee895b9 100644
--- a/src/cairo-fixed-private.h
+++ b/src/cairo-fixed-private.h
@@ -53,6 +53,9 @@
 #define CAIRO_FIXED_ONE_DOUBLE ((double)(1 << CAIRO_FIXED_FRAC_BITS))
 #define CAIRO_FIXED_EPSILON    ((cairo_fixed_t)(1))
 
+#define CAIRO_FIXED_MAX		(~0u >> (CAIRO_FIXED_FRAC_BITS + 1))
+#define CAIRO_FIXED_MIN		(-(int)CAIRO_FIXED_MAX)
+
 #define CAIRO_FIXED_ERROR_DOUBLE (1. / (2 * CAIRO_FIXED_ONE_DOUBLE))
 
 #define CAIRO_FIXED_FRAC_MASK  ((cairo_fixed_t)(((cairo_fixed_unsigned_t)(-1)) >> (CAIRO_FIXED_BITS - CAIRO_FIXED_FRAC_BITS)))
@@ -123,6 +126,16 @@ _cairo_fixed_from_double (double d)
 #endif
 }
 
+static inline cairo_bool_t
+_cairo_fixed_from_double_safe (cairo_fixed_t *f, double d)
+{
+    if (unlikely (d < CAIRO_FIXED_MIN || d > CAIRO_FIXED_MAX))
+	return FALSE;
+
+    *f = _cairo_fixed_from_double (d);
+    return TRUE;
+}
+
 #else
 # error Please define a magic number for your fixed point type!
 # error See cairo-fixed-private.h for details.
diff --git a/src/cairo-path-stroke-boxes.c b/src/cairo-path-stroke-boxes.c
index 7f25bf76..9d3ffe9e 100644
--- a/src/cairo-path-stroke-boxes.c
+++ b/src/cairo-path-stroke-boxes.c
@@ -98,6 +98,8 @@ _cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t	*stroker,
 				 cairo_antialias_t		 antialias,
 				 cairo_boxes_t			*boxes)
 {
+    double half_line_width;
+
     /* This special-case rectilinear stroker only supports
      * miter-joined lines (not curves) and a translation-only matrix
      * (though it could probably be extended to support a matrix with
@@ -127,15 +129,22 @@ _cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t	*stroker,
     if (! _cairo_matrix_is_scale (ctm))
 	return FALSE;
 
+    half_line_width = stroke_style->line_width / 2.0;
+
+    if (! _cairo_fixed_from_double_safe (&stroker->half_line_x,
+					 fabs(ctm->xx) * half_line_width))
+	    return FALSE;
+    assert (stroker->half_line_x > 0);
+
+    if (! _cairo_fixed_from_double_safe (&stroker->half_line_y,
+					 fabs(ctm->yy) * half_line_width))
+	    return FALSE;
+    assert (stroker->half_line_y > 0);
+
     stroker->stroke_style = stroke_style;
     stroker->ctm = ctm;
     stroker->antialias = antialias;
 
-    stroker->half_line_x =
-	_cairo_fixed_from_double (fabs(ctm->xx) * stroke_style->line_width / 2.0);
-    stroker->half_line_y =
-	_cairo_fixed_from_double (fabs(ctm->yy) * stroke_style->line_width / 2.0);
-
     stroker->open_sub_path = FALSE;
     stroker->segments = stroker->segments_embedded;
     stroker->segments_size = ARRAY_LENGTH (stroker->segments_embedded);
@@ -287,6 +296,8 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
 	    box.p1.x = b->x;
 	    box.p2.x = a->x;
 	}
+	assert (box.p1.x < box.p2.x);
+
 	if (a->y < b->y) {
 	    box.p1.y = a->y;
 	    box.p2.y = b->y;
@@ -294,6 +305,7 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
 	    box.p1.y = b->y;
 	    box.p2.y = a->y;
 	}
+	assert (box.p1.y < box.p2.y);
 
 	status = _cairo_boxes_add (stroker->boxes, stroker->antialias, &box);
 	if (unlikely (status))
@@ -404,6 +416,8 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st
 	    box.p1.x = b->x;
 	    box.p2.x = a->x;
 	}
+	assert (box.p1.x < box.p2.x);
+
 	if (a->y < b->y) {
 	    box.p1.y = a->y;
 	    box.p2.y = b->y;
@@ -411,6 +425,7 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st
 	    box.p1.y = b->y;
 	    box.p2.y = a->y;
 	}
+	assert (box.p1.y < box.p2.y);
 
 	status = _cairo_boxes_add (stroker->boxes, stroker->antialias, &box);
 	if (unlikely (status))
diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index e5082bbe..a68feb62 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -1276,6 +1276,7 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t	*path,
 	for (i = 1; i < polygon->num_limits; i++)
 	     _cairo_box_add_box (&stroker.bounds, &polygon->limits[i]);
 
+	/* XXX check overflow */
 	_cairo_stroke_style_max_distance_from_path (style, path, ctm, &dx, &dy);
 	fdx = _cairo_fixed_from_double (dx);
 	fdy = _cairo_fixed_from_double (dy);
diff --git a/src/cairo-path-stroke-traps.c b/src/cairo-path-stroke-traps.c
index da54e5a3..aad9c7f5 100644
--- a/src/cairo-path-stroke-traps.c
+++ b/src/cairo-path-stroke-traps.c
@@ -146,6 +146,7 @@ stroker_init (struct stroker		*stroker,
 	_cairo_stroke_style_max_line_distance_from_path (stroker->style, path,
 							 stroker->ctm, &dx, &dy);
 
+	/* XXX check overflow */
 	fdx = _cairo_fixed_from_double (dx);
 	fdy = _cairo_fixed_from_double (dy);
 
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 4d4ede81..b4fab7ad 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -110,6 +110,7 @@ _cairo_stroker_limit (cairo_stroker_t *stroker,
     _cairo_stroke_style_max_distance_from_path (&stroker->style, path,
 						stroker->ctm, &dx, &dy);
 
+    /* XXX report overflow! */
     fdx = _cairo_fixed_from_double (dx);
     fdy = _cairo_fixed_from_double (dy);
 


More information about the cairo-commit mailing list