Commit 913a36509099640dcbf5ace70b220d05eaa7b5c7

Werner Lemberg 2006-11-19T09:19:17

Because FT_Load_Glyph expects CID values for CID-keyed fonts, the test for a valid glyph index must be deferred to the font drivers. This patch fixes Savannah bug #18301. * src/base/ftobjs.c (FT_Load_Glyph): Don't check `glyph_index'. * src/bdf/bdfdrivr.c (BDF_Glyph_Load), src/cff/cffgload.c (cff_slot_load), src/cid/cidgload.c (cid_slot_load_glyph), src/pcf/pcfdrivr.c (PCF_Glyph_Load), src/pfr/pfrobjs.c (pfr_slot_load), src/truetype/ttdriver.c (Load_Glyph), src/type1/t1gload.c (T1_Load_Glyph), src/winfonts/winfnt.c (FNT_Load_Glyph): Check validity of `glyph_index'.

diff --git a/ChangeLog b/ChangeLog
index c8aef2c..37be0cb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2006-11-18  Werner Lemberg  <wl@gnu.org>
+
+	Because FT_Load_Glyph expects CID values for CID-keyed fonts, the
+	test for a valid glyph index must be deferred to the font drivers. 
+	This patch fixes Savannah bug #18301.
+
+	* src/base/ftobjs.c (FT_Load_Glyph): Don't check `glyph_index'.
+	* src/bdf/bdfdrivr.c (BDF_Glyph_Load), src/cff/cffgload.c
+	(cff_slot_load), src/cid/cidgload.c (cid_slot_load_glyph),
+	src/pcf/pcfdrivr.c (PCF_Glyph_Load), src/pfr/pfrobjs.c
+	(pfr_slot_load), src/truetype/ttdriver.c (Load_Glyph),
+	src/type1/t1gload.c (T1_Load_Glyph), src/winfonts/winfnt.c
+	(FNT_Load_Glyph): Check validity of `glyph_index'.
+
 2006-11-13  David Turner  <david@freetype.org>
 
 	* src/truetype/ttinterp.c (FIX_BYTECODE): Undefine.  The interpreter
diff --git a/src/base/ftcalc.c b/src/base/ftcalc.c
index 95db279..b7fb781 100644
--- a/src/base/ftcalc.c
+++ b/src/base/ftcalc.c
@@ -315,6 +315,23 @@
 
   /* documentation is in freetype.h */
 
+  /* The FT_MulDiv function has been optimized thanks to ideas from      */
+  /* Graham Asher.  The trick is to optimize computation when everything */
+  /* fits within 32-bits (a rather common case).                         */
+  /*                                                                     */
+  /*  we compute 'a*b+c/2', then divide it by 'c'. (positive values)     */
+  /*                                                                     */
+  /*  46340 is FLOOR(SQRT(2^31-1)).                                      */
+  /*                                                                     */
+  /*  if ( a <= 46340 && b <= 46340 ) then ( a*b <= 0x7FFEA810 )         */
+  /*                                                                     */
+  /*  0x7FFFFFFF - 0x7FFEA810 = 0x157F0                                  */
+  /*                                                                     */
+  /*  if ( c < 0x157F0*2 ) then ( a*b+c/2 <= 0x7FFFFFFF )                */
+  /*                                                                     */
+  /*  and 2*0x157F0 = 176096                                             */
+  /*                                                                     */
+
   FT_EXPORT_DEF( FT_Long )
   FT_MulDiv( FT_Long  a,
              FT_Long  b,
@@ -551,7 +568,7 @@
 
 
   /* apparently, the second version of this code is not compiled correctly */
-  /* on Mac machines with the MPW C compiler..  tsk, tsk, tsk...         */
+  /* on Mac machines with the MPW C compiler..  tsk, tsk, tsk...           */
 
 #if 1
 
@@ -588,7 +605,7 @@
     if ( r >= (FT_UInt32)y ) /* we know y is to be treated as unsigned here */
       return ( s < 0 ? 0x80000001UL : 0x7FFFFFFFUL );
                              /* Return Max/Min Int32 if division overflow. */
-                             /* This includes division by zero! */
+                             /* This includes division by zero!            */
     q = 0;
     for ( i = 0; i < 32; i++ )
     {
diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
index 417dc70..6a26140 100644
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -549,8 +549,8 @@
     if ( !face || !face->size || !face->glyph )
       return FT_Err_Invalid_Face_Handle;
 
-    if ( glyph_index >= (FT_UInt)face->num_glyphs )
-      return FT_Err_Invalid_Argument;
+    /* The validity test for `glyph_index' is performed by the */
+    /* font drivers.                                           */
 
     slot = face->glyph;
     ft_glyphslot_clear( slot );
