[PATCH 1/5] gdi32: Don't overflow the buffer in GetGlyphOutline.

Matteo Bruni mbruni at codeweavers.com
Tue Sep 30 07:51:43 CDT 2014


The code already mixes tabs and spaces; since newer stuff seems to be
using spaces I'm using spaces for the new code too. I'm cleaning up the
lines nearby while at it.
It's quite a bit of code motion, hopefully the actual changes are still
readable enough.
---
 dlls/gdi32/freetype.c | 401 ++++++++++++++++++++++++++++----------------------
 1 file changed, 229 insertions(+), 172 deletions(-)

diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index fae9ffe..a3fa99d 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -6189,6 +6189,203 @@ static BOOL check_unicode_tategaki(WCHAR uchar)
     return (orientation ==  1 || orientation == 3);
 }
 
+static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
+{
+    TTPOLYGONHEADER *pph;
+    TTPOLYCURVE *ppc;
+    unsigned int needed = 0, point = 0, contour, first_pt;
+    unsigned int pph_start, cpfx;
+    DWORD type;
+
+    for (contour = 0; contour < outline->n_contours; contour++)
+    {
+        /* Ignore contours containing one point */
+        if (point == outline->contours[contour])
+        {
+            point++;
+            continue;
+        }
+
+        pph_start = needed;
+        pph = (TTPOLYGONHEADER *)(buf + needed);
+        first_pt = point;
+        if (buf)
+        {
+            pph->dwType = TT_POLYGON_TYPE;
+            FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
+        }
+        needed += sizeof(*pph);
+        point++;
+        while (point <= outline->contours[contour])
+        {
+            ppc = (TTPOLYCURVE *)(buf + needed);
+            type = outline->tags[point] & FT_Curve_Tag_On ?
+                TT_PRIM_LINE : TT_PRIM_QSPLINE;
+            cpfx = 0;
+            do
+            {
+                if (buf)
+                    FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+                cpfx++;
+                point++;
+            } while (point <= outline->contours[contour] &&
+                    (outline->tags[point] & FT_Curve_Tag_On) ==
+                    (outline->tags[point-1] & FT_Curve_Tag_On));
+            /* At the end of a contour Windows adds the start point, but
+               only for Beziers */
+            if (point > outline->contours[contour] &&
+               !(outline->tags[point-1] & FT_Curve_Tag_On))
+            {
+                if (buf)
+                    FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
+                cpfx++;
+            }
+            else if (point <= outline->contours[contour] &&
+                      outline->tags[point] & FT_Curve_Tag_On)
+            {
+                /* add closing pt for bezier */
+                if (buf)
+                    FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+                cpfx++;
+                point++;
+            }
+            if (buf)
+            {
+                ppc->wType = type;
+                ppc->cpfx = cpfx;
+            }
+            needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
+        }
+        if (buf)
+            pph->cb = needed - pph_start;
+    }
+    return needed;
+}
+
+static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
+{
+    /* Convert the quadratic Beziers to cubic Beziers.
+       The parametric eqn for a cubic Bezier is, from PLRM:
+       r(t) = at^3 + bt^2 + ct + r0
+       with the control points:
+       r1 = r0 + c/3
+       r2 = r1 + (c + b)/3
+       r3 = r0 + c + b + a
+
+       A quadratic Bezier has the form:
+       p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
+
+       So equating powers of t leads to:
+       r1 = 2/3 p1 + 1/3 p0
+       r2 = 2/3 p1 + 1/3 p2
+       and of course r0 = p0, r3 = p2
+    */
+    int contour, point = 0, first_pt;
+    TTPOLYGONHEADER *pph;
+    TTPOLYCURVE *ppc;
+    DWORD pph_start, cpfx, type;
+    FT_Vector cubic_control[4];
+    unsigned int needed = 0;
+
+    for (contour = 0; contour < outline->n_contours; contour++)
+    {
+        pph_start = needed;
+        pph = (TTPOLYGONHEADER *)(buf + needed);
+        first_pt = point;
+        if (buf)
+        {
+            pph->dwType = TT_POLYGON_TYPE;
+            FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
+        }
+        needed += sizeof(*pph);
+        point++;
+        while (point <= outline->contours[contour])
+        {
+            ppc = (TTPOLYCURVE *)(buf + needed);
+            type = outline->tags[point] & FT_Curve_Tag_On ?
+                TT_PRIM_LINE : TT_PRIM_CSPLINE;
+            cpfx = 0;
+            do
+            {
+                if (type == TT_PRIM_LINE)
+                {
+                    if (buf)
+                        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+                    cpfx++;
+                    point++;
+                }
+                else
+                {
+                    /* Unlike QSPLINEs, CSPLINEs always have their endpoint
+                       so cpfx = 3n */
+
+                    /* FIXME: Possible optimization in endpoint calculation
+                       if there are two consecutive curves */
+                    cubic_control[0] = outline->points[point-1];
+                    if (!(outline->tags[point-1] & FT_Curve_Tag_On))
+                    {
+                        cubic_control[0].x += outline->points[point].x + 1;
+                        cubic_control[0].y += outline->points[point].y + 1;
+                        cubic_control[0].x >>= 1;
+                        cubic_control[0].y >>= 1;
+                    }
+                    if (point+1 > outline->contours[contour])
+                        cubic_control[3] = outline->points[first_pt];
+                    else
+                    {
+                        cubic_control[3] = outline->points[point+1];
+                        if (!(outline->tags[point+1] & FT_Curve_Tag_On))
+                        {
+                            cubic_control[3].x += outline->points[point].x + 1;
+                            cubic_control[3].y += outline->points[point].y + 1;
+                            cubic_control[3].x >>= 1;
+                            cubic_control[3].y >>= 1;
+                        }
+                    }
+                    /* r1 = 1/3 p0 + 2/3 p1
+                       r2 = 1/3 p2 + 2/3 p1 */
+                    cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
+                    cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
+                    cubic_control[2] = cubic_control[1];
+                    cubic_control[1].x += (cubic_control[0].x + 1) / 3;
+                    cubic_control[1].y += (cubic_control[0].y + 1) / 3;
+                    cubic_control[2].x += (cubic_control[3].x + 1) / 3;
+                    cubic_control[2].y += (cubic_control[3].y + 1) / 3;
+                    if (buf)
+                    {
+                        FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
+                        FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
+                        FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
+                    }
+                    cpfx += 3;
+                    point++;
+                }
+            } while (point <= outline->contours[contour] &&
+                    (outline->tags[point] & FT_Curve_Tag_On) ==
+                    (outline->tags[point-1] & FT_Curve_Tag_On));
+            /* At the end of a contour Windows adds the start point,
+               but only for Beziers and we've already done that.
+            */
+            if (point <= outline->contours[contour] &&
+               outline->tags[point] & FT_Curve_Tag_On)
+            {
+                /* This is the closing pt of a bezier, but we've already
+                   added it, so just inc point and carry on */
+                point++;
+            }
+            if (buf)
+            {
+                ppc->wType = type;
+                ppc->cpfx = cpfx;
+            }
+            needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
+        }
+        if (buf)
+            pph->cb = needed - pph_start;
+    }
+    return needed;
+}
+
 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
 
 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
