Commit 67cf7a8841b0bbf6aa3085216fcb5ba7340473ca

Andrew Church 2013-06-18T09:35:34

Fix Savannah bug #39266. If memory allocations fail at certain points while opening a font, FreeType can either crash due to a NULL dereference or leak memory. * include/freetype/internal/ftobjs.c (FT_Face_InternalRec, FT_LibraryRec): Make `refcount' a signed integer. If, for example, FT_Open_Face() fails in a memory allocation before the face's reference count is set to 1, a subsequent `FT_Done_Library' call would otherwise loop over `FT_Done_Face' 2^32 times before freeing the face. * src/base/ftobjs.c (open_face): Initialize `stream' and friends earlier. (FT_Open_Face) <Fail>: Behave correctly if `node' is NULL. (FT_Destroy_Module) <Fail>: Check that `renderer_clazz' is valid.

diff --git a/ChangeLog b/ChangeLog
index 9e9297b..51c884e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,23 @@
-2013-06-14  Werner Lemberg  <wl@gnu.org>.
+2013-06-18  Andrew Church  <achurch+savannah@achurch.org>
+
+	Fix Savannah bug #39266.
+
+	If memory allocations fail at certain points while opening a font,
+	FreeType can either crash due to a NULL dereference or leak memory.
+
+	* include/freetype/internal/ftobjs.c (FT_Face_InternalRec,
+	FT_LibraryRec): Make `refcount' a signed integer.  If, for example,
+	FT_Open_Face() fails in a memory allocation before the face's
+	reference count is set to 1, a subsequent `FT_Done_Library' call
+	would otherwise loop over `FT_Done_Face' 2^32 times before freeing
+	the face.
+
+	* src/base/ftobjs.c (open_face): Initialize `stream' and friends
+	earlier.
+	(FT_Open_Face) <Fail>: Behave correctly if `node' is NULL.
+	(FT_Destroy_Module) <Fail>: Check that `renderer_clazz' is valid.
+
+2013-06-14  Werner Lemberg  <wl@gnu.org>
 
 	* src/smooth/ftgrays.c One final pragma to silence 64-bit MSVC.
 
@@ -10,7 +29,7 @@
 	* src/cff/cffgload.c (cff_slot_load): If we get
 	FT_Err_Glyph_Too_Big, retry unhinted and scale up later on.
 
-2013-06-12  Werner Lemberg  <wl@gnu.org>.
+2013-06-12  Werner Lemberg  <wl@gnu.org>
 
 	Another try on pragmas.
 
diff --git a/include/freetype/internal/ftobjs.h b/include/freetype/internal/ftobjs.h
index 8a309b8..701c850 100644
--- a/include/freetype/internal/ftobjs.h
+++ b/include/freetype/internal/ftobjs.h
@@ -363,7 +363,7 @@ FT_BEGIN_HEADER
 #endif
 
     FT_Bool             ignore_unpatented_hinter;
-    FT_UInt             refcount;
+    FT_Int              refcount;
 
   } FT_Face_InternalRec;
 
@@ -883,7 +883,7 @@ FT_BEGIN_HEADER
     FT_PIC_Container   pic_container;
 #endif
 
-    FT_UInt            refcount;
+    FT_Int             refcount;
 
   } FT_LibraryRec;
 
diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
index d6b2126..e9a2981 100644
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -1153,15 +1153,15 @@
     if ( FT_ALLOC( face, clazz->face_object_size ) )
       goto Fail;
 
+    face->driver = driver;
+    face->memory = memory;
+    face->stream = stream;
+
     if ( FT_NEW( internal ) )
       goto Fail;
 
     face->internal = internal;
 
-    face->driver   = driver;
-    face->memory   = memory;
-    face->stream   = stream;
-
 #ifdef FT_CONFIG_OPTION_INCREMENTAL
     {
       int  i;
@@ -2265,7 +2265,10 @@
     goto Exit;
 
   Fail:
-    FT_Done_Face( face );
+    if ( node )
+      FT_Done_Face( face );    /* face must be in the driver's list */
+    else if ( face )
+      destroy_face( memory, face, driver );
 
   Exit:
     FT_TRACE4(( "FT_Open_Face: Return %d\n", error ));
@@ -4308,7 +4311,8 @@
       FT_Renderer  renderer = FT_RENDERER( module );
 
 
-      if ( renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
+      if ( renderer->clazz                                          &&
+           renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
            renderer->raster                                         )
         renderer->clazz->raster_class->raster_done( renderer->raster );
     }