shithub: freetype+ttf2subf

Download patch

ref: e66d7300fec2f9fc60e43a924af1972b07ee316b
parent: 9b710cd56eb66c379686e82d7fe371c212aebc37
author: Werner Lemberg <[email protected]>
date: Wed May 31 12:16:50 EDT 2017

[cff] 32bit integer overflow run-time errors 2/2 (#46149).

This commit handles the new engine.

* include/freetype/internal/ftcalc.h (OVERFLOW_ADD_INT32,
OVERFLOW_SUB_INT32, OVERFLOW_MUL_INT32, NEG_INT, NEG_LONG,
NEG_INT32): New macros.

* src/cff/cf2ft.c (cf2_getScaleAndHintFlag): Use OVERFLOW_ADD_INT32.

* src/cff/cf2hints.c (cf2_getWindingMomentum, cf2_hint_init,
cf2_hintmap_map, cf2_glyphpath_hintPoint,
cf2_glyphpath_computeIntersection, cf2_glyphpath_computeOffset,
cf2_glyphpath_lineTo, cf2_glyphpath_curveTo): Use
OVERFLOW_ADD_INT32, OVERFLOW_SUB_INT32, OVERFLOW_MUL_INT32, and
NEG_INT32 where appropriate.

* src/cff/cf2intrp.c (cf2_doFlex, cf2_doBlend,
cf2_interpT2CharString): Ditto.
Also add some other code where needed to avoid overflow.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2017-05-31  Werner Lemberg  <[email protected]>
+
+	[cff] 32bit integer overflow run-time errors 2/2 (#46149).
+
+	This commit handles the new engine.
+
+	* include/freetype/internal/ftcalc.h (OVERFLOW_ADD_INT32,
+	OVERFLOW_SUB_INT32, OVERFLOW_MUL_INT32, NEG_INT, NEG_LONG,
+	NEG_INT32): New macros.
+
+	* src/cff/cf2ft.c (cf2_getScaleAndHintFlag): Use OVERFLOW_ADD_INT32.
+
+	* src/cff/cf2hints.c (cf2_getWindingMomentum, cf2_hint_init,
+	cf2_hintmap_map, cf2_glyphpath_hintPoint,
+	cf2_glyphpath_computeIntersection, cf2_glyphpath_computeOffset,
+	cf2_glyphpath_lineTo, cf2_glyphpath_curveTo): Use
+	OVERFLOW_ADD_INT32, OVERFLOW_SUB_INT32, OVERFLOW_MUL_INT32, and
+	NEG_INT32 where appropriate.
+
+	* src/cff/cf2intrp.c (cf2_doFlex, cf2_doBlend,
+	cf2_interpT2CharString): Ditto.
+	Also add some other code where needed to avoid overflow.
+
 2017-05-30  Werner Lemberg  <[email protected]>
 
 	[cff] 32bit integer overflow run-time errors 1/2 (#46149).
--- a/include/freetype/internal/ftcalc.h
+++ b/include/freetype/internal/ftcalc.h
@@ -423,6 +423,8 @@
           (FT_Int)( (FT_UInt)(a) - (FT_UInt)(b) )
 #define OVERFLOW_MUL_INT( a, b )                  \
           (FT_Int)( (FT_UInt)(a) * (FT_UInt)(b) )
+#define NEG_INT( a )                              \
+          (FT_Int)( -(FT_UInt)(a) )
 
 #define OVERFLOW_ADD_LONG( a, b )                    \
           (FT_Long)( (FT_ULong)(a) + (FT_ULong)(b) )
@@ -430,6 +432,17 @@
           (FT_Long)( (FT_ULong)(a) - (FT_ULong)(b) )
 #define OVERFLOW_MUL_LONG( a, b )                    \
           (FT_Long)( (FT_ULong)(a) * (FT_ULong)(b) )
+#define NEG_LONG( a )                                \
+          (FT_Long)( -(FT_ULong)(a) )
+
+#define OVERFLOW_ADD_INT32( a, b )                      \
+          (FT_Int32)( (FT_UInt32)(a) + (FT_UInt32)(b) )
+#define OVERFLOW_SUB_INT32( a, b )                      \
+          (FT_Int32)( (FT_UInt32)(a) - (FT_UInt32)(b) )
+#define OVERFLOW_MUL_INT32( a, b )                      \
+          (FT_Int32)( (FT_UInt32)(a) * (FT_UInt32)(b) )
+#define NEG_INT32( a )                                  \
+          (FT_Int32)( -(FT_UInt32)(a) )
 
 
 FT_END_HEADER
--- a/src/cff/cf2ft.c
+++ b/src/cff/cf2ft.c
@@ -267,8 +267,10 @@
 
     if ( *hinted )
     {
-      *x_scale = ( decoder->builder.glyph->x_scale + 32 ) / 64;
-      *y_scale = ( decoder->builder.glyph->y_scale + 32 ) / 64;
+      *x_scale = OVERFLOW_ADD_INT32( decoder->builder.glyph->x_scale,
+                                     32 ) / 64;
+      *y_scale = OVERFLOW_ADD_INT32( decoder->builder.glyph->y_scale,
+                                     32 ) / 64;
     }
     else
     {
--- a/src/cff/cf2hints.c
+++ b/src/cff/cf2hints.c
@@ -74,8 +74,8 @@
     /* cross product of pt1 position from origin with pt2 position from  */
     /* pt1; we reduce the precision so that the result fits into 32 bits */
 
-    return ( x1 >> 16 ) * ( ( y2 - y1 ) >> 16 ) -
-           ( y1 >> 16 ) * ( ( x2 - x1 ) >> 16 );
+    return ( x1 >> 16 ) * ( OVERFLOW_SUB_INT32( y2, y1 ) >> 16 ) -
+           ( y1 >> 16 ) * ( OVERFLOW_SUB_INT32( x2, x1 ) >> 16 );
   }
 
 
@@ -185,11 +185,11 @@
     /* darkening.  Bottoms are not changed; tops are incremented by twice */
     /* `darkenY'.                                                         */
     if ( cf2_hint_isTop( hint ) )
-      hint->csCoord += 2 * font->darkenY;
+      hint->csCoord = OVERFLOW_ADD_INT32( hint->csCoord, 2 * font->darkenY );
 
-    hint->csCoord += hintOrigin;
-    hint->scale    = scale;
-    hint->index    = indexStemHint;   /* index in original stem hint array */
+    hint->csCoord = OVERFLOW_ADD_INT32( hint->csCoord, hintOrigin );
+    hint->scale   = scale;
+    hint->index   = indexStemHint;   /* index in original stem hint array */
 
     /* if original stem hint has been used, use the same position */
     if ( hint->flags != 0 && stemHint->used )
@@ -314,6 +314,7 @@
       /* start linear search from last hit */
       CF2_UInt  i = hintmap->lastIndex;
 
+
       FT_ASSERT( hintmap->lastIndex < CF2_MAX_HINT_EDGES );
 
       /* search up */
@@ -330,9 +331,10 @@
       if ( i == 0 && csCoord < hintmap->edge[0].csCoord )
       {
         /* special case for points below first edge: use uniform scale */
-        return FT_MulFix( csCoord - hintmap->edge[0].csCoord,
-                          hintmap->scale ) +
-                 hintmap->edge[0].dsCoord;
+        return OVERFLOW_ADD_INT32(
+                 FT_MulFix( csCoord - hintmap->edge[0].csCoord,
+                            hintmap->scale ),
+                 hintmap->edge[0].dsCoord );
       }
       else
       {
@@ -340,9 +342,10 @@
          * Note: entries with duplicate csCoord are allowed.
          * Use edge[i], the highest entry where csCoord >= entry[i].csCoord
          */
-        return FT_MulFix( csCoord - hintmap->edge[i].csCoord,
-                          hintmap->edge[i].scale ) +
-                 hintmap->edge[i].dsCoord;
+        return OVERFLOW_ADD_INT32(
+                 FT_MulFix( csCoord - hintmap->edge[i].csCoord,
+                            hintmap->edge[i].scale ),
+                 hintmap->edge[i].dsCoord );
       }
     }
   }
@@ -781,7 +784,7 @@
                            cf2_arrstack_size( hStemHintArray ) +
                              cf2_arrstack_size( vStemHintArray ) );
       if ( !cf2_hintmask_isValid( hintMask ) )
