Commit e421a0bffc13299f3d8f0229a312991d85bcc23a

Werner Lemberg 2016-09-10T08:02:30

[sfnt] Fix previous commit. Problems reported as https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=40 We now map the strike index right before accessing the physical data, not earlier. * src/sfnt/sfobjs.c (sfnt_load_face): Set `face->sbit_strike_map' after creating the map so that... * src/sfnt/ttsbit.c (tt_face_load_strike_metrics): ... this function can be used before and after setting up `sbit_strike_map'. (tt_face_set_sbit_strike): Revert change. (tt_sbit_decoder_init, tt_face_load_sbix_image): Map strike index. * src/truetype/ttdriver.c (tt_size_select): Revert change.

diff --git a/ChangeLog b/ChangeLog
index 6beb471..b4e80ca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2016-09-10  Werner Lemberg  <wl@gnu.org>
+
+	[sfnt] Fix previous commit.
+
+	Problems reported as
+
+	  https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=40
+
+	We now map the strike index right before accessing the physical
+	data, not earlier.
+
+	* src/sfnt/sfobjs.c (sfnt_load_face): Set `face->sbit_strike_map'
+	after creating the map so that...
+
+	* src/sfnt/ttsbit.c (tt_face_load_strike_metrics): ... this function
+	can be used before and after setting up `sbit_strike_map'.
+	(tt_face_set_sbit_strike): Revert change.
+	(tt_sbit_decoder_init, tt_face_load_sbix_image): Map strike index.
+
+	* src/truetype/ttdriver.c (tt_size_select): Revert change.
+
 2016-09-09  Werner Lemberg  <wl@gnu.org>
 
 	[ftfuzzer] Minor improvements.
diff --git a/src/sfnt/sfobjs.c b/src/sfnt/sfobjs.c
index 5d5a448..ceeae20 100644
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -1423,7 +1423,8 @@
           FT_Short         avgwidth = face->os2.xAvgCharWidth;
           FT_Size_Metrics  metrics;
 
-          FT_UInt  strike_idx, bsize_idx;
+          FT_UInt*  sbit_strike_map = NULL;
+          FT_UInt   strike_idx, bsize_idx;
 
 
           if ( em_size == 0 || face->os2.version == 0xFFFFU )
@@ -1436,7 +1437,7 @@
           /* of `FT_Face', we map `available_sizes' indices to strike    */
           /* indices                                                     */
           if ( FT_NEW_ARRAY( root->available_sizes, count ) ||
-               FT_NEW_ARRAY( face->sbit_strike_map, count ) )
+               FT_NEW_ARRAY( sbit_strike_map, count ) )
             goto Exit;
 
           bsize_idx = 0;
@@ -1447,7 +1448,7 @@
 
             error = sfnt->load_strike_metrics( face, strike_idx, &metrics );
             if ( error )
-              goto Exit;
+              continue;
 
             bsize->height = (FT_Short)( metrics.height >> 6 );
             bsize->width  = (FT_Short)(
@@ -1461,14 +1462,21 @@
 
             /* only use strikes with valid PPEM values */
             if ( bsize->x_ppem && bsize->y_ppem )
-              face->sbit_strike_map[bsize_idx++] = strike_idx;
+              sbit_strike_map[bsize_idx++] = strike_idx;
           }
 
           /* reduce array size to the actually used elements */
-          (void)FT_RENEW_ARRAY( face->sbit_strike_map, count, bsize_idx );
+          (void)FT_RENEW_ARRAY( sbit_strike_map, count, bsize_idx );
 
-          root->face_flags     |= FT_FACE_FLAG_FIXED_SIZES;
-          root->num_fixed_sizes = (FT_Int)bsize_idx;
+          /* from now on, all strike indices are mapped */
+          /* using `sbit_strike_map'                    */
+          if ( bsize_idx )
+          {
+            face->sbit_strike_map = sbit_strike_map;
+
+            root->face_flags     |= FT_FACE_FLAG_FIXED_SIZES;
+            root->num_fixed_sizes = (FT_Int)bsize_idx;
+          }
         }
       }
 
diff --git a/src/sfnt/ttsbit.c b/src/sfnt/ttsbit.c
index b4902be..0a90111 100644
--- a/src/sfnt/ttsbit.c
+++ b/src/sfnt/ttsbit.c
@@ -251,14 +251,7 @@
                            FT_Size_Request  req,
                            FT_ULong*        astrike_index )
   {
-    FT_Error  error;
-
-
-    error = FT_Match_Size( (FT_Face)face, req, 0, astrike_index );
-    if ( !error )
-      *astrike_index = face->sbit_strike_map[*astrike_index];
-
-    return error;
+    return FT_Match_Size( (FT_Face)face, req, 0, astrike_index );
   }
 
 
@@ -267,8 +260,22 @@
                                FT_ULong          strike_index,
                                FT_Size_Metrics*  metrics )
   {
-    if ( strike_index >= (FT_ULong)face->sbit_num_strikes )
-      return FT_THROW( Invalid_Argument );
+    /* we have to test for the existence of `sbit_strike_map'    */
+    /* because the function gets also used at the very beginning */
+    /* to construct `sbit_strike_map' itself                     */
+    if ( face->sbit_strike_map )
+    {
+      if ( strike_index >= (FT_ULong)face->root.num_fixed_sizes )
+        return FT_THROW( Invalid_Argument );
+
+      /* map to real index */
+      strike_index = face->sbit_strike_map[strike_index];
+    }
+    else
+    {
+      if ( strike_index >= (FT_ULong)face->sbit_num_strikes )
+        return FT_THROW( Invalid_Argument );
+    }
 
     switch ( (FT_UInt)face->sbit_table_type )
     {
@@ -457,6 +464,8 @@
     FT_Stream  stream = face->root.stream;
 
 
+    strike_index = face->sbit_strike_map[strike_index];
+
     if ( !face->ebdt_size )
       goto Exit;
     if ( FT_STREAM_SEEK( face->ebdt_start ) )
@@ -1418,6 +1427,8 @@
     FT_UNUSED( map );
 
 
+    strike_index = face->sbit_strike_map[strike_index];
+
     metrics->width  = 0;
     metrics->height = 0;
 
diff --git a/src/truetype/ttdriver.c b/src/truetype/ttdriver.c
index 8c98867..b96a227 100644
--- a/src/truetype/ttdriver.c
+++ b/src/truetype/ttdriver.c
@@ -273,21 +273,19 @@
 
   static FT_Error
   tt_size_select( FT_Size   size,
-                  FT_ULong  bsize_index )
+                  FT_ULong  strike_index )
   {
     TT_Face   ttface = (TT_Face)size->face;
     TT_Size   ttsize = (TT_Size)size;
     FT_Error  error  = FT_Err_Ok;
 
-    FT_UInt  strike_index = ttface->sbit_strike_map[bsize_index];
-
 
     ttsize->strike_index = strike_index;
 
     if ( FT_IS_SCALABLE( size->face ) )
     {
       /* use the scaled metrics, even when tt_size_reset fails */
-      FT_Select_Metrics( size->face, bsize_index );
+      FT_Select_Metrics( size->face, strike_index );
 
       tt_size_reset( ttsize ); /* ignore return value */
     }