diff --git a/ChangeLog b/ChangeLog index b358116f8..d58c429a4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2013-11-20 Werner Lemberg + + [truetype] Don't trust `maxp's `maxSizeOfInstructions'. + + Problem reported by Hin-Tak Leung ; see + + http://lists.nongnu.org/archive/html/freetype-devel/2013-08/msg00005.html + + for details. + + * src/base/ftobjs.c (FT_Load_Glyph): Check size of `fpgm' and `prep' + tables also for setting `autohint'. + + * src/truetype/ttgload.c (TT_Load_Simple_Glyph): Use code from + `TT_Process_Composite_Glyph' for handling unreliable values of + `maxSizeOfInstructions'. + 2013-11-16 Werner Lemberg [sfnt] Fix `OS/2' table version 5 support. diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c index 46429ab88..b1c2a2bf1 100644 --- a/src/base/ftobjs.c +++ b/src/base/ftobjs.c @@ -665,11 +665,18 @@ /* the check for `num_locations' assures that we actually */ /* test for instructions in a TTF and not in a CFF-based OTF */ + /* */ + /* since `maxSizeOfInstructions' might be unreliable, we */ + /* check the size of the `fpgm' and `prep' tables, too -- */ + /* the assumption is that there don't exist real TTFs where */ + /* both `fpgm' and `prep' tables are missing */ if ( mode == FT_RENDER_MODE_LIGHT || face->internal->ignore_unpatented_hinter || ( FT_IS_SFNT( face ) && ttface->num_locations && - ttface->max_profile.maxSizeOfInstructions == 0 ) ) + ttface->max_profile.maxSizeOfInstructions == 0 && + ttface->font_program_size == 0 && + ttface->cvt_program_size == 0 ) ) autohint = TRUE; } } diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c index aaeae34bb..cc62f93b7 100644 --- a/src/truetype/ttgload.c +++ b/src/truetype/ttgload.c @@ -349,8 +349,9 @@ FT_Int n_contours = load->n_contours; FT_Outline* outline; TT_Face face = (TT_Face)load->face; - FT_UShort n_ins; + FT_UShort n_ins, max_ins; FT_Int n_points; + FT_ULong tmp; FT_Byte *flag, *flag_limit; FT_Byte c, count; @@ -416,12 +417,29 @@ FT_TRACE5(( " Instructions size: %u\n", n_ins )); - if ( n_ins > face->max_profile.maxSizeOfInstructions ) + /* check it */ + max_ins = face->max_profile.maxSizeOfInstructions; + if ( n_ins > max_ins ) { - FT_TRACE0(( "TT_Load_Simple_Glyph: too many instructions (%d)\n", - n_ins )); - error = FT_THROW( Too_Many_Hints ); - goto Fail; + /* don't trust `maxSizeOfInstructions'; */ + /* only do a rough safety check */ + if ( (FT_Int)n_ins > load->byte_len ) + { + FT_TRACE1(( "TT_Load_Simple_Glyph:" + " too many instructions (%d) for glyph with length %d\n", + n_ins, load->byte_len )); + return FT_THROW( Too_Many_Hints ); + } + + tmp = load->exec->glyphSize; + error = Update_Max( load->exec->memory, + &tmp, + sizeof ( FT_Byte ), + (void*)&load->exec->glyphIns, + n_ins ); + load->exec->glyphSize = (FT_UShort)tmp; + if ( error ) + return error; } if ( ( limit - p ) < n_ins ) @@ -743,8 +761,8 @@ #ifdef TT_USE_BYTECODE_INTERPRETER if ( loader->glyph->control_len > 0xFFFFL ) { - FT_TRACE1(( "TT_Hint_Glyph: too long instructions " )); - FT_TRACE1(( "(0x%lx byte) is truncated\n", + FT_TRACE1(( "TT_Hint_Glyph: too long instructions" )); + FT_TRACE1(( " (0x%lx byte) is truncated\n", loader->glyph->control_len )); } n_ins = (FT_UInt)( loader->glyph->control_len ); @@ -1216,11 +1234,12 @@ max_ins = ((TT_Face)loader->face)->max_profile.maxSizeOfInstructions; if ( n_ins > max_ins ) { - /* acroread ignores this field, so we only do a rough safety check */ + /* don't trust `maxSizeOfInstructions'; */ + /* only do a rough safety check */ if ( (FT_Int)n_ins > loader->byte_len ) { - FT_TRACE1(( "TT_Process_Composite_Glyph: " - "too many instructions (%d) for glyph with length %d\n", + FT_TRACE1(( "TT_Process_Composite_Glyph:" + " too many instructions (%d) for glyph with length %d\n", n_ins, loader->byte_len )); return FT_THROW( Too_Many_Hints ); }