Mercurial > hg > release > icedtea6-1.12
view patches/openjdk/8020983-outofmemoryerror_jpegimagewriter.patch @ 3024:3b654e7cbe51
Backport a number of JPEG fixes from 7u.
S4893408: JPEGReader throws IllegalArgException when setting the destination to BYTE_GRAY
S6631559: Registration of ImageIO plugins should not cause loading of jpeg.dlli and cmm.dll
S6791502: IIOException "Invalid icc profile" on jpeg after update from JDK5 to JDK6
S6793818: JpegImageReader is too greedy creating color profiles
S6888215: memory leak in jpeg plugin
S6989760: cmm native compiler warnings
S6989774: imageio compiler warnings in native code
S7013519: [parfait] Integer overflows in 2D code
S7018912: [parfait] potential buffer overruns in imageio jpeg
S8005194: [parfait] #353 sun/awt/image/jpeg/imageioJPEG.c Memory leak of pointer 'scale' allocated with calloc()
S8020983, RH976897: OutOfMemoryError caused by non garbage collected JPEGImageWriter Instances
2013-08-30 Andrew John Hughes <gnu.andrew@redhat.com>
* Makefile.am:
(ICEDTEA_PATCHES): Add new patches.
* NEWS: Updated with new patches.
* patches/imageiojpeg_sync.patch:
Bring in changes to imageioJPEG.c made between
the start of OpenJDK 6 and the start of OpenJDK 7's
hg repositories.
* patches/libraries.patch: Updated against patches below.
* patches/openjdk/4893408-jpegreader_byte_gray.patch,
* patches/openjdk/6631559-dont_load_libjpeg_to_register_imageio_plugins.patch,
* patches/openjdk/6791502-invalid_icc_profile.patch,
* patches/openjdk/6793818-jpegimagereader_too_greedy.patch,
* patches/openjdk/6888215-jpeg_memory_leak.patch,
* patches/openjdk/6989760-native_warnings.patch,
* patches/openjdk/6989774-imageio_compiler_warnings.patch,
* patches/openjdk/7013519-integer_overflows.patch,
* patches/openjdk/7018912-potential_buffer_overruns_in_jpeg.patch,
* patches/openjdk/8005194-scale_memory_leak.patch,
* patches/openjdk/8020983-outofmemoryerror_jpegimagewriter.patch:
New backports from OpenJDK 7u.
author | Andrew John Hughes <gnu.andrew@redhat.com> |
---|---|
date | Tue, 19 Nov 2013 18:39:31 +0000 |
parents | |
children |
line wrap: on
line source
# HG changeset patch # User bae # Date 1375300838 -14400 # Thu Aug 01 00:00:38 2013 +0400 # Node ID 46b203b37e061aa0a95992cfcfa0d4066422ada7 # Parent cd7a4d0b218f98511068d8336aa3f4cbaf10b128 8020983: OutOfMemoryError caused by non garbage collected JPEGImageWriter Instances Reviewed-by: prr, flar diff --git a/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/src/share/native/sun/awt/image/jpeg/imageioJPEG.c --- openjdk/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c +++ openjdk/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c @@ -106,7 +106,7 @@ /******************** StreamBuffer definition ************************/ typedef struct streamBufferStruct { - jobject stream; // ImageInputStream or ImageOutputStream + jweak ioRef; // weak reference to a provider of I/O routines jbyteArray hstreamBuffer; // Handle to a Java buffer for the stream JOCTET *buf; // Pinned buffer pointer */ size_t bufferOffset; // holds offset between unpin and the next pin @@ -125,6 +125,15 @@ */ #define STREAMBUF_SIZE 4096 +#define GET_IO_REF(io_name) \ + do { \ + if ((*env)->IsSameObject(env, sb->ioRef, NULL) || \ + ((io_name) = (*env)->NewLocalRef(env, sb->ioRef)) == NULL) \ + { \ + cinfo->err->error_exit((j_common_ptr) cinfo); \ + } \ + } while (0) \ + /* * Used to signal that no data need be restored from an unpin to a pin. * I.e. the buffer is empty. @@ -159,7 +168,7 @@ } - sb->stream = NULL; + sb->ioRef = NULL; sb->buf = NULL; @@ -191,9 +200,9 @@ * All other state is reset. */ static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb) { - if (sb->stream != NULL) { - (*env)->DeleteGlobalRef(env, sb->stream); - sb->stream = NULL; + if (sb->ioRef != NULL) { + (*env)->DeleteWeakGlobalRef(env, sb->ioRef); + sb->ioRef = NULL; } unpinStreamBuffer(env, sb, NULL); sb->bufferOffset = NO_DATA; @@ -571,7 +580,7 @@ static void imageio_set_stream(JNIEnv *env, j_common_ptr cinfo, imageIODataPtr data, - jobject stream){ + jobject io){ streamBufferPtr sb; sun_jpeg_error_ptr jerr; @@ -579,13 +588,13 @@ resetStreamBuffer(env, sb); // Removes any old stream - /* Now we need a new global reference for the stream */ - if (stream != NULL) { // Fix for 4411955 - sb->stream = (*env)->NewGlobalRef(env, stream); - if (sb->stream == NULL) { + /* Now we need a new weak global reference for the I/O provider */ + if (io != NULL) { // Fix for 4411955 + sb->ioRef = (*env)->NewWeakGlobalRef(env, io); + if (sb->ioRef == NULL) { JNU_ThrowByName(env, "java/lang/OutOfMemoryError", - "Setting Stream"); + "Setting I/O provider"); return; } } @@ -895,6 +904,7 @@ streamBufferPtr sb = &data->streamBuf; JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); int ret; + jobject input = NULL; /* This is where input suspends */ if (sb->suspendable) { @@ -920,9 +930,11 @@ * Now fill a complete buffer, or as much of one as the stream * will give us if we are near the end. */ + GET_IO_REF(input); + RELEASE_ARRAYS(env, data, src->next_input_byte); ret = (*env)->CallIntMethod(env, - sb->stream, + input, JPEGImageReader_readInputDataID, sb->hstreamBuffer, 0, sb->bufferLength); @@ -982,6 +994,7 @@ JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); jint ret; size_t offset, buflen; + jobject input = NULL; /* * The original (jpegdecoder.c) had code here that called @@ -1003,6 +1016,9 @@ if (src->next_input_byte > sb->buf) { memcpy(sb->buf, src->next_input_byte, offset); } + + GET_IO_REF(input); + RELEASE_ARRAYS(env, data, src->next_input_byte); buflen = sb->bufferLength - offset; if (buflen <= 0) { @@ -1012,7 +1028,7 @@ return; } - ret = (*env)->CallIntMethod(env, sb->stream, + ret = (*env)->CallIntMethod(env, input, JPEGImageReader_readInputDataID, sb->hstreamBuffer, offset, buflen); @@ -1075,6 +1091,7 @@ JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); jlong ret; jobject reader; + jobject input = NULL; if (num_bytes < 0) { return; @@ -1104,9 +1121,11 @@ return; } + GET_IO_REF(input); + RELEASE_ARRAYS(env, data, src->next_input_byte); ret = (*env)->CallLongMethod(env, - sb->stream, + input, JPEGImageReader_skipInputBytesID, (jlong) num_bytes); if ((*env)->ExceptionOccurred(env) @@ -2285,11 +2304,14 @@ imageIODataPtr data = (imageIODataPtr) cinfo->client_data; streamBufferPtr sb = &data->streamBuf; JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); + jobject output = NULL; + + GET_IO_REF(output); RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); (*env)->CallVoidMethod(env, - sb->stream, + output, JPEGImageWriter_writeOutputDataID, sb->hstreamBuffer, 0, @@ -2322,11 +2344,16 @@ /* find out how much needs to be written */ /* this conversion from size_t to jint is safe, because the lenght of the buffer is limited by jint */ jint datacount = (jint)(sb->bufferLength - dest->free_in_buffer); + if (datacount != 0) { + jobject output = NULL; + + GET_IO_REF(output); + RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); (*env)->CallVoidMethod(env, - sb->stream, + output, JPEGImageWriter_writeOutputDataID, sb->hstreamBuffer, 0, diff --git a/test/javax/imageio/plugins/jpeg/JpegWriterLeakTest.java b/test/javax/imageio/plugins/jpeg/JpegWriterLeakTest.java new file mode 100644 --- /dev/null +++ openjdk/jdk/test/javax/imageio/plugins/jpeg/JpegWriterLeakTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2013, 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. + */ + +/** + * @test + * @bug 8020983 + * @summary Test verifies that jpeg writer instances are collected + * even if destroy() or reset() methods is not invoked. + * + * @run main JpegWriterLeakTest + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Random; +import javax.imageio.ImageIO; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; + +public class JpegWriterLeakTest { + + public static void main(String[] args) { + final ReferenceQueue<ImageWriter> queue = new ReferenceQueue<>(); + final ArrayList<Reference<? extends ImageWriter>> refs = new ArrayList<>(); + + int count = 2; + + do { + ImageWriter writer = + ImageIO.getImageWritersByFormatName("jpeg").next(); + + final WeakReference<? extends ImageWriter> ref = + new WeakReference<>(writer, queue); + + refs.add(ref); + + + try { + final ImageOutputStream os = + ImageIO.createImageOutputStream(new ByteArrayOutputStream()); + writer.setOutput(os); + + writer.write(getImage()); + + + // NB: dispose() or reset() workarounds the problem. + } catch (IOException e) { + } finally { + writer = null; + } + count--; + } while (count > 0); + + + System.out.println("Wait for GC..."); + + final long testTimeOut = 60000L; + + final long startTime = System.currentTimeMillis(); + + while (!refs.isEmpty()) { + // check for the test timeout + final long now = System.currentTimeMillis(); + + if (now - startTime > testTimeOut) { + System.out.println(); + throw new RuntimeException("Test FAILED."); + } + + System.gc(); + + try { + System.out.print("."); + Thread.sleep(1000); + } catch (InterruptedException e) { + }; + + Reference<? extends ImageWriter> r = queue.poll(); + if (r != null) { + System.out.println("Got reference: " + r); + refs.remove(r); + } + } + System.out.println("Test PASSED."); + } + + private static BufferedImage getImage() { + int width = 2500; + int height = new Random().nextInt(2500) + 1; + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + + Graphics2D g = image.createGraphics(); + g.setColor(Color.blue); + g.fillRect(0, 0, width, height); + + return image; + } +}