Commit bb7668d7c30e16ef1d6442c4aa2b694fadd15295

Nikhil Ramakrishnan 2019-07-28T19:38:05

[woff2] Improve memory and error handling. Free up memory after use, and improve error handling. * src/sfnt/sfwoff2.c (reconstruct_font, woff2_open_font): Implement changes.

diff --git a/ChangeLog b/ChangeLog
index 5bd878b..52087be 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2019-08-27  Nikhil Ramakrishnan  <ramakrishnan.nikhil@gmail.com>
 
+	[woff2] Improve memory and error handling.
+
+	Free up memory after use, and improve error handling.
+
+	* src/sfnt/sfwoff2.c (reconstruct_font, woff2_open_font): Implement
+	changes.
+
+2019-08-27  Nikhil Ramakrishnan  <ramakrishnan.nikhil@gmail.com>
+
 	[woff2] Avoid too many calls to `FT_REALLOC'.
 
 	We do this by using `totalSfntSize' as an initial reference, and
diff --git a/src/sfnt/sfwoff2.c b/src/sfnt/sfwoff2.c
index 3f79654..cda2b59 100644
--- a/src/sfnt/sfwoff2.c
+++ b/src/sfnt/sfwoff2.c
@@ -1333,6 +1333,7 @@
     FT_Int     nn            = 0;
     FT_UShort  num_hmetrics;
     FT_ULong   font_checksum = info->header_checksum;
+    FT_Bool    is_glyf_xform = FALSE;
 
     FT_ULong     table_entry_offset = 12;
     WOFF2_Table  head_table;
@@ -1370,7 +1371,8 @@
     if ( FT_NEW( stream ) )
       return FT_THROW( Invalid_Table );
     FT_Stream_OpenMemory( stream, transformed_buf, transformed_buf_size );
-    stream->close = stream_close;
+    stream->memory = memory;
+    stream->close  = stream_close;
 
     FT_ASSERT( FT_STREAM_POS() == 0 );
 
