Commit 2862686996955651538bf9e4481b52d3ff8bad74

Werner Lemberg 2013-11-20T21:06:18

[truetype] Don't trust `maxp's `maxSizeOfInstructions'. Problem reported by Hin-Tak Leung <htl10@users.sourceforge.net>; 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'.

diff --git a/ChangeLog b/ChangeLog
index b358116..d58c429 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2013-11-20  Werner Lemberg  <wl@gnu.org>
+
+	[truetype] Don't trust `maxp's `maxSizeOfInstructions'.
+
+	Problem reported by Hin-Tak Leung <htl10@users.sourceforge.net>; 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  <wl@gnu.org>
 
 	[sfnt] Fix `OS/2' table version 5 support.
diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
index 46429ab..b1c2a2b 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 aaeae34..cc62f93 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 );
         }