From 1a878cc4ad5e44dae59f86fcb0a70da97669fbfb Mon Sep 17 00:00:00 2001 From: psadhukhan Date: Mon, 5 Oct 2015 15:36:43 +0300 Subject: [PATCH] 8132985: Crash in freetypescaler.c due to double free Reviewed-by: prr, simonis --- src/share/native/sun/font/freetypeScaler.c | 25 +++--- .../FontDisposer/FontDisposeTest.java | 84 +++++++++++++++++++ 2 files changed, 95 insertions(+), 14 deletions(-) create mode 100644 test/java/awt/FontClass/FontDisposer/FontDisposeTest.java diff --git a/src/share/native/sun/font/freetypeScaler.c b/src/share/native/sun/font/freetypeScaler.c index 1e417cb86..5ca7ba521 100644 --- a/src/share/native/sun/font/freetypeScaler.c +++ b/src/share/native/sun/font/freetypeScaler.c @@ -60,6 +60,7 @@ typedef struct { JNIEnv* env; FT_Library library; FT_Face face; + FT_Stream faceStream; jobject font2D; jobject directBuffer; @@ -107,16 +108,10 @@ static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) { 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 @@ static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) { free(scalerInfo->fontData); } - if (stream != NULL) { - free(stream); - } - + if (scalerInfo->faceStream != NULL) { + free(scalerInfo->faceStream); + } free(scalerInfo); } @@ -302,6 +296,9 @@ Java_sun_font_FreetypeFontScaler_initNativeScaler( &ft_open_args, indexInCollection, &scalerInfo->face); + if (!error) { + scalerInfo->faceStream = ftstream; + } } if (error || scalerInfo->directBuffer == NULL) { free(ftstream); diff --git a/test/java/awt/FontClass/FontDisposer/FontDisposeTest.java b/test/java/awt/FontClass/FontDisposer/FontDisposeTest.java new file mode 100644 index 000000000..319dcbd45 --- /dev/null +++ b/test/java/awt/FontClass/FontDisposer/FontDisposeTest.java @@ -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(); + } +} -- GitLab