Commit 441b3f389856805ee692dd08849976460ad309e9

Werner Lemberg 2014-07-13T02:28:14

[truetype] Improve handling of buggy `prep' tables. In case of an error in the `prep' table, no longer try to execute it again and again. This makes FreeType handle endless loops in buggy fonts much faster. * src/truetype/ttobjs.h (TT_SizeRec): The fields `bytecode_ready' and `cvt_ready' are now negative if not initialized yet, otherwise they indicate the error code of the last run. * src/truetype/ttobjs.c (tt_size_run_fpgm, tt_size_run_prep, tt_size_done_bytecode, tt_size_init_bytecode, tt_size_ready_bytecode, tt_size_init, tt_size_done, tt_size_reset): Updated. * src/truetype/ttgload.c (tt_loader_init): Updated. * src/truetype/ttinterp.c (TT_RunIns): Force reexecution of `fpgm' and `prep' only if we are in the `glyf' table.

diff --git a/ChangeLog b/ChangeLog
index c832cff..f2b3e2b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2014-07-13  Werner Lemberg  <wl@gnu.org>
+
+	[truetype] Improve handling of buggy `prep' tables.
+
+	In case of an error in the `prep' table, no longer try to execute it
+	again and again.  This makes FreeType handle endless loops in buggy
+	fonts much faster.
+
+	* src/truetype/ttobjs.h (TT_SizeRec): The fields `bytecode_ready'
+	and `cvt_ready' are now negative if not initialized yet, otherwise
+	they indicate the error code of the last run.
+
+	* src/truetype/ttobjs.c (tt_size_run_fpgm, tt_size_run_prep,
+	tt_size_done_bytecode, tt_size_init_bytecode,
+	tt_size_ready_bytecode, tt_size_init, tt_size_done, tt_size_reset):
+	Updated.
+
+	* src/truetype/ttgload.c (tt_loader_init): Updated.
+	* src/truetype/ttinterp.c (TT_RunIns): Force reexecution of `fpgm'
+	and `prep' only if we are in the `glyf' table.
+
 2014-07-12  Werner Lemberg  <wl@gnu.org>
 
 	* builds/vms/ftconfig.h: Synchronize.
diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c
index 02298e3..ff2b339 100644
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -2120,7 +2120,7 @@
       FT_Bool  reexecute = FALSE;
 
 
-      if ( !size->cvt_ready )
+      if ( size->bytecode_ready < 0 || size->cvt_ready < 0 )
       {
         FT_Error  error = tt_size_ready_bytecode( size, pedantic );
 
@@ -2128,6 +2128,10 @@
         if ( error )
           return error;
       }
+      else if ( size->bytecode_ready )
+        return size->bytecode_ready;
+      else if ( size->cvt_ready )
+        return size->cvt_ready;
 
       /* query new execution context */
       exec = size->debug ? size->context
@@ -2238,12 +2242,15 @@
 
       if ( reexecute )
       {
-        FT_UInt  i;
+        FT_UInt   i;
+        FT_Error  error;
 
 
         for ( i = 0; i < size->cvt_size; i++ )
           size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale );
-        tt_size_run_prep( size, pedantic );
+        error = tt_size_run_prep( size, pedantic );
+        if ( error )
+          return error;
       }
 
       /* see whether the cvt program has disabled hinting */
diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c
index f71d306..9491533 100644
--- a/src/truetype/ttinterp.c
+++ b/src/truetype/ttinterp.c
@@ -9035,10 +9035,13 @@
     /* If any errors have occurred, function tables may be broken. */
     /* Force a re-execution of `prep' and `fpgm' tables if no      */
     /* bytecode debugger is run.                                   */
-    if ( CUR.error && !CUR.instruction_trap )
+    if ( CUR.error
+         && !CUR.instruction_trap
+         && CUR.curRange == tt_coderange_glyph )
     {
       FT_TRACE1(( "  The interpreter returned error 0x%x\n", CUR.error ));
-      exc->size->cvt_ready      = FALSE;
+      exc->size->bytecode_ready = -1;
+      exc->size->cvt_ready      = -1;
     }
 
     return CUR.error;
diff --git a/src/truetype/ttobjs.c b/src/truetype/ttobjs.c
index 4adba58..05a121c 100644
--- a/src/truetype/ttobjs.c
+++ b/src/truetype/ttobjs.c
@@ -813,6 +813,8 @@
     else
       error = FT_Err_Ok;
 
+    size->bytecode_ready = error;
+
     if ( !error )
       TT_Save_Context( exec, size );
 
@@ -884,6 +886,8 @@
     else
       error = FT_Err_Ok;
 
+    size->cvt_ready = error;
+
     /* UNDOCUMENTED!  The MS rasterizer doesn't allow the following */
     /* graphics state variables to be modified by the CVT program.  */
 