-          return;                   /* too many stem hints */
+        return;                   /* too many stem hints */
     }
 
     /* begin by clearing the map */
@@ -797,7 +800,7 @@
 
     /* Defense-in-depth.  Should never return here. */
     if ( bitCount > hintMask->bitCount )
-        return;
+      return;
 
     /* synthetic embox hints get highest priority */
     if ( font->blues.doEmBoxHints )
@@ -1095,16 +1098,20 @@
     FT_Vector  pt;   /* hinted point in upright DS */
 
 
-    pt.x = FT_MulFix( glyphpath->scaleX, x ) +
-             FT_MulFix( glyphpath->scaleC, y );
+    pt.x = OVERFLOW_ADD_INT32( FT_MulFix( glyphpath->scaleX, x ),
+                               FT_MulFix( glyphpath->scaleC, y ) );
     pt.y = cf2_hintmap_map( hintmap, y );
 
-    ppt->x = FT_MulFix( glyphpath->font->outerTransform.a, pt.x )   +
-               FT_MulFix( glyphpath->font->outerTransform.c, pt.y ) +
-               glyphpath->fractionalTranslation.x;
-    ppt->y = FT_MulFix( glyphpath->font->outerTransform.b, pt.x )   +
-               FT_MulFix( glyphpath->font->outerTransform.d, pt.y ) +
-               glyphpath->fractionalTranslation.y;
+    ppt->x = OVERFLOW_ADD_INT32(
+               FT_MulFix( glyphpath->font->outerTransform.a, pt.x ),
+               OVERFLOW_ADD_INT32(
+                 FT_MulFix( glyphpath->font->outerTransform.c, pt.y ),
+                 glyphpath->fractionalTranslation.x ) );
+    ppt->y = OVERFLOW_ADD_INT32(
+               FT_MulFix( glyphpath->font->outerTransform.b, pt.x ),
+               OVERFLOW_ADD_INT32(
+                 FT_MulFix( glyphpath->font->outerTransform.d, pt.y ),
+                 glyphpath->fractionalTranslation.y ) );
   }
 
 
