2163516: Font.createFont can be persuaded to leak temporary files
authorprr
Tue, 03 Mar 2009 16:10:37 -0800
changeset 2609 1db65c97bddc
parent 2608 fe2af56a83d3
child 2610 9856ea68e32b
2163516: Font.createFont can be persuaded to leak temporary files Reviewed-by: igor
jdk/src/share/classes/sun/font/FontManager.java
jdk/src/share/classes/sun/font/TrueTypeFont.java
jdk/src/share/classes/sun/font/Type1Font.java
jdk/test/java/awt/FontClass/CreateFont/DeleteFont.java
--- a/jdk/src/share/classes/sun/font/FontManager.java	Fri Feb 20 13:48:32 2009 +0300
+++ b/jdk/src/share/classes/sun/font/FontManager.java	Tue Mar 03 16:10:37 2009 -0800
@@ -2361,7 +2361,7 @@
                 font2D = new TrueTypeFont(fontFilePath, null, 0, true);
                 break;
             case Font.TYPE1_FONT:
-                font2D = new Type1Font(fontFilePath, null);
+                font2D = new Type1Font(fontFilePath, null, isCopy);
                 break;
             default:
                 throw new FontFormatException("Unrecognised Font Format");
--- a/jdk/src/share/classes/sun/font/TrueTypeFont.java	Fri Feb 20 13:48:32 2009 +0300
+++ b/jdk/src/share/classes/sun/font/TrueTypeFont.java	Tue Mar 03 16:10:37 2009 -0800
@@ -174,8 +174,17 @@
         super(platname, nativeNames);
         useJavaRasterizer = javaRasterizer;
         fontRank = Font2D.TTF_RANK;
-        verify();
-        init(fIndex);
+        try {
+            verify();
+            init(fIndex);
+        } catch (Throwable t) {
+            close();
+            if (t instanceof FontFormatException) {
+                throw (FontFormatException)t;
+            } else {
+                throw new FontFormatException("Unexpected runtime exception.");
+            }
+        }
         Disposer.addObjectRecord(this, disposerRecord);
     }
 
--- a/jdk/src/share/classes/sun/font/Type1Font.java	Fri Feb 20 13:48:32 2009 +0300
+++ b/jdk/src/share/classes/sun/font/Type1Font.java	Tue Mar 03 16:10:37 2009 -0800
@@ -39,6 +39,7 @@
 import java.nio.channels.ClosedChannelException;
 import java.nio.channels.FileChannel;
 import sun.java2d.Disposer;
+import sun.java2d.DisposerRecord;
 import java.util.HashSet;
 import java.util.HashMap;
 import java.awt.Font;
@@ -76,6 +77,27 @@
  */
 public class Type1Font extends FileFont {
 
+     private static class T1DisposerRecord  implements DisposerRecord {
+        String fileName = null;
+
+        T1DisposerRecord(String name) {
+            fileName = name;
+        }
+
+        public synchronized void dispose() {
+            java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction() {
+                    public Object run() {
+
+                        if (fileName != null) {
+                            (new java.io.File(fileName)).delete();
+                        }
+                        return null;
+                    }
+             });
+        }
+    }
+
     WeakReference bufferRef = new WeakReference(null);
 
     private String psName = null;
@@ -125,18 +147,42 @@
 
 
     /**
+     * Constructs a Type1 Font.
+     * @param platname - Platform identifier of the font. Typically file name.
+     * @param nativeNames - Native names - typically XLFDs on Unix.
+     */
+    public Type1Font(String platname, Object nativeNames)
+        throws FontFormatException {
+
+        this(platname, nativeNames, false);
+    }
+
+    /**
      * - does basic verification of the file
      * - reads the names (full, family).
      * - determines the style of the font.
      * @throws FontFormatException - if the font can't be opened
      * or fails verification,  or there's no usable cmap
      */
-    public Type1Font(String platname, Object nativeNames)
+    public Type1Font(String platname, Object nativeNames, boolean createdCopy)
         throws FontFormatException {
         super(platname, nativeNames);
         fontRank = Font2D.TYPE1_RANK;
         checkedNatives = true;
-        verify();
+        try {
+            verify();
+        } catch (Throwable t) {
+            if (createdCopy) {
+                T1DisposerRecord ref = new T1DisposerRecord(platname);
+                Disposer.addObjectRecord(bufferRef, ref);
+                bufferRef = null;
+            }
+            if (t instanceof FontFormatException) {
+                throw (FontFormatException)t;
+            } else {
+                throw new FontFormatException("Unexpected runtime exception.");
+            }
+        }
     }
 
     private synchronized ByteBuffer getBuffer() throws FontFormatException {
--- a/jdk/test/java/awt/FontClass/CreateFont/DeleteFont.java	Fri Feb 20 13:48:32 2009 +0300
+++ b/jdk/test/java/awt/FontClass/CreateFont/DeleteFont.java	Tue Mar 03 16:10:37 2009 -0800
@@ -55,17 +55,23 @@
         if (!gotException) {
             throw new RuntimeException("No expected IOException");
         }
-        badRead(-2);
-        badRead(8193);
+        badRead(-2, Font.TRUETYPE_FONT);
+        badRead(8193, Font.TRUETYPE_FONT);
+
+        badRead(-2, Font.TYPE1_FONT);
+        badRead(8193, Font.TYPE1_FONT);
+
+        // Make sure GC has a chance to clean up before we exit.
+        System.gc(); System.gc();
     }
 
-    static void badRead(final int retval) {
+    static void badRead(final int retval, int fontType) {
         int num = 2;
         byte[] buff = new byte[16*8192]; // Multiple of 8192 is important.
         for (int ct=0; ct<num; ++ct) {
             try {
                 Font.createFont(
-                    Font.TRUETYPE_FONT,
+                    fontType,
                     new ByteArrayInputStream(buff) {
                         @Override
                         public int read(byte[] buff, int off, int len) {