8132985: Crash in freetypescaler.c due to double free
authorpsadhukhan
Mon, 05 Oct 2015 15:36:43 +0300
changeset 33250 047311011afe
parent 33249 334120f2d641
child 33251 938892557272
8132985: Crash in freetypescaler.c due to double free Reviewed-by: prr, simonis
jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c
jdk/test/java/awt/FontClass/FontDisposer/FontDisposeTest.java
--- a/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c	Mon Oct 05 15:29:23 2015 +0300
+++ b/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c	Mon Oct 05 15:36:43 2015 +0300
@@ -60,6 +60,7 @@
     JNIEnv* env;
     FT_Library library;
     FT_Face face;
+    FT_Stream faceStream;
     jobject font2D;
     jobject directBuffer;
 
@@ -107,16 +108,10 @@
     if (scalerInfo == NULL)
         return;
 
-    //apparently Done_Face will only close the stream
-    // but will not relase the memory of stream structure.
-    // We need to free it explicitly to avoid leak.
-    //Direct access to the stream field might be not ideal solution as
-    // it is considred to be "private".
-    //Alternatively we could have stored pointer to the structure
-    // in the scalerInfo but this will increase size of the structure
-    // for no good reason
-    stream = scalerInfo->face->stream;
-
+    // FT_Done_Face always closes the stream, but only frees the memory
+    // of the data structure if it was internally allocated by FT.
+    // We hold on to a pointer to the stream structure if we provide it
+    // ourselves, so that we can free it here.
     FT_Done_Face(scalerInfo->face);
     FT_Done_FreeType(scalerInfo->library);
 
@@ -128,10 +123,9 @@
         free(scalerInfo->fontData);
     }
 
-   if (stream != NULL) {
-        free(stream);
-   }
-
+    if (scalerInfo->faceStream != NULL) {
+        free(scalerInfo->faceStream);
+    }
     free(scalerInfo);
 }
 
@@ -302,6 +296,9 @@
                                          &ft_open_args,
                                          indexInCollection,
                                          &scalerInfo->face);
+                    if (!error) {
+                        scalerInfo->faceStream = ftstream;
+                    }
                 }
                 if (error || scalerInfo->directBuffer == NULL) {
                     free(ftstream);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/FontClass/FontDisposer/FontDisposeTest.java	Mon Oct 05 15:36:43 2015 +0300
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.font.FontRenderContext;
+import java.awt.image.BufferedImage;
+import java.io.FileInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import sun.font.Font2DHandle;
+import sun.font.Font2D;
+import sun.font.FontScaler;
+import sun.font.Type1Font;
+
+/**
+ * @bug 8132985
+ * @summary Tests to verify Type1 Font scaler dispose crashes
+ * @modules java.desktop/sun.font
+ */
+public class FontDisposeTest
+{
+    public static void main(String[] args) throws Exception
+    {
+        // The bug only happens with Type 1 fonts. The Ghostscript font files
+        // should be commonly available. From distro pacakge or
+        //  ftp://ftp.gnu.org/gnu/ghostscript/gnu-gs-fonts-other-6.0.tar.gz
+        // Pass pfa/pfb font file as argument
+        String path = args[0];
+
+        // Load
+        InputStream stream = new FileInputStream(path);
+        Font font = Font.createFont(Font.TYPE1_FONT,stream);
+
+        // Ensure native bits have been generated
+        BufferedImage img = new BufferedImage(100,100,
+                                 BufferedImage.TYPE_INT_ARGB);
+        Graphics2D g2d = img.createGraphics();
+        FontRenderContext frc = g2d.getFontRenderContext();
+
+        font.getLineMetrics("derp",frc);
+
+        // Force disposal -
+        // System.gc() is not sufficient.
+        Field font2DHandleField = Font.class.getDeclaredField("font2DHandle");
+        font2DHandleField.setAccessible(true);
+        sun.font.Font2DHandle font2DHandle =
+                      (sun.font.Font2DHandle)font2DHandleField.get(font);
+
+        sun.font.Font2D font2D = font2DHandle.font2D;
+        sun.font.Type1Font type1Font = (sun.font.Type1Font)font2D;
+
+        Method getScalerMethod =
+        sun.font.Type1Font.class.getDeclaredMethod("getScaler");
+        getScalerMethod.setAccessible(true);
+        sun.font.FontScaler scaler =
+                  (sun.font.FontScaler)getScalerMethod.invoke(type1Font);
+
+        // dispose should not crash due to double free
+        scaler.dispose();
+    }
+}