@@ -1154,12 +1161,12 @@
     CF2_Fixed  denominator, s;
 
 
-    u.x = CF2_CS_SCALE( u2->x - u1->x );
-    u.y = CF2_CS_SCALE( u2->y - u1->y );
-    v.x = CF2_CS_SCALE( v2->x - v1->x );
-    v.y = CF2_CS_SCALE( v2->y - v1->y );
-    w.x = CF2_CS_SCALE( v1->x - u1->x );
-    w.y = CF2_CS_SCALE( v1->y - u1->y );
+    u.x = CF2_CS_SCALE( OVERFLOW_SUB_INT32( u2->x, u1->x ) );
+    u.y = CF2_CS_SCALE( OVERFLOW_SUB_INT32( u2->y, u1->y ) );
+    v.x = CF2_CS_SCALE( OVERFLOW_SUB_INT32( v2->x, v1->x ) );
+    v.y = CF2_CS_SCALE( OVERFLOW_SUB_INT32( v2->y, v1->y ) );
+    w.x = CF2_CS_SCALE( OVERFLOW_SUB_INT32( v1->x, u1->x ) );
+    w.y = CF2_CS_SCALE( OVERFLOW_SUB_INT32( v1->y, u1->y ) );
 
     denominator = cf2_perp( u, v );
 
@@ -1168,9 +1175,14 @@
 
     s = FT_DivFix( cf2_perp( w, v ), denominator );
 
-    intersection->x = u1->x + FT_MulFix( s, u2->x - u1->x );
-    intersection->y = u1->y + FT_MulFix( s, u2->y - u1->y );
+    intersection->x = OVERFLOW_ADD_INT32(
+                        u1->x,
+                        FT_MulFix( s, OVERFLOW_SUB_INT32( u2->x, u1->x ) ) );
+    intersection->y = OVERFLOW_ADD_INT32(
+                        u1->y,
+                        FT_MulFix( s, OVERFLOW_SUB_INT32( u2->y, u1->y ) ) );
 
+
     /*
      * Special case snapping for horizontal and vertical lines.
      * This cleans up intersections and reduces problems with winding
@@ -1180,25 +1192,35 @@
      *
      */
 
-    if ( u1->x == u2->x                                                     &&
-         cf2_fixedAbs( intersection->x - u1->x ) < glyphpath->snapThreshold )
+    if ( u1->x == u2->x                                       &&
+         cf2_fixedAbs( OVERFLOW_SUB_INT32(
+                         intersection->x,
+                         u1->x ) ) < glyphpath->snapThreshold )
       intersection->x = u1->x;
-    if ( u1->y == u2->y                                                     &&
-         cf2_fixedAbs( intersection->y - u1->y ) < glyphpath->snapThreshold )
+    if ( u1->y == u2->y                                       &&
+         cf2_fixedAbs( OVERFLOW_SUB_INT32(
+                         intersection->y,
+                         u1->y ) ) < glyphpath->snapThreshold )
       intersection->y = u1->y;
 
