diff --git a/ChangeLog b/ChangeLog index dc3f7f5c9..c38b5af66 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2017-05-31 Werner Lemberg + + [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 [cff] 32bit integer overflow run-time errors 1/2 (#46149). diff --git a/include/freetype/internal/ftcalc.h b/include/freetype/internal/ftcalc.h index 1cd32c892..2b040feea 100644 --- a/include/freetype/internal/ftcalc.h +++ b/include/freetype/internal/ftcalc.h @@ -423,6 +423,8 @@ FT_BEGIN_HEADER (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_BEGIN_HEADER (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 diff --git a/src/cff/cf2ft.c b/src/cff/cf2ft.c index eb8472f11..3bc007b9b 100644 --- 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 { diff --git a/src/cff/cf2hints.c b/src/cff/cf2hints.c index a6fcef44d..5efb180dc 100644 --- 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,8 +1175,13 @@ 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. @@ -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,16 +1468,16 @@ 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 */ /* 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 ) { diff --git a/src/cff/cf2intrp.c b/src/cff/cf2intrp.c index 40bd9059a..8f0785d59 100644 --- 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,18 +1717,23 @@ if ( ( count - idx ) & 1 ) { - x1 = cf2_stack_getReal( opStack, idx ) + curX; + x1 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx ), + curX ); idx++; } 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,17 +1767,22 @@ if ( ( count - idx ) & 1 ) { - y1 = cf2_stack_getReal( opStack, idx ) + curY; + y1 = OVERFLOW_ADD_INT32( cf2_stack_getReal( opStack, idx ), + curY ); idx++; } 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++; }