diff --git a/src/bdf/bdfdrivr.c b/src/bdf/bdfdrivr.c
index c7939e3..3407148 100644
--- a/src/bdf/bdfdrivr.c
+++ b/src/bdf/bdfdrivr.c
@@ -648,16 +648,17 @@ THE SOFTWARE.
                   FT_UInt       glyph_index,
                   FT_Int32      load_flags )
   {
-    BDF_Face     face   = (BDF_Face)FT_SIZE_FACE( size );
+    BDF_Face     bdf    = (BDF_Face)FT_SIZE_FACE( size );
+    FT_Face      face   = FT_FACE( bdf );
     FT_Error     error  = BDF_Err_Ok;
     FT_Bitmap*   bitmap = &slot->bitmap;
     bdf_glyph_t  glyph;
-    int          bpp    = face->bdffont->bpp;
+    int          bpp    = bdf->bdffont->bpp;
 
     FT_UNUSED( load_flags );
 
 
-    if ( !face )
+    if ( !face || glyph_index >= (FT_UInt)face->num_glyphs )
     {
       error = BDF_Err_Invalid_Argument;
       goto Exit;
@@ -665,12 +666,12 @@ THE SOFTWARE.
 
     /* index 0 is the undefined glyph */
     if ( glyph_index == 0 )
-      glyph_index = face->default_glyph;
+      glyph_index = bdf->default_glyph;
     else
       glyph_index--;
 
     /* slot, bitmap => freetype, glyph => bdflib */
-    glyph = face->bdffont->glyphs[glyph_index];
+    glyph = bdf->bdffont->glyphs[glyph_index];
 
     bitmap->rows  = glyph.bbx.height;
     bitmap->width = glyph.bbx.width;
@@ -712,7 +713,7 @@ THE SOFTWARE.
      * used here, provided such fonts do exist.
      */
     ft_synthesize_vertical_metrics( &slot->metrics,
-                                    face->bdffont->bbx.height << 6 );
+                                    bdf->bdffont->bbx.height << 6 );
 
   Exit:
     return error;
diff --git a/src/cff/cffgload.c b/src/cff/cffgload.c
index 673a814..ca6bb0f 100644
--- a/src/cff/cffgload.c
+++ b/src/cff/cffgload.c
@@ -2285,6 +2285,20 @@
     FT_Vector     font_offset;
 
 
+    /* in a CID-keyed font, consider `glyph_index' as a CID and map */
+    /* it immediately to the real glyph_index -- if it isn't a      */
+    /* subsetted font, glyph_indices and CIDs are identical, though */
+    if ( cff->top_font.font_dict.cid_registry != 0xFFFFU &&
+         cff->charset.cids )
+    {
+      if ( glyph_index < cff->charset.max_cid )
+        glyph_index = cff->charset.cids[glyph_index];
+      else
+        return CFF_Err_Invalid_Argument;
+    }
+    else if ( glyph_index >= cff->num_glyphs )
+      return CFF_Err_Invalid_Argument;
+
     if ( load_flags & FT_LOAD_NO_RECURSE )
       load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
 
@@ -2376,18 +2390,6 @@
       FT_ULong  charstring_len;
 
 
-      /* in a CID-keyed font, consider `glyph_index' as a CID and map */
-      /* it immediately to the real glyph_index -- if it isn't a      */
-      /* subsetted font, glyph_indices and CIDs are identical, though */
-      if ( cff->top_font.font_dict.cid_registry != 0xFFFFU &&
-           cff->charset.cids )
-      {
-        if ( glyph_index < cff->charset.max_cid )
-          glyph_index = cff->charset.cids[glyph_index];
-        else
-          glyph_index = 0;
-      }
-
       cff_decoder_init( &decoder, face, size, glyph, hinting,
                         FT_LOAD_TARGET_MODE( load_flags ) );
 
diff --git a/src/cff/cffload.c b/src/cff/cffload.c
index cd88788..0c7025a 100644
--- a/src/cff/cffload.c
+++ b/src/cff/cffload.c
@@ -1946,7 +1946,8 @@
 
         encoding->count = 0;
 
-        error = cff_charset_compute_cids( charset, num_glyphs, stream->memory );
+        error = cff_charset_compute_cids( charset, num_glyphs,
+                                          stream->memory );
         if ( error )
           goto Exit;
 
diff --git a/src/cid/cidgload.c b/src/cid/cidgload.c
index 68bd14e..aec3485 100644
--- a/src/cid/cidgload.c
+++ b/src/cid/cidgload.c
@@ -275,6 +275,12 @@
     FT_Vector      font_offset;
 
 
+    if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
+    {
+      error = CID_Err_Invalid_Argument;
+      goto Exit;
+    }
+
     if ( load_flags & FT_LOAD_NO_RECURSE )
       load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
 
diff --git a/src/pcf/pcfdrivr.c b/src/pcf/pcfdrivr.c
index 6b4f30a..c0f0e49 100644
--- a/src/pcf/pcfdrivr.c
+++ b/src/pcf/pcfdrivr.c
@@ -442,7 +442,7 @@ THE SOFTWARE.
 
     FT_TRACE4(( "load_glyph %d ---", glyph_index ));
 
-    if ( !face )
+    if ( !face || glyph_index >= (FT_UInt)face->root.num_glyphs )
     {
       error = PCF_Err_Invalid_Argument;
       goto Exit;
diff --git a/src/pfr/pfrobjs.c b/src/pfr/pfrobjs.c
index 8d29d5f..f891cf5 100644
--- a/src/pfr/pfrobjs.c
+++ b/src/pfr/pfrobjs.c
@@ -296,8 +296,11 @@
     if ( gindex > 0 )
       gindex--;
 
-    /* check that the glyph index is correct */
-    FT_ASSERT( gindex < face->phy_font.num_chars );
+    if ( !face || gindex >= face->phy_font.num_chars )
+    {
+      error = PFR_Err_Invalid_Argument;
+      goto Exit;
+    }
 
     /* try to load an embedded bitmap */
     if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 )
diff --git a/src/truetype/ttdriver.c b/src/truetype/ttdriver.c
index 24cbd0e..828b264 100644
--- a/src/truetype/ttdriver.c
+++ b/src/truetype/ttdriver.c
@@ -243,6 +243,7 @@
   {
     TT_GlyphSlot  slot = (TT_GlyphSlot)ttslot;
     TT_Size       size = (TT_Size)ttsize;
+    FT_Face       face = ttslot->face;
     FT_Error      error;
 
 
@@ -252,6 +253,9 @@
     if ( !size )
       return TT_Err_Invalid_Size_Handle;
 
+    if ( !face || glyph_index >= (FT_UInt)face->num_glyphs )
+      return TT_Err_Invalid_Argument;
+
     if ( load_flags & ( FT_LOAD_NO_RECURSE | FT_LOAD_NO_SCALE ) )
     {
       load_flags |= FT_LOAD_NO_HINTING |
diff --git a/src/type1/t1gload.c b/src/type1/t1gload.c
index 7012b4a..e08a428 100644
--- a/src/type1/t1gload.c
+++ b/src/type1/t1gload.c
@@ -225,6 +225,12 @@
 #endif
 
 
+    if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
+    {
+      error = T1_Err_Invalid_Argument;
+      goto Exit;
+    }
+
     FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) );
 
     if ( load_flags & FT_LOAD_NO_RECURSE )
diff --git a/src/winfonts/winfnt.c b/src/winfonts/winfnt.c
index 3523b14..d3d6024 100644
--- a/src/winfonts/winfnt.c
+++ b/src/winfonts/winfnt.c
@@ -649,7 +649,8 @@
     FT_UNUSED( load_flags );
 
 
-    if ( !face || !font )
+    if ( !face || !font ||
+         glyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) )
     {
       error = FNT_Err_Invalid_Argument;
       goto Exit;