From 2a7bb4596f566a34fd53932af0ef53b956459d25 Mon Sep 17 00:00:00 2001 From: Alexei Podtelezhnikov Date: Thu, 20 Jun 2024 20:49:56 -0400 Subject: [PATCH] Use unsigned point and contour indexing in `FT_Outline`. This doubles the number or allowed points, see https://github.com/harfbuzz/harfbuzz/issues/4752 Although it is hardly practical to use more than 32767 points, other font engines seem to support it. * docs/CHANGES: Announce it. * include/freetype/ftimage.h (FT_Outline): Do it and update limits. * src/*: Update `FT_Outline` users. --- docs/CHANGES | 12 ++++++++++-- include/freetype/ftimage.h | 16 ++++++++-------- include/freetype/internal/tttypes.h | 4 ++-- src/autofit/afhints.c | 10 +++++----- src/base/ftbbox.c | 2 +- src/base/ftoutln.c | 8 +++++--- src/base/ftstroke.c | 10 +++++----- src/pfr/pfrgload.c | 2 +- src/pshinter/pshalgo.c | 6 +++--- src/raster/ftraster.c | 2 +- src/sdf/ftsdf.c | 2 +- src/smooth/ftgrays.c | 2 +- src/truetype/ttgload.c | 29 ++++++++++++++--------------- src/truetype/ttinterp.c | 14 ++++++-------- src/truetype/ttobjs.c | 2 +- src/truetype/ttobjs.h | 2 +- 16 files changed, 65 insertions(+), 58 deletions(-) diff --git a/docs/CHANGES b/docs/CHANGES index fc18eb10a..4c98128f8 100644 --- a/docs/CHANGES +++ b/docs/CHANGES @@ -1,13 +1,21 @@ CHANGES BETWEEN 2.13.2 and 2.13.3 (2024-Mmm-DD) - I. IMPORTANT BUG FIXES + I. IMPORTANT CHANGES + + - Some fields in the `FT_Outline` structure have been changed + from signed to unsigned type, which better reflects the actual + usage. It is also an additional means to protect against + malformed input. + + + II. IMPORTANT BUG FIXES - Rare double-free crashes in the cache subsystem have been fixed. - Excessive stack allocation in the autohinter has been fixed. - II. MISCELLANEOUS + III. MISCELLANEOUS - The B/W rasterizer has received a major upkeep that resulted in large performance improvement. The rendering speed has increased diff --git a/include/freetype/ftimage.h b/include/freetype/ftimage.h index 7d4a99f38..6795a8ed0 100644 --- a/include/freetype/ftimage.h +++ b/include/freetype/ftimage.h @@ -345,14 +345,14 @@ FT_BEGIN_HEADER */ typedef struct FT_Outline_ { - short n_contours; /* number of contours in glyph */ - short n_points; /* number of points in the glyph */ + unsigned short n_contours; /* number of contours in glyph */ + unsigned short n_points; /* number of points in the glyph */ - FT_Vector* points; /* the outline's points */ - char* tags; /* the points flags */ - short* contours; /* the contour end points */ + FT_Vector* points; /* the outline's points */ + char* tags; /* the points flags */ + unsigned short* contours; /* the contour end points */ - int flags; /* outline masks */ + int flags; /* outline masks */ } FT_Outline; @@ -360,8 +360,8 @@ FT_BEGIN_HEADER /* Following limits must be consistent with */ /* FT_Outline.{n_contours,n_points} */ -#define FT_OUTLINE_CONTOURS_MAX SHRT_MAX -#define FT_OUTLINE_POINTS_MAX SHRT_MAX +#define FT_OUTLINE_CONTOURS_MAX USHRT_MAX +#define FT_OUTLINE_POINTS_MAX USHRT_MAX /************************************************************************** diff --git a/include/freetype/internal/tttypes.h b/include/freetype/internal/tttypes.h index 44a0165cc..7053e656a 100644 --- a/include/freetype/internal/tttypes.h +++ b/include/freetype/internal/tttypes.h @@ -1655,9 +1655,9 @@ FT_BEGIN_HEADER { FT_Memory memory; FT_UShort max_points; - FT_Short max_contours; + FT_UShort max_contours; FT_UShort n_points; /* number of points in zone */ - FT_Short n_contours; /* number of contours */ + FT_UShort n_contours; /* number of contours */ FT_Vector* org; /* original point coordinates */ FT_Vector* cur; /* current point coordinates */ diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c index 099a5f82a..6b48bc598 100644 --- a/src/autofit/afhints.c +++ b/src/autofit/afhints.c @@ -980,7 +980,7 @@ { FT_Vector* vec = outline->points; char* tag = outline->tags; - FT_Short endpoint = outline->contours[0]; + FT_UShort endpoint = outline->contours[0]; AF_Point end = points + endpoint; AF_Point prev = end; FT_Int contour_index = 0; @@ -1046,10 +1046,10 @@ /* set up the contours array */ { - AF_Point* contour = hints->contours; - AF_Point* contour_limit = contour + hints->num_contours; - short* end = outline->contours; - FT_Int idx = 0; + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + FT_UShort* end = outline->contours; + FT_Int idx = 0; for ( ; contour < contour_limit; contour++, end++ ) diff --git a/src/base/ftbbox.c b/src/base/ftbbox.c index e98c29fc7..d6aa5d56d 100644 --- a/src/base/ftbbox.c +++ b/src/base/ftbbox.c @@ -489,7 +489,7 @@ return FT_THROW( Invalid_Outline ); /* if outline is empty, return (0,0,0,0) */ - if ( outline->n_points == 0 || outline->n_contours <= 0 ) + if ( outline->n_points == 0 || outline->n_contours == 0 ) { abbox->xMin = abbox->xMax = 0; abbox->yMin = abbox->yMax = 0; diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c index c7564dbd3..dc242e3f8 100644 --- a/src/base/ftoutln.c +++ b/src/base/ftoutln.c @@ -332,8 +332,8 @@ FT_NEW_ARRAY( anoutline->contours, numContours ) ) goto Fail; - anoutline->n_points = (FT_Short)numPoints; - anoutline->n_contours = (FT_Short)numContours; + anoutline->n_points = (FT_UShort)numPoints; + anoutline->n_contours = (FT_UShort)numContours; anoutline->flags |= FT_OUTLINE_OWNER; return FT_Err_Ok; @@ -359,12 +359,14 @@ FT_Int n; + FT_TRACE5(( "FT_Outline_Check: contours = %d, points = %d\n", + n_contours, n_points )); /* empty glyph? */ if ( n_points == 0 && n_contours == 0 ) return FT_Err_Ok; /* check point and contour counts */ - if ( n_points <= 0 || n_contours <= 0 ) + if ( n_points == 0 || n_contours == 0 ) goto Bad; end0 = -1; diff --git a/src/base/ftstroke.c b/src/base/ftstroke.c index 443b48aaf..21fa0d425 100644 --- a/src/base/ftstroke.c +++ b/src/base/ftstroke.c @@ -727,10 +727,10 @@ /* copy contours */ { - FT_UInt count = border->num_points; - FT_Byte* tags = border->tags; - FT_Short* write = outline->contours + outline->n_contours; - FT_Short idx = (FT_Short)outline->n_points; + FT_UInt count = border->num_points; + FT_Byte* tags = border->tags; + FT_UShort* write = outline->contours + outline->n_contours; + FT_UShort idx = outline->n_points; for ( ; count > 0; count--, tags++, idx++ ) @@ -743,7 +743,7 @@ } } - outline->n_points += (short)border->num_points; + outline->n_points += (FT_UShort)border->num_points; FT_ASSERT( FT_Outline_Check( outline ) == 0 ); } diff --git a/src/pfr/pfrgload.c b/src/pfr/pfrgload.c index 8ad65ec9d..ec0a87893 100644 --- a/src/pfr/pfrgload.c +++ b/src/pfr/pfrgload.c @@ -108,7 +108,7 @@ /* don't add empty contours */ if ( last >= first ) - outline->contours[outline->n_contours++] = (short)last; + outline->contours[outline->n_contours++] = (FT_UShort)last; glyph->path_begun = 0; } diff --git a/src/pshinter/pshalgo.c b/src/pshinter/pshalgo.c index 2d7b9c227..18695936c 100644 --- a/src/pshinter/pshalgo.c +++ b/src/pshinter/pshalgo.c @@ -1171,8 +1171,8 @@ FT_QNEW_ARRAY( glyph->contours, outline->n_contours ) ) goto Exit; - glyph->num_points = (FT_UInt)outline->n_points; - glyph->num_contours = (FT_UInt)outline->n_contours; + glyph->num_points = outline->n_points; + glyph->num_contours = outline->n_contours; { FT_UInt first = 0, next, n; @@ -1186,7 +1186,7 @@ PSH_Point point; - next = (FT_UInt)outline->contours[n] + 1; + next = outline->contours[n] + 1; count = next - first; contour->start = points + first; diff --git a/src/raster/ftraster.c b/src/raster/ftraster.c index 51ad66b60..02c2d63ec 100644 --- a/src/raster/ftraster.c +++ b/src/raster/ftraster.c @@ -2683,7 +2683,7 @@ return FT_THROW( Invalid_Outline ); /* return immediately if the outline is empty */ - if ( outline->n_points == 0 || outline->n_contours <= 0 ) + if ( outline->n_points == 0 || outline->n_contours == 0 ) return Raster_Err_Ok; if ( !outline->contours || !outline->points ) diff --git a/src/sdf/ftsdf.c b/src/sdf/ftsdf.c index 4394001e2..dc55d4263 100644 --- a/src/sdf/ftsdf.c +++ b/src/sdf/ftsdf.c @@ -3837,7 +3837,7 @@ } /* if the outline is empty, return */ - if ( outline->n_points <= 0 || outline->n_contours <= 0 ) + if ( outline->n_points == 0 || outline->n_contours == 0 ) goto Exit; /* check whether the outline has valid fields */ diff --git a/src/smooth/ftgrays.c b/src/smooth/ftgrays.c index f011e9f8d..b7c0632a6 100644 --- a/src/smooth/ftgrays.c +++ b/src/smooth/ftgrays.c @@ -1981,7 +1981,7 @@ typedef ptrdiff_t FT_PtrDist; return FT_THROW( Invalid_Outline ); /* return immediately if the outline is empty */ - if ( outline->n_points == 0 || outline->n_contours <= 0 ) + if ( outline->n_points == 0 || outline->n_contours == 0 ) return Smooth_Err_Ok; if ( !outline->contours || !outline->points ) diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c index b7d8e1d66..e6806b0cb 100644 --- a/src/truetype/ttgload.c +++ b/src/truetype/ttgload.c @@ -353,7 +353,8 @@ FT_Byte c, count; FT_Vector *vec, *vec_limit; FT_Pos x, y; - FT_Short *cont, *cont_limit, last; + FT_UShort *cont, *cont_limit; + FT_Int last; /* check that we can add the contours to the glyph */ @@ -372,7 +373,7 @@ last = -1; for ( ; cont < cont_limit; cont++ ) { - *cont = FT_NEXT_SHORT( p ); + *cont = FT_NEXT_USHORT( p ); if ( *cont <= last ) goto Invalid_Outline; @@ -530,8 +531,8 @@ *flag = (FT_Byte)( f & ON_CURVE_POINT ); } - outline->n_points = (FT_Short)n_points; - outline->n_contours = (FT_Short)n_contours; + outline->n_points = (FT_UShort)n_points; + outline->n_contours = (FT_UShort)n_contours; load->cursor = p; @@ -752,10 +753,8 @@ FT_UInt start_point, FT_UInt start_contour ) { - zone->n_points = (FT_UShort)load->outline.n_points + 4 - - (FT_UShort)start_point; - zone->n_contours = load->outline.n_contours - - (FT_Short)start_contour; + zone->n_points = load->outline.n_points + 4 - (FT_UShort)start_point; + zone->n_contours = load->outline.n_contours - (FT_UShort)start_contour; zone->org = load->extra_points + start_point; zone->cur = load->outline.points + start_point; zone->orus = load->extra_points2 + start_point; @@ -1044,7 +1043,7 @@ current.points = gloader->base.outline.points + num_base_points; current.n_points = gloader->base.outline.n_points - - (short)num_base_points; + (FT_UShort)num_base_points; have_scale = FT_BOOL( subglyph->flags & ( WE_HAVE_A_SCALE | WE_HAVE_AN_XY_SCALE | @@ -1057,7 +1056,7 @@ /* get offset */ if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) ) { - FT_UInt num_points = (FT_UInt)gloader->base.outline.n_points; + FT_UInt num_points = gloader->base.outline.n_points; FT_UInt k = (FT_UInt)subglyph->arg1; FT_UInt l = (FT_UInt)subglyph->arg2; FT_Vector* p1; @@ -1719,8 +1718,8 @@ FT_List_Add( &loader->composites, node ); } - start_point = (FT_UInt)gloader->base.outline.n_points; - start_contour = (FT_UInt)gloader->base.outline.n_contours; + start_point = gloader->base.outline.n_points; + start_contour = gloader->base.outline.n_contours; /* for each subglyph, read composite header */ error = face->read_composite_glyph( loader ); @@ -1872,7 +1871,7 @@ linear_hadvance = loader->linear; linear_vadvance = loader->vadvance; - num_base_points = (FT_UInt)gloader->base.outline.n_points; + num_base_points = gloader->base.outline.n_points; error = load_truetype_glyph( loader, (FT_UInt)subglyph->index, @@ -1896,7 +1895,7 @@ loader->vadvance = linear_vadvance; } - num_points = (FT_UInt)gloader->base.outline.n_points; + num_points = gloader->base.outline.n_points; if ( num_points == num_base_points ) continue; @@ -2717,7 +2716,7 @@ size->metrics->y_ppem < 24 ) glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; - FT_TRACE1(( " subglyphs = %u, contours = %hd, points = %hd," + FT_TRACE1(( " subglyphs = %u, contours = %hu, points = %hu," " flags = 0x%.3x\n", loader.gloader->base.num_subglyphs, glyph->outline.n_contours, diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c index 0889c6151..951891dbf 100644 --- a/src/truetype/ttinterp.c +++ b/src/truetype/ttinterp.c @@ -5270,11 +5270,11 @@ FT_UShort refp; FT_F26Dot6 dx, dy; - FT_Short contour, bounds; + FT_UShort contour, bounds; FT_UShort start, limit, i; - contour = (FT_Short)args[0]; + contour = (FT_UShort)args[0]; bounds = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours; if ( BOUNDS( contour, bounds ) ) @@ -5290,15 +5290,13 @@ if ( contour == 0 ) start = 0; else - start = (FT_UShort)( exc->zp2.contours[contour - 1] + 1 - - exc->zp2.first_point ); + start = exc->zp2.contours[contour - 1] + 1 - exc->zp2.first_point; /* we use the number of points if in the twilight zone */ if ( exc->GS.gep2 == 0 ) limit = exc->zp2.n_points; else - limit = (FT_UShort)( exc->zp2.contours[contour] - - exc->zp2.first_point + 1 ); + limit = exc->zp2.contours[contour] + 1 - exc->zp2.first_point; for ( i = start; i < limit; i++ ) { @@ -5341,9 +5339,9 @@ /* Normal zone's `n_points' includes phantoms, so must */ /* use end of last contour. */ if ( exc->GS.gep2 == 0 ) - limit = (FT_UShort)exc->zp2.n_points; + limit = exc->zp2.n_points; else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 ) - limit = (FT_UShort)( exc->zp2.contours[exc->zp2.n_contours - 1] + 1 ); + limit = exc->zp2.contours[exc->zp2.n_contours - 1] + 1; else limit = 0; diff --git a/src/truetype/ttobjs.c b/src/truetype/ttobjs.c index 05489d732..08aee62a8 100644 --- a/src/truetype/ttobjs.c +++ b/src/truetype/ttobjs.c @@ -115,7 +115,7 @@ FT_LOCAL_DEF( FT_Error ) tt_glyphzone_new( FT_Memory memory, FT_UShort maxPoints, - FT_Short maxContours, + FT_UShort maxContours, TT_GlyphZone zone ) { FT_Error error; diff --git a/src/truetype/ttobjs.h b/src/truetype/ttobjs.h index 0a63e6729..9c36ca783 100644 --- a/src/truetype/ttobjs.h +++ b/src/truetype/ttobjs.h @@ -105,7 +105,7 @@ FT_BEGIN_HEADER FT_LOCAL( FT_Error ) tt_glyphzone_new( FT_Memory memory, FT_UShort maxPoints, - FT_Short maxContours, + FT_UShort maxContours, TT_GlyphZone zone ); #endif /* TT_USE_BYTECODE_INTERPRETER */