@@ -912,10 +916,6 @@
     return error;
   }
 
-#endif /* TT_USE_BYTECODE_INTERPRETER */
-
-
-#ifdef TT_USE_BYTECODE_INTERPRETER
 
   static void
   tt_size_done_bytecode( FT_Size  ftsize )
@@ -953,8 +953,8 @@
     size->max_func = 0;
     size->max_ins  = 0;
 
-    size->bytecode_ready = 0;
-    size->cvt_ready      = 0;
+    size->bytecode_ready = -1;
+    size->cvt_ready      = -1;
   }
 
 
@@ -974,8 +974,8 @@
     TT_MaxProfile*  maxp = &face->max_profile;
 
 
-    size->bytecode_ready = 1;
-    size->cvt_ready      = 0;
+    size->bytecode_ready = -1;
+    size->cvt_ready      = -1;
 
     size->max_function_defs    = maxp->maxFunctionDefs;
     size->max_instruction_defs = maxp->maxInstructionDefs;
@@ -1052,15 +1052,14 @@
     FT_Error  error = FT_Err_Ok;
 
 
-    if ( !size->bytecode_ready )
-    {
+    if ( size->bytecode_ready < 0 )
       error = tt_size_init_bytecode( (FT_Size)size, pedantic );
-      if ( error )
-        goto Exit;
-    }
+
+    if ( error || size->bytecode_ready )
+      goto Exit;
 
     /* rescale CVT when needed */
-    if ( !size->cvt_ready )
+    if ( size->cvt_ready < 0 )
     {
       FT_UInt  i;
       TT_Face  face = (TT_Face)size->root.face;
@@ -1087,8 +1086,6 @@
       size->GS = tt_default_graphics_state;
 
       error = tt_size_run_prep( size, pedantic );
-      if ( !error )
-        size->cvt_ready = 1;
     }
 
   Exit:
@@ -1119,8 +1116,8 @@
     FT_Error  error = FT_Err_Ok;
 
 #ifdef TT_USE_BYTECODE_INTERPRETER
-    size->bytecode_ready = 0;
-    size->cvt_ready      = 0;
+    size->bytecode_ready = -1;
+    size->cvt_ready      = -1;
 #endif
 
     size->ttmetrics.valid = FALSE;
@@ -1148,7 +1145,7 @@
 
 
 #ifdef TT_USE_BYTECODE_INTERPRETER
-    if ( size->bytecode_ready )
+    if ( size->bytecode_ready >= 0 )
       tt_size_done_bytecode( ttsize );
 #endif
 
@@ -1229,7 +1226,7 @@
     }
 
 #ifdef TT_USE_BYTECODE_INTERPRETER
-    size->cvt_ready = 0;
+    size->cvt_ready = -1;
 #endif /* TT_USE_BYTECODE_INTERPRETER */
 
     if ( !error )
diff --git a/src/truetype/ttobjs.h b/src/truetype/ttobjs.h
index a11dd37..47d50d9 100644
--- a/src/truetype/ttobjs.h
+++ b/src/truetype/ttobjs.h
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    Objects manager (specification).                                     */
 /*                                                                         */
-/*  Copyright 1996-2009, 2011-2013 by                                      */
+/*  Copyright 1996-2009, 2011-2014 by                                      */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -333,8 +333,10 @@ FT_BEGIN_HEADER
     FT_Bool            debug;
     TT_ExecContext     context;
 
-    FT_Bool            bytecode_ready;
-    FT_Bool            cvt_ready;
+    /* if negative, `fpgm' (resp. `prep'), wasn't executed yet; */
+    /* otherwise it is the returned error code                  */
+    FT_Error           bytecode_ready;
+    FT_Error           cvt_ready;
 
 #endif /* TT_USE_BYTECODE_INTERPRETER */
 
diff --git a/src/truetype/ttsubpix.c b/src/truetype/ttsubpix.c
index 28470ad..9871994 100644
--- a/src/truetype/ttsubpix.c
+++ b/src/truetype/ttsubpix.c
@@ -956,7 +956,7 @@
       if ( loader->exec->rasterizer_version != TT_INTERPRETER_VERSION_35 )
       {
         loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
-        loader->exec->size->cvt_ready    = FALSE;
+        loader->exec->size->cvt_ready    = -1;
 
         tt_size_ready_bytecode(
           loader->exec->size,
@@ -971,7 +971,7 @@
            SPH_OPTION_SET_RASTERIZER_VERSION )
       {
         loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
-        loader->exec->size->cvt_ready    = FALSE;
+        loader->exec->size->cvt_ready    = -1;
 
         tt_size_ready_bytecode(
           loader->exec->size,