-    if ( v1->x == v2->x                                                     &&
-         cf2_fixedAbs( intersection->x - v1->x ) < glyphpath->snapThreshold )
+    if ( v1->x == v2->x                                       &&
+         cf2_fixedAbs( OVERFLOW_SUB_INT32(
+                         intersection->x,
+                         v1->x ) ) < glyphpath->snapThreshold )
       intersection->x = v1->x;
-    if ( v1->y == v2->y                                                     &&
-         cf2_fixedAbs( intersection->y - v1->y ) < glyphpath->snapThreshold )
+    if ( v1->y == v2->y                                       &&
+         cf2_fixedAbs( OVERFLOW_SUB_INT32(
+                         intersection->y,
+                         v1->y ) ) < glyphpath->snapThreshold )
       intersection->y = v1->y;
 
     /* limit the intersection distance from midpoint of u2 and v1 */
-    if ( cf2_fixedAbs( intersection->x - ( u2->x + v1->x ) / 2 ) >
-           glyphpath->miterLimit                                   ||
-         cf2_fixedAbs( intersection->y - ( u2->y + v1->y ) / 2 ) >
-           glyphpath->miterLimit                                   )
+    if ( cf2_fixedAbs( intersection->x -
+                       OVERFLOW_ADD_INT32( u2->x, v1->x ) / 2 ) >
+           glyphpath->miterLimit                                  ||
+         cf2_fixedAbs( intersection->y -
+                       OVERFLOW_ADD_INT32( u2->y, v1->y ) / 2 ) >
+           glyphpath->miterLimit                                  )
       return FALSE;
 
     return TRUE;