@@ -6583,6 +6780,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
 
 	if(!buf || !buflen) break;
         if (!needed) return GDI_ERROR;  /* empty glyph */
+        if (needed > buflen)
+            return GDI_ERROR;
 
 	switch(ft_face->glyph->format) {
 	case ft_glyph_format_bitmap:
@@ -6634,6 +6833,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
 
 	if(!buf || !buflen) break;
         if (!needed) return GDI_ERROR;  /* empty glyph */
+        if (needed > buflen)
+            return GDI_ERROR;
 
         max_level = get_max_level( format );
 
@@ -6706,6 +6907,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
 
             if (!buf || !buflen) break;
             if (!needed) return GDI_ERROR;  /* empty glyph */
+            if (needed > buflen)
+                return GDI_ERROR;
 
             memset(buf, 0, buflen);
             dst = buf;
@@ -6767,6 +6970,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
             needed = pitch * height;
 
             if (!buf || !buflen) break;
+            if (needed > buflen)
+                return GDI_ERROR;
 
             memset(buf, 0, buflen);
             dst = buf;
@@ -6863,188 +7068,40 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
 
     case GGO_NATIVE:
       {
-	int contour, point = 0, first_pt;
-	FT_Outline *outline = &ft_face->glyph->outline;
-	TTPOLYGONHEADER *pph;
-	TTPOLYCURVE *ppc;
-	DWORD pph_start, cpfx, type;
+        FT_Outline *outline = &ft_face->glyph->outline;
 
-	if(buflen == 0) buf = NULL;
+        if(buflen == 0) buf = NULL;
 
-	if (needsTransform && buf) {
-		pFT_Outline_Transform(outline, &transMatTategaki);
-	}
+        if (needsTransform && buf)
+            pFT_Outline_Transform(outline, &transMatTategaki);
 
-        for(contour = 0; contour < outline->n_contours; contour++) {
-            /* Ignore contours containing one point */
-            if(point == outline->contours[contour]) {
-                point++;
-                continue;
-            }
+        needed = get_native_glyph_outline(outline, buflen, NULL);
 
-	    pph_start = needed;
-	    pph = (TTPOLYGONHEADER *)((char *)buf + needed);
-	    first_pt = point;
-	    if(buf) {
-	        pph->dwType = TT_POLYGON_TYPE;
-		FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
-	    }
-	    needed += sizeof(*pph);
-	    point++;
-	    while(point <= outline->contours[contour]) {
-	        ppc = (TTPOLYCURVE *)((char *)buf + needed);
-		type = (outline->tags[point] & FT_Curve_Tag_On) ?
-		  TT_PRIM_LINE : TT_PRIM_QSPLINE;
-		cpfx = 0;
-		do {
-		    if(buf)
-		        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
-		    cpfx++;
-		    point++;
-		} while(point <= outline->contours[contour] &&
-			(outline->tags[point] & FT_Curve_Tag_On) ==
-			(outline->tags[point-1] & FT_Curve_Tag_On));
-		/* At the end of a contour Windows adds the start point, but
-		   only for Beziers */
-		if(point > outline->contours[contour] &&
-		   !(outline->tags[point-1] & FT_Curve_Tag_On)) {
-		    if(buf)
-		        FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
-		    cpfx++;
-		} else if(point <= outline->contours[contour] &&
-			  outline->tags[point] & FT_Curve_Tag_On) {
-		  /* add closing pt for bezier */
-		    if(buf)
-		        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
-		    cpfx++;
-		    point++;
-		}
-		if(buf) {
-		    ppc->wType = type;
-		    ppc->cpfx = cpfx;
-		}
-		needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
-	    }
-	    if(buf)
-	        pph->cb = needed - pph_start;
-	}
-	break;
+        if (!buf || !buflen)
+            return needed;
+        if (needed > buflen)
+            return GDI_ERROR;
+
+        get_native_glyph_outline(outline, buflen, buf);
+        break;
       }
     case GGO_BEZIER:
       {
-	/* Convert the quadratic Beziers to cubic Beziers.
-	   The parametric eqn for a cubic Bezier is, from PLRM:
-	   r(t) = at^3 + bt^2 + ct + r0
-	   with the control points:
-	   r1 = r0 + c/3
-	   r2 = r1 + (c + b)/3
-	   r3 = r0 + c + b + a
-
-	   A quadratic Bezier has the form:
-	   p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
-
-	   So equating powers of t leads to:
-	   r1 = 2/3 p1 + 1/3 p0
-	   r2 = 2/3 p1 + 1/3 p2
-	   and of course r0 = p0, r3 = p2
-	*/
-
-	int contour, point = 0, first_pt;
-	FT_Outline *outline = &ft_face->glyph->outline;
-	TTPOLYGONHEADER *pph;
-	TTPOLYCURVE *ppc;
-	DWORD pph_start, cpfx, type;
-	FT_Vector cubic_control[4];
-	if(buflen == 0) buf = NULL;
+        FT_Outline *outline = &ft_face->glyph->outline;
+        if(buflen == 0) buf = NULL;
 
-	if (needsTransform && buf) {
+        if (needsTransform && buf)
 		pFT_Outline_Transform(outline, &transMat);
-	}
 
-        for(contour = 0; contour < outline->n_contours; contour++) {
-	    pph_start = needed;
-	    pph = (TTPOLYGONHEADER *)((char *)buf + needed);
-	    first_pt = point;
-	    if(buf) {
-	        pph->dwType = TT_POLYGON_TYPE;
-		FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
-	    }
-	    needed += sizeof(*pph);
-	    point++;
-	    while(point <= outline->contours[contour]) {
-	        ppc = (TTPOLYCURVE *)((char *)buf + needed);
-		type = (outline->tags[point] & FT_Curve_Tag_On) ?
-		  TT_PRIM_LINE : TT_PRIM_CSPLINE;
-		cpfx = 0;
-		do {
-		    if(type == TT_PRIM_LINE) {
-		        if(buf)
-			    FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
-			cpfx++;
-			point++;
-		    } else {
-		      /* Unlike QSPLINEs, CSPLINEs always have their endpoint
-			 so cpfx = 3n */
-
-		      /* FIXME: Possible optimization in endpoint calculation
-			 if there are two consecutive curves */
-		        cubic_control[0] = outline->points[point-1];
-		        if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
-			    cubic_control[0].x += outline->points[point].x + 1;
-			    cubic_control[0].y += outline->points[point].y + 1;
-			    cubic_control[0].x >>= 1;
-			    cubic_control[0].y >>= 1;
-			}
-			if(point+1 > outline->contours[contour])
- 			    cubic_control[3] = outline->points[first_pt];
-			else {
-			    cubic_control[3] = outline->points[point+1];
-			    if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
-			        cubic_control[3].x += outline->points[point].x + 1;
-				cubic_control[3].y += outline->points[point].y + 1;
-				cubic_control[3].x >>= 1;
-				cubic_control[3].y >>= 1;
-			    }
-			}
-			/* r1 = 1/3 p0 + 2/3 p1
-			   r2 = 1/3 p2 + 2/3 p1 */
-		        cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
-			cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
-			cubic_control[2] = cubic_control[1];
-			cubic_control[1].x += (cubic_control[0].x + 1) / 3;
-			cubic_control[1].y += (cubic_control[0].y + 1) / 3;
-			cubic_control[2].x += (cubic_control[3].x + 1) / 3;
-			cubic_control[2].y += (cubic_control[3].y + 1) / 3;
-		        if(buf) {
-			    FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
-			    FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
-			    FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
-			}
-			cpfx += 3;
-			point++;
-		    }
-		} while(point <= outline->contours[contour] &&
-			(outline->tags[point] & FT_Curve_Tag_On) ==
-			(outline->tags[point-1] & FT_Curve_Tag_On));
-		/* At the end of a contour Windows adds the start point,
-		   but only for Beziers and we've already done that.
-		*/
-		if(point <= outline->contours[contour] &&
-		   outline->tags[point] & FT_Curve_Tag_On) {
-		  /* This is the closing pt of a bezier, but we've already
-		     added it, so just inc point and carry on */
-		    point++;
-		}
-		if(buf) {
-		    ppc->wType = type;
-		    ppc->cpfx = cpfx;
-		}
-		needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
-	    }
-	    if(buf)
-	        pph->cb = needed - pph_start;
-	}
-	break;
+        needed = get_bezier_glyph_outline(outline, buflen, NULL);
+
+        if (!buf || !buflen)
+            return needed;
+        if (needed > buflen)
+            return GDI_ERROR;
+
+        get_bezier_glyph_outline(outline, buflen, buf);
+        break;
       }
 
     default:
-- 
1.8.5.5




More information about the wine-patches mailing list