@@ -1432,6 +1434,7 @@
 
         if( table.Tag == TTAG_glyf )
         {
+          is_glyf_xform    = TRUE;
           table.dst_offset = dest_offset;
 
           if( reconstruct_glyf( stream, &table, &checksum,
@@ -1447,6 +1450,12 @@
         }
         else if( table.Tag == TTAG_hmtx )
         {
+          if( !is_glyf_xform )
+          {
+            FT_ERROR(( "hmtx is transformed but glyf is not.\n" ));
+            error = FT_THROW( Unimplemented_Feature );
+            goto Fail;
+          }
           table.dst_offset = dest_offset;
           if( reconstruct_hmtx( stream, table.src_length, info->num_glyphs,
                                 info->num_hmetrics, info->x_mins, &checksum,
@@ -1501,7 +1510,11 @@
 
     /* Set pointer of sfnt stream to its correct value. */
     *sfnt_bytes = sfnt;
+
     FT_FREE( table_entry );
+    FT_Stream_Close( stream );
+    FT_FREE( stream );
+
     return error;
 
     Fail:
@@ -1509,10 +1522,10 @@
         error = FT_THROW( Invalid_Table );
 
       FT_FREE( table_entry );
+      FT_Stream_Close( stream );
+      FT_FREE( stream );
 
       return error;
-
-    /* TODO free the uncompressed stream after everything is done. */
   }
 
 
@@ -1673,14 +1686,16 @@
         if( table->Tag == TTAG_loca && table->TransformLength )
         {
           FT_ERROR(( "woff_font_open: Invalid loca `transformLength'.\n" ));
-          return FT_THROW( Invalid_Table );
+          error = FT_THROW( Invalid_Table );
+          goto Exit;
         }
       }
 
       if ( src_offset + table->TransformLength < src_offset )
       {
         FT_ERROR(( "woff_font_open: invalid WOFF2 table directory.\n" ));
-        return FT_THROW( Invalid_Table );
+        error = FT_THROW( Invalid_Table );
+        goto Exit;
       }
 
       table->src_offset = src_offset;
@@ -1708,7 +1723,11 @@
     woff2.uncompressed_size = last_table->src_offset
                               + last_table->src_length;
     if( woff2.uncompressed_size < last_table->src_offset )
-        return FT_THROW( Invalid_Table );
+    {
+      error = FT_THROW( Invalid_Table );
+      goto Exit;
+    }
+
     /* DEBUG - Remove later. */
     FT_TRACE2(( "Uncompressed size: %ld\n", woff2.uncompressed_size ));
 
@@ -1724,7 +1743,10 @@
       FT_TRACE2(( "Header version: %lx\n", woff2.header_version ));
       if( woff2.header_version != 0x00010000 &&
           woff2.header_version != 0x00020000 )
-        return FT_THROW( Invalid_Table );
+      {
+        error = FT_THROW( Invalid_Table );
+        goto Exit;
+      }
 
       if( READ_255USHORT( woff2.num_fonts ) )
         goto Exit;
@@ -1779,10 +1801,10 @@
         {
           if( glyf_index > loca_index      ||
               loca_index - glyf_index != 1 )
-            return FT_THROW( Invalid_Table );
-          /* DEBUG - Remove later */
-          else
-            FT_TRACE2(( "glyf and loca indices are valid.\n" ));
+          {
+            error = FT_THROW( Invalid_Table );
+            goto Exit;
+          }
         }
       }
       /* Collection directory reading complete. */
@@ -1795,24 +1817,36 @@
 
     /* Few more checks before we start reading the tables. */
     if( file_offset > woff2.length )
-      return FT_THROW( Invalid_Table );
+    {
+      error = FT_THROW( Invalid_Table );
+      goto Exit;
+    }
 
     if ( woff2.metaOffset )
     {
       if ( file_offset != woff2.metaOffset )
-        return FT_THROW( Invalid_Table );
+      {
+        error = FT_THROW( Invalid_Table );
+        goto Exit;
+      }
       file_offset = ROUND4(woff2.metaOffset + woff2.metaLength);
     }
 
     if( woff2.privOffset )
     {
       if( file_offset != woff2.privOffset )
-        return FT_THROW( Invalid_Table );
+      {
+        error = FT_THROW( Invalid_Table );
+        goto Exit;
+      }
       file_offset = ROUND4(woff2.privOffset + woff2.privLength);
     }
 
     if( file_offset != ( ROUND4( woff2.length ) ) )
-      return FT_THROW( Invalid_Table );
+    {
+      error = FT_THROW( Invalid_Table );
+      goto Exit;
+    }
 
     /* Only retain tables of the requested face in a TTC. */
     /* TODO Check whether it is OK for rest of the code to be unaware of the
@@ -1919,13 +1953,15 @@
     error = woff2_uncompress( uncompressed_buf, woff2.uncompressed_size,
                               stream->cursor, woff2.totalCompressedSize );
     if( error )
-        goto Exit;
+      goto Exit;
 
     FT_FRAME_EXIT();
 
-    reconstruct_font( uncompressed_buf, woff2.uncompressed_size,
-                      indices, &woff2, &info, &sfnt, &sfnt_size,
-                      memory );
+    error = reconstruct_font( uncompressed_buf, woff2.uncompressed_size,
+                              indices, &woff2, &info, &sfnt, &sfnt_size,
+                              memory );
+    if( error )
+      goto Exit;
 
     /* Resize `sfnt' to actual size of sfnt stream. */
     if ( woff2.actual_sfnt_size < sfnt_size )
@@ -1953,7 +1989,7 @@
 
     face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
 
-    /* Set face_index to 0.  */
+    /* Set face_index to 0. */
     *face_instance_index = 0;
 
     /* error = FT_THROW( Unimplemented_Feature ); */
@@ -1964,13 +2000,15 @@
   Exit:
     FT_FREE( tables );
     FT_FREE( indices );
-    FT_FREE( uncompressed_buf );
 
     if( error )
     {
       FT_FREE( sfnt );
-      FT_Stream_Close( sfnt_stream );
-      FT_FREE( sfnt_stream );
+      if ( sfnt_stream )
+      {
+        FT_Stream_Close( sfnt_stream );
+        FT_FREE( sfnt_stream );
+      }
     }
 
     return error;