@@ -1446,8 +1468,8 @@
                                CF2_Fixed*     x,
                                CF2_Fixed*     y )
   {
-    CF2_Fixed  dx = x2 - x1;
-    CF2_Fixed  dy = y2 - y1;
+    CF2_Fixed  dx = OVERFLOW_SUB_INT32( x2, x1 );
+    CF2_Fixed  dy = OVERFLOW_SUB_INT32( y2, y1 );
 
 
     /* note: negative offsets don't work here; negate deltas to change */
@@ -1454,8 +1476,8 @@
     /* quadrants, below                                                */
     if ( glyphpath->font->reverseWinding )
     {
-      dx = -dx;
-      dy = -dy;
+      dx = NEG_INT32( dx );
+      dy = NEG_INT32( dy );
     }
 
     *x = *y = 0;
@@ -1474,13 +1496,13 @@
       {
         /* first quadrant, +x +y */
 
-        if ( dx > 2 * dy )
+        if ( dx > OVERFLOW_MUL_INT32( 2, dy ) )
         {
           /* +x */
           *x = 0;
           *y = 0;
         }
-        else if ( dy > 2 * dx )
+        else if ( dy > OVERFLOW_MUL_INT32( 2, dx ) )
         {
           /* +y */
           *x = glyphpath->xOffset;
@@ -1499,16 +1521,16 @@
       {
         /* fourth quadrant, +x -y */
 
-        if ( dx > -2 * dy )
+        if ( dx > OVERFLOW_MUL_INT32( -2, dy ) )
         {
           /* +x */
           *x = 0;
           *y = 0;
         }
-        else if ( -dy > 2 * dx )
+        else if ( NEG_INT32( dy ) > OVERFLOW_MUL_INT32( 2, dx ) )
         {
           /* -y */
-          *x = -glyphpath->xOffset;
+          *x = NEG_INT32( glyphpath->xOffset );
           *y = glyphpath->yOffset;
         }
         else
@@ -1527,13 +1549,13 @@
       {
         /* second quadrant, -x +y */
 
-        if ( -dx > 2 * dy )
+        if ( NEG_INT32( dx ) > OVERFLOW_MUL_INT32( 2, dy ) )
         {
           /* -x */
           *x = 0;
-          *y = 2 * glyphpath->yOffset;
+          *y = OVERFLOW_MUL_INT32( 2, glyphpath->yOffset );
         }
-        else if ( dy > -2 * dx )
+        else if ( dy > OVERFLOW_MUL_INT32( -2, dx ) )
         {
           /* +y */
           *x = glyphpath->xOffset;
@@ -1552,16 +1574,16 @@
       {
         /* third quadrant, -x -y */
 
-        if ( -dx > -2 * dy )
+        if ( NEG_INT32( dx ) > OVERFLOW_MUL_INT32( -2, dy ) )
         {
           /* -x */
           *x = 0;
-          *y = 2 * glyphpath->yOffset;
+          *y = OVERFLOW_MUL_INT32( 2, glyphpath->yOffset );
         }
-        else if ( -dy > -2 * dx )
+        else if ( NEG_INT32( dy ) > OVERFLOW_MUL_INT32( -2, dx ) )
         {
           /* -y */
-          *x = -glyphpath->xOffset;
+          *x = NEG_INT32( glyphpath->xOffset );
           *y = glyphpath->yOffset;
         }
         else
@@ -1675,10 +1697,10 @@
                                  &yOffset );
 
     /* construct offset points */
-    P0.x = glyphpath->currentCS.x + xOffset;
-    P0.y = glyphpath->currentCS.y + yOffset;
-    P1.x = x + xOffset;
-    P1.y = y + yOffset;
+    P0.x = OVERFLOW_ADD_INT32( glyphpath->currentCS.x, xOffset );
+    P0.y = OVERFLOW_ADD_INT32( glyphpath->currentCS.y, yOffset );
+    P1.x = OVERFLOW_ADD_INT32( x, xOffset );
+    P1.y = OVERFLOW_ADD_INT32( y, yOffset );
 
     if ( glyphpath->moveIsPending )
     {
@@ -1757,15 +1779,15 @@
       cf2_getWindingMomentum( x1, y1, x2, y2 );
 
     /* construct offset points */
-    P0.x = glyphpath->currentCS.x + xOffset1;
-    P0.y = glyphpath->currentCS.y + yOffset1;
-    P1.x = x1 + xOffset1;
-    P1.y = y1 + yOffset1;
+    P0.x = OVERFLOW_ADD_INT32( glyphpath->currentCS.x, xOffset1 );
+    P0.y = OVERFLOW_ADD_INT32( glyphpath->currentCS.y, yOffset1 );
+    P1.x = OVERFLOW_ADD_INT32( x1, xOffset1 );
+    P1.y = OVERFLOW_ADD_INT32( y1, yOffset1 );
     /* note: preserve angle of final segment by using offset3 at both ends */
-    P2.x = x2 + xOffset3;
-    P2.y = y2 + yOffset3;
-    P3.x = x3 + xOffset3;
-    P3.y = y3 + yOffset3;
+    P2.x = OVERFLOW_ADD_INT32( x2, xOffset3 );
+    P2.y = OVERFLOW_ADD_INT32( y2, yOffset3 );
+    P3.x = OVERFLOW_ADD_INT32( x3, xOffset3 );
+    P3.y = OVERFLOW_ADD_INT32( y3, yOffset3 );
 
     if ( glyphpath->moveIsPending )
     {
--- a/src/cff/cf2intrp.c
+++ b/src/cff/cf2intrp.c
@@ -348,7 +348,9 @@
     {
       vals[i + 2] = vals[i];
       if ( readFromStack[i] )
-        vals[i + 2] += cf2_stack_getReal( opStack, idx++ );
+        vals[i + 2] = OVERFLOW_ADD_INT32( vals[i + 2],
+                                          cf2_stack_getReal( opStack,
+                                                             idx++ ) );
     }
 
     if ( isHFlex )
@@ -363,24 +365,26 @@
 
       if ( lastIsX )
       {
-        vals[12] = vals[10] + lastVal;
+        vals[12] = OVERFLOW_ADD_INT32( vals[10], lastVal );
         vals[13] = *curY;
       }
       else
       {
         vals[12] = *curX;
-        vals[13] = vals[11] + lastVal;
+        vals[13] = OVERFLOW_ADD_INT32( vals[11], lastVal );
       }
     }
     else
     {
       if ( readFromStack[10] )
-        vals[12] = vals[10] + cf2_stack_getReal( opStack, idx++ );
+        vals[12] = OVERFLOW_ADD_INT32( vals[10],
+                                       cf2_stack_getReal( opStack, idx++ ) );
       else
         vals[12] = *curX;
 
       if ( readFromStack[11] )
-        vals[13] = vals[11] + cf2_stack_getReal( opStack, idx );
+        vals[13] = OVERFLOW_ADD_INT32( vals[11],
+                                       cf2_stack_getReal( opStack, idx ) );
       else
         vals[13] = *curY;
     }
@@ -426,7 +430,10 @@
 
 
       for ( j = 1; j < blend->lenBV; j++ )
-        sum += FT_MulFix( *weight++, cf2_stack_getReal( opStack, delta++ ) );
+        sum = OVERFLOW_ADD_INT32(
+                sum,
+                FT_MulFix( *weight++,
+                           cf2_stack_getReal( opStack, delta++ ) ) );
 
       /* store blended result  */
       cf2_stack_setReal( opStack, i + base, sum );
@@ -767,7 +774,7 @@
         if ( font->decoder->width_only )
           goto exit;
 
-        curY += cf2_stack_popFixed( opStack );
+        curY = OVERFLOW_ADD_INT32( curY, cf2_stack_popFixed( opStack ) );
 
         cf2_glyphpath_moveTo( &glyphPath, curX, curY );
 
@@ -783,8 +790,12 @@
 
           for ( idx = 0; idx < count; idx += 2 )
           {
-            curX += cf2_stack_getReal( opStack, idx + 0 );
-            curY += cf2_stack_getReal( opStack, idx + 1 );
+            curX = OVERFLOW_ADD_INT32( curX,
+                                       cf2_stack_getReal( opStack,
+                                                          idx + 0 ) );
+            curY = OVERFLOW_ADD_INT32( curY,
+                                       cf2_stack_getReal( opStack,
+                                                          idx + 1 ) );
 
             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
           }
@@ -810,9 +821,9 @@
 
 
             if ( isX )
-              curX += v;
+              curX = OVERFLOW_ADD_INT32( curX, v );
             else
-              curY += v;
+              curY = OVERFLOW_ADD_INT32( curY, v );
 
             isX = !isX;
 
@@ -835,14 +846,22 @@
 
           while ( idx + 6 <= count )
           {
-            CF2_Fixed  x1 = cf2_stack_getReal( opStack, idx + 0 ) + curX;
-            CF2_Fixed  y1 = cf2_stack_getReal( opStack, idx + 1 ) + curY;
-            CF2_Fixed  x2 = cf2_stack_getReal( opStack, idx + 2 ) + x1;
-            CF2_Fixed  y2 = cf2_stack_getReal( opStack, idx + 3 ) + y1;
-            CF2_Fixed  x3 = cf2_stack_getReal( opStack, idx + 4 ) + x2;
-            CF2_Fixed  y3 = cf2_stack_getReal( opStack, idx + 5 ) + y2;
+            CF2_Fixed  x1, y1, x2, y2, x3, y3;
 
 
+            x1 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ),
+                                     curX );
+            y1 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ),
+                                     curY );
+            x2 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ),
+                                     x1 );
+            y2 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ),
+                                     y1 );
+            x3 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ),
+                                     x2 );
+            y3 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 5 ),
+                                     y2 );
+
             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
 
             curX  = x3;
@@ -852,8 +871,12 @@
 
           if ( op1 == cf2_cmdRCURVELINE )
           {
-            curX += cf2_stack_getReal( opStack, idx + 0 );
-            curY += cf2_stack_getReal( opStack, idx + 1 );
+            curX = OVERFLOW_ADD_INT32( curX,
+                                       cf2_stack_getReal( opStack,
+                                                          idx + 0 ) );
+            curY = OVERFLOW_ADD_INT32( curY,
+                                       cf2_stack_getReal( opStack,
+                                                          idx + 1 ) );
 
             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
           }
@@ -1129,7 +1152,10 @@
 
                     arg = cf2_stack_popFixed( opStack );
 
-                    cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
+                    if ( arg < -CF2_FIXED_MAX )
+                      cf2_stack_pushFixed( opStack, CF2_FIXED_MAX );
+                    else
+                      cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
                   }
                   continue; /* do not clear the stack */
 
@@ -1144,7 +1170,9 @@
                     summand2 = cf2_stack_popFixed( opStack );
                     summand1 = cf2_stack_popFixed( opStack );
 
-                    cf2_stack_pushFixed( opStack, summand1 + summand2 );
+                    cf2_stack_pushFixed( opStack,
+                                         OVERFLOW_ADD_INT32( summand1,
+                                                             summand2 ) );
                   }
                   continue; /* do not clear the stack */
 
@@ -1159,7 +1187,9 @@
                     subtrahend = cf2_stack_popFixed( opStack );
                     minuend    = cf2_stack_popFixed( opStack );
 
-                    cf2_stack_pushFixed( opStack, minuend - subtrahend );
+                    cf2_stack_pushFixed( opStack,
+                                         OVERFLOW_SUB_INT32( minuend,
+                                                             subtrahend ) );
                   }
                   continue; /* do not clear the stack */
 
@@ -1174,7 +1204,8 @@
                     divisor  = cf2_stack_popFixed( opStack );
                     dividend = cf2_stack_popFixed( opStack );
 
-                    cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) );
+                    cf2_stack_pushFixed( opStack,
+                                         FT_DivFix( dividend, divisor ) );
                   }
                   continue; /* do not clear the stack */
 
@@ -1187,7 +1218,10 @@
 
                     arg = cf2_stack_popFixed( opStack );
 
-                    cf2_stack_pushFixed( opStack, -arg );
+                    if ( arg < -CF2_FIXED_MAX )
+                      cf2_stack_pushFixed( opStack, CF2_FIXED_MAX );
+                    else
+                      cf2_stack_pushFixed( opStack, -arg );
                   }
                   continue; /* do not clear the stack */
 
@@ -1257,7 +1291,8 @@
                     arg2  = cf2_stack_popFixed( opStack );
                     arg1  = cf2_stack_popFixed( opStack );
 
-                    cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 );
+                    cf2_stack_pushFixed( opStack,
+                                         cond1 <= cond2 ? arg1 : arg2 );
                   }
                   continue; /* do not clear the stack */
 
@@ -1291,7 +1326,8 @@
                     factor2 = cf2_stack_popFixed( opStack );
                     factor1 = cf2_stack_popFixed( opStack );
 
-                    cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) );
+                    cf2_stack_pushFixed( opStack,
+                                         FT_MulFix( factor1, factor2 ) );
                   }
                   continue; /* do not clear the stack */
 
@@ -1305,7 +1341,9 @@
                     arg = cf2_stack_popFixed( opStack );
                     if ( arg > 0 )
                     {
-                      FT_Fixed  root = arg;
+                      /* use a start value that doesn't make */
+                      /* the algorithm's addition overflow   */
+                      FT_Fixed  root = arg < 10 ? arg : arg >> 1;
                       FT_Fixed  new_root;
 
 
@@ -1369,7 +1407,8 @@
 
                     if ( size > 0 )
                     {
-                      /* for `cf2_stack_getReal', index 0 is bottom of stack */
+                      /* for `cf2_stack_getReal',   */
+                      /* index 0 is bottom of stack */
                       CF2_UInt  gr_idx;
 
 
@@ -1381,7 +1420,8 @@
                         gr_idx = size - 1 - (CF2_UInt)idx;
 
                       cf2_stack_pushFixed( opStack,
-                                           cf2_stack_getReal( opStack, gr_idx ) );
+                                           cf2_stack_getReal( opStack,
+                                                              gr_idx ) );
                     }
                   }
                   continue; /* do not clear the stack */
@@ -1416,7 +1456,8 @@
              cf2_stack_count( opStack ) == 5 )
         {
           if ( !haveWidth )
-            *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
+            *width = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, 0 ),
+                                         nominalWidthX );
         }
 
         /* width is defined or default after this */
@@ -1564,7 +1605,8 @@
         FT_TRACE4(( " rmoveto\n" ));
 
         if ( cf2_stack_count( opStack ) > 2 && !haveWidth )
-          *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
+          *width = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, 0 ),
+                                       nominalWidthX );
 
         /* width is defined or default after this */
         haveWidth = TRUE;
@@ -1583,7 +1625,8 @@
         FT_TRACE4(( " hmoveto\n" ));
 
         if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
-          *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
+          *width = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, 0 ),
+                                       nominalWidthX );
 
         /* width is defined or default after this */
         haveWidth = TRUE;
@@ -1591,7 +1634,7 @@
         if ( font->decoder->width_only )
           goto exit;
 
-        curX += cf2_stack_popFixed( opStack );
+        curX = OVERFLOW_ADD_INT32( curX, cf2_stack_popFixed( opStack ) );
 
         cf2_glyphpath_moveTo( &glyphPath, curX, curY );
 
@@ -1607,8 +1650,12 @@
 
           while ( idx + 6 < count )
           {
-            curX += cf2_stack_getReal( opStack, idx + 0 );
-            curY += cf2_stack_getReal( opStack, idx + 1 );
+            curX = OVERFLOW_ADD_INT32( curX,
+                                       cf2_stack_getReal( opStack,
+                                                          idx + 0 ) );
+            curY = OVERFLOW_ADD_INT32( curY,
+                                       cf2_stack_getReal( opStack,
+                                                          idx + 1 ) );
 
             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
             idx += 2;
@@ -1616,14 +1663,28 @@
 
           while ( idx < count )
           {
-            CF2_Fixed  x1 = cf2_stack_getReal( opStack, idx + 0 ) + curX;
-            CF2_Fixed  y1 = cf2_stack_getReal( opStack, idx + 1 ) + curY;
-            CF2_Fixed  x2 = cf2_stack_getReal( opStack, idx + 2 ) + x1;
-            CF2_Fixed  y2 = cf2_stack_getReal( opStack, idx + 3 ) + y1;
-            CF2_Fixed  x3 = cf2_stack_getReal( opStack, idx + 4 ) + x2;
-            CF2_Fixed  y3 = cf2_stack_getReal( opStack, idx + 5 ) + y2;
+            CF2_Fixed  x1, y1, x2, y2, x3, y3;
 
 
+            x1 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack,
+                                                        idx + 0 ),
+                                     curX );
+            y1 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack,
+                                                        idx + 1 ),
+                                     curY );
+            x2 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack,
+                                                        idx + 2 ),
+                                     x1 );
+            y2 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack,
+                                                        idx + 3 ),
+                                     y1 );
+            x3 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack,
+                                                        idx + 4 ),
+                                     x2 );
+            y3 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack,
+                                                        idx + 5 ),
+                                     y2 );
+
             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
 
             curX  = x3;
@@ -1656,7 +1717,8 @@
 
             if ( ( count - idx ) & 1 )
             {
-              x1 = cf2_stack_getReal( opStack, idx ) + curX;
+              x1 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx ),
+                                       curX );
 
               idx++;
             }
@@ -1663,11 +1725,15 @@
             else
               x1 = curX;
 
-            y1 = cf2_stack_getReal( opStack, idx + 0 ) + curY;
-            x2 = cf2_stack_getReal( opStack, idx + 1 ) + x1;
-            y2 = cf2_stack_getReal( opStack, idx + 2 ) + y1;
+            y1 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ),
+                                     curY );
+            x2 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ),
+                                     x1 );
+            y2 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ),
+                                     y1 );
             x3 = x2;
-            y3 = cf2_stack_getReal( opStack, idx + 3 ) + y2;
+            y3 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ),
+                                     y2 );
 
             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
 
@@ -1701,7 +1767,8 @@
 
             if ( ( count - idx ) & 1 )
             {
-              y1 = cf2_stack_getReal( opStack, idx ) + curY;
+              y1 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx ),
+                                       curY );
 
               idx++;
             }
@@ -1708,10 +1775,14 @@
             else
               y1 = curY;
 
-            x1 = cf2_stack_getReal( opStack, idx + 0 ) + curX;
-            x2 = cf2_stack_getReal( opStack, idx + 1 ) + x1;
-            y2 = cf2_stack_getReal( opStack, idx + 2 ) + y1;
-            x3 = cf2_stack_getReal( opStack, idx + 3 ) + x2;
+            x1 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ),
+                                     curX );
+            x2 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ),
+                                     x1 );
+            y2 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ),
+                                     y1 );
+            x3 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ),
+                                     x2 );
             y3 = y2;
 
             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
@@ -1750,15 +1821,21 @@
 
             if ( alternate )
             {
-              x1 = cf2_stack_getReal( opStack, idx + 0 ) + curX;
+              x1 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ),
+                                       curX );
               y1 = curY;
-              x2 = cf2_stack_getReal( opStack, idx + 1 ) + x1;
-              y2 = cf2_stack_getReal( opStack, idx + 2 ) + y1;
-              y3 = cf2_stack_getReal( opStack, idx + 3 ) + y2;
+              x2 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ),
+                                       x1 );
+              y2 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ),
+                                       y1 );
+              y3 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ),
+                                       y2 );
 
               if ( count - idx == 5 )
               {
-                x3 = cf2_stack_getReal( opStack, idx + 4 ) + x2;
+                x3 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack,
+                                                            idx + 4 ),
+                                         x2 );
 
                 idx++;
               }
@@ -1770,14 +1847,20 @@
             else
             {
               x1 = curX;
-              y1 = cf2_stack_getReal( opStack, idx + 0 ) + curY;
-              x2 = cf2_stack_getReal( opStack, idx + 1 ) + x1;
-              y2 = cf2_stack_getReal( opStack, idx + 2 ) + y1;
-              x3 = cf2_stack_getReal( opStack, idx + 3 ) + x2;
+              y1 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ),
+                                       curY );
+              x2 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ),
+                                       x1 );
+              y2 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ),
+                                       y1 );
+              x3 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ),
+                                       x2 );
 
               if ( count - idx == 5 )
               {
-                y3 = cf2_stack_getReal( opStack, idx + 4 ) + y2;
+                y3 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack,
+                                                            idx + 4 ),
+                                         y2 );
 
                 idx++;
               }